KSI일기장
0501spring 게시판(1) 글 조회 (pagination(페이지번호) 포함) 본문
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}"><<</a></li>
<!-- 이전 목록 마지막 번호로 이동 -->
<li><a href="${url}${pagination.prevPage}${sURL}"><</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}">></a></li>
<!-- 끝 페이지로 이동 -->
<li><a href="${url}${pagination.maxPage}${sURL}">>></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>
<!-- 게시글 목록 조회 -->
<!-- < : .xml에서 부등호(<)를 쓸수 없으므로 사용
> : .xml에서 부등호(>)를 쓸수 없으므로 사용 -->
<select id="selectBoardList" resultMap="board_rm">
SELECT BOARD_NO,
BOARD_TITLE, MEMBER_NICK, READ_COUNT,
CASE WHEN SYSDATE - CREATE_DT < 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}" />
결과
'Spring' 카테고리의 다른 글
jstl scope 4가지 종류 (0) | 2023.05.02 |
---|---|
0502spring 게시판(2) 글 상세조회 (0) | 2023.05.02 |
0501spring sql log출력, (0) | 2023.05.01 |
spring 파일업로드 중 에러springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactoryBean' defined in class with path resource (0) | 2023.04.29 |
0428spring마이페이지 (0) | 2023.04.28 |