이번 시간은 저번시간에 이어 게시글 상세 조회를 진행할 것이다.
이번에도 @PathVariable 이용해서 진행할 예정이다.
만약, @ PathVariable 이게 무엇인지 기억이 안난다면 저번시간에 작성한 내용을 확인하고 오길 .
게시글 상세 클릭하게 되면 주소가 "/board/1/1998?cp=1"이 될거니까, boardCode / boardNo를 이용해서 작성하면된다.
그렇다면 @PathVariable 다중 파라미터를 받아야하는데 다중 파라미터값을 받는 방법은 아래와 같다.
📖 @ PathVariable 다중 파라미터값 받는방법
1. @GetMapping & @POST Mapping("/{변수명}/{변수명}")
2. @PathVariable("변수명") 자료형 변수명 , @PathVariable("변수명") 자료형 변수명
💻 코드 보기 🖱
📚 Spring
📗 Board.java
@GetMapping("/{boardCode}/{boardNo}")
public String boardDetail(@PathVariable("boardCode") int boardCode
,@PathVariable("boardNo") int boardNo
,Model model // 데이터 전달용 객체
,RedirectAttributes ra// 리다이렉트 시 데이터 전달용 객체
) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("boardCode", boardCode);
map.put("boardNo", boardNo);
Board board = service.selectBoardList(map);
String path = null;
if(board != null ) { //조회 결과가 있을 경우 (forward할 jsp 경로)
path = "board/boardDetail";
model.addAttribute("board",board);
}else { // 조회 결과가 없을 경우(게시판 첫 페이지로 리 다이렉트)
path = "redirect:/board/"+boardCode;
ra.addFlashAttribute("message","해당 게시글이 존재하지 않습니다.");
}
return path;
}
🤔 혹시 ? 이거를 모를까 ?
자료형을 Board로 받아야하는 이유가 있을까 ?
Board로 받을 필요는 없지만 dto에 Board로 만들어놨고 그 안에 필드명을 사용할 수 있다.
map 형식으로 받은 이유는 ?
dao 에서 파라미터 값을 2개 전달 할 수 없어! 그러니까 map 형식으로 controller에서 받고 가자!
📗 Board.java
/**게시글 상세 조회
* @param map
* @return board
*/
Board selectBoardList(Map<String, Object> map);
📗 BoardServiceImpl.java
// 게시글 상세 조회
@Override
public Board selectBoardList(Map<String, Object> map) {
return dao.selectBoard(map);
}
📗 BoardDAO.java
/** 게시글 상세 조회
* @param map
* @return board
*/
public Board selectBoard(Map<String, Object> map) {
return sqlSession.selectOne("boardMapper.selectBoard",map);
}
📗 board-mapper.xml
📖 collection 태그란?
💭한행의 여러개의 정보(list)가 필요할때 (=1:N) 사용하는 것이 mybatis resultMap collection💭
<!-- collection 태그
select로 조회된 결과를 컬렉션(List)에 담아
지정된 필드에 세팅
property : List를 담을 DTO의 필드명
select : 실행할 select의 id
column : 조회 결과 중 지정된 컬럼의 값을 파라미터로 전달
javaType : List(컬렉션)의 타입을 지정
ofType : List(컬렉션)의 제네릭(타입제한) 지정 -> mybatis-config에 있는 별칭
-->
만약, collection 태그가 없다면 dao에서 이미지 / 댓글 부분을 두번이나 갔다와야하는데
collection 태그가 있어서 1번만 갔다 올 수 있다.
<resultMap type="Board" id="board_rm">
<id property="boardNo" column="BOARD_NO"/>
<result property="boardTitle" column="BOARD_TITLE"/>
<result property="boardContent" column="BOARD_CONTENT"/>
<result property="boardCreateDate" column="B_CREATE_DATE"/>
<result property="boardUpdateDate" column="B_UPDATE_DATE"/>
<result property="readCount" column="READ_COUNT"/>
<result property="commentCount" column="COMMENT_COUNT"/>
<result property="likeCount" column="LIKE_COUNT"/>
<result property="memberNickname" column="MEMBER_NICKNAME"/>
<result property="memberNo" column="MEMBER_NO"/>
<result property="profileImage" column="PROFILE_IMG"/>
<result property="thumbnail" column="THUMBNAIL"/>
<collection property="imageList"
select="selectImageList"
column="BOARD_NO"
javaType ="java.util.ArrayList"
ofType = "BoardImage">
</collection>
<collection property="commentList"
select="selectCommentList"
column="BOARD_NO"
javaType ="java.util.ArrayList"
ofType = "Comment">
</collection>
<!-- 게시글 상세 조회 -->
<select id="selectBoard" resultMap="board_rm">
SELECT BOARD_NO, BOARD_TITLE, BOARD_CONTENT,BOARD_CODE,
READ_COUNT,MEMBER_NICKNAME,MEMBER_NO,PROFILE_IMG,
TO_CHAR(B_CREATE_DATE,'YYYY"년" MM"월" DD"일" HH24:MI:SS')B_CREATE_DATE,
TO_CHAR(B_UPDATE_DATE,'YYYY"년" MM"월" DD"일" HH24:MI:SS')B_UPDATE_DATE,
(SELECT COUNT(*)
FROM BOARD_LIKE L
WHERE L.BOARD_NO = B.BOARD_NO)LIKE_COUNT
FROM BOARD B
JOIN MEMBER USING (MEMBER_NO)
WHERE BOARD_DEL_FL='N'
AND BOARD_CODE= #{boardCode}
AND BOARD_NO = #{boardNo}
</select>
<!-- 특정게시글 이미지 조회 -->
<select id="selectImageList" resultMap="boardImage_rm">
SELECT * FROM BOARD_IMG
WHERE BOARD_NO = #{boardNo}
ORDER BY IMG_ORDER
</select>
<!-- 특정 게시글 댓글 예정 -->
<select id="selectCommentList" resultMap="comment_rm">
SELECT COMMENT_NO, COMMENT_CONTENT,
TO_CHAR(C_CREATE_DATE, 'YYYY"년" MM"월" DD"일" HH24"시" MI"분" SS"초"') C_CREATE_DATE,
BOARD_NO, MEMBER_NO, MEMBER_NICKNAME, PROFILE_IMG, PARENT_NO, COMMENT_DEL_FL
FROM "COMMENT"
JOIN MEMBER USING(MEMBER_NO)
WHERE BOARD_NO = #{boardNo}
ORDER BY COMMENT_NO
</select>
🤔 그럼 ? collection을 안쓰면 어떻게 되는데 ?
위에 xml 코드에서 collection 부분만 주석하고 확인해보면 이미지 댓글이 빠진 상태를 볼 수 있다.
💻 출력화면 ( collection 부분 제외)
💻 출력화면 ( collection 부분 포함)
📚 VS code
📕 boardDetail.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="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<c:forEach items="${boardTypeList}" var="boardType">
<c:if test="${boardType.BOARD_CODE == boardCode}" >
<c:set var="boardName" value="${boardType.BOARD_NAME}"/>
</c:if>
</c:forEach>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${boardName}</title>
<link rel="stylesheet" href="/resources/css/board/boardDetail-style.css">
<link rel="stylesheet" href="/resources/css/board/comment-style.css">
</head>
<body>
<main>
<jsp:include page="/WEB-INF/views/common/header.jsp"/>
<section class="board-detail">
<!-- 제목 -->
<h1 class="board-title">${board.boardTitle} <span> - ${boardName}</span> </h1>
<!-- 프로필 + 닉네임 + 작성일 + 조회수 -->
<div class="board-header">
<div class="board-writer">
<!-- 프로필 이미지 -->
<c:choose>
<c:when test="${empty board.profileImage}">
<%-- 프로필 이미지가 없을 경우 기본 이미지 출력 --%>
<img src="/resources/images/user.png">
</c:when>
<c:otherwise>
<img src="${board.profileImage}"/>
</c:otherwise>
</c:choose>
<span>${board.memberNickname}</span>
<!-- 좋아요 하트 -->
<span class="like-area">
<%-- 좋아요 누른적이 없거나 , 로그인 x --%>
<c:if test="${empty likeCheck}" >
<i class="fa-regular fa-heart" id="boardLike"></i>
</c:if>
<%-- 좋아요 누른적이 있을 때, 로그인 o --%>
<c:if test="${!empty likeCheck}" >
<i class="fa-solid fa-heart" id="boardLike"></i>
</c:if>
<span>${board.likeCount}</span>
</span>
</div>
<div class="board-info">
<p> <span>작성일</span> ${board.boardCreateDate} </p>
<!-- 수정한 게시글인 경우 -->
<c:if test="{!empty board.boardUpdate}" >
<p> <span>마지막 수정일</span> ${board.boardUpdateDate} </p>
</c:if>
<p> <span>조회수</span> ${board.readCount} </p>
</div>
</div>
<!-- 이미지가 있을 경우 -->
<c:if test="${!empty board.imageList}" >
<!-- 썸네일 영역(썸네일이 있을 경우) -->
<%--
- 이미지는 IMG_ORDER 오름차순으로 정렬된다
- IMG_ORDER의 값이 0인 이미지가 썸네일이다.
-> imageList에 썸네일이 있다면 조회되었을때 IMG_ORDER가 0인 이미지가
imageList[0]에 저장 되었을 것이다.
--%>
<c:if test="${board.imageList[0].imageOrder==0}" >
<h5>썸네일</h5>
<div class="img-box">
<div class="boardImg thumbnail">
<img src="${board.imageList[0].imagePath}${board.imageList[0].imageReName}">
<a href="${board.imageList[0].imagePath}${board.imageList[0].imageReName}"
download="${board.imageList[0].imageOriginal}">다운로드</a>
</div>
</div>
</c:if>
</c:if>
<%-- 썸네일을 제외하고 나머지 이미지의 시작 인덱스 번호 --%>
<%-- 썸네일이 있을 경우 --%>
<c:if test="${board.imageList[0].imageOrder==0}" >
<c:set var="start" value="1"/>
</c:if>
<%-- 썸네일이 없을 경우 --%>
<c:if test="${board.imageList[0].imageOrder!=0}" >
<c:set var="start" value="0"/>
</c:if>
<%-- ${fn:length(board.imageList)} : imageList의 길이 --%>
<%-- 일반 이미지가 있을 경우 --%>
<c:if test="${fn:length(board.imageList)>start}" >
<!-- 업로드 이미지가 있는 경우 -->
<!-- 업로드 이미지 영역 -->
<h5>업로드 이미지</h5>
<div class="img-box">
<c:forEach var="i" begin="${start}" end="${fn:length(board.imageList)-1}" >
<div class="boardImg">
<c:set var="path" value="${board.imageList[i].imagePath}${board.imageList[i].imageReName}"/>
<img src="${path}">
<a href="${path}"
download="${board.imageList[i].imageOriginal}">다운로드</a>
</div>
</c:forEach>
</div>
</c:if>
<!-- 내용 -->
<div class="board-content">${board.boardContent}</div>
<!-- 버튼 영역-->
<div class="board-btn-area">
<!-- 로그인한 회원과 게시글 작성자 번호가 같은 경우-->
<c:if test="${loginMember.memberNo == board.memberNo}" >
<button id="updateBtn">수정</button>
<button id="deleteBtn">삭제</button>
</c:if>
<button id="goToListBtn">목록으로</button>
</div>
</section>
<!-- 댓글 include-->
<jsp:include page="comment.jsp"/>
</main>
<jsp:include page="/WEB-INF/views/common/footer.jsp"/>
</body>
</html>
📕 comment.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<div id="commentArea">
<!-- 댓글 목록 -->
<div class="comment-list-area">
<ul id="commentList">
<c:forEach items="${board.commentList}" var="comment">
<!-- 부모 댓글 -->
<li class="comment-row">
<p class="comment-writer">
<!-- 프로필 이미지 -->
<c:if test="${empty comment.profileImage}" >
<%-- 프로필 이미지가 없을 경우 --%>
<img src="/resources/images/user.png">
</c:if>
<c:if test="${!empty comment.profileImage}" >
<%-- 프로필 이미지가 없을 경우 --%>
<img src="${comment.profileImage}">
</c:if>
<!-- 닉네임 -->
<span>${comment.memberNickname}</span>
<!-- 작성일 -->
<span class="comment-date">${comment.commentCreateDate}</span>
</p>
<!-- 댓글 내용 -->
<p class="comment-content">${comment.commentContent}</p>
<!-- 버튼 영역 -->
<div class="comment-btn-area">
<button>답글</button>
<!-- 로그인 회원과 댓글 작성자가 같은 경우 -->
<c:if test="${loginMember.memberNo == comment.memberNo}" >
<button id="updateBtn">수정</button>
<button id="deleteBtn">삭제</button>
</c:if>
</div>
</li>
</c:forEach>
<!-- 자식 댓글 -->
<li class="comment-row child-comment">
<p class="comment-writer">
<!-- 프로필 이미지 -->
<img src="/resources/images/user.png">
<!-- 닉네임 -->
<span>닉네임</span>
<!-- 작성일 -->
<span class="comment-date">2023년 05월 9일 12시 20분 10초</span>
</p>
<!-- 댓글 내용 -->
<p class="comment-content">자식 댓글 입니다</p>
<!-- 버튼 영역 -->
<div class="comment-btn-area">
<button>답글</button>
</div>
</li>
</ul>
</div>
<!-- 댓글 작성 부분 -->
<div class="comment-write-area">
<textarea id="commentContent"></textarea>
<button id="addComment">
댓글<br>
등록
</button>
</div>
</div>
'ON > spring' 카테고리의 다른 글
[ Spring ] 프로필 이미지 추가 | 변경 | 삭제 ⑨ (1) | 2023.08.24 |
---|---|
[ Spring ] 게시글 상세 좋아요 | 조회수 ⑧ (0) | 2023.08.23 |
[ Spring ] 게시글 목록 조회 ⑥ (1) | 2023.08.21 |
[ Spring ] Interceptor란 ? (0) | 2023.08.21 |
[ Spring ] 이메일 인증 기능 - SMTP (0) | 2023.08.21 |