[Framework] TIL 062 - 23.10.17

유진·2023년 10월 17일
0

07_Framework


-> 다운로드 받기

header.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
    
<link rel="stylesheet" href="/resources/css/main-style.css">

	<header>

            <!-- 클릭 시 메인페이지로 이동하는 로고 -->
            <section>
                <a href="/">
                    <img src="/resources/images/logo.jpg" id="homeLogo">
                </a>
            </section>

            <!-- 검색창 부분 -->
            <section>
                <section class="search-area">
                    <!-- form 내부 input 태그 값을 서버 또는 페이지로 전달 -->
                    <form action="/search" method="GET" name="search-form">

                        <!-- fieldset : form 내부에서 input을 종류별로 묶는 용도로 자주 사용 -->
                        <fieldset>

                            <!-- search : 텍스트 타입과 기능적으로는 똑같으나,
                                브라우저에 의해 다르게 표현될 수 있음. -->
                            <!-- autocomplete : HTML 기본 자동완성 사용 X -->
                            <input type="search" id="query" name="query"
                                autocomplete="off" placeholder="회원을 닉네임으로 검색해주세요."
                            >

                            <button id="searchBtn" class="fa-solid fa-magnifying-glass"></button>
                        </fieldset>

                    </form>

                </section>
            </section>

            <section></section>
        </header>

        <!-- 보통은 header안에 작성하나 사이드에 nav가 있는 경우도 있기 때문에 따로 작성해본다! -->
        <nav>
            <ul>
            	<%--
                <li><a href="#">공지사항</a></li>
                <li><a href="#">자유게시판</a></li>
                <li><a href="#">질문게시판</a></li>
                <li><a href="#">FAQ</a></li>
                <li><a href="#">1:1문의</a></li>
                 --%>
                 
                 <%-- interceptor를 이용해서 조회된 boardTypeList를
                 	application scope에서 얻어와 화면에 출력
                 --%>
                  
                 <%--
                 [
                 {BOARD_NAME=공지사항, BOARD_CODE=1},
                 {BOARD_NAME=자유 게시판, BOARD_CODE=2},
                 {BOARD_NAME=테스트 게시판, BOARD_CODE=3},
                 {BOARD_NAME=질문 게시판, BOARD_CODE=4},
                 {BOARD_NAME=점심 게시판, BOARD_CODE=5}
                 ]
                  --%>
                 <c:forEach var="boardType" items="${boardTypeList}">
                 	<li>
                 		<a href="/board/${boardType.BOARD_CODE}">${boardType.BOARD_NAME}</a>
                 	</li>
                 </c:forEach> 
            </ul>
        </nav>

BoardController.java

* 이러한 흐름으로 진행될 예정
100개
1페이지당 10개
1page -> 100 ~ 91 (cp = 1)
2page - > 90 ~ 81 (cp = 2)
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/1/insert
	 *  수정 : /board2/1/1500/update
	 *  삭제 : /board2/1/1500/delete
	 * */
	
	/*
	 * ******** @PathVariable 사용 시 문제점과 해결법 ********
	 * 
	 * 문제점 : 요청 주소와 @PathVariable로 가져다 쓸 주소와 레벨이 같다면
	 * 		구분하지 않고 모두 매핑되는 문제가 발생
	 * 
	 * 해결방법 : @PathVariable 지정 시 정규 표현식 사용
	 * {키:정규표현식}
	 * 
	 * 
	 * @PathVariable : URL 경로에 있는 값을 매개변수로 이용할 수 있게하는 어노테이션
	 * + request scope에 세팅
	 * 
	 * /board/1    /board?code=1 -> 용도의 차이점이 존재
	 * 
	 * - 자원(resource) 구분/식별
	 * ex) github.com/cmhinst
	 * ex) github.com/testUser
	 * 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:[0-9]+}") // boardCode는 1자리 이상 숫자
									   // @PathVariable : 주소를 값 자체로 쓸 수 있는 것
	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";
	}

}

Board.java

@Getter
@Setter
@ToString
public class Board {
    private int boardNo;
    private String boardTitle;
    private String boardContent;
    private String boardCreateDate;
    private String boardUpdateDate;
    private int readCount;
    private int boardCode;
    
    
    // 서브쿼리
    private int commentCount; // 댓글 수
    private int likeCount;    // 좋아요 수
    
    // 회원 join
    private String memberNickname; 
    private int memberNo;
    private String profileImage;
    
    // BOARD_IMG 테이블 join
    private String thumbnail;
    
    // 이미지 목록
    private List<BoardImage> imageList;
    
    // 댓글 목록
    private List<Comment> commentList;
}

BoardService.java

package edu.kh.project.board.model.service;

import java.util.List;
import java.util.Map;

public interface BoardService {

	List<Map<String, Object>> selectBoardTypeList();

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

}

BoardServiceImpl.java

package edu.kh.project.board.model.service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import edu.kh.project.board.model.dao.BoardDAO;
import edu.kh.project.board.model.dto.Board;
import edu.kh.project.board.model.dto.Pagination;

@Service
public class BoardServiceImpl implements BoardService{
	
	@Autowired
	private BoardDAO dao;

	// 게시판 종류 목록 조회
	@Override
	public List<Map<String, Object>> selectBoardTypeList() {
		return dao.selectBoardTypeList();
	}

	// 게시글 목록 조회
	@Override
	public Map<String, Object> selectBoardList(int boardCode, int cp) {
		
		// 1. 특정 게시판의 삭제되지 않은 게시글 수 조회
		int listCount = dao.getListCount(boardCode);
		
		// 2. 1번 조회 결과 + cp 를 이용해서 Pagination 객체 생성
		// -> 내부 필드가 모두 계산되어 초기화됨
		Pagination pagination = new Pagination(listCount, cp);
		
		// 3. 특정 게시판에서
		// 현재 페이지에 해당하는 부분에 대한 게시글 목록 조회
		// ex) 100개
		//	   10개 씩 보여준다
		//	   1page -> 100 ~ 91
		//     2page -> 90  ~ 81
		// 어떤 게시판에서(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("boarList", boardList);
		
		
		return map;
	}
	
}

BoardDAO.java

package edu.kh.project.board.model.dao;

import java.util.List;
import java.util.Map;

import org.apache.ibatis.session.RowBounds;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import edu.kh.project.board.model.dto.Board;
import edu.kh.project.board.model.dto.Pagination;

@Repository
public class BoardDAO {
	
	@Autowired
	private SqlSessionTemplate sqlSession;
	
	
	/** 게시판 종류 목록 조회
	 * @return
	 */
	public List<Map<String, Object>> selectBoardTypeList() {
		return sqlSession.selectList("boardMapper.selectBoardTypeList");
	}


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


	/** 특정 게시판에서 현재 페이지에 해당하는 부분에 대한 게시글 목록 조회
	 * @param pagination
	 * @param boardCode
	 * @return
	 */
	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", 파라미터(boardCode), RowBounds) 호출 
		return sqlSession.selectList("boardMapper.selectBoardList", boardCode, rowBounds);
	}

}

board-mapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="boardMapper">


	<!-- Board DTO에 대한 resultMap -->
	<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"/>
	</resultMap>
	

	<!-- 
		resultType이 "map"인 경우
		K : 컬럼명(BOARD_CODE, BOARD_NAME)
		V : 컬럼 값(	  1	   ,   공지 사항  )
		
		[{BOARD_NAME= 공지사항, BOARD_CODE=1}, {BOARD_NAME= 자유게시판, BOARD_CODE=2}, ...]
	 -->

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

	<!-- CDATA 태그 : 해당 태그 내부에 작성된 것은 모두 문자로 취급 -->
	<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>
	

</mapper>

Pagination.java

package edu.kh.project.board.model.dto;

// 페이징 처리에 필요한 모든 값들을 저장 하고있는 객체
public class Pagination {
	
	private int currentPage;		// 현재 페이지 번호
	private int listCount;			// 전체 게시글 수
	
	private int limit = 10;			// 한 페이지 목록에 보여지는 게시글 수
	private int pageSize = 10;		// 보여질 페이지 번호 개수
	
	private int maxPage;			// 마지막 페이지 번호
	private int startPage;			// 보여지는 맨 앞 페이지 번호 
	private int endPage;			// 보여지는 맨 뒤 페이지 번호
	
	private int prevPage;			// 이전 페이지의 페이지 번호 맨 끝
	private int nextPage;			// 다음 페이지의 페이지 번호 맨 앞
	
	
	public Pagination(int listCount, int currentPage) {
		
		this.listCount = listCount;
		this.currentPage = currentPage;
		
		// 객체 생성 시 전달 받은 값을 이용해
		// 나머지 필드 값 생성
		makePagination();
	}
	
	public Pagination(int listCount, int currentPage, int limit, int pageSize) {
		this.listCount = listCount;
		this.currentPage = currentPage;
		this.limit = limit;
		this.pageSize = pageSize;
		
		makePagination();
	}
	
	
	
	
	public int getCurrentPage() {
		return currentPage;
	}
	
	public void setCurrentPage(int currentPage) {
		this.currentPage = currentPage;
		makePagination();
	}
	
	public int getListCount() {
		return listCount;
	}
	
	public void setListCount(int listCount) {
		this.listCount = listCount;
		makePagination();
	}
	
	public int getLimit() {
		return limit;
	}
	
	public void setLimit(int limit) {
		this.limit = limit;
		makePagination();
	}
	
	public int getPageSize() {
		return pageSize;
	}
	
	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
		makePagination();
	}
	
	public int getMaxPage() {
		return maxPage;
	}
	public void setMaxPage(int maxPage) {
		this.maxPage = maxPage;
	}
	public int getStartPage() {
		return startPage;
	}
	public void setStartPage(int startPage) {
		this.startPage = startPage;
	}
	public int getEndPage() {
		return endPage;
	}
	public void setEndPage(int endPage) {
		this.endPage = endPage;
	}
	public int getPrevPage() {
		return prevPage;
	}
	public void setPrevPage(int prevPage) {
		this.prevPage = prevPage;
	}
	public int getNextPage() {
		return nextPage;
	}
	public void setNextPage(int nextPage) {
		this.nextPage = nextPage;
	}
	
	
	@Override
	public String toString() {
		return "Pagination [currentPage=" + currentPage + ", listCount=" + listCount + ", limit=" + limit
				+ ", pageSize=" + pageSize + ", maxPage=" + maxPage + ", startPage=" + startPage + ", endPage="
				+ endPage + ", prevPage=" + prevPage + ", nextPage=" + nextPage + "]";
	}

	
	
	// 페이징 처리에 필요한 값을 계산하는 메소드
	private void makePagination() {
		
		// * maxPage : 최대 페이지 == 마지막 페이지 == 총 페이지 수
		
		// 한 페이지에 글이 10개 씩 보여질 경우
		// - 게시글이 95개인 경우 필요한 페이지 수 :  10 페이지
		// - 게시글이 100개인 경우 필요한 페이지 수 : 10 페이지
		// - 게시글이 101개인 경우 필요한 페이지 수 : 11 페이지
		// - 게시글이 109개인 경우 필요한 페이지 수 : 11 페이지
		
		// 전체 게시글 수 / 한 페이지에 보여지는 글 수 -> 올림처리
		//   95  /  10 = 9.5  == 10
		//  100  /  10 = 10   == 10
		//  101  /  10 = 10.1 == 11
		maxPage  =   (int)Math.ceil( (double)listCount / limit );
		
		
		
		// * startPage : 페이지네이션 목록에서 제일 앞에 보여지는 페이지 번호
		
		// 페이지네이션 목록이 10개씩 보여진다고 했을 때
		// 현재 페이지가 1~10 인 경우 :  1 페이지
		// 현재 페이지가 11~20 인 경우 : 11 페이지
		// 현재 페이지가 21~30 인 경우 : 21 페이지
		
		startPage = (currentPage-1) / pageSize * pageSize + 1;
		
		
		
		// * endPage : 페이지네이션 목록에서 가장 끝 페이지 번호
		// 페이지네이션 목록이 10개씩 보여진다고 했을 때
		// 현재 페이지가 1~10 인 경우 :  10 페이지
		// 현재 페이지가 11~20 인 경우 : 20 페이지
		// 현재 페이지가 21~30 인 경우 : 30 페이지
		endPage = startPage + pageSize - 1;
		
		
		
		// ** 계산된 endPage가 전체 페이지네이션 목록 수(maxPage)를 초과하는 경우
		if(endPage > maxPage) {
			endPage = maxPage;
		}
		
		
		// prevPage : 이전 페이지네이션 목록의 끝 번호
		// nextPage : 다음 페이지네이션 목록의 시작 번호
		
		if(currentPage <= 10)	prevPage = 1;
		else
			//prevPage = (currentPage - 1) / pageSize * pageSize;
			prevPage = startPage - 1;
		
		if(endPage == maxPage) nextPage = maxPage;
		else				   nextPage = endPage + 1;
		
	}
}

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" >
<configuration>

	<!-- SqlSessionTemplate 관련 설정 -->
	<settings>
	
		<!-- insert, update 사용 값중 null 이 있을 경우 
			SQL 구문에 null 포함되어 있다는 오류 발생
			이 설정 후, 오류 발생 X, NULL 값을 컬럼에 대입
			단, NOT NULL 제약조건이 없는 컬럼에만 가능
		-->
		<setting name="jdbcTypeForNull" value="NULL"/>
	</settings>
	
	<!-- 별칭 작성 부분 -->
	<!-- VO/DTO 클래스의 패키지명+클래스명 작성하는게 불편하기 때문에 짧은 별칭을 부여 -->
	<typeAliases>
		<typeAlias type="edu.kh.project.member.model.dto.Member" alias="Member"/>
		<typeAlias type="edu.kh.project.board.model.dto.Board" alias="Board"/>
	
	</typeAliases>
	
	
	<!-- mapper파일(SQL 작성되는파일) 위치 등록 부분 -->
	<mappers>
		<mapper resource="/mappers/member-mapper.xml"/>
		<mapper resource="/mappers/ajax-mapper.xml"/>
		<mapper resource="/mappers/email-mapper.xml"/>
		<mapper resource="/mappers/myPage-mapper.xml"/>
		<mapper resource="/mappers/board-mapper.xml"/>
		<!-- 추후 board-mapper를 사용하고 싶다면 추가해야 함!
		<mapper resource="/mappers/board-mapper.xml"/>
		 -->
	</mappers>


</configuration>

boardList.jsp

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


<!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>게시판 이름</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">게시판 이름</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>
                    		<%-- 조회된 게시글 목록이 비어있거나 null 경우 --%>
                    		<c:when test="${empty boardList}">
                    			<!-- 게시글 목록 조회 결과가 비어있다면 -->
		                         <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="${not 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="#">&lt;&lt;</a></li>

                    <!-- 이전 목록 마지막 번호로 이동 -->
                    <li><a href="#">&lt;</a></li>

					
                    <!-- 특정 페이지로 이동 -->
                    
                    <!-- 현재 보고있는 페이지 -->
                    <li><a class="current">1</a></li>
                    
                    <!-- 현재 페이지를 제외한 나머지 -->
                    <li><a href="#">2</a></li>
                    <li><a href="#">3</a></li>
                    <li><a href="#">4</a></li>
                    <li><a href="#">5</a></li>
                    <li><a href="#">6</a></li>
                    <li><a href="#">7</a></li>
                    <li><a href="#">8</a></li>
                    <li><a href="#">9</a></li>
                    <li><a href="#">10</a></li>
                    
                    <!-- 다음 목록 시작 번호로 이동 -->
                    <li><a href="#">&gt;</a></li>

                    <!-- 끝 페이지로 이동 -->
                    <li><a href="#">&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>





boardList.jsp

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

<c:set var="boardName" value="${boardTypeList[boardCode-1].BOARD_NAME}"/>



<!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>
                    		<%-- 조회된 게시글 목록이 비어있거나 null 경우 --%>
                    		<c:when test="${empty boardList}">
                    			<!-- 게시글 목록 조회 결과가 비어있다면 -->
		                         <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="${not 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}" step="1">
                    	<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>


pagination도 잘됨

0개의 댓글