📗 self-study/📗 KH정보교육원 당산지원

[Spring] Spring에서 Ajax 사용하기 3-2 활용 - 🔥 댓글 리스트 조회 기능 🔥

천재강쥐 2022. 11. 28. 11:09

 

🔥 댓글 리스트 조회 기능 🔥

✔️ 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>

Maven Dependencies에 잘 등록됐는지 확인 후 진행할 것!

 

💻 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