Notice
Recent Posts
Recent Comments
Link
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
Archives
Today
Total
관리 메뉴

KSI일기장

0501spring 게시판(1) 글 조회 (pagination(페이지번호) 포함) 본문

Spring

0501spring 게시판(1) 글 조회 (pagination(페이지번호) 포함)

MyDiaryYo 2023. 5. 1. 21:45

Board

package edu.kh.comm.board.model.vo;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
public class Board {
	private int boardNo;
	private String boardTitle;
	private String memberNickname;
	private String createDate;
	private int readCount;
	private String thumbnail;
}

BoardDetail

package edu.kh.comm.board.model.vo;

import java.util.List;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
public class BoardDetail {
	private int boardNo;
	private String boardTitle;
	private String boardContent;
	private String createDate;
	private String updateDate;
	private int readCount;
	private String memberNickname;
	private String profileImage;
	private int memberNo;
	private String boardName;

	private List<BoardImage> imageList;

	private int boardCode;

}

BoardImage

package edu.kh.comm.board.model.vo;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
public class BoardImage {
	private int imageNo;
	private String imageReName;
	private String imageOriginal;
	private int imageLevel;
	private int boardNo;
}

BoardType

package edu.kh.comm.board.model.vo;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
public class BoardType {

	private int boardCode;
	private String boardName;
}

Pagination

package edu.kh.comm.board.model.vo;

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 currentPage, int listCount) {
		this.currentPage = currentPage;
		this.listCount = listCount;

		calculatePagination(); // 계산 메서드 호출
	}


	public int getCurrentPage() {
		return currentPage;
	}


	public void setCurrentPage(int currentPage) {
		this.currentPage = currentPage;

		calculatePagination();
	}


	public int getListCount() {
		return listCount;
	}


	public void setListCount(int listCount) {
		this.listCount = listCount;

		calculatePagination();
	}


	public int getLimit() {
		return limit;
	}


	public void setLimit(int limit) {
		this.limit = limit;

		calculatePagination();
	}


	public int getPageSize() {
		return pageSize;
	}


	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;

		calculatePagination();
	}


	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 calculatePagination() {

		// * maxPage 계산 : 최대 페이지 수 == 마지막 페이지 번호

		// 전체 게시글 수 : 500개  //  보여지는 게시글 수: 10개
		// -> 마지막 페이지 번호는?  500 / 10 =  50

		// 전체 게시글 수 : 501개  //  보여지는 게시글 수: 10개
		// -> 마지막 페이지 번호는?  501 / 10 =  51  (50.1의 올림 처리)

		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(>) : 목록 하단에 노출된 번호의 다음 목록 시작 번호


		// 현재 페이지가  1~10 일 경우
		// < :  1 페이지
		// > : 11 페이지

		// 현재 페이지가 11~20 일 경우
		// < : 10 페이지
		// > : 21 페이지

		// 현재 페이지가 41~50 일 경우  (maxPage가 50)
		// < : 40 페이지
		// > : 50 페이지

		if(currentPage <= pageSize) {
			prevPage = 1;
		}else {
			prevPage = startPage - 1;
		}


		if(endPage == maxPage) {
			nextPage = maxPage;
		}else {
			nextPage = endPage + 1;
		}

	}

}

 

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

	<!-- 클릭 시 메인페이지로 이동하는 로고 -->
	<section>
	    <a href="${contextPath}">
	    
	    	<!-- header를 별도의 jsp로 분리한 경우
	    		상대경로로 작성된 이미지의 경로가 일치하지 않게됨
	    		
	    		* 지금처럼 분리시켜둔 jsp에 경로를 지정하는 경우
	    		  상대경로는 문제가 발생할 가능성이 높음!!
	    		  -> 절대 경로 사용이 바람직함
	    	 -->
	  
	  		<%--
	  		/community
	   		<%=  request.getContextPath() %>
	    	${pageContext.servletContext.contextPath }
	    	
	    	위에 작성된 내용은 모두 같은 결과이나 하자가 조금씩 있음 ...
	    	-> 모든 주소 요청 시 동작하는 EncodingFilter에서
	    		application scope에 최상위 주소를 간단히 부를 수 있는 형태로 저장
	    	
	    	 --%>
	     
	        <img src="${contextPath}/resources/images/logo.jpg" id="home-logo">
	      	
	    </a>
	</section>
	
	<section>
	    <article class="search-area">
	        <!-- form 내부 input 태그 값을 서버 또는 페이지로 전달 -->
	        <form action="#" name="search-form">
	
	            <!-- fieldset: form 내부에서 input을 종류별로 묶는 용도로 많이 사용 -->
	            <fieldset>
	
	                <!-- autocomplete="off" : HTML 기본 자동완성 사용 X -->
	                <input type="search" id="query" name="query" 
	                    autocomplete="off" placeholder="검색어를 입력해주세요.">
	
	                <!-- 검색 버튼 -->
	                    <button type="submit" id="search-btn" class="fa-solid fa-magnifying-glass"></button>  
	                </fieldset>
	            </form>
	        </article>
	    </section>
	
	    <section></section>
	
</header>
	
<!-- 
	쿼리스트링 : 주소에 담겨져서 전달되는 파라미터를 나타내는 문자열
	주소?name속성=값&name속성=값
	/member/login  ?memberEmail=user01&memberPw=1234
 -->

<nav>
    <ul>
    
    	<%--
    	 <li><a href="${contextPath}/board/list?type=1">공지사항</a></li>
        <li><a href="${contextPath}/board/list?type=2">자유 게시판</a></li>
        <li><a href="${contextPath}/board/list?type=3">질문 게시판</a></li>
    	 --%>
    	
    <c:forEach var="boardType" items="${boardTypeList}">
    	
    	<li><a href="${contextPath}/board/list/${boardType.boardCode}">${boardType.boardName}</a></li>
    
    </c:forEach>
       <!-- ${boardType.boardCode}의 boardCode는 VO BoardType의 boardCode
       		${boardType.boardName}의 boardName는 VO BoardType의 boardName -->
       
       

        <li><a href="#">FAQ</a></li>
        <li><a href="#">1:1문의</a></li>
    </ul>
</nav>

 

boardList.jsp 에서 하단 페이지번호(pagination) 관련 부분

  <div class="pagination-area">

                <!-- 페이지네이션 a태그에 사용될 공통 주소를 저장한 변수 선언 -->
                <c:set var="url" value="${boardCode}?cp="/>


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

                    <!-- 이전 목록 마지막 번호로 이동 -->
                    <li><a href="${url}${pagination.prevPage}${sURL}">&lt;</a></li>

                    <!-- 범위가 정해진 일반 for문 사용 -->
                    <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="${url}${i}${sURL}">${i}</a></li>        
                            </c:otherwise>
                        </c:choose>

                    </c:forEach>
                    
                    <!-- 다음 목록 시작 번호로 이동 -->
                    <li><a href="${url}${pagination.nextPage}${sURL}">&gt;</a></li>

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

                </ul>
            </div>

            <!-- /board/list?type=1&cp=3 -->

            <!-- /board/list?type=1&cp=10 &key=t&query=안녕 -->

 

BoardController

package edu.kh.comm.board.model.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 edu.kh.comm.board.model.service.BoardService;

@Controller
@RequestMapping("/board")
public class BoardController {

	@Autowired
	private BoardService service;

	//게시글 목록 조회
	//@PathVariable("value") :URL 경로에 포함되있는 값을 변수로 사용할 수 있게하는 역할
	//-> 자동으로 request scope에 등록된다 -> jsp ${value} EL 작성 가능
    
	@GetMapping("/list/{boardCode}")	//header.jsp에서의 경로
	public String boardList(@PathVariable("boardCode") int boardCode,
							@RequestParam(value="cp", required = false, defaultValue = "1") int cp,
							Model model){
		//@GetMapping("/list/{boardCode}")에서 {boardCode} 값이 들어오면
		//@PathVariable("boardCode")에서 "boardCode"에 값이 들어오고
		//int boardCode에 값이 들어간다
        
        //cp사용이유: pagination에서 번호 클릭시 게시글 목록 조회를 위해
        

		/* 게시글 목록 조회 서비스 호출
		 *1.게시판 이름 조회
		 *2.페이지네이션 객체 생성 ( 1, 2, 3, 4, 하단 페이지 번호)
		 *3.게시글 목록 조회
		 */

		Map<String, Object> map = null;

		map = service.selectBoardList(cp, boardCode);

		//map.put("boardCode", boardCode);

		model.addAttribute("map", map);


		return "board/boardList";
           // WEB-INF/views/board/boardDetail
	}

}

BoardService

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

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

import edu.kh.comm.board.model.vo.BoardType;

public interface BoardService {

	/**
	 * @return
	 */
	List<BoardType> selectBoardType();

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


}

BoardServiceImpl

package edu.kh.comm.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.comm.board.model.dao.BoardDAO;
import edu.kh.comm.board.model.vo.Board;
import edu.kh.comm.board.model.vo.BoardType;
import edu.kh.comm.board.model.vo.Pagination;

@Service
public class BoardServiceImpl implements BoardService{

	@Autowired
	private BoardDAO dao;

	//게시판코드, 이름조회
	@Override
	public List<BoardType> selectBoardType() {
		return dao.selectBoardType();
	}

	//게시글 목록조회 서비스 구현
	@Override
	public Map<String, Object> selectBoardList(int cp, int boardCode) {

		//1.게시판 이름 조회 -> 인터셉터(BoardTypeInterceptor) application에 있는 boardTypeList 쓸 수 있을듯 하다
        //->boardTypeList에는 DB에서 조회한 BOARD_CD, BOARD_NM가 담겨져있다(boardCode, boardName)
        
        //2.페이지네이션 객체 생성 ( 1, 2, 3, 4, 하단 페이지 번호) - listCount
		int listCount = dao.getListCount(boardCode);
       //-> listCount에 getListCount(특정게시판의 전체게시물 수)를 조회해 담았다
       
		Pagination pagination = new Pagination(cp, listCount);  

		//3.게시글 목록 조회
		List<Board> boardList = dao.selectBoardList(pagination, boardCode);

		//map만들어 담기
		Map<String, Object> map = new HashMap<>();
		map.put("pagination", pagination);
		map.put("boardList", boardList);
		map.put("boardCode", boardCode);

		return map;
	}

}

BoardDAO

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

import java.util.List;

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.comm.board.model.vo.Board;
import edu.kh.comm.board.model.vo.BoardType;
import edu.kh.comm.board.model.vo.Pagination;

@Repository
public class BoardDAO {

	/**게시판 코드, 이름 조회DAO
	 *
	 */
	@Autowired
	private SqlSessionTemplate sqlSession;

	public List<BoardType> selectBoardType() {

		return sqlSession.selectList("boardMapper.selectBoardType");
	}


	/**특정 게시판 전체게시글 수 조회DAO
	 * @param boardCode
	 * @return
	 */
	public int getListCount(int boardCode) {
		return sqlSession.selectOne("boardMapper.getListCount", boardCode);
	}


	/**게시판 목록 조회 DAO
	 * @param pagination
	 * @param boardCode
	 * @return
	 */
	public List<Board> selectBoardList(Pagination pagination, int boardCode) {

		//MyBatis에서 제공하는 RowBounds 객체 사용
		//:전체조회 결과에서 몇개의 행을 건너뛰고(offset)
		//그 다음 몇개의 행만 조회할 것인지(limit) 지정하는 객체

		int offset = (pagination.getCurrentPage() -1) * pagination.getLimit();

		RowBounds rowBounds = new RowBounds(offset, pagination.getLimit());

		return sqlSession.selectList("boardMapper.selectBoardList", boardCode, rowBounds);


	}


}

BoardTypeInterceptor

package edu.kh.comm.common.interceptor;

import java.util.List;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import edu.kh.comm.board.model.service.BoardService;
import edu.kh.comm.board.model.vo.BoardType;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class BoardTypeInterceptor implements HandlerInterceptor {

	/*인터셉터가 요청을 가로채는 시기
	 * 1.preHandle(전처리) :컨트롤러 수행 전
	 * 2.postHandle(후처리) :컨트롤러 수행 후, 컨트롤러 수행 후 결과값 참조 가능
	 * 3.afterCompletion(view단 처리 후) : 보통 자원 반환( close() )을 수행
	 * 단, 비동기요청(자바내부에서의 비동기요청(ajax X) )은 가로채지 않는다
	 */

	@Autowired
	private BoardService boardService;


	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		log.info("전처리 수행");

		//application scope에 "boardTypeList"가 없을 경우
		//이를 조회하는 Service 호출 후 결과를 세팅

		//application scope 객체얻어오기
		ServletContext application = request.getServletContext();

		if(application.getAttribute("boardTypeList") == null) {
			List<BoardType> boardTypeList = boardService.selectBoardType();

			application.setAttribute("boardTypeList", boardTypeList);

		}


		return HandlerInterceptor.super.preHandle(request, response, handler);
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		log.info("후처리 수행");
		HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		log.info("view처리 완료 후 수행");
		HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
	}



}

인터셉터 :컨트롤러의 핸들러를 호출하기 전과 후에 요청과응답을 참조하거나 가공할 수 있는 일종의 필터

                :특정 컨트롤러 핸들러가 실행되기 전이나 후에 추가적인 작업을 원할때 인터셉터를 사용한다

인터셉터 동작 위치 및 순서

:사용자가 서버에 원하는 작업을 요청하기 위해 url을 통해 Request객체를 보낸다

 DispatcherServlet은 해당 Request객체를 받아 분석한뒤 HandlerMapping에게

사용자 요청을 처리할 핸들러를 찾도록 요청한다

그 다음 실행체인(HandlerExectuonChanin)이 동작하게 되는데, 핸들러 실행체인은 하나이상의

핸들러 인터셉터를 거쳐서 컨트롤러가 실행 될 수 있도록 구성되있다

인터셉터를 등록하지 않았다면 컨트롤러가 바로 실행되고, 하나이상 인터셉터가 지정되있다면 지정순서에 따라 

언터셉터를 거쳐서 컨트롤러를 실행한다

 

servlet-context.xml

<!-- interceptors :인터셉터를 모아둔 태그 -->
	<interceptors>
		
		<!-- interceptor :요청이 Dispatcher Servlet에서 Controller에 도달하기 전
		또는 후에 요청/응답 객체(req, resp)를 가로채서 사용할 수 있는 객체 -->
		<interceptor>
		
			<!-- 가로챌 요청의 패턴을 지정 -->
			<mapping path="/**"/>
			<!-- /* : /member까지만 /board까지만
				/** : /member에서 모든 요청 -->
			
			<!-- 인터셉터 역할을 수행할 클래스(BoardTypeInterceptor)를 찾아서 bean으로 등록 -->
			<beans:bean id="boardTypeInterceptor" class = "edu.kh.comm.common.interceptor.BoardTypeInterceptor"/>
			
		
		
		</interceptor>
		
	</interceptors>
	
	
</beans:beans>

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>

	<!-- MyBatis 관련 설정 작성 -->
	<!-- *****1.settings, 2.typeAlliases, 3.mappers 순서중요***** -->
	
	<!-- SqlSessionTemplate 관련 설정 -->
	<settings>
	
		<!-- insert/update진행시 null이 포함되있는 경우
		MyBatis는 에러를 발생 시킨다
		->해당구문이 작성되면 지정된 value로 값을 insert/update 시켜준다
		null값이 있으면 NULL(무조건 대문자)을 insert/update해라 -->
		
		<!-- JDBC에서 null일 때의 처리방법 셋팅 -->
		<setting name="jdbcTypeForNull" value="NULL"></setting>
	
	</settings>
	
	<!-- 별칭 작성 부분 -->
	<typeAliases>
		<typeAlias type="edu.kh.comm.member.model.vo.Member" alias="member"></typeAlias>
		<typeAlias type="edu.kh.comm.board.model.vo.Board"  		alias="board"/>
		<typeAlias type="edu.kh.comm.board.model.vo.BoardDetail"  	alias="detail"/>
		<typeAlias type="edu.kh.comm.board.model.vo.BoardImage"  	alias="boardImage"/>
		<typeAlias type="edu.kh.comm.board.model.vo.BoardType"  	alias="boardType"/>
		
	</typeAliases>
	
	<!-- SQL이 작성되는 mappers파일 위치를 등록 -->
	<mappers>
		<!-- resource="mapper파일 경로"
			->경로작성 기준: src/main/resources 폴더 -->
		<mapper resource="/mappers/member-mapper.xml"/>
		<mapper resource="/mappers/myPage-mapper.xml"/>
		<mapper resource="/mappers/board-mapper.xml"/>
	</mappers>

</configuration>

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



	<!-- 게시글 코드,이름 resultMap -->
	<resultMap type="boardType" id="boardType_rm">
		<id property="boardCode" column="BOARD_CD" />
		<result property="boardName" column="BOARD_NM" />
	</resultMap>



	<!-- 게시글 목록용 resultMap -->
	<resultMap type="board" id="board_rm">
		<id property="boardNo" column="BOARD_NO" />
		<result property="boardTitle" column="BOARD_TITLE" />
		<result property="createDate" column="CREATE_DT" />
		<result property="readCount" column="READ_COUNT" />
		<result property="memberNickname" column="MEMBER_NICK" />
		<result property="thumbnail" column="THUMBNAIL" />
	</resultMap>
    
    
    
    <!-- 게시판 코드, 이름조회 -->
	<select id="selectBoardType" resultMap="boardType_rm">
		SELECT * FROM BOARD_TYPE
		ORDER BY BOARD_CD
	</select>
    <!-- ORDER BY : 정렬해서 출력할때 사용 기본값 ASC(오름차순:작은~큰) DESC(내림차순:큰~작은) -->

	<!-- 특정게시판 전체 게시글 수 조회 -->
	<select id="getListCount" resultType="_int">
		SELECT COUNT(*)  FROM BOARD
		WHERE BOARD_CD = #{boardCode}
		AND BOARD_ST = 'N'
	</select>
	
	
	<!-- 게시글 목록 조회 -->
	<!-- &lt : .xml에서 부등호(<)를 쓸수 없으므로 사용 
		&gt : .xml에서 부등호(>)를 쓸수 없으므로 사용  -->
	<select id="selectBoardList" resultMap="board_rm">
		SELECT BOARD_NO,
		BOARD_TITLE, MEMBER_NICK, READ_COUNT,
		CASE WHEN SYSDATE - CREATE_DT &lt; 1
		THEN TO_CHAR(CREATE_DT, 'HH:MI')
		ELSE TO_CHAR(CREATE_DT, 'YYYY-MM-DD')
		END CREATE_DT,

		(SELECT IMG_RENAME FROM BOARD_IMG
		WHERE BOARD.BOARD_NO = BOARD_IMG.BOARD_NO
		AND IMG_LEVEL = 0) THUMBNAIL

		FROM BOARD
		JOIN BOARD_TYPE USING(BOARD_CD)
		JOIN MEMBER_S USING(MEMBER_NO)
		WHERE BOARD_ST = 'N'
		AND BOARD_CD = ${boardCode}
		ORDER BY BOARD_NO DESC
	</select>

게시물 목록 조회 SQL문 해석

  • SELECT 절에서는 테이블에서 검색할 열을 지정합니다.
    • BOARD_NO, BOARD_TITLE, MEMBER_NICK, READ_COUNT는 BOARD 테이블의 열
    • CREATE_DT도 BOARD 테이블의 열입니다. 그러나 SYSDATE - CREATE_DT 표현식의 값에 따라 다르게 서식이 지정됩니다. 이 값이 1일 미만이면 CREATE_DT 열이 'HH:MI' (시간 및 분만)로 서식이 지정되고, 그렇지 않으면 'YYYY-MM-DD' (년-월-일)로 서식이 지정됩니다.
    • SELECT 절 내의 하위 쿼리는 BOARD_IMG 테이블에서 IMG_LEVEL 값이 0이고 BOARD_NO 값과 일치하는 레코드의 IMG_RENAME 열을 검색합니다.
  • FROM 절에서는 조인할 테이블을 지정합니다.
    • BOARD는 메인 테이블입니다.
    • BOARD_TYPE 및 MEMBER_S는 각각 BOARD_CD 및 MEMBER_NO 외래 키를 사용하여 추가 정보를 검색합니다.
  • WHERE 절에서는 일부 조건을 기반으로 데이터를 필터링합니다.
    • BOARD_ST = 'N'는 BOARD_ST 필드 값이 'N'인 레코드를 필터링합니다.
    • BOARD_CD = ${boardCode}는 BOARD_CD 필드 값이 boardCode 변수의 값과 일치하는 레코드를 필터링합니다. (boardCode 변수는 실제 값으로 대체되어야 합니다.)
  • ORDER BY 절에서는 BOARD_NO 열을 기준으로 내림차순으로 데이터를 정렬합니다.

결론: 이 쿼리는 활성화된 게시물(BOARD_ST = 'N') 중에서 특정 게시판 유형(BOARD_CD = ${boardCode})에 속하는 게시물의 BOARD_NO, BOARD_TITLE, MEMBER_NICK, READ_COUNT를 검색하고 CREATE_DT도 값이 1일 미만이면 CREATE_DT 열이 'HH:MI' (시간 및 분만)로 서식이 지정되고, 그렇지 않으면 'YYYY-MM-DD' (년-월-일)로 서식이 지정되 검색됩니다. 또 각 게시물에 대한 썸네일 이미지도 함께 검색됩니다.

 

 

 

boardList.jsp

 

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:forEach var = "boardType" items="${boardTypeList}">

	<c:if test="${boardCode == boardType.boardCode}">
		<c:set var="boardName" value="${boardType.boardCode}" />
	</c:if>

</c:forEach>


<c:set var="pagination" value="${map.pagination}" />
<c:set var="boardList" value="${map.boardList}" />

결과