Spring10_댓글 기능 구현

3 minute read



댓글달기

  • 우선 spring을 구현하기 위해서는 t_board 테이블과, t_reply테이블이 필요하다
    • t_board : 게시물
    • t_reply : 게시물에 연결된 댓글
-- 답글기능을 넣을 것을 고려하여 아래와 같이 테이블을 구성했다.

create table t_reply(
  no number(5) primary key
  , board_no number(5) not null
  , comments varchar2(1000) not null
  , writer varchar2(100) not null
  , reg_date date default sysdate
  , groupid number(5) not null
  , parentid number(5) not null
  , cstep number(5) not null
  , constraint t_reply_board_no_fk foreign key(board_no) references t_board(no)
);

create sequence seq_t_reply_no;
create sequence seq_t_reply_groupid;

-- 댓글 등록
insert into t_reply(no, board_no, comments, writer, groupid, parentid, cstep ) 
    values( seq_t_reply_no.nextval, 11, '정말 열심히 하시는군요!', 'kopo1234', seq_t_reply_groupid.nextval, 0, 0); 
insert into t_reply(no, board_no, comments, writer, groupid, parentid, cstep ) 
    values( seq_t_reply_no.nextval, 11, 'ㅇㅈ', 'bbbb', 1, 1, 1); 
insert into t_reply(no, board_no, comments, writer, groupid, parentid, cstep ) 
    values( seq_t_reply_no.nextval, 11, '222', 'eeee', 1, 1, 1); 
insert into t_reply(no, board_no, comments, writer, groupid, parentid, cstep ) 
    values( seq_t_reply_no.nextval, 11, 'ㅇㅈㅇㅈ', 'aaaa', 1, 2, 2); 
insert into t_reply(no, board_no, comments, writer, groupid, parentid, cstep ) 
    values( seq_t_reply_no.nextval, 11, '최고다!', 'user', seq_t_reply_groupid.nextval, 0, 0); 

-- 댓글 불러오기
select no, board_no, comments, writer, groupid, parentid, cstep, reg_date
from t_reply
where board_no = 11
start with parentid = 0
connect by prior no = parentid
order siblings by groupid asc;

1. 구조설명

  1. detail.jsp(게시물상세)에 댓글을 작성하는 기능이 구현되어있다.
  2. 등록 버튼을 클릭했을 때 데이터를 넘긴다. ( 데이터의 형식은 json/딕셔너리형식으로 설정했다.)
  3. ajax를 이용하여 가상의 uri /board/reply.json에 댓글 데이터를 전송
  4. 성공시 Controller에서는 자동으로 ReplyVO가 넘어가고, 이것을 session 로그인 ID 정보(writer)와 함께 insert 해준다.
  5. 만약 insert성공시 1을 반환하게 되는데 1이 반환될 경우 ObjectMapper를 이용하여 ReplyVO를 json형식의 String으로 리턴한다.
    • 실패시 “err”리턴


2. 구현코드

1. 댓글기능 프론트 구현

  • detail.jsp
  • 입력칸

<div style="margin-bottom:20px;">
  <table border="1" style="width:100%;">
    <tr>
      <td width="80%">
        <textarea rows="2" cols="60" placeholder="댓글을 입력하세요!"  id="comments"></textarea>
      </td>
      <td>
        <button id="submitBtn"> 등록</button>
      </td>
    </tr>
  </table>
</div>

  • 출력칸

<c:if test="${ not empty requestScope.replyList }">
  <table id="replyShow" border="1" width="100%" >
    <c:forEach items="${ requestScope.replyList }" var="replyVO" varStatus="loop">

        <tr>
          <th>${ replyVO.writer }</th>
          <td>${ replyVO.comments }</td>
          <td>${ replyVO.regDate }</td>
          <td>답글작성</td>
        </tr>
    </c:forEach>
  </table>

</c:if>


2. 등록버튼 눌렀을 경우 데이터 넘기기 (ajax)

  • spring-mvc.xml
    • ajax에서 Controller로 데이터를 넘겼을 때 알아서 VO가 인식하도록 하기 위해서는 message-converters가 필요하다
    • 아래의 xml 코드를 spring-mvc.xml 설정 파일의 <mvc:annotation-driven>태그 아래에 넣는다. (없으면 만들기)
    • messageConverter란?
      • HTTP통신에서 일반 문자열이 아닌 XML이나 JSON으로 통신하기 위해 사용
      • 왜 JSON을 쓸까? XMLHttpRequest라는 내장 브라우저가 존재하여 Ajax 통신이 가능한데 XML로 데이터를 전송하는 것은 비효율적이므로 JSON으로 주고받음
<mvc:message-converters>
  <bean class="org.springframework.http.converter.StringHttpMessageConverter">
    <property name="supportedMediaTypes">
      <list>
        <value>text/html; charset=utf-8</value>
        <value>application/json; charset=utf-8</value>
      </list>
    </property>
  </bean>

</mvc:message-converters>


  • pom.xml
<!-- jackson -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.1.1</version>
</dependency>


  • detail.jsp의 script파일/코드
  • ajax에서 데이터를 넘긴다.
    • 성공시 크롬브라우저 console창에 출력
$(document).ready(function(){
  $('#submitBtn').click(function(){
    var date = new Date();
    
    // 데이터 넘기기
    var info={
        boardNo: '${board.no}', // 현재 게시물 번호
        comments:$('#comments').val() // 댓글내용
    }

    $.ajax({
            url: "${ pageContext.request.contextPath }/board/reply.json", // ${ pageContext.request.contextPath } + controller에서 작성한 uri
            type: "GET",
            data: info,
            success: function(data){
                console.log(data) // 데이터 콘솔창 출력
            },
            error: function(){
                alert("simpleWithObject err");
            }
        });
  })
})


3. Controller 에서 값 받고 넘기기

  • ResponseBody : 데이터를 RequestMapping에 설정한 uri에 바로 전달.
  • jsp파일이 없어도 알아서 뿌려주게 됨.
@ResponseBody
@RequestMapping("/board/reply.json")
public String insertComments(ReplyVO reply, HttpSession session) throws JsonProcessingException {

  MemberVO userVO = (MemberVO)session.getAttribute("userVO"); // 작성자 설정을 위해 session에서 값 불러옴
  reply.setWriter(userVO.getId()); // ReplyVO에 Writer로 지정

  int result = service.insertComments(reply); // insert하면 몇개가 insert 되었는지 리턴됨.
  if (result == 1) { // 댓글 하나만 넣으니까 1일 경우에만 VO를 json형태의 string으로 리턴
    ObjectMapper mapper = new ObjectMapper();
    String json = mapper.writeValueAsString(reply);// json 모양의 String으로 변환 
    return json;
  }
  return "err";
}

service

public int insertComments(ReplyVO reply) {
  int result = boardDAO.insertComments(reply);
  return result;
}

DAO

public int insertComments(ReplyVO reply) {
  int result = sqlSessionTemplate.insert("board.BoardDAO.insertComment", reply);
  return result; // insert 성공한 개수 반환
}

sqlmap-board.xml(MyBatis)

<insert id="insertComment" parameterType="replyVO" >
  insert into t_reply(no, board_no, comments, writer, groupid, parentid, cstep ) 
      values( seq_t_reply_no.nextval, #{boardNo}, #{comments}, #{writer}, seq_t_reply_groupid.nextval, 0, 0)
</insert>


4. ajax 통신 성공시 날아온 데이터를 파싱하여 append하기

  • 2번의 코드를 아래와 같이 변경한다.
$(document).ready(function(){
  $('#submitBtn').click(function(){
    var date = new Date();
    
    // 데이터 넘기기
    var info={
        boardNo: '${board.no}', // 현재 게시물 번호
        comments:$('#comments').val() // 댓글내용
    }

    $.ajax({
            url: "${ pageContext.request.contextPath }/board/reply.json", // ${ pageContext.request.contextPath } + controller에서 작성한 uri
            type: "GET",
            data: info,
            success: function(data){
                console.log(data)
                var comm = JSON.parse(data) // 날아온 데이터(string)를 json형식으로 변환 
                //console.log(comm)
                
                // 댓글 목록 table안에 제일 마지막에 입력한 정보 붙이기
                $('#replyShow').append("<tr>")
                $('#replyShow').append("<th>"+comm.writer+"</th>")
                $('#replyShow').append("<td>"+comm.comments+"</td>")
                $('#replyShow').append("<td>"+date.getFullYear()+"-"+ ('0' + (date.getMonth() + 1)).slice(-2) +"-"+('0' + date.getDate()).slice(-2)+"</td>")
                $('#replyShow').append("<td>답글작성</td>")
                $('#replyShow').append("</tr>")
            },
            error: function(){
                alert("simpleWithObject err");
            }
        });
  })
})