안녕하세요, 코린이의 코딩 학습기 채니 입니다.
개인 포스팅용으로 내용에 오류 및 잘못된 정보가 있을 수 있습니다.
BoardList 조회
DB 구조
-- 게시판 | 첨부파일 테이블 생성
create table board(
no number,
title varchar2(1000) not null,
member_id varchar2(15),
content varchar2(4000),
read_count number default 0,
created_at date default sysdate,
updated_at date,
constraint pk_board_no primary key(no),
constraint fk_board_member_id foreign key(member_id) references member(member_id) on delete set null
);
create sequence seq_board_no;
create table attachment(
no number,
board_no number not null,
original_filename varchar2(256) not null,
renamed_filename varchar2(256) not null,
download_count number default 0,
created_at date default sysdate,
constraint pk_attachment_no primary key(no),
constraint fk_attachment_board_no foreign key (board_no) references board(no) on delete cascade
);
create sequence seq_attachment_no;
Dto
BoardEntity
// DB랑 구조가 같은 클래스
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BoardEntity {
private int no;
private String title;
private String memberId;
private String content;
private int readCount;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
Board
@Data
@NoArgsConstructor
@ToString(callSuper = true)
public class Board extends BoardEntity {
private int attachCount;
public Board(int no, String title, String memberId, String content, int readCount, LocalDateTime createdAt,
LocalDateTime updatedAt, int attachCount) {
super(no, title, memberId, content, readCount, createdAt, updatedAt);
this.attachCount = attachCount;
}
}
Lombok의 @AllArgsConstructor 어노테이션을 사용하면 상속받고 있는 부모(super)필드까지 포함된 생성자를 만들어 주진 않습니다.
@NoArgsConstructor
@AllArgsConstructor 어노테이션 사용 시
이처럼 해당 클래스의 필드만을 인식하여 생성자를 만들어주므로, 파라미터 생성자는 lombok 대신 별도로 생성해주었습니다.
@Data 어노테이션 내의 ToString 또한 부모의 ToString을 호출해주지 않기 때문에 @ToString 어노테이션의 callsuper속성을 이용해 부모의 tostring도 호출되도록 하였습니다.
Controller
BoardController
@Controller
@Slf4j
@RequestMapping("/board")
public class BoardController {
@Autowired
private BoardService boardService;
@RequestMapping("/boardList.do")
public void boardList(Model model) {
List<Board> list = boardService.selectAll();
log.debug("list = {}", list);
model.addAttribute("list", list);
}
}
Service
BoardService interface 생략
BoardServiceImpl
@Service
public class BoardServiceImpl implements BoardService {
@Autowired
private BoardDao boardDao;
@Override
public List<Board> selectAll() {
return boardDao.selectAll();
}
}
Dao
BoardDao interface
@Mapper
public interface BoardDao {
@Select("select b.*, (select count(*) from attachment where board_no = b.no) attach_count from board b order by no desc")
List<Board> selectAll();
}
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"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<jsp:include page="/WEB-INF/views/common/header.jsp">
<jsp:param value="게시판" name="title"/>
</jsp:include>
<style>
/*글쓰기버튼*/
input#btn-add{float:right; margin: 0 0 15px;}
</style>
<section id="board-container" class="container">
<input type="button" value="글쓰기" id="btn-add" class="btn btn-outline-success"/>
<table id="tbl-board" class="table table-striped table-hover">
<tr>
<th>번호</th>
<th>제목</th>
<th>작성자</th>
<th>작성일</th>
<th>첨부파일</th> <!-- 첨부파일 있을 경우, /resources/images/file.png 표시 width: 16px-->
<th>조회수</th>
</tr>
<c:if test="${not empty list}">
<c:forEach items="${list}" var="list">
<tr>
<td>${list.no}</td>
<td>${list.title}</td>
<td>${list.memberId}</td>
<td>
<fmt:parseDate value="${list.createdAt}" var="createdAt" pattern="yyyy-MM-dd'T'HH:mm" />
<fmt:formatDate value="${createdAt}" pattern="yy/MM/dd HH:mm"/>
</td>
<td>
<c:if test="${list.attachCount gt 0}">
<img src="${pageContext.request.contextPath}/resources/images/file.png" width="16px"/>
</c:if>
</td>
<td>${list.readCount}</td>
</tr>
</c:forEach>
</c:if>
<c:if test="${empty list}">
<tr>
<td colspan="6" class="text-center">조회된 게시글이 없습니다.</td>
</tr>
</c:if>
</table>
</section>
<jsp:include page="/WEB-INF/views/common/footer.jsp"></jsp:include>
페이징 처리
Mybatis에서 제공하는 페이징객체처리 RowBounds 이용! (limit, offset)
cPage - 현재 페이지
limit - 한 페이지에서 보여줄 개수
offset - 건너뛸 개수
Controller
BoardController
@RequestMapping("/boardList.do")
public void boardList(@RequestParam(defaultValue = "1") int cPage, Model model) {
Map<String, Integer> param = new HashMap<>();
param.put("cPage", cPage);
param.put("limit", 10);
List<Board> list = boardService.selectAll(param);
log.debug("list = {}", list);
model.addAttribute("list", list);
}
현재 페이지를 cPage로 받아 처리하며, 게시판 페이지에 처음 올 경우 cPage가 없기 때문에 defaultValue를 "1"로 지정해주었습니다.
Service
BoardService interface 생략
BoardServiceImpl
@Override
public List<Board> selectAll(Map<String, Integer> param) {
// mybatis에서 제공하는 페이징처리객체 RowBounds
// offset, limit
int limit = param.get("limit"); // 한 페이지에서 보여줄 개수
int offset = (param.get("cPage") - 1) * limit; // 건너뛸 개수
RowBounds rowBounds = new RowBounds(offset, limit);
return boardDao.selectAll(rowBounds);
}
cPage = 1 ? offset = (1-1) * 10, 즉 offset은 0이므로, 건너뛰는 개수가 없습니다.
cPage = 2 ? offset = (2-1) * 10, 즉 offset은 10이므로, 10개의 게시글을 건너뛰어 11~20개의 게시글을 랜더링
cPage = 3 ? offset = (3-1) * 10, 즉 offset은 20이므로, 20개의 게시글을 건너뛰어 21~30개의 게시글을 랜더링
...
...
이와 같은 구조를 가지고 있어 쉽게 페이징 처리를 할 수 있습니다.
Dao
BoardDao interface 생략
@Mapper
public interface BoardDao {
@Select("select b.*, (select count(*) from attachment where board_no = b.no) attach_count from board b order by no desc")
List<Board> selectAll(RowBounds rowBounds);
}
페이징 처리에 따라서 랜더링되는 게시글이 다른 것을 확인할 수 있습니다.
페이지 바 처리
Controller
BoardController
@RequestMapping("/boardList.do")
public void boardList(@RequestParam(defaultValue = "1") int cPage, Model model, HttpServletRequest request) {
// 1. content 영역
Map<String, Integer> param = new HashMap<>();
int limit = 10;
param.put("cPage", cPage);
param.put("limit", 10);
List<Board> list = boardService.selectAll(param);
log.debug("list = {}", list);
model.addAttribute("list", list);
// 2. pagebar 영역
int totalContent = boardService.getTotalContent();
String url = request.getRequestURI();
String pagebar = HelloSpringUtils.getPagebar(cPage, limit, totalContent, url);
log.debug(pagebar);
model.addAttribute("pagebar", pagebar);
}
HelloSpringUtils
getPagebar
public class HelloSpringUtils {
/**
* totalPage 전체페이지수
* pagebarSize
* pageNo
* pagebarStart
* pagebarEnd
*/
public static String getPagebar(int cPage, int limit, int totalContent, String url) {
StringBuffer pagebar = new StringBuffer();
url += "?cPage=";
final int pagebarSize = 5;
final int totalPage = (int)Math.ceil((double)totalContent / limit);
final int pagebarStart = ((cPage - 1) / pagebarSize) * pagebarSize + 1;
final int pagebarEnd = pagebarStart + pagebarSize - 1;
int pageNo = pagebarStart;
pagebar.append("<ul class=\"pagination justify-content-center\">\n");
// 1. previous
if(cPage == 1) {
pagebar.append("<li class=\"page-item disabled\">\n"
+ " <a class=\"page-link\" href=\"#\" aria-label=\"Previous\">\n"
+ " <span aria-hidden=\"true\">«</span>\n"
+ " <span class=\"sr-only\">Previous</span>\n"
+ " </a>\n"
+ " </li>\n");
} else {
pagebar.append("<li class=\"page-item\">\n"
+ " <a class=\"page-link\" href=\"" + url + (pageNo-1) + "\" aria-label=\"Previous\">\n"
+ " <span aria-hidden=\"true\">«</span>\n"
+ " <span class=\"sr-only\">Previous</span>\n"
+ " </a>\n"
+ " </li>\n");
}
// 2. pageNo
while(pageNo <= pagebarEnd && pageNo <= totalPage) {
if(pageNo == cPage) {
pagebar.append("<li class=\"page-item active\"><a class=\"page-link\" href=\"#\">" + pageNo + "</a></li>\n");
} else {
pagebar.append("<li class=\"page-item\"><a class=\"page-link\" href=\"" + url + pageNo +"\">" + pageNo + "</a></li>\n");
}
pageNo++;
}
// 3. next
if(pageNo > totalPage) {
pagebar.append("<li class=\"page-item disabled\">\n"
+ " <a class=\"page-link\" href=\"#\" aria-label=\"Next\">\n"
+ " <span aria-hidden=\"true\">»</span>\n"
+ " <span class=\"sr-only\">Next</span>\n"
+ " </a>\r\n"
+ " </li>\n");
} else {
pagebar.append("<li class=\"page-item\">\n"
+ " <a class=\"page-link\" href=\"" + url + pageNo + "\" aria-label=\"Next\">\n"
+ " <span aria-hidden=\"true\">»</span>\n"
+ " <span class=\"sr-only\">Next</span>\n"
+ " </a>\n"
+ " </li>\n");
}
pagebar.append("</ul>");
return pagebar.toString();
}
}
※ 페이지 바 처리 관련 자세한 설명은 아래 포스팅 참고
https://chanychu.tistory.com/322
'Java > Spring' 카테고리의 다른 글
Spring) 파일 업로드 처리 (0) | 2022.08.31 |
---|---|
Spring) 게시글 작성 - 파일 업로드 처리를 위한 설정 (0) | 2022.08.30 |
Spring) AOP - 특정 메소드 소요시간 계산, Escaping 처리, ErrorLog처리 (0) | 2022.08.28 |
Spring) AOP 흐름 이해하기, 원리 및 구조 파악 (0) | 2022.08.25 |
Spring) AOP 개념 정리 (0) | 2022.08.25 |