**인터셉터 

게시글쓰기, 상세보기, 수정, 삭제 등은 로그인 되어 있지 않은 유저는 작업을 수행할 수 없도록 하고자 하는 경우 이러한 코드를 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>






+ Recent posts