게시판 만들기 - 2(페이징)
2021. 8. 12. 10:42ㆍ(구)공부/SpringBoot
728x90
PageVO
package com.bit.vo;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
//브라우저에서 전달되는 페이지 번호와 게시물 수
public class PageVO {
private static final int DEFAULT_SIZE = 10;
private static final int DEFAULT_MAX_SIZE=50;
private int page;
private int size;
private String type;
private String keyword;
PageVO(){
this.page = 1;
size = DEFAULT_SIZE;
}
public int getPage() {
return page;
}
public int getSize() {
return size;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
public void setPage(int page) {
this.page = page<=0?1:page;
}
public void setSize(int size) {
this.size = size < DEFAULT_SIZE ||
size > DEFAULT_MAX_SIZE ? DEFAULT_SIZE : size;
}
public Pageable makePageable(int direction, String...props) {
Sort.Direction dir = direction == 0 ? Sort.Direction.DESC :
Sort.Direction.ASC;
return PageRequest.of(this.page-1, this.size, dir, props);
}
}
WebBoardRepository
package com.bit.persistence;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.data.repository.CrudRepository;
import com.bit.domain.QWebBoard;
import com.bit.domain.WebBoard;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Predicate;
public interface WebBoardRepository extends CrudRepository<WebBoard, Long>, QuerydslPredicateExecutor<WebBoard>{
//java 8.0 : 디폴트 메소드 -> 오버라이딩하지 않으면 이 메소드 그대로 사용
public default Predicate makePredicate(String type, String keyword) {
BooleanBuilder builder = new BooleanBuilder();
QWebBoard board = QWebBoard.webBoard;
//bno>0
builder.and(board.bno.gt(0));
if(type==null) {
return builder;
}
//검색 로직
switch(type) {
case "t":
builder.and(board.title.like("%"+keyword+"%"));
break;
case "c":
builder.and(board.content.like("%"+keyword+"%"));
break;
case "w":
builder.and(board.writer.like("%"+keyword+"%"));
break;
}
return builder;
}
}
WebBoard
package com.bit.domain;
import java.sql.Timestamp;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter @Setter @ToString
@Entity @Table(name = "tbl_webboards")
@EqualsAndHashCode(of="bno")
public class WebBoard {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long bno;
private String title;
private String writer;
private String content;
@CreationTimestamp
private Timestamp regdate;
@UpdateTimestamp
private Timestamp updatedate;
}
PageMaker
package com.bit.vo;
import java.util.ArrayList;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import lombok.Getter;
import lombok.ToString;
import lombok.extern.java.Log;
@Getter
@ToString(exclude="pageList")
@Log
public class PageMaker<T> {
private Page<T> result;
private Pageable prevPage;
private Pageable nextPage;
private int currentPageNum;
private int totalPageNum;
private Pageable currentPage;
private List<Pageable> pageList;
public PageMaker(Page<T> result){
this.result = result;
this.currentPage = result.getPageable();
this.currentPageNum = currentPage.getPageNumber() + 1;
this.totalPageNum = result.getTotalPages();
this.pageList = new ArrayList<>();
calcPages();
}
private void calcPages(){
int tempEndNum = (int)(Math.ceil(this.currentPageNum/10.0)* 10);
int startNum = tempEndNum -9;
Pageable startPage = this.currentPage;
//move to start Pageble
for(int i = startNum; i < this.currentPageNum; i++){
startPage = startPage.previousOrFirst();
}
this.prevPage = startPage.getPageNumber() <= 0? null :startPage.previousOrFirst();
// log.info("tempEndNum: " + tempEndNum);
// log.info("total: "+ totalPageNum);
if(this.totalPageNum < tempEndNum){
tempEndNum = this.totalPageNum;
this.nextPage = null;
}
for(int i = startNum ; i <= tempEndNum; i++){
pageList.add(startPage);
startPage = startPage.next();
}
this.nextPage = startPage.getPageNumber() +1 <= totalPageNum ? startPage: null;
}
}
WebBoardController
package com.bit.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.bit.domain.WebBoard;
import com.bit.persistence.WebBoardRepository;
import com.bit.vo.PageMaker;
import com.bit.vo.PageVO;
import lombok.extern.java.Log;
@Controller
@RequestMapping("/boards")
@Log
public class WebBoardController {
@Autowired
private WebBoardRepository repo;
@GetMapping("/list")
public void list(@ModelAttribute("pageVO")PageVO vo ,Model model) { //boards/list.html 호출
Pageable page = vo.makePageable(0, "bno");
Page<WebBoard> result = repo.findAll(repo.makePredicate(vo.getType(),vo.getKeyword()),page);
log.info("list() called " + page);
log.info(result+"");
// model.addAttribute("result",result);
model.addAttribute("result",new PageMaker(result));
}
@GetMapping("/register")
public void registerGET(@ModelAttribute("vo")WebBoard vo) {
log.info("registerGET...");
vo.setTitle("샘플제목");
vo.setContent("샘플 내용");
vo.setWriter("user00");
}
@PostMapping("/register")
public String registerPOST(@ModelAttribute("vo")WebBoard vo
, RedirectAttributes rttr) {
log.info("registerPOST...");
log.info(vo+"");
repo.save(vo);
//addFlashAttribute : url에 붙지 않고, 한번 사용후 데이터 소멸
rttr.addFlashAttribute("msg","success");
vo.setTitle("샘플제목");
vo.setContent("샘플 내용");
vo.setWriter("user00");
return "redirect:/boards/list";
}
@GetMapping("/view")
public void view(Long bno, @ModelAttribute("pageVO") PageVO vo,
Model model) {
log.info("bno : " + bno);
repo.findById(bno).ifPresent(board->model.addAttribute("vo",board));
}
}
list.html, view.html, register.html 얘네 위치는 다 boards
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{/layout/layout1}">
<div layout:fragment="content">
<div class="panel-heading">List Page</div>
<div class="panel-body pull-right">
<h3><a class="label label-default" th:href="@{register}">Register</a></h3>
</div>
<div class="panel-body">
<p>[[${result}]]</p>
<div th:with="result=${result.result}">
<table class="table table-striped table-bordered table-hover" id="dataTables-example">
<thead>
<tr>
<th>BNO</th>
<th>TITLE</th>
<th>WRITER</th>
<th>REGDATE</th>
</tr>
</thead>
<tbody>
<tr class="odd gradeX" th:each="board:${result.content}">
<td>[[${board.bno}]]</td>
<td><a th:href="${board.bno}" class="boardLink">
[[${board.title}]]</a> </td>
<td>[[${board.writer}]]</td>
<td class="center">
[[${#dates.format(board.regdate,'yyyy-MM-dd')}]]</td>
</tr>
</tbody>
</table>
<div>
<select id='searchType'>
<option>--</option>
<option value='t' th:selected="${pageVO.type} =='t'" >Title</option>
<option value='c' th:selected="${pageVO.type} =='c'">Content</option>
<option value='w' th:selected="${pageVO.type} =='w'">Writer</option>
</select>
<input type='text' id='searchKeyword' th:value="${pageVO.keyword}">
<button id='searchBtn'>Search</button>
</div>
</div>
<!--paging-->
<nav>
<div>
<ul class="pagination">
<li class="page-item" th:if="${result.prevPage}">
<a th:href="${result.prevPage.pageNumber}+1">PREV [[${result.prevPage.pageNumber}+1]]</a>
</li>
<li th:classappend="${p.pageNumber==result.currentPageNum-1}?active:' '"
th:each="p:${result.pageList}">
<a th:href="${p.pageNumber}+1">[[${p.pageNumber}+1]]</a>
</li>
<li class="page-item" th:if="${result.nextPage}">
<a th:href="${result.nextPage.pageNumber}+1">NEXT [[${result.nextPage.pageNumber}+1]]</a>
</li>
</ul>
</div>
</nav>
</div>
<form id='f1' th:action="@{list}" method="get">
<input type='hidden' name='page' th:value=${result.currentPageNum}>
<input type='hidden' name='size' th:value=${result.currentPage.pageSize}>
<input type='hidden' name='type' th:value=${pageVO.type}>
<input type='hidden' name='keyword' th:value=${pageVO.keyword}>
</form>
</div>
<!-- end fragment -->
<th:block layout:fragment="script">
<script th:inline="javascript">
var formObj = $("#f1");
$(window).load(function () {
var msg = [[${msg}]];
if (msg == 'success') {
alert("정상적으로 처리되었습니다.");
var stateObj = {msg: ""};
}
});
$(document).ready(function () {
$(".pagination a").click(function (e) {
e.preventDefault();
formObj.find('[name="page"]').val($(this).attr('href'));
formObj.submit();
});
});
$("#searchBtn").click(function (e) {
var typeStr = $("#searchType").find(":selected").val();
var keywordStr = $("#searchKeyword").val();
console.log(typeStr, "", keywordStr);
formObj.find("[name='type']").val(typeStr);
formObj.find("[name='keyword']").val(keywordStr);
formObj.find("[name='page']").val("1");
formObj.submit();
});
$(".boardLink").click(function (e) {
e.preventDefault();
var boardNo = $(this).attr("href");
formObj.attr("action", [[@{'/boards/view'}]]);
formObj.append("<input type='hidden' name='bno' value='" + boardNo + "'>");
formObj.submit();
});
</script>
</th:block>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{/layout/layout1}">
<div layout:fragment="content">
<div class="panel-heading">Register Page</div>
<div class="panel-body">
<form th:action="@{register}" method="post">
<div class="form-group">
<label>Title</label> <input class="form-control" name="title"
th:value="${vo.title}" />
<p class="help-block">Title text here.</p>
</div>
<div class="form-group">
<label>Content</label>
<textarea class="form-control" rows="3" name='content'
th:text="${vo.content}"></textarea>
</div>
<div class="form-group">
<label>Writer</label> <input class="form-control" name="writer"
th:value="${vo.writer}" />
</div>
<button type="submit" class="btn btn-default">Submit Button</button>
<button type="reset" class="btn btn-primary">Reset Button</button>
</form>
</div>
</div>
<!-- end fragment -->
<th:block layout:fragment="script">
<script th:inline="javascript">
</script>
</th:block>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{/layout/layout1}">
<div layout:fragment="content">
<div class="panel-heading">View Page</div>
<div class="panel-body">
<div class="form-group">
<label>BNO</label> <input class="form-control" name="bno"
th:value="${vo.bno}" readonly="readonly" />
</div>
<div class="form-group">
<label>Title</label> <input class="form-control" name="title"
th:value="${vo.title}" readonly="readonly" />
<p class="help-block">Title text here.</p>
</div>
<div class="form-group">
<label>Content</label>
<textarea class="form-control" rows="3" name='content'
th:text="${vo.content}" readonly="readonly"></textarea>
</div>
<div class="form-group">
<label>Writer</label> <input class="form-control" name="writer"
th:value="${vo.writer}" readonly="readonly" />
</div>
<div class="form-group">
<label>RegDate</label><input class="form-control" name="regDate"
th:value="${#dates.format(vo.regdate,'yyyy-MM-dd')}"
readonly="readonly" />
</div>
<div class="pull-right">
<a th:href="@{modify(page=${pageVO.page},
size=${pageVO.size},
type=${pageVO.type},
keyword=${pageVO.keyword},
bno =${vo.bno}
)}" class="btn btn-default">Modify/Delete</a>
<a th:href="@{list(page=${pageVO.page},
size=${pageVO.size},
type=${pageVO.type},
keyword=${pageVO.keyword},
bno = ${vo.bno}
)}" class="btn btn-primary">Go List</a>
</div>
</div>
</div>
<!-- end fragment -->
<th:block layout:fragment="script">
<script th:inline="javascript">
</script>
</th:block>
728x90
'(구)공부 > SpringBoot' 카테고리의 다른 글
entity 설정 (0) | 2021.11.10 |
---|---|
게시판 - 3 (수정,삭제) 최종 (1) | 2021.08.14 |
게시판 만들기 - 1 (0) | 2021.08.11 |
Thymeleaf 입문 (0) | 2021.08.10 |
JPA 다양한 select 메소드 (0) | 2021.08.06 |