국비 88 - 글 목록 조회 (스프링)

냐아암·2023년 8월 21일
0

국비

목록 보기
103/114

🔑 인덱스 활용 !!

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"  %>

<%-- map에 저장된 값들을 각각 변수에 저잗 --%>
<c:set var="pagination" value="${map.pagination}"/>
<c:set var="boardList" value="${map.boardList}"/>

<%-- boardList의 인덱스를 활용하기 ! 
    인덱스는 0부터 시작인데 boardCode는 1부터 시작이라서 -1 처리 함 --%>
<%-- <c:set var="boardName" value="${boardTypeList[boardCode-1].BOARD_NAME}"/> --%>

<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/boardList-style.css">

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

        
        <section class="board-list">

            <h1 class="board-name">${boardName}</h1>


            <div class="list-wrapper">
                <table class="list-table">
                    
                    <thead>
                        <tr>
                            <th>글번호</th>
                            <th>제목</th>
                            <th>작성자</th>
                            <th>작성일</th>
                            <th>조회수</th>
                            <th>좋아요</th>
                        </tr>
                    </thead>

                    <tbody>

                    <c:choose>
                       <c:when test="${empty boardList}">
                            <%-- 조회된 게시글 목록이 비어있거나 null인 경우 --%>
                            <tr>
                                <th colspan="6">게시글이 존재하지 않습니다.</th>
                            </tr>
                       </c:when>
                    
                       <c:otherwise>
                        <!-- 게시글 목록 조회 결과가 있다면 -->
                        <c:forEach items="${boardList}" var="board">
                            <tr>
                                <td>${board.boardNo}</td>
                                <td> 
                                <%-- 썸네일이 있을 경우 --%>
                                <c:if test="${!empty board.thumbnail}" >
                                    <img class="list-thumbnail" src="${board.thumbnail}">
                                </c:if>
                                    <%-- ${boardCode} : @Pathvariable로 request scope에 추가된 값 --%>
                                    <a href="/board/${boardCode}/${board.boardNo}?cp=${pagination.currentPage}">${board.boardTitle}</a>   
                                    [${board.commentCount}]                        
                                </td>
                                <td>${board.memberNickname}</td>
                                <td>${board.boardCreateDate}</td>
                                <td>${board.readCount}</td>
                                <td>${board.likeCount}</td>
                            </tr>
                        </c:forEach>
                       </c:otherwise>
                    </c:choose>
                    </tbody>
                </table>
            </div>


            <div class="btn-area">

            <!-- 로그인 상태일 경우 글쓰기 버튼 노출 -->
                <button id="insertBtn">글쓰기</button>                     

            </div>


            <div class="pagination-area">


                <ul class="pagination">
                
                    <!-- 첫 페이지로 이동 -->
                    <li><a href="/board/${boardCode}?cp=1">&lt;&lt;</a></li>

                    <!-- 이전 목록 시작 번호로 이동 -->
                    <li><a href="/board/${boardCode}?cp=${pagination.prevPage}">&lt;</a></li>

               
                    <!-- 특정 페이지로 이동 -->

                    <c:forEach var="i" begin="${pagination.startPage}" end="${pagination.endPage}">
                        <!-- 현재 보고있는 페이지 -->
                        <c:choose>
                           <c:when test="${i == pagination.currentPage}">
                                <li><a class="current">${i}</a></li>
                           </c:when>
                        
                           <c:otherwise>
                                <li><a href="/board/${boardCode}?cp=${i}">${i}</a></li>
                           </c:otherwise>
                        </c:choose>
                        
                        <!-- 현재 페이지를 제외한 나머지 -->
                    </c:forEach>
                    
                    
                    
                    <!-- 다음 목록 시작 번호로 이동 -->
                    <li><a href="/board/${boardCode}?cp=${pagination.nextPage}">&gt;</a></li>

                    <!-- 끝 페이지로 이동 -->
                    <li><a href="/board/${boardCode}?cp=${pagination.maxPage}">&gt;&gt;</a></li>

                </ul>
            </div>


         <!-- 검색창 -->
            <form action="#" method="get" id="boardSearch">

                <select name="key" id="searchKey">
                    <option value="t">제목</option>
                    <option value="c">내용</option>
                    <option value="tc">제목+내용</option>
                    <option value="w">작성자</option>
                </select>

                <input type="text" name="query"  id="searchQuery" placeholder="검색어를 입력해주세요.">

                <button>검색</button>
            </form>

        </section>
    </main>
    
    
    <!-- 썸네일 클릭 시 모달창 출력 -->
    <div class="modal">
        <span id="modalClose">&times;</span>
        <img id="modalImage" src="/resources/images/user.png">
    </div>


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

</body>
</html>
 

📍 @PathVariable

  • url 경로에 있는 값을 매개변수로 이용할 수 있게 하는 어노테이션
  • request scope에 세팅

🔑 Query String과 비교하며 사용하기

Controller

package edu.kh.project.board.controller;

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;

import edu.kh.project.board.model.service.BoardService;

@SessionAttributes("loginMember")
@RequestMapping("/board")
@Controller
public class BoardController {
	
	@Autowired
	private BoardService service;
	
	/* 목록 조회 : /board/1?cp=1 (cp : current page(현재 페이지))
	 * 상세 조회 : /board/1/1500?cp=1
	 * 
	 * ** 컨트롤러 따로 생성 예정 **
	 * 삽입 : /board2/insert?code=1 (code == BOARD_CODE, 게시판 종류)
	 * 수정 : /board2/udpate?code=1&no=1500 (no = BOARD_NO, 게시글 번호)
	 * 삭제 : /board2/delete?code=1&no=1500
	 * */
	
	// @PathVariable
	// url 경로에 있는 값을 매개변수로 이용할 수 있게 하는 어노테이션
	// + request scope에 세팅
	
	// /board?code=1
	// /board?code=2
	
	// @PathVariable을 사용하는 경우
	// - 자원(resource) 구분/식별
	// ex) https://github.com/hj-1008
	// ex) /board/1 -> 1번(공지사항) 게시판
	// ex) /board/2 -> 2번(자유 게시판) 게시판
	
	// Query String을 사용하는 경우
	// - 정렬, 필터링
	// ex) search.naver.com?query=날씨
	// ex) search.naver.com?query=점심
	// ex) /board2/insert?code=1
	// ex) /board2/insert?code=2
	//  -> 삽입이라는 공통된 동작 수행
	// 단, code에 따라 어디에 삽입할지 지정(필터링)
	// ex) /board/list?order=recent(최신순)
	// ex) /board/list?order=most(인기순)
	
	// 게시글 목록 조회
	@GetMapping("/{boardCode}")
	public String selectBoardList(@PathVariable("boardCode") int boardCode
								, @RequestParam(value="cp", required=false, defaultValue = "1") int cp
								, Model model) {
		
		// boardCode 확인
		// System.out.println("boardCode : " + boardCode);
		
		// 게시글 목록 조회 서비스 호출
		Map<String, Object> map = service.selectBoardList(boardCode, cp);
		
		// 조회 결과를 request scope에 세팅 후 forward
		model.addAttribute("map", map);
		
		return "board/boardList";
	}

}

Service

/** 게시글 목록 조회
	 * @param boardCode
	 * @param cp
	 * @return map
	 */
	Map<String, Object> selectBoardList(int boardCode, int cp);

ServiceImpl

// 게시글 목록 조회
	@Override
	public Map<String, Object> selectBoardList(int boardCode, int cp) {
		
		// 1. 특정 게시판의 삭제되지 않은 게시글 수 조회
		int listCount = dao.getListCount(boardCode);
		
		// 2. 1번의 조회 결과 + cp를 이용해서 페이지네이션 객체 생성
		// -> 내부 필드가 계산되어서 모두 초기화 됨
		Pagination pagination = new Pagination(cp, listCount);
		
		// 3. 특정 게시판에서 현재 페이지에 해당하는 부분에 대한 게시글 목록 조회
		// 어떤 게시판(boardCode)에서 몇 페이지(pagination.currentPage)에 대한
		// 게시글 몇 개 (pagination.limit) 조회
		List<Board> boardList = dao.selectBoardList(pagination, boardCode);
		
		// 4. pagination, boardList를  Map에 담아서 반환
		Map<String, Object> map = new HashMap<String, Object>();
		
		map.put("pagination", pagination);
		map.put("boardList", boardList);
		
		return map;
	}

DAO

/** 특정 게시판 삭제되지 않은 게시글 수 조회 DAO
	 * @param boardCode
	 * @return listCount
	 */
	public int getListCount(int boardCode) {
		return sqlSession.selectOne("boardMapper.getListCount", boardCode);
	}

sql

<!-- 특정 게시판 삭제되지 않은 게시글 수 조회 -->
	<select id="getListCount" resultType="_int">
		SELECT COUNT(*) FROM BOARD
		WHERE BOARD_CODE = #{boardCode}
		AND BOARD_DEL_FL = 'N'
	</select>
    

📍 RowBounds

  • 마이바티스에서 페이징 처리를 위해 제공하는 객체
  • offset만큼 건너뛰고 그 다음 지정된 행 개수(limit)만큼 조회

🔑 Mybatis에서 SQL 수행 시 전달할 수 있는 파라미터의 개수는 하나이다. 하지만 RowBounds는 예외

DAO

/** 특정 게시판에서 현재 페이지에 해당하는 부분에 대한 게시글 목록 조회 DAO
	 * @param pagination
	 * @param boardCode
	 * @return boardList
	 */
	public List<Board> selectBoardList(Pagination pagination, int boardCode) {
		
		// RowBounds 객체
		// - 마이바티스에서 페이징 처리를 위해 제공하는 객체
		// - offset만큼 건너뛰고
		//   그 다음 지정된 행 개수(limit)만큼 조회
		
		// 1) offset 계산
		int offset
		= (pagination.getCurrentPage() - 1) * pagination.getLimit();
		
		// 2) Rowbounds 객체 생성
		RowBounds rowBounds = new RowBounds(offset, pagination.getLimit());
		
		// 3) selectList("namespace.id", 파라미터, Rowbounds) 호출
		return sqlSession.selectList("boardMapper.selectBoardList", boardCode, rowBounds);
		
	}

📍 CDATA 태그

해당 태그 내부에 작성된 것은 모두 문자로 취급

🔑 서브쿼리 공부 파이팅...

sql

<!-- 게시글 목록 조회 -->
	<select id="selectBoardList" resultMap="board_rm">
		SELECT BOARD_NO, BOARD_TITLE, MEMBER_NICKNAME, READ_COUNT, 
         
         <![CDATA[
            CASE  
               WHEN SYSDATE - B_CREATE_DATE < 1/24/60
               THEN FLOOR( (SYSDATE - B_CREATE_DATE) * 24 * 60 * 60 ) || '초 전'
               WHEN SYSDATE - B_CREATE_DATE < 1/24
               THEN FLOOR( (SYSDATE - B_CREATE_DATE) * 24 * 60) || '분 전'
               WHEN SYSDATE - B_CREATE_DATE < 1
               THEN FLOOR( (SYSDATE - B_CREATE_DATE) * 24) || '시간 전'
               ELSE TO_CHAR(B_CREATE_DATE, 'YYYY-MM-DD')
            END B_CREATE_DATE,
            
         ]]>
         (SELECT COUNT(*) FROM "COMMENT" C
          WHERE C.BOARD_NO = B.BOARD_NO) COMMENT_COUNT,
          
         (SELECT COUNT(*) FROM BOARD_LIKE L
          WHERE L.BOARD_NO = B.BOARD_NO) LIKE_COUNT,
          
         (SELECT IMG_PATH || IMG_RENAME FROM BOARD_IMG I
         WHERE I.BOARD_NO = B.BOARD_NO
         AND IMG_ORDER = 0) THUMBNAIL
      FROM "BOARD" B
      JOIN "MEMBER" USING(MEMBER_NO)
      WHERE BOARD_DEL_FL = 'N'
      AND BOARD_CODE = #{boardCode}
      ORDER BY BOARD_NO DESC
	</select>
profile
개발 일지

0개의 댓글