티스토리 뷰
사소해 보였지만 매우 사소하지 않았던 애를 많이 먹은 구현사항이였다.
참고서적 : 자바 웹개발 워크북
요구조건
게시글을 선택 후 상세조회 게시글에서 '목록' 버튼을 눌러 나올때 원래라면 초기화된 기본 1페이지로 나온다.
초기화 시키지 말고 전 페이지로 보내주자.
예시
PageRequestDTO
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PageRequestDTO {
/**
* 현재 페이지
*/
@Builder.Default
@Min(value = 1)
@Positive
private int page = 1;
/**
* 페이지당 조회 게시글 수
*/
@Builder.Default
@Positive
private int size = 10;
/**
* 게시글 몇번째 부터 보여줄지(mybatis에서 사용)
*/
public int getSkip() {
return (page - 1) * 10;
}
/* 검색조건 */
/**
* 날짜 시작
*/
private LocalDate startDate;
/**
* 날짜 종료
*/
private LocalDate endDate;
/**
* 카테고리 검색
*/
private String categoryBoard;
/**
* 검색어
*/
private String keyword;
/**
* 페이지 이동 link
*/
private String link;
/**
* link 값 파싱 후 전달
* @return
*/
public String getLink() {
StringBuilder builder = new StringBuilder();
builder.append("page=" + this.page);
if (categoryBoard != null) {
builder.append("&categoryBoard=" + URLEncoder.encode(categoryBoard, StandardCharsets.UTF_8));
}
if (startDate != null) {
builder.append("&startDate=" + startDate);
}
if (endDate != null) {
builder.append("&endDate=" + endDate);
}
if (keyword != null) {
builder.append("&keyword=" + URLEncoder.encode(keyword, StandardCharsets.UTF_8));
}
return builder.toString();
}
}
주목할 부분은 맨 아래의 private String link와 그 link를 getter한 getLink() 메서드 이다.
getLink() 메서드는 검색조건에 데이터가 있을시 페이지 정보와 같이 파라미터로 달고 다니며 활동할 녀석들이다.
기본적으로 'page'파라미터는 바로 url옆에 붙으며 정보를 전달하고
그 아래 if문들은 검색조건의 상황에 맞춰서 추가되면서 파라미터에 들어갈 것이다.
HTML - List
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout/basic.html}">
<div layout:fragment="content">
<div class="container">
<form action="/free" method="get">
<div class="row g-3" style="margin: auto">
<input type="hidden" name="categoryBoard" value="FREE">
<div class="col-auto">
<input type="date" class="form-control" name="startDate">
</div>
<div class="col-auto">
~
</div>
<div class="col-auto">
<input type="date" class="form-control" name="endDate">
</div>
<div class="col-auto">
<input type="text" class="form-control" name="keyword" th:value="${pageRequestDTO.keyword}">
</div>
<div class="col-auto input-group-append">
<button class="btn btn-outline-secondary searchBtn" type="submit">검색</button>
</div>
</div>
</form>
<div class="row mt-3">
<div class="col">
<div class="card">
<div class="card-header">
자유게시판
</div>
<div class="card-body">
<table class="table text-center table-hover">
<thead class="table-light">
<tr>
<th style="width: 50%">제목</th>
<th>작성자</th>
<th>조회수</th>
<th>등록일시</th>
<th>수정일시</th>
</tr>
</thead>
<tbody th:with="link = ${pageRequestDTO.getLink()}">
<tr th:each="list : ${freeBoardList}">
<td><a th:href="|@{/free/{boardNo}(boardNo=${list.boardNo})}?${link}|">
[[ ${list.boardTitle} ]]
</a></td>
<td>[[ ${list.boardWriter} ]]</td>
<td>[[ ${list.boardView} ]]</td>
<td>[[ ${list.boardRegDate} ]]</td>
<td th:text="${list.boardModDate == null ? '-' : list.boardModDate}"></td>
</tr>
</tbody>
</table>
<div>
<ul class="pagination justify-content-center">
<li class="page-item" th:if="${pagination.prev}">
<a class="page-link" th:data-num="${pagination.startPage - 1}">이전</a>
</li>
<th:block th:each="i : ${#numbers.sequence(pagination.startPage, pagination.endPage)}">
<li th:class="${pagination.page == i} ? 'page-item active' : 'page-item'">
<a class="page-link" th:data-num="${i}">[[ ${i} ]]</a>
</li>
</th:block>
<li class="page-item" th:if="${pagination.next}">
<a class="page-link" th:data-num="${pagination.endPage + 1}">다음</a>
</li>
</ul>
</div>
<a href="/free/write" role="button" class="btn btn-primary float-end">글쓰기</a>
</div>
</div>
</div>
</div>
</div>
</div>
<script layout:fragment="script" th:inline="javascript">
document.querySelector(".pagination").addEventListener("click", function (e) {
e.preventDefault()
e.stopPropagation()
const target = e.target
if(target.tagName !== 'A') {
return
}
const num = target.getAttribute("data-num")
const formObj = document.querySelector("form")
formObj.innerHTML += `<input type='hidden' name='page' value='${num}'>`
formObj.submit();
},false)
</script>
매우 복잡하지만..(화면은 정말 초보자 수준이다..)
일단 유의하며 볼 부분은 4부분이다.
//검색조건에 keyword부분
<div class="col-auto">
<input type="text" class="form-control" name="keyword" th:value="${pageRequestDTO.keyword}">
</div>
```
//테이블에 제목, 상세조회로 넘어가는 a태그
<tbody th:with="link = ${pageRequestDTO.getLink()}">
<tr th:each="list : ${freeBoardList}">
<td><a th:href="|@{/free/{boardNo}(boardNo=${list.boardNo})}?${link}|">
[[ ${list.boardTitle} ]]
</a></td>
```
//페이지네이션
<div>
<ul class="pagination justify-content-center">
<li class="page-item" th:if="${pagination.prev}">
<a class="page-link" th:data-num="${pagination.startPage - 1}">이전</a>
</li>
<th:block th:each="i : ${#numbers.sequence(pagination.startPage, pagination.endPage)}">
<li th:class="${pagination.page == i} ? 'page-item active' : 'page-item'">
<a class="page-link" th:data-num="${i}">[[ ${i} ]]</a>
</li>
</th:block>
<li class="page-item" th:if="${pagination.next}">
<a class="page-link" th:data-num="${pagination.endPage + 1}">다음</a>
</li>
</ul>
</div>
```
//스크립트 태그
<script layout:fragment="script" th:inline="javascript">
document.querySelector(".pagination").addEventListener("click", function (e) {
e.preventDefault()
e.stopPropagation()
const target = e.target
if(target.tagName !== 'A') {
return
}
const num = target.getAttribute("data-num")
const formObj = document.querySelector("form")
formObj.innerHTML += `<input type='hidden' name='page' value='${num}'>`
formObj.submit();
},false)
</script>
주석 스크립트 태그 부분은 페이지네이션을 구현하기 위해 나온것이다.
keyword의 경우 th:value를 사용하지 않으면 검색조건으로 검색해도 데이터가 가지 않는다.
테이블에 제목 부분은 th:with이 변수를 지정하는 타임리프 문법이고 pageRequestDTO의 getLink()메서드를 찾아서 데이터를 넣어준다.
마지막 페이지네이션은 target으로 지정된 a태그를 data-num안에 formObj를 입력하여 페이지를 이동할때마다 전달하는 것이다.
'자바 웹개발 워크북'의 코드를 참고하여 구현하였다.
HTML - View
게시판을 구현했다면 제목으로 들어간 상세조회 페이지에서도 전달받은 파라미터를 넘겨줘야한다.
<div class="my-4">
<div class="float-end" th:with="link = ${pageRequestDTO.getLink()}">
<a th:href="|@{/free}?${link}|" class="text-decoration-none">
<button type="button" class="btn btn-secondary">목록</button>
</a>
<a th:href="@{/free/modify/{boardNo}(boardNo=${dto.boardNo})}" class="text-decoration-none">
<button type="button" class="btn btn-primary">수정</button>
</a>
</div>
</div>
전체를 볼 필요없이 목록으로 돌아가는 버튼에 th:with 변수를 지정하여 link를 전달해주면 된다.
그리고 그 전에 Controller에 고쳐야 될 부분이 있다.
/**
* 자유게시판 특정게시글 조회
* @param boardNo
* @param model
* @return
*/
@GetMapping("/free/{boardNo}")
public String getFreeView(@PathVariable Long boardNo,
/* 추가해야될 파라미터 */
PageRequestDTO pageRequestDTO,
Model model) {
BoardDTO dto = freeService.getFreeViewArticle(boardNo);
List<ReplyDTO> replyDtoList = replyService.getReply(boardNo);
model.addAttribute("dto", dto);
model.addAttribute("replyDto", replyDtoList);
return "board/free/freeView";
}
파라미터를 사용하진 않지만 pageRequestDTO 파라미터를 만들어 보내주니 Controller에선 이 데이터를 매개변수로 받아주어야 한다.
그 후 목록 버튼을 누른다면 검색조건이든 페이지데이터든 달고 다니며 사용할 수 있을것이다.
검색조건 + 페이징 을 달고다니는 문제는 궁금하여 다른 커뮤니티 사이트도 많이 참고했다.
그 결과 내가 확인한 거의 모든 사이트들은 url에 파라미터 값으로 전달하는 것을 알게되었다.
많이 더러워지는것 같다고 생각했지만 어쩔 수 없이 노가다로 하나하나 옮겨주어야 되는 문제였었다.
https://github.com/Mo-Greene/SpringBoot_Admin_MPA
GitHub - Mo-Greene/SpringBoot_Admin_MPA: MPA 관리자 게시판
MPA 관리자 게시판. Contribute to Mo-Greene/SpringBoot_Admin_MPA development by creating an account on GitHub.
github.com
글로 설명하기 어려운 부분이라 참고를 원한다면..
'Backend > SpringBoot' 카테고리의 다른 글
SpringBoot 동적인(?) 파일 수정 (0) | 2023.05.15 |
---|---|
SpringBoot 비동기 댓글 (0) | 2023.04.27 |
SpringSecurity 없이 SpringBoot 자동로그인 구현 (0) | 2023.04.24 |
[객체지향적 생각?] 게시글과 댓글로 생각해본 SRP(단일 책임 원칙) (0) | 2023.04.11 |
SpringBoot 파일 다운로드 (0) | 2023.04.10 |
- 토스페이먼츠
- mybatis구현
- script setup
- 짝지어제거하기
- 객체지향의 사실과 오해
- 한권으로끝내기리눅스마스터2급
- 리눅스마스터2급
- 함께모으기
- for
- 알고리즘
- vuex
- pinia
- SpringSecurity
- 책리뷰
- LEVEL2
- springboot
- 객체 지도
- it책 리뷰
- 타임리프
- 다음 큰 숫자
- JWT
- 맥 error
- 정수형으로 변환
- CompositionAPI
- Vue.js3
- vue.js
- 객체지향
- 프로그래머스
- java 플레이그라운드
- 스프링부트
- Total
- Today
- Yesterday