국비 66 - 게시글 상세 조회

냐아암·2023년 8월 7일
0

국비

목록 보기
82/114

게시글 상세 조회

📍 제목, 내용, 작성자 등 조회
📍 이미지 조회

<a href="detail?no=${board.boardNo}&cp=${pagination.currentPage}&type=${param.type}${sURL}">${board.boardTitle}</a>

package edu.kh.community.board.controller;

import java.io.IOException;
import java.util.List;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import edu.kh.community.board.model.service.BoardService;
import edu.kh.community.board.model.service.ReplyService;
import edu.kh.community.board.model.vo.BoardDetail;
import edu.kh.community.board.model.vo.Reply;

@WebServlet("/board/detail")
public class BoardDetailServlet extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		
		try {
			// 파라미터 중 게시글 번호(no) 얻어오기
			int boardNo = Integer.parseInt(req.getParameter("no"));
			
			BoardService service = new BoardService();
			
			// 게시글 정보 + 이미지 리스트 조회
			BoardDetail detail = service.selectBoardDetail(boardNo);
			
			// 게시글 상세조회된 내용이 있을 경우 댓글 목록 조회
			if(detail != null) {
				List<Reply> rList = new ReplyService().selectReplyList(boardNo);
				
				req.setAttribute("rList", rList);
			}
			
			req.setAttribute("detail", detail);
			
			String path = "/WEB-INF/views/board/boardDetail.jsp";
			RequestDispatcher dispatcher = req.getRequestDispatcher(path);
			
			dispatcher.forward(req, resp);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}
}

Service

/** 게시글 상세 조회 service
	 * @param boardNo
	 * @return detail
	 * @throws Exception
	 */
	public BoardDetail selectBoardDetail(int boardNo) throws Exception {
		
		Connection conn = getConnection();
		
		// 1) 게시글 (BOARD 테이블) 관련 내용만 조회
		BoardDetail detail = dao.selectBoardDetail(conn, boardNo);
		
		
		if(detail != null) { // 게시글 상세 조회 결과가 있을 경우
			// 2) 게시글에 첨부된 이미지(BOARD_IMG 테이블 조회)
			List<BoardImage> imageList = dao.selectImageList(conn, boardNo);
			
			// 조회된 imageList를 BoardDetail 객체에 세팅
			detail.setImageList(imageList);
		}
		
		close(conn);
		
		return detail;
	}

DAO

/** 게시글 상세 조회 DAO
	 * @param conn
	 * @param boardNo
	 * @return detail
	 * @throws Exception
	 */
	public BoardDetail selectBoardDetail(Connection conn, int boardNo) throws Exception{
		
		BoardDetail detail=null;
		
		try {
			
			String sql = prop.getProperty("selectBoardDetail");
			
			pstmt = conn.prepareStatement(sql);
			
			pstmt.setInt(1, boardNo);
			rs = pstmt.executeQuery();
			
			if(rs.next()) {
				detail = new BoardDetail();
	            
	            detail.setBoardNo(rs.getInt(1));
	            detail.setBoardTitle(rs.getString(2));
	            detail.setBoardContent(rs.getString(3));
	            detail.setCreateDate(rs.getString(4));
	            detail.setUpdateDate(rs.getString(5));
	            detail.setReadCount(rs.getInt(6));
	            detail.setMemberNickname(rs.getString(7));
	            detail.setProfileImage(rs.getString(8));
	            detail.setMemberNo(rs.getInt(9));
	            detail.setBoardName(rs.getString(10));
			}
			
			
		} finally {
			close(rs);
			close(pstmt);
		}
		
		return detail;
	}

SQL

<!-- 특정 게시글 상세 조회 -->
	<entry key="selectBoardDetail">
		SELECT BOARD_NO, BOARD_TITLE, BOARD_CONTENT, 
	        TO_CHAR(CREATE_DT,'YYYY"년" MM"월" DD"일" HH24:MI:SS') CREATE_DT,
	        TO_CHAR(UPDATE_DT,'YYYY"년" MM"월" DD"일" HH24:MI:SS') UPDATE_DT,
	        READ_COUNT, MEMBER_NICK, PROFILE_IMG, MEMBER_NO, BOARD_NM
		FROM BOARD
		JOIN MEMBER USING(MEMBER_NO)
		JOIN BOARD_TYPE USING(BOARD_CD)
		WHERE BOARD_NO = ?
		AND BOARD_ST = 'N'
	</entry>

/** 게시글에 첨부된 이미지 리스트 조회 DAO
	 * @param conn
	 * @param boardNo
	 * @return imageList
	 * @throws Exception
	 */
	public List<BoardImage> selectImageList(Connection conn, int boardNo) throws Exception {
		
		List<BoardImage> imageList = new ArrayList<>();
		
		try {
			String sql = prop.getProperty("selectImageList");
			
			pstmt = conn.prepareStatement(sql);
			
			pstmt.setInt(1, boardNo);
			
			rs = pstmt.executeQuery();
			
			while(rs.next()) {
				BoardImage image = new BoardImage();
	            
	            image.setImageNo(rs.getInt(1));
	            image.setImageReName(rs.getString(2));
	            image.setImageOriginal(rs.getString(3));
	            image.setImageLevel(rs.getInt(4));
	            image.setBoardNo(rs.getInt(5));
	            
	            imageList.add(image);
			}
		} finally {
			close(rs);
			close(pstmt);
		}
		
		return imageList;
	}

SQL

<!-- 게시글에 첨부된 이미지 리스트 조회 -->
	<entry key="selectImageList">
		SELECT * FROM BOARD_IMG 
		WHERE BOARD_NO=?
		ORDER BY IMG_LEVEL
	</entry>

Service

/** 댓글 목록 조회 service
	 * @param boardNo
	 * @return replyList
	 * @throws Exception
	 */
	public List<Reply> selectReplyList(int boardNo) throws Exception{
		
		Connection conn = getConnection();
		
		List<Reply> replyList = dao.selectReplyList(conn, boardNo);
		
		close(conn);
		
		return replyList;
	}

DAO

/** 댓글 목록 조회 DAO
	 * @param conn
	 * @param boardNo
	 * @return replyList
	 * @throws Exception
	 */
	public List<Reply> selectReplyList(Connection conn, int boardNo) throws Exception {
		
		List<Reply> replyList = new ArrayList<Reply>();
		
		try {
			
			String sql = prop.getProperty("selectReplyList");
			
			pstmt = conn.prepareStatement(sql);
			
			pstmt.setInt(1, boardNo);
			
			rs = pstmt.executeQuery();
			
			while(rs.next()) {
				
				Reply r = new Reply();
				
				r.setReplyNo(rs.getInt("REPLY_NO"));
				r.setReplyContent(rs.getString(2));
				r.setCreateDate(rs.getString(3));
				r.setBoardNo(rs.getInt(4));
				r.setMemberNo(rs.getInt(5));
				r.setMemberNickname(rs.getString(6));
				r.setProfileImage(rs.getString(7));
				
				replyList.add(r);
				
			}
			
		} finally {
			close(rs);
			close(pstmt);
		}
		
		
		
		return replyList;
	}

댓글 관련 코드는 다음 게시물애 이어서


화면

📍; 뒤로가기
📍 history.go(숫자) : 양수(앞으로 가기), 음수(뒤로 가기)

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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>게시판</title>

    <link rel="stylesheet" href="${contextPath}/resources/css/boardDetail-style.css">
    <link rel="stylesheet" href="${contextPath}/resources/css/main-style.css">
    <link rel="stylesheet" href="${contextPath}/resources/css/reply-style.css">
    <script src="https://kit.fontawesome.com/8f020b2fa9.js" crossorigin="anonymous"></script>
</head>
<body>

    <main>
        <jsp:include page="/WEB-INF/views/common/header.jsp"/>

         <section class="board-detail">

            <!-- 제목 -->
            <div class="board-title">${detail.boardTitle} <span> - ${detail.boardName}</span></div>

            <!-- 프로필 + 닉네임 + 작성일 + 조회수 -->
            <div class="board-header">
                <div class="board-writer">

                    <c:if test="${empty detail.profileImage}">
                        <!-- 프로픨 이미지가 없는 경우 -->
                        <img src="${contextPath}/resources/images/user.png">
                    </c:if>

                    <c:if test="${!empty detail.profileImage}">
                        <!-- 프로픨 이미지가 있는 경우 -->
                        <img src="${contextPath}${detail.profileImage}">
                    </c:if>
                    <span>${detail.memberNickname}</span>
                </div>
                <div class="board-info">
                    <p><span>작성일</span>  ${detail.createDate} </p>
                    <c:if test="${ !empty detail.updateDate}">
                        <!-- updateDate가 존재하는 경우에만 보여짐 -->
                        <p><span>마지막 수정일</span>  ${detail.updateDate} </p>
                    </c:if>
                    <p><span>조회수</span>  ${detail.readCount}</p>
                </div>
            </div>

            <!-- 이미지가 있을 경우 -->
            <c:if test="${!empty detail.imageList}">
                <!-- 썸네일이 있을 경우 변수 생성 -->
                <c:if test="${detail.imageList[0].imageLevel == 0}">
                    <c:set var="thumbnail" value="${detail.imageList[0]}"/>
                    <!-- page scope(페이지 내 어디서든 사용 가능) -->
                </c:if>

            </c:if>



            <!-- 썸네일 영역(썸네일이 있을 경우) -->
            <c:if test="${!empty thumbnail}">

                <h5>썸네일</h5>
                <div class="img-box">
                    <div class="boardImg thumbnail">
                        <img src="${contextPath}${thumbnail.imageReName}">
                        <a href="${contextPath}${thumbnail.imageReName}" download="${thumbnail.imageOriginal}">다운로드</a>
                    </div>
                </div>

            </c:if>

            <c:if test="${empty thumbnail}"> <!-- 썸네일 X -->
                <c:set var="start" value="0"/>
            </c:if>

            <c:if test="${!empty thumbnail}"> <!-- 썸네일 O -->
                <c:set var="start" value="1"/>
            </c:if>

            <!-- 업로드 이미지가 있는 경우 -->
            <c:if test="${fn:length(detail.imageList) > start}">

                <!-- 업로드 이미지 영역 -->
                <h5>업로드 이미지</h5>
                <div class="img-box">
    
                    <c:forEach var="i" begin="${start}" end="${fn:length(detail.imageList)-1}">
                        <div class="boardImg">
                            <img src="${contextPath}${detail.imageList[i].imageReName}">
                            <a href="${contextPath}${detail.imageList[i].imageReName}" download="${detail.imageList[i].imageOriginal}">다운로드</a>
                        </div>
                    </c:forEach>
                    
                </div>

            </c:if>


            

            <!-- 내용 -->
            <div class="board-content">
               ${detail.boardContent}
            </div>

            <!-- 버튼 영역 -->
            <div class="board-btn-area">

                <c:if test="${loginMember.memberNo == detail.memberNo}">

                    <%-- cp가 없을 경우에 대한 처리 --%>
                    <c:if test="${empty param.cp}">
                        <!-- 파라미터에 cp가 없을 경우 1 -->
                        <c:set var="cp" value="1"/>
                    </c:if>
                    <c:if test="${!empty param.cp}">
                        <!-- 파라미터에 cp가 있을 경우 param.cp -->
                        <c:set var="cp" value="${param.cp}"/>
                    </c:if>
                                                                                                                
                    <button id="updateBtn" onclick="location.href='write?mode=update&type=${param.type}&cp=${cp}&no=${param.no}'">수정</button>

                    <button id="deleteBtn">삭제</button>
                </c:if>
                <!--; 뒤로가기
                     history.go(숫자) : 양수(앞으로 가기), 음수(뒤로 가기)
                -->
                <button id="goToListBtn" >목록으로</button>
            </div>
         </section>

         <!-- 댓글 -->
         <jsp:include page="/WEB-INF/views/board/reply.jsp"/>
    </main>

    <jsp:include page="/WEB-INF/views/common/footer.jsp"/>

    <!-- jQuery 추가 -->
    <script src="https://code.jquery.com/jquery-3.7.0.min.js" integrity="sha256-2Pmvv0kuTBOenSvLm6bvfBSSHrUJ+3A7x6P5Ebd07/g=" crossorigin="anonymous"></script>

    <script src="${contextPath}/resources/js/board/board.js"></script>

    <script>
        // 댓글 관련 JS 코드에 필요한 값을 전역변수로 선언

        // jsp 파일: html, css, js, el, jstl 사용 가능
        // js 파일 : js

        // 코드 해석 순서 : EL == JSTL > HTML > JS

        // ** JS 코드에서 EL, JSTL을 작성하게 된다면 반드시 ""를 양쪽에 추가 **

        // 최상위 주소
        const contextPath = "${contextPath}";

        // 게시글 번호
        const boardNo = "${detail.boardNo}"; // 문자열 "500"

        // 로그인한 회원번호
        const loginMemberNo = "${loginMember.memberNo}";
        // -> 로그인 O : "10";
        // -> 로그인 X : ""; (빈문자열)

    </script>

    <script src="${contextPath}/resources/js/board/reply.js"></script>
</body>
</html>

JS

📍 절대경로, 상대경로 지정법

// 상세조회, 게시글 작성 - 목록으로 버튼

(function(){

    const goToListBtn = document.getElementById("goToListBtn");

    if(goToListBtn != null){ // 목록으로 버튼이 화면에 있을 때만 이벤트 추가
        goToListBtn.addEventListener("click", function(){

            // location 객체(BOM)

            // 뮨자열.substring(시작, 끝) : 시작 이상 끝 미만 인덱스까지 문자열 자르기

            // 문자열.indexOf("검색 문자열", 시작 인덱스)
            // : 문자열에서 "검색 문자열"의 위치(인덱스)를 찾아서 반환
            //   단, 시작 인덱스 이후부터 검색

            const pathname = location.pathname; // 주소상에서 요청 경로 반환
            //      /community.board.detail

            // 이동할 주소 저장
            let url = pathname.substring(0, pathname.indexOf("/",1));
            //      /community

            url += "/board/list?"; //   /community/board/list?

            // url 내장 객체 : 주소 관련 정보를 나타내는 객체
            // location.href : 현재 페이지 주소 + 쿼리스트링
            // URL.searchParams : 쿼리 스트링만 별도 객체 반환

            const params = new URL(location.href).searchParams; 

            const type = "type=" + params.get("type"); // type=1
            let cp;

            if(params.get("cp") != "") { // 쿼리스트링에 cp가 있을 경우
                cp = "cp=" + params.get("cp"); // cp=1
            } else {
                cp = "cp=1";
            }
            
            //const cp = "cp=" + (params.get("cp") !=null ? params.get("cp") : 1); // cp=1

            // 조립
            url += type + "&" + cp;

            // 검색 key, query가 존재하는 경우, url에 추가
            if(params.get("key") != null){
                const key = "&key=" + params.get("key");
                const query = "&query=" + params.get("query");

                url += key + query; // url 뒤에 붙이기
            }


            // location.href = "주소"; -> 해당 주소로 이동
            location.href = url;

        })
    }

})();


// 즉시 실행 함수 : 성능 up(속도), 변수명 중복 X
(function(){

    const deleteBtn = document.getElementById("deleteBtn"); // 존재하지 않으면 null

    if(deleteBtn != null) { // 버튼이 화면에 존재할 때만
        deleteBtn.addEventListener("click", function(){

            // 현재 : /community/board/detail?no=1111&cp=1&type=1

            // 목표 : /community/board/delete?no=1111&type=1

            // 상대경로 : delete?no=1111&type=1

            let url = "delete"; // 상대경로로 작성

            // 주소에 작성된 쿼리스트링에서 필요한 파라미터만 얻어와서 사용

            // 1) 쿼리스트링에 존재하는 파라미터 모두 얻어오기
            // location.href : 현재 페이지 주소(http://~)
            const params = new URL(location.href).searchParams; // 파라미터만 뽑아서 저장
                            // 자바스크립트 내장 객체
            // 2) 원하는 파라미터만 얻어 와 변수에 저장
            const no = "?no=" + params.get("no"); // ?no=1111

            const type = "&type=" + params.get("type"); // &type=1

            // url에 쿼리스트링 추가
            url += no + type // delete?no=1111&type=1
            
            if(confirm("정말 삭제하시겠습니까?")){
                location.href = url; // get방식으로 url에 요청
            }

        })
    }

})();


profile
개발 일지

0개의 댓글