국비 89 - 글 상세 조회(스프링)

냐아암·2023년 8월 22일
0

국비

목록 보기
104/114

<%@ 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">

                        <%-- 좋아요 누른 적이 없거나 로그인이 안 되어있는 경우 --%>
                        <c:if test="${empty likeCheck}" >
                            <i class="fa-regular fa-heart" id="boardLike"></i>
                        </c:if>

                        <%-- 좋아요를 누른 적이 있는 경우 --%>
                        <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.boardUpdateDate}" >
                        <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">
                                                    <%-- end는 이하이다. --%>
                    <c:forEach begin="${start}" end="${fn:length(board.imageList) - 1}" var="i">
                        <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>


            <%-- white-space: pre-wrap; --%>
            <!-- 내용 -->
            <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>

Controller

// 게시글 상세 조회
	@GetMapping("/{boardCode}/{boardNo}")
	public String boardDetail(@PathVariable("boardCode") int boardCode
								, @PathVariable("boardNo") int boardNo
								, Model model /*데이터 전달용 객체*/
								, RedirectAttributes ra /*리다이렉트 시 데이터 전달용 객체*/
								, @SessionAttribute(value="loginMember", required=false) Member loginMember) {
									// 세션에서 로그인 멤버를 얻어오는데 없으면 null, 있으면 회원 정보 저장
		Map<String, Object> map = new HashMap<String, Object>();
		
		map.put("boardCode", boardCode);
		map.put("boardNo", boardNo);
		
		// 게시글 상세 조회 서비스 호출
		Board board = service.selectBoard(map);
		
		String path = null;
		
		if(board != null) { // 조회 결과가 있을 경우
			
			// -----------------------------------------------------
			// 현재 로그인 상태인 경우
			// 로그인 한 회원이 해당 게시글에 좋아요를 눌렀는지 확인
			// -----------------------------------------------------
			
			if(loginMember != null) { // 로그인 상태인 경우
				// 회원번호를 map에 추가
				// map(boardCode, boardNo, memberNo)
				map.put("memberNo", loginMember.getMemberNo());
				
				// 좋아요 여부 확인 서비스 호출
				int result = service.boardLikeCheck(map);
				
				// 좋아요를 누른 적이 있을 경우
				if(result>0) model.addAttribute("likeCheck", "on");
				
			}
			
			
			model.addAttribute("board",board);
			path = "board/boardDetail";
		} else {
			path ="redirect:/board/" + boardCode; // 게시판 첫 페이지로 리다이렉트
			ra.addFlashAttribute("message", "존재하지 않는 게시글입니다.");
		}
		
		return path;
	}
    

Service

/** 게시글 상세 조회
	 * @param map
	 * @return board
	 */
	Board selectBoard(Map<String, Object> map);

ServiceImpl

// 게시글 상세 조회
	@Override
	public Board selectBoard(Map<String, Object> map) {
		return dao.selectBoard(map);
	}

DAO

/** 게시글 상세 조회 
	 * @param map
	 * @return board
	 */
	public Board selectBoard(Map<String, Object> map) {
		return sqlSession.selectOne("boardMapper.selectBoard", map);
	}

📍 Collection 태그

select로 조회된 결과를 컬렉션(list)에 담아서 지정된 필드에 세팅

  • property : list를 담을 dto의 필드명
  • select : 실행할 select의 id
  • column : 조회 결과 중 지정된 컬럼의 값을 파라미터로 전달
  • javaType : List(컬렉션)의 타입을 지정
  • ofType : List(컬렉션)의 제네릭(타입 제한)

🔑 게시글 상세조회의 경우, 글/이미지리스트/댓글리스트 총 세 번의 sql문이 실행되어야 하는데, 이때 DAO를 여러 번 실행하는 것이 아닌 collection 태그로 한 번에 실행할 수 있게 한다.

sql


<!-- 게시글 상세 조회 -->
	<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>

🔑 resultMap에 작성된 collection 태그

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

🔑 collection태그의 select에 작성된 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>
    

좋아요 여부 확인

<!-- 좋아요 하트 -->
                    <span class="like-area">

                        <%-- 좋아요 누른 적이 없거나 로그인이 안 되어있는 경우 --%>
                        <c:if test="${empty likeCheck}" >
                            <i class="fa-regular fa-heart" id="boardLike"></i>
                        </c:if>

                        <%-- 좋아요를 누른 적이 있는 경우 --%>
                        <c:if test="${!empty likeCheck}" >
                            <i class="fa-solid fa-heart" id="boardLike"></i>
                        </c:if>

                        <span>${board.likeCount}</span>
                    </span>

Service

/** 좋아요 여부 확인
	 * @param map
	 * @return result
	 */
	int boardLikeCheck(Map<String, Object> map);

ServiceImpl

// 좋아요 여부 확인
	@Override
	public int boardLikeCheck(Map<String, Object> map) {
		return dao.boardLikeCheck(map);
	}
/** 좋아요 여부 확인
	 * @param map
	 * @return result
	 */
	public int boardLikeCheck(Map<String, Object> map) {
		return sqlSession.selectOne("boardMapper.boardLikeCheck", map);
	}
<!-- 좋아요 여부 확인 -->
	<select id="boardLikeCheck" resultType="_int">
		SELECT COUNT(*) FROM BOARD_LIKE
		WHERE BOARD_NO = #{boardNo}
		AND MEMBER_NO = #{memberNo}
	</select>
profile
개발 일지

0개의 댓글