[Spring] Spring에서 Ajax 사용하기 3-2 활용 - 🔥 댓글 리스트 조회 기능 🔥
🔥 댓글 리스트 조회 기능 🔥
✔️ Spring_Project에서 진행함
💻 pom.xml
👉🏻 Ajax 관련 두 개의 라이브러리 추가 후 Update Project
<!-- 5. Ajax 관련 두 개의 라이브러리 -->
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10</version>
</dependency>
💻 Reply
👉🏻 sqlDeveloper의 테이블 참고해서 클래스 구성할 것
👉🏻 롬복을 사용하되 모든 필드를 매개변수로 가지는 생성자는 생성하지 않을 것
💡 @AllArgsConstructor를 적지 않는 이유?
보통 기본 생성자로 생성 후 setter로 넘겨 주는 꼴이기 때문에 모든 필드를 매개변수로 가지는 생성자는 만들지 않아 볼 것
package com.kh.spring.board.model.vo;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@NoArgsConstructor
@Setter
@Getter
@ToString
public class Reply {
private int replyNo; // REPLY_NO NUMBER
private String replyContent; // REPLY_CONTENT VARCHAR2(400 BYTE)
private int refBoardNo; // REF_BNO NUMBER
private String replyWriter; // REPLY_WRITER VARCHAR2(30 BYTE)
private String createDate; // CREATE_DATE DATE
private String status; // STATUS VARCHAR2(1 BYTE)
}
⌨️ 차근차근 빌드업 boardDetailView.jsp
👉🏻 모든 요소들이 화면에 출력된 다음 내가 원하는 이벤트가 일어날 수 있게끔 $(function(){ });을 사용할 것
👉🏻 함수를 따로 빼 놓고 내가 원할 때마다(Interval) 실행하도록 선언적 함수로 빼 놓음 🌟실시간으로 댓글 업데이트 효과 🌟
<script>
// 모든 요소들이 화면에 출력된 다음 바로 실행
$(function() {
selectReplyList();
});
// 해당 게시글에 딸린 댓글 리스트 조회용 ajax 요청
function selectReplyList() {
$.ajax({
url : "rlist.bo",
data : {bno: xxx},
success : function() {
},
error : function() {
console.log("댓글 리스트 조회용 ajax 통신 실패!");
}
});
}
</script>
👉🏻 이제 bno를 받아서 넘겨야 하는데 생각해 보니 이 페이지는 게시글 상세조회 페이지임
👉🏻 이미 bno를 받았던 적이 있지 않을까? 해서 스크롤을 올려 봤더니 있음!
👉🏻 EL 구문 사용하여 바로 적용하기
<script>
// 모든 요소들이 화면에 출력된 다음 바로 실행
$(function() {
selectReplyList();
});
// 해당 게시글에 딸린 댓글 리스트 조회용 ajax 요청
function selectReplyList() {
$.ajax({
url : "rlist.bo",
data : {bno: ${ b.boardNo }}, // 요걸 추가해 준 것!
success : function() {
},
error : function() {
console.log("댓글 리스트 조회용 ajax 통신 실패!");
}
});
}
</script>
⌨️ bno가 잘 넘어오는지 확인하기 위한 AjaxController
@RequestMapping(value="rlist.bo")
public void ajaxSelectReplyList(int bno) {
System.out.println(bno);
}
📌 현재 상황
👉🏻 서버 리스타트 후 게시판 접속
👉🏻 21번 게시글 들어가 보자
👉🏻 콘솔을 확인해 보니 bno를 잘 받아옴!
💻 BoardService에 댓글 리스트 조회용 메소드 추가
// 댓글 리스트 조회 서비스 (select)
ArrayList<Reply> selectReplyList(int boardNo);
💻 BoardServiceImpl에 추가된 메소드 Add
@Override
public ArrayList<Reply> selectReplyList(int boardNo) {
return boardDao.selectReplyList(sqlSession, boardNo);
}
💻 BoardDao
👉🏻 ArrayList로 강제 형변환(다운캐스팅) 후 return 해 줘야 함을 주의!
👉🏻 하지만 이때 제네릭 설정까지는 하지 않음!
public ArrayList<Reply> selectReplyList(SqlSessionTemplate sqlSession, int boardNo) {
return (ArrayList)sqlSession.selectList("boardMapper.selectReplyList", boardNo);
}
⌨️ board-mapper.xml
👉🏻 resultMap과 쿼리문 생성
<resultMap id="replyResultSet" type="reply">
<result column="REPLY_NO" property="replyNo" />
<result column="REPLY_WRITER" property="replyWriter" />
<result column="REPLY_CONTENT" property="replyContent" />
<result column="CREATE_DATE" property="createDate" />
</resultMap>
<select id="selectReplyList" parameterType="_int" resultMap="replyResultSet">
SELECT REPLY_NO
, REPLY_WRITER
, REPLY_CONTENT
, TO_CHAR(CREATE_DATE, 'YYYY-MM-DD') AS "CREATE_DATE"
FROM REPLY
WHERE STATUS = 'Y'
AND REF_BNO = #{boardNo}
ORDER BY REPLY_NO DESC
</select>
🙋🏻♀️ CREATE_DATE 기준 내림차순은 안 되나요?
🙅🏻♀️ 안 돼요! String 타입으로 년월일까지만 받았기 때문에 시/분/초의 순서가 엉킬 수 있음
🙋🏻♀️ resultMap에 풀 클래스명 안 쓰나요?
🙆🏻♀️ mybatis-config.xml에 이미 등록된 별칭이기 때문에 사용 가능함
⌨️ (추가한 코드 아님) mybatis-config.xml의 현재 코드 기술 상황
<typeAliases>
<typeAlias type="com.kh.spring.member.model.vo.Member" alias="member" />
<typeAlias type="com.kh.spring.board.model.vo.Board" alias="board" />
<typeAlias type="com.kh.spring.board.model.vo.Reply" alias="reply" />
</typeAliases>
💻 BoardController
👉🏻 Gson().toJson 메소드에 넘길 값 담기
👉🏻 응답페이지가 아닌 응답 데이터로 인식할 수 있게 @ResponseBody 어노테이션 삽입
👉🏻 @RequestMapping 어노테이션의 속성으로 produce 추가해 주기
@ResponseBody
@RequestMapping(value="rlist.bo", produces="application/json; charset=UTF-8")
public String ajaxSelectReplyList(int bno) {
// System.out.println(bno);
ArrayList<Reply> list = boardService.selectReplyList(bno);
return new Gson().toJson(list);
}
⌨️ 입력한 값들이 잘 넘어오는지 조회 boardDetailView.jsp
<script>
// 모든 요소들이 화면에 출력된 다음 바로 실행
$(function() {
selectReplyList();
});
// 해당 게시글에 딸린 댓글 리스트 조회용 ajax 요청
function selectReplyList() {
$.ajax({
url : "rlist.bo",
data : {bno: ${ b.boardNo }},
success : function(result) {
console.log(result);
},
error : function() {
console.log("댓글 리스트 조회용 ajax 통신 실패!");
}
});
}
</script>
👉🏻 아직 하드코딩 상태로 나오긴 하지만 콘솔에는 해당 게시글 번호에 대한 댓글이 잘 찍힘!
💻 boardDetailView.jsp
👉🏻 selectReplyList() ajax success 코드 기술
👉🏻 댓글 기본 개수 3에서 0으로 수정
<%@ 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>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style>
table * {margin:5px;}
table {width:100%;}
</style>
</head>
<body>
<jsp:include page="../common/header.jsp" />
<div class="content">
<br><br>
<div class="innerOuter">
<h2>게시글 상세보기</h2>
<br>
<a class="btn btn-secondary" style="float:right;" href="list.bo">목록으로</a>
<br><br>
<table id="contentArea" algin="center" class="table">
<tr>
<th width="100">제목</th>
<!-- 여기서 잘못 넣어 주면 getter 오류 남! -->
<td colspan="3">${ b.boardTitle }</td>
</tr>
<tr>
<th>작성자</th>
<td>${ b.boardWriter }</td>
<th>작성일</th>
<td>${ b.createDate }</td>
</tr>
<tr>
<th>첨부파일</th>
<td colspan="3">
<c:choose>
<c:when test="${ empty b.originName }">
첨부파일이 없습니다.
</c:when>
<c:otherwise>
<!-- 그냥 download로만 적어도 다운로드는 가능하지만, 그렇게 되면 수정명으로 파일 다운로드되므로 원본 파일명으로 처리해 줄 것! -->
<a href="${ b.changeName }" download="${ b.originName }">${ b.originName }</a>
</c:otherwise>
</c:choose>
</td>
</tr>
<tr>
<th>내용</th>
<td colspan="3"></td>
</tr>
<tr>
<td colspan="4"><p style="height:150px;">${ b.boardContent }</p></td>
</tr>
</table>
<br>
<c:if test="${ loginUser.userId eq b.boardWriter }">
<div align="center">
<!-- 수정하기, 삭제하기 버튼은 이 글이 본인이 작성한 글일 경우에만 보여져야 함 -->
<a class="btn btn-primary" onclick="postFormSubmit(1);">수정하기</a>
<a class="btn btn-danger" onclick="postFormSubmit(2);">삭제하기</a>
</div>
<br><br>
<!-- action 속성 비워 놓고 아래 script에서 action 속성만 바꿔치기 하는 게 포인트! -->
<form id="postForm" action="" method="post">
<input type="hidden" name="bno" value="${ b.boardNo }">
<!-- input 태그의 submit 버튼도 만들지 않음! -->
<input type="hidden" name="filePath" value="${ b.changeName }">
<!-- 두 번 일하지 않게끔 애초에 changeName으로 넘기기! -->
</form>
<script>
function postFormSubmit(num) {
// action 속성값을 부여 후 연이어서 곧바로 submit 시키기
if(num == 1) { // 수정하기 버튼 클릭 시 num == 1 : updateForm.bo
// location.href="updateForm.bo"; // get방식이기 때문에 url 노출됨! 우리의 목적에 적합하지 않음
$("#postForm").attr("action", "updateForm.bo").submit();
} else { // 삭제하기 버튼 클릭 시 num == 2 : delete.bo
$("#postForm").attr("action", "delete.bo").submit();
// 폼 태그 선택, action 속성을 바꾸고, 메소드 체이닝을 통해 submit
}
}
</script>
</c:if>
<!-- 댓글 기능은 나중에 ajax 배우고 나서 구현할 예정! 우선은 화면구현만 해놓음 -->
<table id="replyArea" class="table" align="center">
<thead>
<tr>
<th colspan="2">
<textarea class="form-control" name="" id="content" cols="55" rows="2" style="resize:none; width:100%;"></textarea>
</th>
<th style="vertical-align:middle"><button class="btn btn-secondary">등록하기</button></th>
</tr>
<tr>
<td colspan="3">댓글(<span id="rcount">0</span>)</td>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<br><br>
<script>
// 모든 요소들이 화면에 출력된 다음 바로 실행
$(function() {
selectReplyList();
});
// 해당 게시글에 딸린 댓글 리스트 조회용 ajax 요청
function selectReplyList() {
$.ajax({
url : "rlist.bo",
data : {bno: ${ b.boardNo }},
success : function(result) {
// console.log(result);
var resultStr = "";
for(var i = 0; i < result.length; i++) {
resultStr += "<tr>"
+ "<td>" + result[i].replyWriter + "</td>"
+ "<td>" + result[i].replyContent + "</td>"
+ "<td>" + result[i].createDate + "</td>"
+ "</tr>";
}
$("#replyArea>tbody").html(resultStr);
// 댓글 개수 출력 => 기존 0에서 조회된 값으로 덮어씌우기
$("#rcount").text(result.length);
},
error : function() {
console.log("댓글 리스트 조회용 ajax 통신 실패!");
}
});
}
</script>
</div>
<jsp:include page="../common/footer.jsp" />
</body>
</html>
📌 현재 상황
👉🏻 댓글이 없는 경우
👉🏻 댓글이 있는 경우 1
👉🏻 댓글이 있는 경우 2