1. pom.xml

 

 

2. web.xml

- servlet-mapping (url-pattern : *.do)

- servlet-context.xml, root-context.xml

- CharacterEncodingFilter

3. servlet-context.xml

- base-package 지정 (com.ch.webSock)

- ViewResolver : prefix, suffix

- 웹 소켓 기능을 처리하기 위한 클래스 경로 매핑

chat-ws.do 값을 요청했을 때, webChatHandler bean 객체가 동작한다.

 

4. root-context.xml, configuration.xml, mapper.xml

- DB 연동을 하지 않기 때문에 현재는 비어있다.

크롬과 익스플로러를 켜서 실행시켜보았다.

 

index 파일을 실행한다.

chat.do 값을 찾아 컨트롤러로 이동한다.

메소드에 별다른 내용이 없어서 바로 뷰 페이지로 이동한다.

 

 

 

뷰 페이지 chat.jsp

head 영역에 여러 함수들이 정의되어 있고,

body 태그에는 채팅을 하기 위한 최소한의 기능인

닉네임 설정 양식과 채팅방 입장, 채팅 입력 양식과 채팅창, 퇴장 기능이 설정되어 있다.

 

각 버튼의 id값은 enterBtn, exitBtn, sendBtn 인데,

이 id값을 가진 버튼에 클릭 이벤트가 발생했을 때, 함수가 실행되도록 설정된 구조다.

현재, 대화영역의 입력 양식의 id 값은 message로 지정되어 있다.

 

이 message 입력 양식에 keypress 이벤트가 발생하면 함수가 실행되는데,

만약 enter키를 누르면 send() 메소드를 실행시키는 함수이다.

keycode == 13 이 enter 키 입력이다. (아스키 코드)

 

또, 입력 양식 옆의 전송 버튼을 클릭 해도 send() 메소드를 실행하여

메시지가 전송된다.

 
 

[입장] 버튼을 클릭하면 connect 함수를 호출한다.

 

생성자에 들어간 url 값은 servlet-context.xml 의 핸들러 클래스를 동작시키기 위한 것이다.

핸들러 클래스 WebChatHandler가 실행된다.

afterConnectionEstablished : 입장

afterConnectionClosed : 퇴장

handleTextMessage : 채팅

 
 
 

입장 메소드를 실행하고 다시 chat.jsp로 돌아간다.

chat-ws.do 값 요청에 따른 핸들러 동작이 이루어지고 난 이후로는

onopen 함수와 onMessage 함수가 차례대로 실행된다.

 
 

메시지를 입력하고 [메시지 전송] 을 클릭하면 클릭 이벤트가 발생하여 (또는 엔터 키 이벤트 발생)

send 메소드를 호출한다.

nickName 변수에 닉네임 값을 구해와 저장하고,

msg 변수에 메시지 값을 구해와 저장한다.

 
 

nickName과 msg 값을 매개로 채팅에 필요한 핸들러 메소드를 동작시킨다.

 

[퇴장] 버튼을 누른 유저만 채팅 그룹에서 빠진다.

 
 

 

[수정] 버튼을 누르면 댓글본문이 textarea로 변경되면서 수정이 가능하도록 변경되고,

[수정] -> [확인] 으로 변경된다.

[확인]을 누르면 수정한 댓글 내용이 DB에 즉각 반영되어 새로운 내용의 댓글을 출력하고,

[취소]를 누르면 textarea가 아닌 원래의 댓글 내용으로 다시 돌아간다.

 

[삭제]를 누르면 별도의 alert 창 없이 곧바로 delete SQL문을 실행한다.

 

 

 

 

댓글 관련 뷰 페이지는 slist.jsp 하나로 처리하고 있다.

body 영역에는 컨트롤러에서 넘겨받은 객체를 가지고 출력하는 내용이 있고,

head 영역에서 [수정], [확인], [취소], [삭제] 버튼 클릭 시 실행할 내용이 있다.

 

 

루프를 돌려 데이터를 꺼내와 하나씩 출력하는데,

각각의 데이터는 ${rb.rno} 값으로 어떤 데이터인지 구분한다.

그래서 이 값은 모든 버튼에 id 값으로 들어가게 된다.

 

 

 

1. [수정] 버튼을 눌렀을 때

 

모든 수정 버튼은 id로 부여된 rb.rno를 통하여 데이터와 매핑이 되어 있고,

class 값은 edit1으로 고정되어 있다.

 

이 edit1을 클릭하면, 이벤트가 발생한다.

 

 

1) 내용을 textarea로 변경, 수정 가능한 상태로 변경

 

this -> 여러개의 수정 버튼 중에서 사용자가 선택해 이벤트를 발생시킨 수정 버튼을 구해온다.

            수정 버튼은 id로 지정된 rb.rno 값으로 각 객체를 구분한다. 

text 함수로 id가 td사이에 있는 텍스트를 구해온다. (댓글 내용 rb.replytext)

그리고 html 함수로 id=td 자리에 rows값이 3이고 cols값이 30, id값이 tt_td_${rb.rno} 인 textarea를 출력시킨다.

 

2) 수정, 삭제 -> 확인, 취소 버튼으로 변경

수정과 삭제 버튼은 id값이 "btn_${rb.rno}" 인 td 태그 사이에 있다.

 

head 영역에서는

html 함수를 사용하여 그런 id 값을 가진 버튼을 확인, 취소 버튼으로 바꾸어주고 있다.

 

3) 확인 버튼

수정한 내용이 바로 DB에 반영되고 slist와 부모글번호를 다시 호출하여 댓글 목록을 보여준다.

확인 버튼을 누르면 id값인 btn_${rb.rno} 값을 매개로 up함수를 호출한다.

 

up 함수는 textarea의 값을 가져와 replytext 변수에 저장한다.

그리고 댓글의 rno값, replytext, 부모글 bno값을 formData에 저장한다.

이후 post 함수로 ${path}/repUpdate 값으로 컨트롤러에 이 요청을 전송하여

DB에 수정된 댓글 내용을 저장한 후 이 내용을 뷰 페이지의 slist 영역에 출력한다.

 

 

 

 

4) 취소 버튼

취소 버튼을 누르면 lst 함수를 호출한다. 이 함수 호출은 매개변수를 필요로 하지 않는다.

수정 내용을 db에 반영하지는 않지만

기존 db의 내용을 다시 불러와 div 영역에 출력시키므로 컨트롤러에 값을 전송하는 내용이다.

 

 

 

5) 삭제 버튼

클릭 이벤트로 del 함수를 불러오는데, rno와 bno 값을 매개로 실행된다.

post함수로 formData 값과 (rno, bno), ${path}/repDelete 요청을 전송한다.

rno 값을 매개로 delete SQL을 실행하는 메소드를 호출한다.

메소드가 실행되면 redirect로 slist/num/ 뷰 페이지에 가는데, 부모글 bno 값을 함께 전송하여

부모글 컬럼 bno에 같은 값을 가진 모든 데이터를 함께 출력한다.

 

 

 

초기 환경설정 (웬만하면 순서대로)

1) pom.xml

2) web.xml

 - DispatcherServlet, servlet-mapping (url-pattern)

 - servlet-context.xml, root-context.xml

 - CharacterEncodingFilter

3) servlet-context.xml

 - base-package

   .java 파일을 저장할 곳의 최상위 폴더

   @Controller, @Autowired(@Inject), @Service, @Repository 어노테이션 문서를 찾는다.

 - ViewResolver beans (prefix, suffix)

4) configuration.xml (mybatis-config.xml)

 - typeAlias : DTO 클래스

5) mapper.xml

 - namespace 지정

6) root-context.xml

 - dataSource : DB 연동 드라이버, url, 계정

 - sqlSessionFactory : dataSource, configuration.xml, mapper.xml

 - SqlSessionTemplate

 

 

 

여태까지 만든 게시판과 다른 점

1) 게시판 페이징 처리

 - service 패키지에 위치한다.

2) 글쓰기 폼과 답글 폼을 분리하지 않았으나 MVC 파일을 분리함

 - replyForm.jsp, reply.jsp 는 없고, insert.jsp, insertForm.jsp에서 답글과 원문 글쓰기 모두를 처리한다.

 - Controller, DAO, DTO, service, mapper가 분리되어 있다.

 

 

3) 분리된 DB 테이블

 - 게시판 테이블 / 댓글 테이블이 분리되어 있다.

   (게시판 테이블은 (board1 프로젝트에서 사용했던 테이블을 그대로 사용)

 - replyboard 테이블의 bno 컬럼에 board 테이블의 num 컬럼을 연결하는 외래키 설정

 - on delete cascade 제약조건을 설정하여

   부모 테이블의 num 데이터가 삭제되면 자식 테이블의 bno 데이터를 함께 삭제한다.

 

 

 

이전 프로젝트의 테이블을 그대로 사용하고 있으므로

index.jsp를 실행하면 글 목록이 그대로 나타난다.

상세 페이지를 누르면 그제서야 달라진 점이 보인다.

 

 

 

 

index.jsp를 실행하면 어노테이션 값을 찾아 컨트롤러로 이동한다.

web.xml에서 어노테이션 설정을 *.do가 아닌 초기값 / 그대로 두었기 때문에

값을 받는 형태가 조금 달라져있다.

 

 

 

list.jsp에 가면

계속해서 ${path} 가 따라다니는데, 프로젝트 명인 sboard이다.

 

 

 

페이지 처리를 위한 컨트롤러 메소드.

처음보는 어노테이션이 등장했는데

@PathVariable (주소값 형태-path- 로 받아옴) 는 @RequestParam (여러 자료형으로 받아옴)과 비슷하게

jsp에서 전달한 값을 받는 어노테이션이다.

 

 

 

 

간단했던 이전 프로젝트의 view.jsp 파일과 달리

새로운 기능인 댓글이 등장했으므로 조금 더 복잡해졌다.

ajax를 활용해 비동기적으로 처리하고 있다.

댓글을 달면 페이지가 바뀌는 것이 아니라 페이지 하단에 즉각 출력된다.

빨간색 영역은 기존의 board1 테이블이 아닌 replyboard 테이블로 DB가 연결된다.

 

 

 

 

 

rno : 값을 넘기면 컨트롤러에서 값을 증가하는 SQL문을 호출한다.

bno : 참조키이므로 부모 테이블에서 값을 받아온다.

replytext : textarea에서 입력한 내용이 전달된다.

replyer : 현재는 부모글의 작성자 이름으로 댓글이 작성되도록 설정했다.

 

지금은 예제 파일이라 다소 엉성하지만 추후 제대로 된 게시판을 만들게 되면

회원 관리 프로그램과 연동하여 사용할 수 있을 것 같다.

 

 

댓글 입력 양식은 폼태그로 감싸져 있다.

동기적으로 처리할 때에는 (페이지를 변경해서 값을 넘길 때에는) action 값을 넣는데,

이건 비동기적 처리 방식이므로 action 값이 지정되어 있지 않다.

현재는 부모글의 작성자 이름으로 댓글이 작성되도록 설정됐기 때문에

hidden 객체로 board.wirter, board.num 값을 넘기도록 되어 있다. (부모글의 정보)

 

 

댓글창에 내용을 입력하고 확인을 누르는 순간 head 영역에 작성된 함수가 호출된다.

 

이 함수는 id가 repInsert인 버튼을 클릭하는 순간 클릭 이벤트가 발생하며, 

그 이전에 load 함수가 먼저 동작한다.

요청값인 '${path}/slist/num/${board.num} 은, slist의 num 변수에 부모글의 정보 board.num 을 전달하는 내용이다.

정보를 전달하고 나면 가장 먼저 조건문으로 댓글창에 내용이 없을 경우 alert 메시지를 띄우고 있고,

만일 조건을 만족하지 않으면 (댓글창에 내용이 있다면)

 

 

 

 

상단의 $('#slist').load('${path}/slist/num/${board.num}') 코드를 내가 알고 있는 형태로 변경하면
load('slist?num=${board.num}') 이다.

 

 

 

load 함수의 요청값은 컨트롤러로 이동한다.

댓글 관련 내용은 본문과 따로 파일이 작성되어 있다.

(컨트롤러, DAO, DTO, 서비스, 매퍼, DB테이블)

 

"/slist/num/{num}" 에서 {num} 은 view페이지에서 board.num 으로 전송한 값이다.

즉, 부모글의 정보인 번호값 이다.

 

이 부모글 num 을 매개변수로 부모글의 정보를 구해와서 DTO 객체 board에 저장한다.

이 num 데이터는 게시판 테이블, 댓글 테이블의 공통 테이블이므로

댓글 목록을 구해오는 메소드 list를 호출하는 매개변수로 쓰인다.

 

 

구해온 값은 slist 라는 이름의 리스트 객체에 저장하여 model 객체로 공유 설정되어

뷰페이지 slist로 이동한다.

 

body 영역에는 forEach로 루프를 돌려서 리스트에 담긴 데이터를 하나씩 꺼내오는 내용이 작성되어 있다.

items로 설정된 ${slist}는 컨트롤러에서 구해와 뷰 페이지까지 전달된 리스트 객체의 이름이다.

 

 

 

수정, 삭제 버튼은 비동기 형식으로 역시 즉각 실행된다.

 

 

 

 

다시 view.jsp 로 돌아가서,

클릭 이벤트의 내용을 살펴본다.

 

만약 textarea가 비어있으면 확인 버튼을 눌렀을 때 alert 창이 뜨게 되어 있다.

 

댓글이 작성되어 있을 때에는 if 문 아래쪽의 내용이 실행된다.

 

댓글 작성 폼에서 넘어가는 값은 총 세 가지 이다.

board.wirter, board.num, 그리고 replytext

이 세 가지 값을 비동기적으로 처리하는 내용이 var frmData 부터 시작하는 단락이다.

 

주석으로 처리한 내용을 축약한 것이 serealize 함수이다.

form 태그 안에 있는 내용을 한꺼번에 구해오는 시리얼라이즈 함수로 한꺼번에 구해온다.

 

 

sInsert 값을 가진 어노테이션을 찾아간다.

 

ReplyBoard 객체 rb 값을 매개로 댓글 insert SQL문을 호출한다.

 

이전에 보지못한 형태의 selectKey 라는 것이 있다.

 

keyProperty : selectKey 괄호 안의 SQL문을 실행한 내용을 담을 변수

order : selectKey를 수행할 순서

           (Before라고 적혀 있으니 insert SQL 실행 이전에 selectKey SQL문을 먼저 실행)

resultType : 돌려줄 자료형

 

selectKey SQL문은 replyBoard 테이블의 rno컬럼의 최대값에 +1을 한 결과를 출력하도록 되어 있다.

여기에서 구한 결과를 rno 변수에 저장하여

insert SQL문을 실행할 때, rno 자리에 #{rno} 를 적어주면 selectKey의 결과값인 rno가 들어가게 된다. 

 

각각의 id를 부여한 SQL문으로 따로 처리할 수도 있지만,

selectKey를 사용하여 한꺼번에 처리할 수도 있다.

 

이렇게 insert문을 실행하고 나서 redirect:slist/num/ 값을 받아 댓글 목록 출력을 계속 유지하게 되는데,

부모글에 대한 정보를 다시 한번 불러온다.

그러면 부모글 컬럼에 같은 값을 가진 댓글 데이터들을 브라우저에 모두 출력하게 된다.

 

 

다시 view페이지로 돌아가면, 

위 sInsert 어노테이션에서 처리한 내용을 slist라는 아이디값을 가진 div 영역에 출력하는 내용이 작성되어 있다.

그리고 replytext의 값은 초기화된다.

 

댓글 폼에 내용을 작성하고 확인을 누르면 위와 같은 과정을 거쳐

새로운 댓글이 화면에 출력되고, 댓글 창의 내용은 지워지게 되는 것이다.

 

이 모든 것들이 페이지를 바꾸지 않고 비동기적으로 처리된다.

 

 

 

상세 페이지

 

list.do 페이지에서 view.do 요청을 받으면 String view 메소드를 찾아온다.

이 때, num, pageNum 두 가지 값을 가지고 온다.

 

 

이 메소드에서는 조회수를 1 증가시키는 selectUpdate 메소드를 호출하고,

글의 상세 정보를 DTO 객체에 담아오는 select 메소드를 호출하여 model 객체로 공유하여 view 페이지로 전달한다.

 

 

 

수정

 

num값과 pageNum 값을 가지고 updateForm.do 어노테이션을 찾아간다.

 

 

 

 

가지고 온 num 값을 매개로 select SQL문으로 특정 글에 대한 정보를 담아 DTO 객체 board에 담는다.

수정 폼 실행시 입력 양식에 기존 작성한 글의 내용을 출력해야 하기 때문이다.

이후로 board 객체와 상세 페이지에서 가지고 온 pageNum을 가지고 updateForm.jsp로 이동한다.

 

 

 

 

db에 저장된 값을 board객체에 담아왔기 때문에

뷰 페이지에서 비밀번호 검증이 가능하다.

 

 

 

 

 

폼 태그의 name 값이 frm으로 설정되어 있고

onsubmit 이벤트 핸들러를 추가하여 submit 실행 시 함수를 불러오는 역할을 하고 있다.

hidden 객체는 함수 실행시 전달되는 객체이므로 비밀번호를 함수에 전달할 수 있다.

 

board 객체에서 추출한 비밀번호는 name=passwd 인데,

수정폼의 비밀번호 입력양식은 name=passwd2 인것을 확인할 수 있다.

 

 

 

 

 

비밀번호 검증이 완료되면 update.do 값을 찾아 컨트롤러로 이동한다.

 

이미 뷰페이지에서 비밀번호 검증을 했기 때문에 메소드 내용이 그리 많지는 않다.

update SQL문 실행 메소드를 호출하고, 그 결과를 result 변수에 담는다.

이 result 변수와 pageNum 변수를 update 뷰 페이지로 전송한다.

 

 

 

 

 

 

 

 

삭제

글의 num값과 글목록의 정보인 pageNum값을 가지고 deleteForm.do를 찾아 컨트롤러로 간다.

 

 

 

글의 상세정보를 구해오는 메소드를 호출해 정보를 DTO 객체 board에 담아

deleteForm.jsp 뷰 페이지로 이동하는 내용이 전부다.

 

 

 

 

수정폼과 마찬가지로 비번 비교를 뷰페이지에서 바로 실행한다.

비밀번호 비교만 하면 되는 페이지라 다른 뷰 페이지에 비해 내용이 단촐하다.

pageNum과 num 값은 계속 가지고 움직이다.

글 삭제가 실행되면 pageNum 값을 사용해 진입했던 페이지로 이동해야 하기 때문이고,

num 값으로 db에서 특정 데이터를 찾아 그 데이터를 대상으로 SQL문을 실행하기 때문이다.

 

delete.do 값을 찾아 컨트롤러로 이동한다.

 

 

 

어노테이션 값과 메소드 이름은 delete 이지만

실행하는 SQL문은 update 이다.

 

원문이나 답글을 작성할 때 del 컬럼에 들어가는 기본값 'n'을 'y'로 수정하는 내용이 담겨 있다.

 

 

삭제가 실행되면 del컬럼의 값이 바뀌고

뷰 페이지에서는 삭제 메시지와 함께 링크가 사라진다.

 

 

 

 

 

원문 작성

 

 

BoardController.java

 

 

답변글이 전송하는 값에 insertForm.do와 함께 nm 이라는 변수가 등장하는데,

글 입력 버튼을 누르면 insertForm.do 값만 컨트롤러에 전송한다.

 

nm = null 원문 작성으로 간주한다.

nm != null 일 경우, 다시 말해 nm에 저장된 값이 있을 경우 답글 작성으로 간주한다.

 

하나의 폼으로 원문, 답변글의 경우가 다르므로 이 nm을 기준으로 조건문을 작성해

원문/답글을 구분하여 각각 다른 내용을 실행한다.

 

게시판 목록의 글 작성이 전송하는 값인 insertForm 값에

nm 변수값을 추가 전송한다. (잘렸는데 pageNum 값도 함께 전송한다.)

 

 

이 nm 값으로 조건문을 작성하여 답변글과 원문글 작성을 나눈다.

 

원문의 경우 if문은 실행되지 않고 바로 model 객체로 값을 공유하고 뷰 페이지를 실행한다.

 

 

 

 

 

insertForm.jsp

 

특별한 내용은 없다.

컨트롤러에서 넘어온 5가지 값 (num, ref, re_step, re_level, pageNum),

입력양식의 4가지 값 (subject, writer, email, passwd) 과 함께

insert.do 값을 컨트롤러에 전송한다.

 

 

 

 

BoardController.java

insertForm.jsp에서 가져온 9가지 값들을 DTO 객체 board에 저장하는데, 

이 중 DTO객체 board의 num값을 int형 변수 num에 할당한다.

 

getMaxNum은 num값 중 최대값, 즉 가장 최신글의 num 값을 구해오는 메소드이다.

서비스와 DAO를 거쳐 mapper에 도달하면 다음과 같은 SQL문을 실행하도록 되어 있다.

만약 가장 처음으로 글을 작성하면

데이터가 아무것도 없는 null 상태이기 때문에 nvl을 사용한다.

그렇게 숫자형으로 변환한 값에 +1 을 하여 int 형 값을 반환하도록 되어 있다.

( 생성하지 않은 시퀀스의 역할을 한다.)

 

이렇게 컨트롤러로 구해온 값을 int형 number 변수에 저장한다.

 

답변과 원문의 경우로 나누어 if문을 실행한다. (else)

 

 

이렇게 실행한 내용을 board 객체에 저장하고,

board를 매개로 insert SQL을 호출하여 반환받은 int형 값을 result 변수에 저장한다.

 

 

result 를 model 객체에 저장하여 뷰 페이지 insert를 실행한다.

 

 

입력에 성공한다면 다시 list.do를 컨트롤러에 요청한다.

 

 

글 목록 출력

 

 

1) 상수 rowPerPage 에 10이라는 값을 부여한다.

 

2) 원문 작성에 대한 내용을 작성하며 pageNum 값을 설정한 적이 없다.

null에 해당되므로 pageNum값으로 1을 부여받는다.

이 값을 형변환 하여 int currentPage에 저장한다.

 

 

검색 결과 글 목록 출력

 

subcon은 select 객체의 name값이다.

(제목+내용, subject + content = subcon)

 

keyword != null if 문에서의 ${search} 값에는 subject, content, writer 값 셋 중 하나가 들어온다.

(search는 select 양식의 name값)

가변적인 값이므로 ${ } 를 사용한다. ( #{ }는 고정값)

 

 

동적 SQL

더보기


MyBatis 의 가장 강력한 기능 중 하나는 동적 SQL 기능이다. 

  • if - where 의 일부로 포함될 수 있다.
  • choose (when, otherwise) - if-else 또는 자바의 switch 구문과 유사하다
  • trim (where, set)
  • foreach

 

 

 

 

페이징 처리

 

 

 

 

 

글 목록 구해오기

 

검색을 먼저하고 정렬은 나중에 한다.

 

 

 

 

list.do를 받는 String list 의 전체 코드

 

 

 

뷰 페이지 list.jsp 가 조금 복잡하다.

경우의 수가 많아 조건문을 많이 사용했다.

 

total 변수에 저장된 전체 데이터 개수의 값이 다르기 때문에

검색했을경우목록 / 전체목록의 페이징 처리는 각각 작성해야 한다.

 

 

 

 

답글 작성

글 입력 버튼과 같은 insertForm.do값을 전송하지만,

.do 값만 가지고 가는 글 입력 버튼과 다르게

답글 작성 버튼은 nm값과 pageNum값을 함께 가지고 간다.

 

 

 

 

컨트롤러로 값을 가지고 오면

nm != null 을 만족하는 if문을 실행하여 답글 메소드를 호출하여

글 정보를 DTO 객체 board에 담는다.

 

 

 

 

model 객체로 공유된 값과 함께 insertForm.jsp로 넘어가면

컨트롤러에서 넘어온 5가지 값 (num, ref, re_step, re_level, pageNum),

입력양식의 4가지 값 (subject, writer, email, passwd) 과 함께

insert.do 값을 컨트롤러에 전송한다.

 

원문 작성 때에는 5가지 값에 0이 담겨져왔고 그대로 0이 다시 나갔지만,

답글 작성의 경우에는 기존에 가지고 왔던 값을 가지고 컨트롤러의 insert.do 로 나간다. 

 

 

 

 

insertForm에서 가져온 글 번호를 int num에 저장하고,

DB에서 num 컬럼의 최대값을 구해서 1 증가 시키는 메소드를 호출하여 int number에 저장하는 것은 같다.

 

이후로는 조건문의 num != 0 이 true이므로 첫번째 블럭의 내용을 실행하고

118줄의 board.setNum(number); 부터 실행한다.

(else 문에 블럭 괄호가 없으므로 else 바로 아래의 한 줄만 적용)

 

 

bs.updateRe(board); 를 따라 mapper 파일에 가면 다음과 같은 SQL문이 작성되어 있다.

 

 

 

board.setRe_level(board.getRe_level()+1); 에서는

기존 re_level값에 1을 증가시킨다. re_step도 마찬가지로 1이 증가된다.

 

이후 board.setNum(number); 아래로는 원문, 답글 모두 실행하는 내용이다.

그리고 insert 뷰 페이지로 보낸다.

 

 

입력에 성공한다면 다시 list.do를 컨트롤러에 요청한다.

초기 환경설정 (웬만하면 순서대로)

1) pom.xml

2) web.xml

 - DispatcherServlet, servlet-mapping (url-pattern)

 - servlet-context.xml, root-context.xml

 - CharacterEncodingFilter

3) servlet-context.xml

 - base-package

   .java 파일을 저장할 곳의 최상위 폴더

   @Controller, @Autowired(@Inject), @Service, @Repository 어노테이션 문서를 찾는다.

 - ViewResolver beans (prefix, suffix)

4) configuration.xml (mybatis-config.xml)

 - typeAlias : DTO 클래스

5) mapper.xml

 - namespace 지정

6) root-context.xml

 - dataSource : DB 연동 드라이버, url, 계정

 - sqlSessionFactory : dataSource, configuration.xml, mapper.xml

 - SqlSessionTemplate

 

 

 

여태까지 만든 게시판과 다른 점

1) 게시판 페이징 처리

 - service 패키지에 위치한다.

2) 글쓰기 폼과 답글 폼을 분리하지 않음

 - replyForm.jsp, reply.jsp 는 없고, insert.jsp, insertForm.jsp에서 답글과 원문 글쓰기 모두를 처리한다.

3) 검색 기능을 위한 동적 SQL문 사용

 - mapper 파일에 여태 본적 없는 형태의 SQL문이 들어가 있는데, 추후 다시 살펴본다.

4) context-root 에 메일 전송을 위한 DB설정

 

 

 

 

 

DB 테이블 생성

글쓰기 폼과 답글 폼을 분리하지 않았기 때문에

시퀀스를 생성하지 않는다.

 

마지막의 del 컬럼에는 Y/N 값만 들어간다.

글을 삭제하면 delete문이 아닌 update문으로 del 컬럼의 값이 변경된다.

처음 글을 써서 insert문을 실행할 때에는 del 컬럼에 기본값으로 n 값이 들어가도록 설정한다.

 

 

 

 

게시판 기능 살펴보기

index 를 실행하고, 글을 몇 개 작성했다.

 

글쓰기 폼과 답변 쓰기 폼은 같지만

차이점은 부모글의 번호와 페이지 값을 함께 가지고 움직인다는 점이다.

 

 

 

글을 삭제하면 delete문 대신 update문으로 delete컬럼의 값을 변경한다.

이 변경된 delete 컬럼의 값에 따라

제목, 작성자, 작성일, 조회수를 출력 형태를 변경하고 링크를 해제한다.

 

del 컬럼의 값을 변경하면 다시 원상복구 된다.

 

 

 

 

검색 기능을 활용해본다.

 

제목, 내용, 작성자, 제목+내용으로 검색 옵션을 설정할 수 있는데

키워드를 넣고 검색을 하면 SQL문이 실행되고 결과에 따라 목록을 출력한다.

 

전체 글 목록과 검색 결과를 같은 문서에 작성하여 따로 표시되도록 해야 한다.

 

 

 

 

DTO 클래스는 기본적으로 DB 컬럼과 같은 이름의 프로퍼티와 getter-setter 메소드로 구성되어 있으나,

페이징 기능을 위한 프로퍼티와 검색 기능을 위한 프로퍼티가 함께 생성되어 있다.

 

search는 select 양식의 name값, keyword는 입력 양식의 name 값이다.

 

 

 

 

페이징 처리를 위한 DTO 클래스 PagingPgm.java

 

 

Mail Server

Windows : Exchange Server

Linux : SendMail, Qmail

 

Mail Server Protocol

송신 : SMTP (Simple Mail Transfer Protocol) - 25

수신 : POP3 (Post Office Protocol 3) - 110

 

 

 

 

네이버 메일 통해 실습을 해본다.

 

환경설정 > POP/IMAP 설정 > POP3/STMP 사용 으로 설정

 

 

 

 

 

예제 프로젝트를 import 했다.

 

에러 표시는 프로젝트 폴더 내의 의존 라이브러리를 다운 받으면 사라진다.

 

 

 

 

 

pom.xml  >  web.xml  >  servlet-context.xml  >  configuration.xml  > 

servlet-context.xml  > mapper.xml  >  root-context.xml

 

 

 

pom.xml

 

이 프로젝트에는 email 전송에 필요한 의존 라이브러리가 들어있다.

 

 

 

 

 

Controller.java

 

package controller;

import java.util.Random;

import org.apache.commons.mail.HtmlEmail;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class MailTest {

	@RequestMapping("/send.do")
	public String send(Model model) {

		Random random = new Random();
		int a = random.nextInt(100);

		// Mail Server 설정
		String charSet = "utf-8";
		String hostSMTP = "smtp.naver.com";
		String hostSMTPid = "@naver.com";	// 메일주소 입력
		String hostSMTPpwd = ""; 		// 로그인 비밀번호 입력

		// 보내는 사람 EMail, 제목, 내용
		String fromEmail = "@naver.com";
		String fromName = "추워요";
		String subject = "감기 조심하세요";

		// 받는 사람 E-Mail 주소
		String mail = "@naver.com";

		try {
			HtmlEmail email = new HtmlEmail();
			email.setDebug(true);
			email.setCharset(charSet);
			email.setSSL(true);
			email.setHostName(hostSMTP);
			email.setSmtpPort(25 또는 465 또는 587);

			email.setAuthentication(hostSMTPid, hostSMTPpwd);
			email.setTLS(true);
			email.addTo(mail, charSet);
			email.setFrom(fromEmail, fromName, charSet);
			email.setSubject(subject);
			email.setHtmlMsg("<p align = 'center'>Overflow에 오신것을 환영합니다.</p><br>" 
							 + "<div align='center'> 인증번호 : " + a + "</div>");
			email.send();
		} catch (Exception e) {
			System.out.println(e);
		}		
		model.addAttribute("result", "good~!!\n 등록된 E-Mail 확인");

		return "result";
	}
}

 

 

 

 

 

실제 받은 메일 내용

 

BoardController.java

 

컨트롤러에서 딱히 할 것은 없어서 바로 뷰 페이지로 이동한다.

 

 

 

boarddeleteform.jsp

 

글 수정 폼 파일을 복사-붙여넣기 하여 필요한 부분을 수정 또는 삭제한다.

글 삭제는 비밀번호 양식과 버튼 양식만 남아 있으면 된다.

 

1)title : 글수정 -> 글삭제form action : boarddelete.dobutton value : 수정 -> 삭제

 

2)hidden 객체로 넘기던 ${page}, ${board.no} 값을

${param.page}, ${param.no} 로 수정

 

 

 

 

BoardController.java

 

db에 저장된 내용을 삭제하기 위해서는

폼에서 입력한 비밀번호와 기존 db에 저장되어 있던 비밀번호가 일치해야 한다.

 

비번이 일치할 경우 update 메소드를 호출하여 SQL문을 실행하도록한다.

이때, delete SQL문이 실행되면 result 에는 1이 저장된다.

일치하지 않을 경우 int result에 -1을 저장하여 board/deleteresult 로 넘기게 된다.

 

 

deleteresult.jsp

updateresult.jsp 파일의 내용을 복사-붙여넣기 하여 필요한 부분을 수정 또는 삭제한다.

 

 

 

 

BoardController.java

 

 

글 상세 내용에서 [수정] 버튼을 클릭하면 컨트롤러로

boardupdateform.do, no, page 이 세 가지 값을 전송한다.

 

 

 

글의 상세 정보를 구해온다. 이미 만들어 둔 메소드를 재활용하여 값을 가져오고

글의 상세 정보와 page 값 이 두 가지를 model 객체 공유 설정한다.

 

 

 

 

 

boardupdateform.jsp

 

boardform.jsp의 내용을 복사-붙여넣기 하여 필요한 부분을 수정 또는 삭제한다.

 

1)

title : 글삭제 -> 글수정

form action : boardwrite.do -> boardupdate.do

button value : 글작성 -> 수정

 

2)

hidden 객체를 생성하여 page, no값을 넘긴다

 

3)

각 입력 양식에 기존 입력했던 내용을 출력하여 수정이 용이하도록 한다.

 

 

 

BoardController.java

 

글 수정 폼에서 내용을 수정하여 submit으로 내용을 넘기면 컨트롤러로 이동한다.

db에 수정된 내용을 저장하기 위해서는

폼에서 입력한 비밀번호와 기존 db에 저장되어 있던 비밀번호가 일치해야 한다.

 

비번이 일치할 경우 update 메소드를 호출하여 SQL문을 실행하도록한다.

이때, update SQL문이 실행되면 result 에는 1이 저장된다.

일치하지 않을 경우 int result에 -1을 저장하여 board/updateresult 로 넘기게 된다.

 

 

 

 

updateresult.jsp

코어 라이브러리를 불러와 body 영역에 조건문을 작성한다.

true일 경우 (비번 일치 시), false일 경우 (비번 불일치 시) 로 나누어

다른 메시지의 alert 창이 출력되도록 한다.

 

 

BoardController.java

 

 

 

게시판 목록에 링크를 걸었을 때 boardcontent.do 값을 요청하도록 되어 있다.

이때, page 값과 글번호 no 값을 함께 전송하도록 되어 있다.

이것이 컨트롤러에 boardcontent.do 와 함께 넘어온다.

 

 

 

no값을 매개로 조회수를 1 증가시켜주는 updatecount 메소드를 생성한다.

 

 

 

no값을 매개로 글의 상세 정보를 구해오는 메소드를 생성한다.

 

 

구해온 글 상세 정보 중, content의 줄바꿈을 처리해준다.

 

 

model 객체로 공유 설정을 하는데,

줄바꿈 처리한 content 를 함께 가져가야 한다.

글 내용이 담긴 board에 포함되어 있지 않은 page 도 공유 설정하고

마지막으로 board 까지 설정한다.

 

리턴 값으로 설정된 뷰 페이지 경로로 넘어간다.

 

 

 

boardcontent.jsp

 

글 내용 레이아웃과 컨트롤러에서 넘긴 값을 활용하여 뷰 페이지를 작성한다.

 

 

 

 

[목록], [수정], [삭제]버튼에 page값을 전달하도록 하여 boardlist.do 링크를 걸어준다.

 

<input type="button" value="목록" onClick="location.href='boardlist.do?page=${page}' ">
<input type="button" value="수정" onClick="location.href='boardupdateform.do?no=${board.no}&page=${page}' ">
<input type="button" value="삭제" onClick="location.href='boarddeleteform.do?no=${board.no}&page=${page}' ">

 

+ Recent posts