**인터셉터 

게시글쓰기, 상세보기, 수정, 삭제 등은 로그인 되어 있지 않은 유저는 작업을 수행할 수 없도록 하고자 하는 경우 이러한 코드를 Controller, Service, Dao 등에 작성하는 것은 이상합니다.

스프링에서는 Interceptor 나 AOP 등을 이용해서 구현 할 수 있습니다.

Interceptor는 URL을 설정해서 URL 요청이 왔을 때 메소드를 호출하도록 할 수 있습니다.


1. 로그인이 되어 있지 않으면 로그인 페이지로 이동시키고 로그인을 하면 작업을 할 수 있는 페이지로 이동하도록 만들어봅시다. 


=> Interceptor : url 요청이 왔을 때 Controller 보내기 전이나 Controller가 작업한 후에 수행할 내용을 작성할 수 있는 Spring이

제공하는 기능 

=>HandlerInterceptor 인터페이스나 HandlerInterceptorAdapter 클래스를 상속받는 클래스를 만들어서 메소드를 재정의 하고 

dispatcher-servlet(Servlet-Context.xml)에 interceptors 태그를 이용해서 설정하면 됩니다.

=> HandlerInterceptorAdapter인터페이스는 모든 메소드가 추상메소드라서 전부 재정의 해야하고 

HandlerInterceptorAdapter 클래스는 모든 메소드가 내용이 없는 상태로 구현되어 있어서 필요한 메소드만 재정의 하면 되는데 

메소드 이름을 기억하기 어려우므로 인터페이스를 이용합시;다. 



2.HandlerInterceptorAdapter를 implements 한 클래스 안의 재정의 된 메소드 설명 

=> com.seunghoo.na.AuthenticationInerceptor


1. preHandle 메소드 : Controller가 처리하기 전에 호출되는 메소드 


2. postHandle 메소드 : Controller가 사용자의 요청을 정상적으로 처리하고 난 후 호출되는 메소드 


3. afterCompletion메소드 :  Controller에서 예외 발생여부에 상관없이 호출되는 메소드 



3.HandlerInterceptorAdapter를 implements 한 클래스를 생성 

@Component

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

throws Exception {


// 로그인을 확인하기 위해서 session 가져오기

HttpSession session = request.getSession();

// 로그인 정보는 session의 user 속성에 저장되어 있습니다.

if (session.getAttribute("user") == null) {

// 사용자의 요청을 session에 dest라는 속성에 저장

// 로그인이 되면 원래의 요청을 처리하기 위해서

// 클라이언트 요청 전체 주소

String requestURI = request.getRequestURI();

// 현재 프로젝트 경로 가져오기

String contextPath = request.getContextPath();

String uri = requestURI.substring(contextPath.length() + 1);

// 주소 뒤에 파라미터를 가져오기

String query = request.getQueryString();

System.out.println("쿼리"+query);

System.out.println("URI"+uri);

// 실제 주소만들기

if (query == null || query.equals("null")) {

query = "";

} else {

query = "?" + query;

}

//세션에 주소 저장하기 

session.setAttribute("dest", uri+query);

//세션에 메시지 저장하기 

session.setAttribute("msg","로그인을 하셔야 이용할 수 있는 서비스 입니다.");


response.sendRedirect(contextPath + "/user/login");

return false;

}

// 로그인된 경우에는 Controller가 처리합니다.


return true;

}

4. UserController 에서 로그인을 처리하는 메소드를 수정 

=> 이전에는 무조건 시작 페이지로 가도록 되어 있었지만 요청이 있는 경우 그페이지로 이동하도록 코드를 수정 

session.setAttribute("user", user);

//이전 요청을 가져오기 

Object dest = session.getAttribute("dest");

//이전 요청이 없으면 시작페이지로 이동 

if(dest==null) {

return "redirect:/";

//이전 요청이 있으면 그 페이지로 이동 

}else {

return "redirect:/"+dest.toString();

}

**게시물 삭제

1.detail.jsp 파일에 삭제를 위한 UI 와 이벤트를 작성

=>jquery ui의 dialog 기능을 이용

1)삭제 버튼(deletebtn)을 눌렀을 때 수행되는 코드가 있으면 제거


2)파일의 하단에 대화상자로 사용할 내용 만들기

<c:if test="${user.email == vo.email}">

<link rel="stylesheet"

href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">

<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>


<div id="dialog-confirm" title="정말로 삭제?" style="display: none">

<p>삭제하시면 복구할 수 없습니다. 그래도 삭제하실 건가요?</p>

</div>


<script>

//삭제 버튼을 눌렀을 때 처리

document.getElementById("deletebtn").addEventListener(

"click", function(){

$("#dialog-confirm").dialog({

      resizable: false,

      height: "auto",

      width: 400,

      modal: true,

      buttons: {

        "삭제": function() {

          $(this).dialog("close");

          location.href="delete?bno=${vo.bno}";

        },

        "취소": function() {

          $(this).dialog("close");

        }

      }

    });

});

</script>

</c:if>


2.board.xml 파일에 게시글을 삭제하는 SQL을 작성

<!-- 게시글 삭제를 위한 SQL -->

<delete id="delete" parameterType="java.lang.Integer">

delete from springboard

where bno=#{bno}

</delete>


3.BoardDao 클래스에 게시글을 삭제하는 메소드를 생성

//글번호에 해당하는 데이터를 삭제를 하는 메소드

public void delete(int bno) {

sqlSession.delete("board.delete", bno);

}


4.BoardService 인터페이스에 게시글을 삭제하는 메소드를 선언

//게시글 삭제를 처리해 줄 메소드를 선언

public void delete(HttpServletRequest request);


5.BoardServiceImpl 클래스에 게시글을 삭제하는 메소드를 구현

@Override

public void delete(HttpServletRequest request) {

//파라미터 읽기

String bno = request.getParameter("bno");

//Dao 메소드 호출

boardDao.delete(Integer.parseInt(bno));

}


6.Controller 에 게시물 삭제를 처리해주는 메소드 생성 


@RequestMapping(value = "board/delete", method = RequestMethod.GET)

public String delete(HttpServletRequest request, RedirectAttributes attr) {

boardService.delete(request);

attr.addFlashAttribute("msg", "삭제");

return "redirect:list";

}

















 게시글 수정 

상세보기를 작업할 때는 글번호를 가지고 이미 데이터를 찾아오는 방법이 있기 때문에 Service부터작업하면 됩니다.


1. BoardService 인터페이스에 게시글을 가져와서 수정보기에 사용할 메소드스를 선언 

//게시물 수정 보기를 위한 메소드 

public Board updateView(HttpServletRequest request);


2. BoardServiceImpl 클래스에 게시글을 가져와 수정보기에 사용할 메소드를 구현 


@Override

public Board updateView(HttpServletRequest request) {

String bno = request.getParameter("bno");

return boardDao.detail(Integer.parseInt(bno));}

3. BoardController 클래스에 게시글을 가져와서 수정보기 화면에 출력하는 메소드를 구현 

@RequestMapping(value = "board/update", method=RequestMethod.GET)

public String update(HttpServletRequest request ,Model model){

Board board = boardService.detail(request);

model.addAttribute("vo", board);

return "board/update";


}


4.Board디렉토리에 update.jsp 파일을 만들고 수정화면을 작성 

<%@ page language="java" contentType="text/html; charset=UTF-8"

pageEncoding="UTF-8"%>

<%@include file="../include/header.jsp"%>

<section class="content">

<div class="box-header">

<h3 class="box-title">게시판 수정</h3>

</div>


<form role="form" method="post">

<!-- 데이터 수정을 할 때 기본키의 값이 있어야 해서 필요하고

작업이 끝나고 결과 페이지로 이동할 때

상세보기로 이동하려면 글번호가 필요합니다. -->

<input type="hidden" name="bno" value="${vo.bno}" />

<div class="box-body">

<div class="form-group">

<label>제목</label> <input type="text" name='title'

class="form-control" value="${vo.title}">

</div>

<div class="form-group">

<label>내용</label>

<textarea class="form-control" name="content" rows="5">${vo.content}</textarea>

</div>


<div class="form-group">

<label>작성자</label> <input type="text" name="nickname"

value="${user.nickname}" class="form-control" readonly="readonly">

</div>

</div>


<div class="box-footer">

<button type="submit" class="btn btn-primary">작성완료</button>

</div>

</form>

</section>

<%@include file="../include/footer.jsp"%>


5. board.xml 파일에 게시글 수정을 위한 SQL 작성 

<update id="update" parameterType="Board">


update springboard

set

title=#{title}, content=#{content}, regdate=sysdate

where bno=#{bno}


</update>

6. BoardDao 클래스에 게시글 수정을 위한 메소드 생성 

public void update(Board board) {

sqlSession.update("board.update",board);

}


7.게시글 수정을 처리해 줄 메소드를 선언 

public void update(HttpServletRequest request);


8.BoardServiceImpl 클래스에 게시글 수정을 처리해 줄 메소드를 구현 

@Override

public void update(HttpServletRequest request) {

// 파라미터 읽기

// 파라미터를 이용해서 수행할 작업이 있으면 수행

String title = request.getParameter("title");

String content = request.getParameter("content");

String ip = request.getRemoteAddr();

String bno = request.getParameter("bno");


// Dao 메소드를 호출

Board board = new Board();

board.setIp(ip);

board.setContent(content);

board.setTitle(title);

board.setBno(Integer.parseInt(bno));

boardDao.update(board);


}


9. BoardController에서 게시물 수정을 처리해줄 메소드  

@RequestMapping(value = "board/update", method=RequestMethod.POST)

public String update(HttpServletRequest request , RedirectAttributes attr){

boardService.update(request);

attr.addFlashAttribute("msg","게시글 수정");

return "redirect:list";


}

**2개 이상의 테이블이 존재하는 경우 특별한 경우가 아니면 2개의 테이블은 오래키로 연결되어야합니다. 

외래키를 설정하는 방법은 2 테이블 간의 candinality를 파악해야 합니다. 대응 수입니다. (1:1, 1:N, N:N)


1:1관계일 때는 양쪽의 기본키를 상대방 테이블의 외래키로 추가해야합니다. 

1:N 관계 일 때는 1쪽의 기본키를 N쪽의 외래키로 추가해 주저야합니다.

N:N 관계일 때는 양쪽의 기본키를 외래키로 갖는 별도의 테이블을 생성해야 합니다. 


회원테이블           게시글테이블             댓글 테이블 



1명의 회원은 몇개의 게시글을 작성할 수 있는가>? N개의 게시글 작성 가능 

 

1개의 게시글은 몇명의 회원이 작성할 수 있는가> ? 1개의 게시글은 1명의 회원 작성 

회원 (1) : 게시글 (N)



게시글 테이블에 회원 테이블의 기본키인 email을 외래키로 추가해주어야 합니다.


1명의 회원은 몇개의 댓글을  작성할 수 있는가? n개의 댓글 작성가능 N

1개의 댓글은 몇명의 회원이 작성할 수 있는가 ? n개의 댓글 작성가능 1명

댓글 테이블에 회원 테이블의 기본키인 email을 외래키로 추가해주어야합니다. 

회원 (N) : 댓글 (1)



1개의 게시글에 몇개의 댓글을 작성할 수 있는가 > N개 

1개의 댓글은 몇개의 게시글에 작성될 수 있는가 ? 1개 

댓글 테이블에 게시글 테이블의 기본키인 글번호를 외래키로 추가해 주어야합니다.



**게시글 작업 준비

1.게시글 테이블 작성

=>글번호, 글제목, 글내용, 작성한 날짜 및 시간, 작성한 곳의 IP, 조회수, 작성한 사람의 email(springuser 테이블의 email을 참조, 작성한 사람의 nickname을 소유

=>글번호는 기본키, 글제목은 not null, 작성한 날짜는 date이고 기본값은 현재 날짜 및 시간, 조회수의 기본값은 0


--게시글 테이블

create table springboard(

bno number(10) primary key,

title varchar2(100) not null,

content clob,

regdate date default sysdate,

readcnt number(10) default 0,

ip varchar2(100),

email varchar2(100) references springuser(email),

nickname varchar2(100))


2.글번호를 일련번호로 삽입할 수 있도록 sequence를 생성

--sequence 생성

drop sequence boardseq;

create sequence boardseq;


3.springboard 테이블에 수행할 sql을 작성할 mapper 파일을 생성

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE mapper

PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="board">


</mapper>


4.dao 패키지에 springboard 테이블에 대한 작업을 수행할 BoardDao 클래스 생성

package kr.co.pk.dao;


import org.apache.ibatis.session.SqlSession;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Repository;


@Repository

public class BoardDao {

@Autowired

private SqlSession sqlSession;

}

 

5.service 패키지에 BoardService 인터페이스 생성

package kr.co.pk.service;


public interface BoardService {


}


6.service 패키지에 BoardServiceImpl 클래스 생성

package kr.co.pk.service;


import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;


import kr.co.pk.dao.BoardDao;


@Service

public class BoardServiceImpl implements BoardService {

@Autowired

private BoardDao boardDao;

}


7.게시글에 대한 요청을 처리해 줄 BoardController를 생성

package kr.co.pk;


import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;


import kr.co.pk.service.BoardService;


@Controller

public class BoardController {

@Autowired

private BoardService boardService;

}


8. Board Dao 클래스 생성 



package com.seunghoo.na.domain;


import java.sql.Date;


public class Board {


private int bno;

private String title;

private String content;

private Date regdate;

private int readcnt;

private String email;

private String ip;

private String nickname;

public int getBno() {

return bno;

}

public void setBno(int bno) {

this.bno = bno;

}

public String getTitle() {

return title;

}

public void setTitle(String title) {

this.title = title;

}

public String getContent() {

return content;

}

public void setContent(String content) {

this.content = content;

}

public Date getRegdate() {

return regdate;

}

public void setRegdate(Date regdate) {

this.regdate = regdate;

}

public int getReadcnt() {

return readcnt;

}

public void setReadcnt(int readcnt) {

this.readcnt = readcnt;

}

public String getEmail() {

return email;

}

public void setEmail(String email) {

this.email = email;

}

public String getIp() {

return ip;

}

public void setIp(String ip) {

this.ip = ip;

}

public String getNickname() {

return nickname;

}

public void setNickname(String nickname) {

this.nickname = nickname;

}

@Override

public String toString() {

return "board [bno=" + bno + ", title=" + title + ", content=" + content + ", regdate=" + regdate + ", readcnt="

+ readcnt + ", email=" + email + ", ip=" + ip + ", nickname=" + nickname + "]";

}

}



1) home.jsp 파일 링크 





2)header.jsp 파일에 추가 

<li role="presentation"><a href="${pageContext.request.contextPath}/board/register">게시물 쓰기</a></li>




=> home.jsp 파일의 위치는 항상 일정하지만 header.jsp의 URL은 다르게 적용이 됩니다. 

header.jsp 파일은 모든 페이지에 포함되서 출력되기 때문입니다. 

이럴 때는 링크의 경롤르 절대경로로 표시를 해주어야합니다. 



2. 게시글 작성 링크를 눌렀을 때 게시글 작성 페이지로 포워딩하도록 해주는 메소드를 BoardController에 작성 

@RequestMapping(value="board/register", method=RequestMethod.GET)

public String register() {

return "board/register";

}


1. 입력받아야할 내용  ;title,content

2. 전달할 내용 title, content, ip, email, nickname

=>session에 email 과 nickname이 저장되어있습니다.


작업을 할 때는 제일먼저 확인할 때 DB를 사용여부 


4. board.xml 파일에 게시글을 저장하는 sql을 생성 

<!--게시글으 ㄹ저장하는 SQL--> 

 <insert id="register">

 

 insert into springboard(bno, title, content, ip, email, nickname) 

  values(boardseq.nextval, #{title}, #{content}, #{ip}, #{email}, #{nickname})

 </insert>

 </mapper>


 

5.BoardDao 클래스에 메소드를 생성 

public void register(Board board) {

return sqlSession.insert("board.register",board);

}



6. BoardService 인터페이스에 게시글 작성 요청을  처리하는 메소드를 선언 


public void insertreg(HttpServletRequest request);


7. boardServiceImpl클래스에 가서 게시글 작성을 요청을 처리하느 메소드를 구현 


@Override

public void insertreg(HttpServletRequest request) {

//파라미터 읽기 

//파라미터를 이용해서 수행할 작업이 있으면 수행 

//Dao 메소드를 호출해야하는 경우 Dao 메소드의 

//파라미터를 생성 

//Dao 메소드를 호출 

//리턴한 결과를 만들어서 리턴 

}

7-1. boardServiceImpl클래스에 게시글작성 요청을 처리하는 메소드를 구현 


@Override

public void insertreg(HttpServletRequest request) {

//파라미터 읽기 

//파라미터를 이용해서 수행할 작업이 있으면 수행 

String title = request.getParameter("title");

String content =request.getParameter("content");

String ip = request.getRemoteAddr();

//Dao 메소드를 호출해야하는 경우 Dao 메소드의 파라미터를 생성 

HttpSession session = request.getSession();

User user = (User)session.getAttribute("user");

String email = user.getEmail();

String nickname = user.getNickname();

//Dao 메소드를 호출 

Board board = new Board();

board.setEmail(email);

board.setIp(ip);

board.setContent(content);

board.setTitle(title);

board.setNickname(nickname);

boardDao.register(board);


}

8. BoardController 클래스에 게시글 저장 요청이 왔을 때 처리하는 메소드를 생성 

@RequestMapping(value="board/register", method=RequestMethod.POST)

public String register(HttpServletRequest request, RedirectAttributes attr, Model model) {

boardService.insertreg(request);

attr.addFlashAttribute("msg","게시글 작성");

//데이터베이스에 저장하는 작업을 수행했으므로 

//리다이렉트로 이동 

return "redirect:list";

}

]

오라클은 날짜가 년도4자리-월2자리 공백 시간2자리:분2자리:초2자리

java.sql.Date 클래스의 toString은 년도4자리-월2라리-일2자리 


**게시물 전체 목록보기 

1. home.jsp 파일에 게시물 목록보기 링크를 생성 

<div class="box-header with-border">

              <a href="board/list"><h3 class="box-title">게시판 목록보기</h3></a>

 </div>


2)header.jsp 파일에 생성 

<a href="${pageContext.request.contextPath}/board/list">목록보기 </a>




2.board.xml 파일에 SpringBoard 테이블의 전체 데이터를 가져오는 SQL을 생성 

<!--게시글 전체를 가져오는 SQL -->

<select id="getAllList"  resultType="Board">

select bno, title, nickname,regdate,readcnt, email

from springboard

</select>


3. BoardDao 클래스에 게시물 전체를 가져오는 메소드를 생성 


//게시물 전체 목록을 가져오는 메소드 

public List<Board> list(){

return sqlSession.selectList("board.getAllList;

}



4. BoardService 인터페이스에 게시물 전체를 가져오는 메소드를 선언 

//게시물 전체를 가져오는 메소드 

public List<Board> list();


5. BoardServiceImpl 클래스에 게시물 전체를 가져오는 메소드를 구현 


@Override

public List<Board> list() { 

return boardDao.list

}

6.Board 크래스의 regdate의 자료형을  String으로 바꿉니다.



7.boardController 클래스에 게시물전체를 가져오는 요청을 처리할 컨트롤러 메소드 생성 

 @RequestMapping(value="board/register" method="RequestMethod.GET"

 public String list(HttpServletRequest request, Model model ) 

 List<Board> list = boardService.list();

 

 model.addAttribute("list", list);

 return "board/list"

 

 


 

 7.Board 폴더에 list.jsp 파일을 생성후 요청한 내용을 보여줄 뷰 작성 


 

 

 

 <%@ page language="java" contentType="text/html; charset=UTF-8"

pageEncoding="UTF-8"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>목록보기</title>

</head>

<body>

<%@include file="../include/header.jsp"%>

<div class="box">

<div class="box-header with-border">

<c:if test="${msg == null}">

<h3 class="box-title">게시판 목록보기</h3>

</c:if>

<c:if test="${msg != null}">

<h3 class="box-title">${msg}</h3>

</c:if>

</div>

<div class="box-body">

<table class="table table-bordered table-hover">

<tr>

<th width="11%">글번호</th>

<th width="46%">제목</th>

<th width="16%">작성자</th>

<th width="16%">작성일</th>

<th width="11%">조회수</th>

</tr>

<c:forEach var="vo" items="${list }">

<tr>

<td align="right">${vo.bno}&nbsp;</td>

<td>&nbsp; <a href='detail?bno=${vo.bno}'>${vo.title}</a></td>

<td>&nbsp;${vo.nickname}</td>


<td>&nbsp; ${vo.dispDate}</td>

<td align="right"><span class="badge bg-blue">

${vo.readcnt}</span>&nbsp;</td>

</tr>

</c:forEach>

</table>

</div>

<div class="box-footer">

<div class="text-center">

<button id='mainBtn' class="btn-primary">메인으로</button>

</div>


<script>

$(function() {

$('#mainBtn').on("click", function(event) {

location.href = "../";

});

});

</script>

</div>

</div>

<%@include file="../include/footer.jsp"%>

</body>

<style>

.table th {

text-align: center;

}

</style>

</html>






 

1. 위도와 경도 구하기 

<script>

setInterval(function(){

//현재 접속한 브라우저의 위도와 경도 출력하기 

navigator.geolocation.getCurrentPosition(function(position){

alert(position.coords.latitude);

alert(position.coords.longitude);

})

},10000)

</script>



2. ajax를 통한 요청 

<script>

setInterval(function(){

//현재 접속한 브라우저의 위도와 경도 출력하기 

navigator.geolocation.getCurrentPosition(function(position){


loc = position.coords.latitude + "-" +position.coords.longitude

//address라는 URL loc를 파라미터로 넘겨서 

//json 타입으로 데이터를 받아오는 ajax 요청 

$.ajax({

url: "",

data:{"loc":loc},

dataType:'json',

success:function(data){

alert(data);

}

});

});

},10000);

</script>



**카카오 API를 이용해서 위도와 경도를 이용해서 주소를 찾아와서 출력하기 

1. kakaoapi에 가서 api를 이용해서 위도와 경도를 이용해서주소를 찾아와서 출력하기

1.userService 인터페이스에 위도와 경도를 받아서 주소를 리턴하는 메소드를 선언 

public String address(String loc)


2. UserServiceImpl 클래스에 위도와 경도를 받아서 주소를 리턴하는 메소드를 구현 



@Override

public String address(String loc) {

String [] ar  = loc.split("-");

String addr = "https://dapi.kakao.com/v2/local/geo/coord2address.json?";

addr= addr+"x=" +ar[1] +"&y="+ar[0];

//위의 주소를 가지고 URL 객체를 생성 

try {

//위의 주소를 가지고 URL 객체를 생성 

URL url = new URL(addr);

//URL 객체를 가지고 HttpURLConnection 객체 만들기

HttpURLConnection con = (HttpURLConnection)url.openConnection();

//인증부분은 받아야 하면 api에 작성되어있습니다.

//인증받기 

con.setRequestProperty("Authorization", "카카오 api 자리");

//옵션 설정 

con.setConnectTimeout(20000);

con.setUseCaches(false);

//줄단위 데이터 읽기 

BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));

StringBuilder sb = new StringBuilder();

while(true) {

String line =br.readLine();

if(line ==null) {

break;

}

//읽은 데이터가 있으면 sb에추가 

sb.append(line);

}

br.close();

con.disconnect();

 

System.out.println(sb);

JSONObject obj = new JSONObject(sb.toString());

System.out.println(obj);

JSONArray imsi = obj.getJSONArray("documents");

System.out.println(imsi);

JSONObject o = imsi.getJSONObject(0);

System.out.println(o);

JSONObject c = o.getJSONObject("address");

String address= c.getString("address_name");

return address;

}catch (Exception e) {

System.out.println("지도보이기" + e.getMessage());

e.printStackTrace();

}

return null;

}


3. JSONController 클래스에 위도와 경도를 받아서 주소를 JSON 문자열로 출력하는 메소드를 생성 


@RequestMapping(value = "address", method = RequestMethod.GET)

public Map<String, Object> login(String loc) {

Map<String, Object> map = new HashMap<String, Object>();

// 서비스에서 주소를 가져오는 메소드 호출

String address = userService.address(loc);

map.put("address", address);


return map;

}

4.home.jsp 파일에 위도와 경도를 Controller에 넘겨서 주소를 가져와서 출력하는 자바스크립트 코드와 출력 영역을 생성

1)출력 영역 생성

<div class="box-header with-border" id="address">

</div>


2)스크립트 코드 추가

ajax success에 

document.getElementById("address").innerHTML="<h3>" + data.address + "</h3>";









String json = {"meta":{"total_count":1},"documents":

[{"road_address":{"address_name":"서울특별시 중구 세종대로 110","region_1depth_name":"서울","region_2depth_name":"중구","region_3depth_name":"","road_name":"세종대로","underground_yn":"N","main_building_no":"110","sub_building_no":"","building_name":"서울시청","zone_no":"04524"},

"address":{"address_name":"서울 중구 태평로1가 31","region_1depth_name":"서울","region_2depth_name":"중구","region_3depth_name":"태평로1가","mountain_yn":"N","main_address_no":"31","sub_address_no":"","zip_code":"100744"}}]}


JSONObject obj = new JSONObject(json);

JSONArray ar = obj.getJSONArray("documents");

JSONObject ob = ar.getJSONArray(0);

String address =ob.getString("address_name");

**Java에서 JSON 파싱 

1. 의존성 라이브러리 추가 

<!--json 파싱 라이브러리 --> 

<!-- json 파싱 라이브러리 -->

<dependency>

<groupId>org.json</groupId>

<artifactId>json</artifactId>

<version>20171018</version>

</dependency>


2.JSONObject와 JSONArray를 이용해서 문자열을 파싱하면 됩니다. 

1) 문자열을 확인하고 그문자열을 생성자에 대입해서 JSONObject나 JSONArray객체로 만듭니다. 


2) get자료형(키 이름 또는 인덱스)를 이용해서 데이터를 읽어가면 됩니다.



 

1:1 통신이 성공하고 난 후 채팅을 만들 때는 클라이언트가 접속을 하면 각각의 클라이언트를 List에 저장을하고 하나의 클라이언트가 메시지를 보내오면 

그 메시지를 List의 모든 클라이언트에게 전송하는 것입니다.


1. Spring Web Socket을 위한 의존성 

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-websocket</artifactId>

<version>${org.springframework-version}</version>

</dependency>


2. 채팅을 위한 웹 소켓 서버 클래스를 생성 

=> com.seunghoo.na.service.ChatHandler클래스 

=> TextWebSocketHandler을 상속받아야합니다.


package com.seunghoo.na.service;


import java.util.ArrayList;

import java.util.List;


import org.springframework.stereotype.Component;

import org.springframework.web.socket.CloseStatus;

import org.springframework.web.socket.TextMessage;

import org.springframework.web.socket.WebSocketSession;

import org.springframework.web.socket.handler.TextWebSocketHandler;

@Component

public class ChatHandler extends TextWebSocketHandler {

// 접속한 클라이언트 세션들을 저장할 LIST를 생성

// 이 List는 1개만 만들어져야 하므로 static으로 선언

private static List<WebSocketSession> list = new ArrayList<WebSocketSession>();


//클라이언트가 접속 했을 때 호출될 메소드 

//클라이언트가 접속 했을 때 호출되는 메소드 

@Override

public void afterConnectionEstablished(WebSocketSession session) throws Exception {

list.add(session);

System.out.println("하나의 클라이언트가 연결됨 ");

}

//클라이언트가 메시지를 보냈을 때 호출되는 메소드 

@Override

protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {

// 전송된 메시지를 List의 모든 세션에 전송

String msg = message.getPayload();

for (WebSocketSession s : list) {

s.sendMessage(new TextMessage(msg));

}

}


// 클라이언트의 접속이 해제 되었을 때 호출되는 메소드

@Override

public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {

System.out.println("클라이언트와 연결 해제됨");

list.remove(session);

}

}



3. home.jsp 파일에 채팅창으로 이동하는 링크를 추가 

<a href ="chat"> 채팅 </a>


4. HomeController에서 chat 요청이 왔을 때 chat.jsp로 이동하도록 메소드 생성 

@RequestMapping(value = "chat", method = RequestMethod.GET)

public void chat(Locale locale, Model model) {

}


5. ChatHandler클래스를 웹 소켓으로 등록 : Servlet-context.xml 파일 

<websocket:mapping handler="chatHandler" path="/chat-ws"/>

6. views 디렉토리에 채팅페이지(chat.jsp)를 생성

<%@ page language="java" contentType="text/html; charset=UTF-8"

pageEncoding="UTF-8"%>

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>Insert title here</title>

</head>

<body>

<div id="one">

별명:<input type="text" id="nickname" /> <input type="button"

id="enter" value="입장" />

</div>

<div id="two" style="display: none">

<input type="button" id="exit" value="퇴장" /><br />

<div id="chatarea" style="width:400px; height:600px; border:1px solid;"></div>

<input type="text" id="message" /> <input type="button" id="send"

value="보내기" />

</div>


</body>

<script>

one = document.getElementById("one");

two = document.getElementById("two");


document.getElementById("enter").addEventListener("click", function() {

//웹 소켓 연결해주는 함수 호출 

connect();

});


document.getElementById("exit").addEventListener("click", function() {

//연결을 해제해주는 함수 호출 

disconnect();

});

document.getElementById("send").addEventListener("click", function() {

//연결을 해제해주는 함수 호출 

send();

});

var websocket;

//입장 버튼을 눌렀을 때 호출되는 함수 

function connect(){

websocket = new WebSocket("ws://localhost:9000/na/chat-ws");

//웹 소켓에 이벤트가 발생했을 때 호출될 함수 등록 

websocket.onopen = onOpen;

websocket.onmessage = onMessage;

websocket.onclose = onClose;

}

//퇴장 버튼을 눌렀을 때 호출되는 함수 

function disconnect(){

msg = document.getElementById("nickname").value;

websocket.send(msg+"님이 퇴장하셨습니다");

websocket.close();

}

//보내기 버튼을 눌렀을 때 호출될 함수 

function send(){

nickname = document.getElementById("nickname").value;

msg = document.getElementById("message").value;

websocket.send(nickname + ":"+ msg);

document.getElementById("message").value = "";

}

//웹 소켓에 연결되었을 때 호출될 함수 

function onOpen(){

nickname = document.getElementById("nickname").value;

websocket.send(nickname + "님 입장하셨습니다.");

}

//웹 소켓에서 연결이 해제 되었을 때 호출될 함수 

function onMessage(evt){

data= evt.data;

chatarea = document.getElementById("chatarea");

chatarea.innerHTML = data + "<br/>" + chatarea.innerHTML

function onClose(){

}

</script>

</html>



*인코딩 

iso-8859-1(iso-lation-1) 기본 인코딩으로 많이 사용 , 한글지원이 안됨 

euc-kr(ms949, cp949) MS가 한글을 지원하기 위해 만든 인코딩 

utf-8 전 세계 모든 글자를 지원하기 위해 만든 인코딩 

최근에는 전부 utf-8로 인코딩합니다.









[ 1. home.jsp 파일에서 파일목록보기를 하면 c:\에 있는 파일들의 목록을 출력하기 ]



<%@ page language="java" contentType="text/html; charset=UTF-8"

    pageEncoding="UTF-8"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>홈</title>

</head>

<body>

  <a href="fileview.do"> 파일목록보기</a>

</body>

</html>


2. ViewService인터페이스를 implements한  ViewServiceImpl에서 파일이 존재하면 list에 저장하는 메소드를 구현 


package com.naseunghoo.service;


import java.io.File;

import java.util.ArrayList;

import java.util.List;


import org.springframework.stereotype.Service;




@Service

public class ViewServiceImpl implements ViewService {


//배열이나 List를 리턴하는 경우에 받는 쪽에서 거의 대부분 

//반복문을 시용하기 때문에 null을 리턴하면 안됩니다.

//객체 생성을 먼저해서 데이터가 없는 경웨 size 0가 

//되게 리턴해야 합니다.

@Override

public List<String> filelist() {

List<String> list = new ArrayList<String>();

//파일 목록을 조사할 디렉토리를 File객체로 생성 

File f= new File("c:\\");

//디렉토리 안의 모든 파일 및 디렉토리를 가져오기 

String [] ar = f.list();

//배열의 모든 데이터를 순회해서 .이 없는 것들만 list에 추가 

//위치를 찾아주는 메소드는 데이터가 없으면 음수를 리턴하거나 

//예외를 발생시킵니다. 

for(String imsi : ar) { 

if(imsi.indexOf(".")>=0) {

list.add(imsi);

}

}

return list;

}


}



3. 화면에 출력하기 

<%@ page language="java" contentType="text/html; charset=UTF-8"

    pageEncoding="UTF-8"%>

    <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>보여주기</title>

</head>

<body>

<table border="1">

<tr><th>파일명</tr>


<c:forEach var="item" items="${list}">

<tr>

<!-- 파라미터 이름  -->

<td><a href="download/${temp}">${temp}</a></td>

</tr>

</c:forEach>

</table>

</body>

</html>



**Web에서 파일 다운로드 

=> web서버에서 파일의 경로만 a href="파일경로"의 형식으로 링크를 걸면 파일을 다운로드 받을 수 있습니다. 

=> 직접 파일 경로를 설정한 경우에는 브라우저가 출력할 수 있는 파일의 경우 

=> 파일을 다운로드 하지 않고 실행을 시킵니다. 

텍스트 파일이나 이미지 파일의 경우는 화면에 출력됩니다.

=> 브라우저가 출력하지 않고 다운로드 하게 만들려면 파일경로에 Controller가 처리할 수 있는 링크를 만들어주고 Controller에서 다운로드하는 

뷰로 출력하도록 설정하면 됩니다 /.


1. fileview.jsp 파일의파일명을 출력하는 부분에 링크를 설정 

<!-- 파라미터 이름  -->

<td><a href="download?filename=${item}">${item}</a></td>


2. homeController에 위의 요청을 처리하는 메소드를 생성 

@RequestMapping(value="download/{}",method=RequestMethod.GET)

public String download(@PathVariable String filename, Model model){

File f= new File("c:\\ + filenaame");

//데이터 저장 

model.addAttribute("file", f);

//출력할 뷰 이름 리턴 

return "download";

}

3. file 이라는 이름으로 넘어온 파일 객체를 가지고 다운로드 화면을 만들어주는 뷰 클래스 생성 

= com.naseunghoo.view.view.DownloadView - AbstractView를 상속 

=> 화면을 직접 만들고자 할 때 AbstractView를 상속 받습니다.


package com.naseunghoo.view.view;


import java.io.File;

import java.io.FileInputStream;

import java.io.OutputStream;

import java.net.URLEncoder;

import java.util.Map;


import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import org.springframework.util.FileCopyUtils;

import org.springframework.web.servlet.view.AbstractView;


public class DownloadView extends AbstractView {


public DownloadView() {

super();

// 파일의 종류 설정 - 다운로드 받을 수 있도록 설정

setContentType("application/download; charset=utf-8");


}


userAgent 는 유저가 접속하는 브라우져를 알기 위해서 확인 

@Override

//

protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,

HttpServletResponse response) throws Exception {


// Controller에서 넘어온 데이터를 가져오기

// Map에서 데이터를 가져올 때는 반드시 원래의 자료형으로 형변환 해주어야합니다.

// model은 Map의 형태로 자료를 가지고 있고 값은 Object 이기 때문에

// 형변환 해주는 것입니다.

//get의 값은 controller에서 model로 보내는 addAttribute 키값을 적어주면 됩니다.  

File file = (File) model.get("file");

// 응답할 객체의 종류와 크기 설정

response.setContentLength((int) file.length());

response.setContentType(getContentType());


// 접속한 클라이언트의 운영체제 종류와 브라우저 종류를

// 알아 낼 수 있는 헤더 가져오기

String userAgent = request.getHeader("User-Agent");


// 접속한 브라우저가 IE 인지 확인

boolean ie = userAgent.indexOf("rv") > -1;

// 브라우저 별 파일 이름 설정

// 브라우저 별로 한글 인코딩은 다르게 설정됩니다.

// IE와 다른 브라우저로 구분

String filename = "";

if (ie) {

filename = URLEncoder.encode(file.getName(), "utf-8");

} else {

filename = new String(file.getName().getBytes("utf-8"), "iso-8859-1");

}


// 응답 객체에 파일 이름을 설정

response.setHeader("Content-Disposition", "attachment; fulename\"" + filename + "\";");


// 원본 파일의 내용을 읽어서 response를 통해서 전송

OutputStream out = response.getOutputStream();


try (FileInputStream fis = new FileInputStream(file)) {


FileCopyUtils.copy(fis, out);


} catch (Exception e) {

System.out.println("[다운로드] 예외 " + e.getMessage());

e.printStackTrace();

}

}


}



4. servlet-context.xml 파일에 가서 기존 ViewResolver의 우선 순위를 변경하고 beanNameViewResolver를 추가하고 download 뷰 요청이 왔을 때 출력할 뷰를 설정 


1) 출력할 뷰를 설정할 때 기존의 jsp가 아닌 직접 작성한 뷰로 출력할 수 있도록 해주는 

BeanNameViewResolver 클래스의 bean 을 생성 

beanNameViewResolver를 통해 똑같은 아이디의 요청이 있는지 확인하고 처리할 빈을 선택해줍니다.

<beans:bean class="org.springframework.web.servlet.view.BeanNameViewResolver">

<beans:property name="order" value="0"></beans:property>

</beans:bean>


2) 기존 VeiwResolver의 우선 순위를 변경 

<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">

에 아래 프로퍼티를 추가 

<beans:property name="order" value="1"></beans:property>



3) controller에서 download라는 뷰 이름을 넘겨줄 때 출력할 뷰를 직접 설정 

<beans:bean id="download" class="com.naseunghoo.view.view.DownloadView"></beans:bean>









[다른방법] 

1. 파라미터를 읽어서 수행해야할 경우 home.jsp  파일에  download 링크 파일을 수정  filename이라는 파라미터속성 추가 작성 


<td><a href="download?filename=${temp}">${temp}</a></td>



@RequestMapping(value="download",method=RequestMethod.GET)

public String download(@RequestParam("filename") String filename, Model model){

File f= new File("c:\\ + filename");

//데이터 저장 

model.addAttribute("file", f);

//출력할 뷰 이름 리턴 

return "download";

}

beanNameViewResolver를 통해 똑같은 아이디의 요청이 있는지 확인하고 처리할 빈을 선택해줍니다.

JdbcTemplate 클래스


=>Spring JDBC 클래스

=>sql의 매개변수를 Object [] 을 이용해서 매핑하는 클래스



[생성자]

JdbcTemplate(DataSource dataSource)


[select 구문을 수행해주는 메소드]


[select 구문의 결과가 여러 개의 행일 때 사용]


List query(String sql, RowMapper rowMapper)

List query(String sql, Object [] args, RowMapper rowMapper)



[select 구문의 결과가 하나의 행일 때 사용]

Object queryForObject(String sql, RowMapper rowMapper)

Object queryForObject(String sql, Object [] args, RowMapper rowMapper)


[select 구문의 결과가 하나의 행일 때 하나의 Map 에 결과를 저장하고자 하는 경우 사용]

Map<String, Object> queryForMap(String sql)

Map<String, Object> queryForMpa(String sql, Object [] args)


[RowMapper 인터페이스]

=>select 구문의 결과로 반환되는 하나의 행을 객체로 만들기 위한 메소드를 소유한 인터페이스

=>mapRow(ResultSet rs, int rownum) 추상 메소드를 소유

=>rs는 하나의 행을 저장한 객체이고 rownum은 행 번호를 저장한 정수



[JdbcTemplate 클래스를 이용한 테이블의 데이터 읽기]

1.spring-jdbc 라이브러리 다운로드
=>pom.xml 파일에 spring-jdbc 의존성 확인

2.spring 설정 파일(bean configuration 파일 - applicationContext.xml)에 DataSource 빈이 추가되어 있는지 확인




3.샘플 테이블 및 데이터 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
--스쿨버스를 위한 db설계 
-- busnum , name , price , sysdate
 
--시퀀스 생성 
create sequence busnumseq;
 
--테이블 생성 
create table schoolbus(
busnumber number(10primary key,
name varchar2(20not null,
price number(10),
writedate date default sysdate
);
 
--샘플데이터
insert into schoolbus (busnumber, name, price, writedate ) values(busnumseq.nextval, '붕붕카'300, sysdate);
insert into schoolbus (busnumber, name, price, writedate ) values(busnumseq.nextval, '서울카'500, sysdate);
 
--데이터 확인 
select *
from schoolbus;
 
--작업완료 
commit
 
cs


4. JdbcTeplate  클래스의 객체를 소유한 Dao 클래스 생성 dao.schoolbus


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package dao;
 
import java.util.Map;
 
import org.springframework.jdbc.core.JdbcTemplate;
 
public class SchoolBus {
    // Spring JDBC 기본 클래스
    private JdbcTemplate jdbcTemplate;
 
    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }
 
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
 
    // 데이터의 개수를 알려주는 메소드
    public Map<String, Object> count() {
        // 하나의 행만 리턴하는 select 구문 수행
        return jdbcTemplate.queryForMap("select count(*) from schoolbus");
 
    }
}
 
 
cs


5. spring 설정파일에 SchoolBus 객체를 만들기  

1
2
3
4
5
6
7
8
9
10
11
<bean class="org.springframework.jdbc.core.JdbcTemplate" id = "jdbcTemplate">
        <!--  생성자 주입  -->
        <constructor-arg ref= "dataSource"></constructor-arg>
    </bean>
    
    
    <!-- school 클래스의 객체를 생성 IOC -->
    <bean class ="dao.SchoolBus" id="shcoolbus">
    <!-- jdbcTemplate이라는  id를 가진 bean을 jdbcTemplate 이라는 프로퍼티에 주입 :DI  -->
    <property name="jdbcTemplate" ref ="jdbcTemplate"></property>
    </bean>
cs


6.main 메소드를 소유한 Main 클래스를 만들고 main 메소드 실행


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import org.springframework.context.support.GenericXmlApplicationContext;
 
import dao.SchoolBus;
 
public class Main {
 
    public static void main(String[] args) {
        GenericXmlApplicationContext context = 
            new GenericXmlApplicationContext(
                            "classpath:applicationContext.xml");
        SchoolBus bus = context.getBean(SchoolBus.class);
        //select 절에 쓴 내용을 적기 
        System.out.println(bus.count().get("COUNT(*)"));
    }
 
}
 
cs



+ Recent posts