이 영역을 누르면 첫 페이지로 이동
나눔코딩 블로그의 첫 페이지로 이동

나눔코딩

페이지 맨 위로 올라가기

09. 스프링 부트 (Spring Boot) - thymeleaf 페이징 처리 Pageable [미완성]

나눔코딩

09. 스프링 부트 (Spring Boot) - thymeleaf 페이징 처리 Pageable [미완성]

  • 2020.11.19 19:33
  • 10. Spring/BOOT
OS Windows 10 Home 64bit 버전 2004 (OS 빌드 19041.630)
Framework Spring Boot 2.3.3 RERELEASE
EditTool Inellij IDEA 2020.1.3
BuildTool Gradle

 

# 참고 사이트
 

스프링 부트, JPA, Thymeleaf를 이용한 페이징 처리 4 - 페이징 구현 (화면)

이제 Controller에서 데이터를 model에 담아 view로 넘겼기 때문에 마지막으로 이전에 생성한 view에서 paging 로직을 개발하면된다. 게시물 리스트 화면에 뿌리기 먼저 게시물 리스트를 화면에 보여주

ivvve.github.io

 

# API
  메소드   설명   리턴 타입
  unpaged()   페이지 매김 설정이 없음을 나타내는
  Pageable 인스턴스를 반환합니다
  Pageable
  isPaged()   현재 Pageable에 페이지 매기기 정보가 포함되어 있는지
  여부를 반환합니다
  boolean
  isUnpaged()   현재 {@link Pageable}에 페이지 매기기 정보가 없는지
  여부를 반환합니다.
  boolean
  getPageNumber()   현재 페이지 번호를 리턴합니다   int
  getPageSize()   한 페이지당 보여 줄 개수를 리턴합니다   int
  getOffset()   기본 페이지 및 페이지 크기에 따라 취할 오프셋을
  반환합니다
  long
  getSort()   정렬 매개변수를 반환합니다   Sort
  getSortOr()   현재Sort 또는 현재 정렬되지 않은 경우 지정된 정렬을
  반환합니다.
  @param 정렬은 null이 아니어야합니다.
  Sort
  next()   다음 페이지를 요청하는Pageable 을 반환합니다   Pageable
  previousOrFirst()   이전 Pageable 또는 현재 페이지가 이미 첫 번째 인 경우
  첫 번째 Pageable 를 반환합니다.
  Pageable
  first()   첫 페이지를 요청하는 @link Pageable 을 반환합니다.   Pageable
  hasPrevious()   현재 페이지에서 액세스 할 수있는 이전 Pageable 가 있는지
  여부를 반환합니다. 현재 Pageable 이 이미 첫 페이지를
  참조하는 경우 false 를 반환합니다.
  boolean

 

 

 

# PageRequest
PageRequest 는 Pageable 인터페이스를 구현 한 클래스이다

 

# Thymeleaf

[결과]

이미지 클릭

 

[JAVA 코드]

@Entity
@Getter
@ToString
@NoArgsConstructor
public class Board extends AbstractEntity {
@Column(name = "title", nullable = false)
public String title;
@Lob
@Column(name = "content", nullable = false)
public String content;
@Builder(builderMethodName = "create")
private Board(String title, String content) {
this.title = title;
this.content = content;
}
}

 

@Controller
@RequiredArgsConstructor
@Slf4j
public class BoardController {
private final BoardService boardService;
@GetMapping("/board")
public String boardPage(Model model, @PageableDefault(page = 0, size = 10, sort = "id", direction = Sort.Direction.DESC) Pageable pageable) {
log.info("[GET] boardPage");
Page<Board> findBoards = boardService.findPage(pageable);
model.addAttribute("boards", findBoards);
return "board/board";
}
}

 

@Service
@Transactional
@RequiredArgsConstructor
public class BoardService {
private final BoardRepository boardRepository;
public Page<Board> findPage(Pageable pageable) {
return boardRepository.findAll(pageable);
}
}

 

[thymeleaf 코드]

<div th:if="${!boards.isEmpty()}">
<nav
th:with="
pageNumber = ${boards.pageable.pageNumber},
pageSize = ${boards.pageable.pageSize},
totalPages = ${boards.totalPages},
startPage = ${T(Math).floor(pageNumber / pageSize) * pageSize + 1},
tempEndPage = ${startPage + pageSize - 1},
endPage = (${tempEndPage > totalPages ? totalPages : tempEndPage})"
aria-label="Page navigation"
>
<ul class="pagination ">
<li th:classappend="${pageNumber + 1 <= pageSize + 1} ? 'disabled'" class="page-item">
<a class="page-link" th:href="@{/board(page=1)}">
<span>&laquo;</span>
<span class="sr-only">First</span>
</a>
</li>
<li th:classappend="${boards.first} ? 'disabled'" class="page-item">
<a class="page-link" th:href="${boards.first} ? '#' : @{/board(page=${#numbers.formatDecimal(startPage - pageSize, 0, -1)})}" aria-label="Previous">
<!-- 개인적으로 int 로 변환하는 법을 몰라서 이렇게 길어졌습니다 -->
<span aria-hidden="true">&lt;</span>
<span class="sr-only">Previous</span>
</a>
</li>
<li th:each="page: ${#numbers.sequence(startPage, endPage)}" th:classappend="${page == pageNumber + 1} ? 'active'" class="page-item">
<a th:text="${page}" class="page-link" th:href="@{/board(page=${page})}"></a>
</li>
<li th:classappend="${boards.last} ? 'disabled'" class="page-item">
<a class="page-link" th:href="${boards.last} ? '#' : @{/board(page=${#numbers.formatDecimal(startPage + pageSize, 0, -1)})}" aria-label="Next">
<span aria-hidden="true">&gt;</span>
<span class="sr-only">Next</span>
</a>
</li>
<li th:classappend=" ${T(Math).floor(totalPages/10)*10 <= startPage} ? 'disabled'" class="page-item">
<a class="page-link" th:href="@{/board(page=${totalPages})}">
<span>&raquo;</span>
<span class="sr-only">First</span>
</a>
</li>
</ul>
</nav>
</div>

 

[설명]

 

+ 개인적으로 다른 템플릿 엔진보다 thymeleaf 템플릿 엔진이 어려운 것 같습니다..

# Vue (준비중)

github.com/akageun/hello-bbs

 

akageun/hello-bbs

Spring Boot & Vue.js를 사용한 게시판 프로젝트입니다. Contribute to akageun/hello-bbs development by creating an account on GitHub.

github.com

daily-life-of-bsh.tistory.com/208

 

Vue + Spring Pagination(Paging) 구현

Vue와 Spring을 이용하여 Paging을 다음과 같은 페이징을 구현하는 방법을 알아보겠습니다. Vue 프로젝트의 파일 구조와 router.js 의 코드입니다. import Vue from "vue"; import VueRouter from "vue-router";..

daily-life-of-bsh.tistory.com

bezkoder.com/vue-pagination-axios/

 

Vue Pagination with Axios and API (Server Side pagination) example - BezKoder

In this tutorial, I will show you how to make Pagination in a Vue.js Application with existing API (Server Side pagination) using Axios and Bootstrap-Vue. Related Posts: – Vue.js 2 CRUD Application with Vue Router & Axios – Vue.js JWT Authentication wi

bezkoder.com

 

[main.js]

import Vue from 'vue'
import App from './App.vue'
import store from './store'
import router from './router'
Vue.config.productionTip = false
new Vue({
store,
router,
render: h => h(App),
}).$mount('#app')

 

[http-common.js]

import axios from 'axios'
export default axios.create({
baseURL: "/api",
headers: {
"Content-type": "application/json"
}
})

 

[App.vue]

<template>
<div id="app">
<router-view/>
</div>
</template>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
#nav {
padding: 30px;
}
#nav a {
font-weight: bold;
color: #2c3e50;
}
#nav a.router-link-exact-active {
color: #42b983;
}
</style>
<script>
export default {
}
</script>

 

[vue.config.js]

module.exports = {
/** 서버 설정 */
devServer: {
port: 3000,
proxy: {
'/api/*': {
target: 'http://localhost:8080'
}
}
}
}

 

[router.js]

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
},
{
path: '/board',
name: 'board',
component: () => import('../views/Board')
}
]
const router = new VueRouter({
mode: 'history',
routes
})
export default router

 

[Board.vue]

<template>
<div class="board">
<table class="table table-striped">
<thead class="thead-default">
<tr>
<th>번호</th>
<th>제목</th>
<th>날짜</th>
</tr>
</thead>
<tbody>
<tr v-for="board in boards" :key="board.id">
<td scope="row">{{ board.id }}</td>
<td>{{ board.title }}</td>
<td>{{ board.createdAt }}</td>
</tr>
</tbody>
</table>
<pagination
:page="page"
:totalElements="totalElements"
:size="size"
:first="first"
:last="last"
:totalPages="totalPages"
:pageRange="pageRange"
@change="handlePageChange"
/>
</div>
</template>
<script>
import boardService from "../service/boardService";
import Pagination from "./Pagination";
export default {
name: "Board",
components: { Pagination },
data() {
return {
boards: [/* id title createdAt*/],
searchTitle: '',
page: 1,
totalPages: 1,
totalElements: 0,
size: 10,
first: false,
last: false,
pageRange: []
}
},
created() {
this.retrieveBoards()
},
methods: {
getRequestParams(searchTitle, page, pageSize) {
let params = {}
if (searchTitle) {
params["title"] = searchTitle
}
if (page) {
params["page"] = page
}
if (pageSize) {
params["size"] = pageSize
}
return params
},
/** 기본 데이터 */
retrieveBoards() {
const params = this.getRequestParams(
this.searchTitle,
this.page,
this.pageSize
);
console.log('현재 페이지 번호는 ', this.page)
boardService.getAll(params)
.then((response) => {
const { content, totalElements, number, size, totalPages, first, last } = response.data;
this.boards = content;
this.totalElements = totalElements;
this.page = number + 1
this.size = size
this.first = first
this.last = last
this.totalPages = totalPages
console.log(response.data);
/** pagination*/
const startPage = Math.floor((this.page -1) / this.size ) * this.size + 1
const tempEndPage = startPage + this.size - 1
const endPage = tempEndPage > this.totalPages ? this.totalPages : tempEndPage
let tempArray = []
for (let i = startPage; i <= endPage; i++) {
tempArray.push(i)
}
this.pageRange = [].concat(tempArray)
})
.catch((e) => {
console.log(e);
});
},
/** 페이지 변경 */
handlePageChange(pageNumber) {
this.page = pageNumber
this.retrieveBoards()
},
handlePageSizeChange(event) {
this.pageSize = event.target.value;
this.page = 1;
this.retrieveBoards();
}
}
}
</script>

 

[Pagination.vue]

<template>
<nav aria-label="Page navigation">
<ul class="pagination">
<li class="page-item" :class="firstCss()">
<a class="page-link" href="javascript:void(0)" aria-label="Previous" @click="prevPage()">
<span aria-hidden="true">&laquo;</span>
<span class="sr-only">Previous</span>
</a>
</li>
<li class="page-item" :class="pageActive(pageNumber)" v-for="pageNumber in pageRange" :key="pageNumber">
<a class="page-link" href="javascript:void(0)" @click="changePage(pageNumber)">{{ pageNumber }}</a>
</li>
<li class="page-item" :class="lastCss()">
<a class="page-link" href="javascript:void(0)" aria-label="Next" @click="nextPage()">
<span aria-hidden="true">&raquo;</span>
<span class="sr-only">Next</span>
</a>
</li>
</ul>
</nav>
</template>
<script>
export default {
name: 'pagination',
props: ['page', 'totalElements', 'size', 'first', 'last', 'totalPages', 'pageRange'],
methods: {
/** 페이지 변환 */
changePage(pageNumber) {
this.$emit('change', pageNumber)
},
/** 페이지 active CSS */
pageActive(pageNumber) {
return pageNumber === this.page ? 'active' : ''
},
firstCss() {
return this.page < this.size + 1 ? 'disabled' : ''
},
lastCss() {
return Math.floor(this.totalPages / 10) * 10 <= this.pageRange[0] ? 'disabled' : ''
},
prevPage() {
this.$emit('change', this.page - this.size)
},
nextPage() {
this.$emit('change', this.page + this.size)
}
}
}
</script>

 

[boardService.js]

import http from '../http-common'
class BoardService {
getAll(params) {
return http.get('/boards', { params })
}
}
export default new BoardService()

 

 

이 글은 본 저작자 표시 규칙 하에 배포할 수 있습니다. 자세한 내용은 Creative Commons 라이선스를 확인하세요.
Creative Commons
본 저작자 표시

'10. Spring > BOOT' 카테고리의 다른 글

스프링 부트 MVC - Handler Interceptor  (0) 2022.04.14
11. 스프링 부트 (Spring Boot 2) & 뷰 (Vue 2)- 환경 구축하기  (0) 2021.03.26
10. 스프링부트 (Spring Boot 2.4.3) - javax Transactional과 spring Transactional  (0) 2021.03.14
06. 스프링 부트 (Spring Boot) - 자바 메일 센더 (Java Mail Sender)  (0) 2020.08.29
02. 스프링부트 (Spring Boot) Profile, JPA Naming, Exception 전략  (0) 2020.07.11

댓글

댓글을 사용할 수 없습니다.

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

  • 11. 스프링 부트 (Spring Boot 2) & 뷰 (Vue 2)- 환경 구축하기

    11. 스프링 부트 (Spring Boot 2) & 뷰 (Vue 2)- 환경 구축하기

    2021.03.26
  • 10. 스프링부트 (Spring Boot 2.4.3) - javax Transactional과 spring Transactional

    10. 스프링부트 (Spring Boot 2.4.3) - javax Transactional과 spring Transactional

    2021.03.14
  • 06. 스프링 부트 (Spring Boot) - 자바 메일 센더 (Java Mail Sender)

    06. 스프링 부트 (Spring Boot) - 자바 메일 센더 (Java Mail Sender)

    2020.08.29
  • 02. 스프링부트 (Spring Boot) Profile, JPA Naming, Exception 전략

    02. 스프링부트 (Spring Boot) Profile, JPA Naming, Exception 전략

    2020.07.11
다른 글 더 둘러보기

정보

나눔코딩 블로그의 첫 페이지로 이동

나눔코딩

  • 나눔코딩의 첫 페이지로 이동

검색

메뉴

  • 홈
  • 태그
  • 방명록

카테고리

  • 분류 전체보기 (316)
    • ∞. 읽은 거리 (3)
    • ∞. 기술 면접 (61)
      • 1. 자료구조 (0)
      • 2. 네트워크 (9)
      • 3. 운영체제 (11)
      • 4. 데이터베이스 (13)
      • 5. 디자인 패턴 (0)
      • 6. 알고리즘 (0)
      • 7. 자바 (15)
      • 8. 자바스크립트 (7)
      • 9. 스프링 (5)
      • 10. 시큐리티 (1)
      • 11. 기타 (0)
      • 12. Vue (0)
    • ∞. 웹개발 유용한 사이트 (14)
    • ∞. 트러블 슈팅 + TIL (7)
    • 00. 출발 (9)
    • 01. 엑셀 (9)
      • 기초 (4)
      • 컴활 1급 (4)
      • VBA (0)
    • 02. 엑세스 (9)
      • 기초 (5)
      • 컴활 1급 (4)
    • 04. Oracle (1)
      • 기초 (1)
    • 03. JAVA (8)
      • 기초 (7)
      • 객체지향 프로그래밍 (0)
    • 05. HTML (13)
      • 기초 (1)
      • css (10)
      • sass (0)
      • less (0)
    • 06. Javascript (16)
      • 기초 (13)
      • ES6 모듈 (2)
      • Canvas (0)
    • 07. JSP (0)
      • 기초 (0)
    • 08. jQuery (0)
      • 기초 (0)
    • 09. BootStrap (1)
      • 기초 (0)
      • v4 - Layout (1)
    • 10. Spring (30)
      • 기초 (3)
      • 실험 (4)
      • MVC (1)
      • BOOT (6)
      • Security (10)
      • Lib (Library) (2)
      • 벤치마킹 (0)
      • JUnit5 (2)
      • DevTools (0)
      • Socket (1)
      • Batch (0)
      • Mobile (0)
      • WebFlux (0)
      • Cloud (0)
      • Thymleaf (0)
      • Actuator (0)
      • 성능 테스트 (1)
    • 11. JetBrains (34)
      • 기초 (1)
      • IntelliJ IDEA (33)
      • WebStorm (0)
      • Pycham (0)
    • 12. API (0)
      • 기초 (0)
      • 네이버 API (0)
      • 카카오 API (0)
      • 구글 API (0)
      • 인스타그램 API (0)
    • 13. AutoHotkey (1)
    • 14. Python (8)
      • 기초 (3)
      • Selenium (2)
      • Beautiful Soup (0)
      • openpyxl (1)
      • Pyqt5 (0)
      • Deep learning (open CV) (0)
      • Geocoder (0)
      • Anaconda (0)
      • DeepLearning (0)
      • Jupyter Nootbook (0)
    • 14.5. R (0)
    • 15. JMeter (0)
      • 다운로드 (0)
    • 16. Vue JS (23)
      • 기초 (3)
      • Vue 2 (15)
      • Vue 3 (5)
      • Vuetify 2.5.8 (0)
    • 17. Git (12)
      • 기초 (8)
      • ItelliJ IDEA (4)
      • SourceTree (0)
    • 18. AWS (5)
      • 기초 (2)
      • Jira (3)
    • 19. Naver Cloud Platform (0)
    • 20. Google Cloud Platform (0)
      • 기초 (0)
      • stt & tts (0)
    • 21. Kotlin (0)
    • 22. Android (0)
      • 기초 (0)
      • Java (0)
      • Kotlin (0)
      • Flutter FrameWork (0)
    • 23. Clean Code [JAVA] (1)
    • 24. BuildTool (1)
      • Maven (1)
      • Gradle (0)
    • 25. 자료 구조와 알고리즘 (18)
      • JAVA (1)
      • Java Script (1)
      • 프로그래머스 (0)
      • 백준 알고리즘 (0)
      • 나의 알고리즘 (14)
      • Brilliant 공부 (0)
    • 26. React (1)
      • 기초 (0)
      • 강의 정리 (1)
    • 27. PostMan (0)
      • 기초 (0)
    • 28. 프로그래머스 (9)
    • 29. Leet Code (0)
    • 30. MySQL (3)
      • 기초 (2)
      • 문제 (1)
    • 73. GraphQL (0)
    • 74. Nuxt JS (0)
    • 75. Electron (0)
    • 76. UX &amp; UI Design Tool (0)
      • 기초 (0)
      • Axure (0)
      • Sketch (0)
      • Figma (0)
    • 77. MarkDown (1)
      • 기초 (1)
    • 78. Tomcat (1)
      • 메모 (1)
    • 79. Element JS (0)
    • 80. Parallax JS (0)
      • 기초 (0)
    • 81. Player JS (0)
      • 기초 (0)
    • 82. Smart Maker (0)
    • 83. Vim (0)
      • 기초 (0)
    • 84. Linux (0)
      • 기초 (0)
      • Centos 7 (0)
      • Ubuntu (0)
    • 85. Node JS (2)
      • 기초 (1)
      • WebRTC (0)
      • NVM (1)
    • 86. Propeller JS (0)
    • 87. FullPage JS (0)
      • 기초 (0)
    • 88. 아두이노 (0)
    • 89. Tensorflow (0)
    • 90. 웹 패킷 분석 (0)
    • 91. 크롬 개발자도구 (0)
    • 92. 디자인 패턴 (7)
      • 생성(Creational) (3)
      • 구조(Structral) (1)
      • 행위(Behavioral) (2)
      • SOLID 패턴 (0)
    • 95. Linux Shell Script (0)
    • 96. 구글 애널리스틱 (0)
    • 97. ffmpeg (0)
    • 98. ShareX (1)
    • 자료실 (0)
    • 기타 (2)

인기 글

공지사항

태그

  • 엑셀 가운데맞춤
  • 엑셀 기본작업
  • 졵
  • 엑셀 글씨
  • 깁
  • 엑셀 기타작업
  • 엑셀 분석작업
  • 엑셀 표시형식

나의 외부 링크

  • 비전공자 개발자
  • 자바 디자인 패턴
  • 자바 디자인 패턴
  • 스프링 블로그
  • 해킹보안 & 웹 관련
  • ERD 생성
  • 전문 기술 블로그
  • Servlet에 대한 개념없이 스프링을 했네요?
  • 스프링 FitlerChainList
  • 알고리즘 파워 블로그

정보

THE HEYDAZE의 나눔코딩

나눔코딩

THE HEYDAZE

블로그 구독하기

  • 구독하기
  • RSS 피드

방문자

  • 전체 방문자
  • 오늘
  • 어제

티스토리

  • 티스토리 홈
  • 이 블로그 관리하기
  • 글쓰기
Powered by Tistory / Kakao. © THE HEYDAZE. Designed by Fraccino.

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.