๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

JPA

JPA์—์„œ Pageable๋กœ ํŽ˜์ด์ง€ ์ฒ˜๋ฆฌํ•˜๊ธฐ

Pageable๋กœ ํŽ˜์ด์ง€ ์ฒ˜๋ฆฌํ•˜๊ธฐ

Pageable์„ ์ด์šฉํ•ด JPA์—์„œ ํŽ˜์ด์ง€ ๋‹จ์œ„๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„๋ณด์ž.

TaskRepository

Task๋ผ๋Š” ๋ชจ๋ธ์„ ๋ฐ›๋Š” TaskRepository๋ฅผ ๋งŒ๋“ค๊ณ , ํŽ˜์ด์ง€ ๋‹จ์œ„๋กœ Task๋ฅผ ๋ฐ›๋„๋ก ํ•ด๋ณด์ž.

import com.vividswan.studymate.model.Task;
import org.springframework.data.jpa.repository.JpaRepository;

public interface TaskRepository extends JpaRepository<Task ,Long> {
}

์šฐ์„  JpaRepository์„ Task ํƒ€์ž…๊ณผ Task์˜ PK ํƒ€์ž…์œผ๋กœ ์ œ๋„ค๋ฆญ ํ•˜์—ฌ ์ƒ์†๋ฐ›๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ž‘์„ฑํ•˜๋ฉด, Task Entity์— ๋Œ€ํ•œ CRUD ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋Š” TaskRepository๊ฐ€ ๋งŒ๋“ค์–ด์ง„๋‹ค.

์—ฌ๊ธฐ์„œ ํŽ˜์ด์ง€ ๋‹จ์œ„๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›๊ธฐ ์œ„ํ•œ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์ž.

package com.vividswan.studymate.repository;

import com.vividswan.studymate.model.Task;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

public interface TaskRepository extends JpaRepository<Task ,Long> {
    Page<Task> findAllByUserIdAndIsSuccess(Long userId, int isSuccess, Pageable pageable);
}

findAllByUserIdAndIsSuccess

Task Table์—์„œ userId๋ผ๋Š” ์†์„ฑ๊ณผ isSuccess๋ผ๋Š” ์†์„ฑ์„ ์ž…๋ ฅ๋ฐ›์•„ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค.

Page

return ๊ฐ’์€ ํŽ˜์ด์ง€ ๋‹จ์œ„์˜ Task ํƒ€์ž…์ด๋‹ค.

๋ฉ”์„œ๋“œ ํŒŒ๋ผ๋ฏธํ„ฐ

Long userId, int isSuccess, Pageable pageable

๋ฉ”์„œ๋“œ์— ๋“ค์–ด๊ฐ€๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ™•์ธํ•ด๋ณด์ž.

userId ์†์„ฑ๊ณผ isSuccess ์†์„ฑ์„ ๋ฐ”ํƒ•์œผ๋กœ ์กฐํšŒ๋ฅผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด ๋‘ ๊ฐ’์„ ํŒŒ๋ผ๋ฏธํ„ฐ์— ๋„ฃ์–ด์ค˜์•ผ ํ•œ๋‹ค.

๊ทธ ๋’ค์— ๊ฐ€์žฅ ์ค‘์š”ํ•œ Page์— ๋Œ€ํ•œ ์„ค์ •๊ฐ’์„ ๋‹ด์•„ ์ค„ Pageable pageable ์„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„ฃ์–ด์ค˜์•ผ ํŽ˜์ด์ง€ ์ฒ˜๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค.

TaskService

package com.vividswan.studymate.service;

import com.vividswan.studymate.config.auth.PrincipalDetails;
import com.vividswan.studymate.model.Task;
import com.vividswan.studymate.repository.TaskRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


@Service
@RequiredArgsConstructor
public class TaskService2 {

    private final TaskRepository taskRepository;


    @Transactional(readOnly = true)
    public Page<Task> findList(PrincipalDetails principalDetails, @PageableDefault(size=8, sort = "deadline", direction = Sort.Direction.ASC) Pageable pageable) {
        return taskRepository.findAllByUserIdAndIsSuccess(principalDetails.getUserId(),0, pageable);
    }

}

๋‹ค์Œ๊ณผ ๊ฐ™์ด Service ๊ณ„์ธต์—์„œ ํŽ˜์ด์ง€ ๋‹จ์œ„๋กœ Task ๊ฐ์ฒด๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๋Š” findList ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ค์–ด์ฃผ์ž.

@Transactional(readOnly = true)

์‚ฝ์ž…, ์ˆ˜์ •, ์‚ญ์ œ๊ฐ€ ์•„๋‹Œ ์กฐํšŒ๋งŒ ํ•˜๋Š” ๋ฉ”์„œ๋“œ์ด๋ฏ€๋กœ readOnly ํŠธ๋žœ์žญ์…˜์„ ์„ ์–ธํ•ด ์ค€๋‹ค.

PrincipalDetails principalDetails

UserId๋ฅผ ์ถœ๋ ฅํ•˜๊ธฐ ์œ„ํ•ด ์„ ์–ธํ–ˆ๋‹ค.

spring security context holder์— ์žˆ๋Š” ์„ธ์…˜ ๊ฐ’์„ ํ†ตํ•ด userId๋ฅผ ๋ถˆ๋Ÿฌ์˜จ๋‹ค.

@PageableDefault

@PageableDefault(size=8, sort = "deadline", direction = Sort.Direction.ASC) Pageable pageable

@PageableDefault ์–ด๋…ธํ…Œ์ด์…˜์„ ์„ ์–ธํ•ด ์ฃผ๊ณ  page์— ๋Œ€ํ•œ ์„ค์ •์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • size : ํ•œ ํŽ˜์ด์ง€์— ๋‹ด์„ ๋ชจ๋ธ์˜ ์ˆ˜๋ฅผ ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • sort : ์ •๋ ฌ์˜ ๊ธฐ์ค€์ด ๋˜๋Š” ์†์„ฑ์„ ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • direction : ์˜ค๋ฆ„์ฐจ์ˆœ๊ณผ ๋‚ด๋ฆผ์ฐจ์ˆœ ์ค‘ ๊ธฐ์ค€์„ ์„ ํƒํ•œ๋‹ค.
  • Pageable pageable : PageableDefault ๊ฐ’์„ ๊ฐ–๊ณ  ์žˆ๋Š” ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•œ๋‹ค.

ํŽ˜์ด์ง€ ์ถœ๋ ฅ

    @GetMapping("/todolist/proceeding")
    @ResponseBody
    public Page<Task> taskView(Model model, @AuthenticationPrincipal PrincipalDetails principalDetails, @PageableDefault(size=8, sort = "deadline", direction = Sort.Direction.ASC) Pageable pageable, int page){
        Page<Task> pagingTasks = taskService.findList(principalDetails, pageable);
        return pagingTasks;
    }

์ปจํŠธ๋กค๋Ÿฌ์—์„œ @ResponseBody๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ JSON ํ˜•ํƒœ๋กœ ๋ฐ›์•„์„œ ํ™•์ธํ•ด๋ณด์ž.

๊ฒฐ๊ณผ

{
  "content": [
    {
      "id": 3,
      "title": "1234",
      "content": "<p>12345</p>",
      "createDate": "2020-10-13T15:31:32.965",
      "deadline": "2020-10-07T15:31:00",
      "user": {
        "id": 1,
        "username": "vividswan",
        "nickname": "์ˆ˜ํ™˜",
        "email": "vividswan@naver.com",
        "password": "$2a$10$V.vNh2.zATNZqTeINZD57eGm6LD4C1ZxBJVah12MVZ6FBs1/tvKki",
        "role": "USER",
        "createDate": "2020-10-13T14:27:09.054"
      },
      "feedbacks": [

      ],
      "isSuccess": 0,
      "stringDeadline": "2020/10/07 03:31"
    }
  ],
  "pageable": {
    "sort": {
      "sorted": true,
      "unsorted": false,
      "empty": false
    },
    "pageNumber": 0,
    "pageSize": 8,
    "offset": 0,
    "paged": true,
    "unpaged": false
  },
  "totalPages": 1,
  "totalElements": 1,
  "last": true,
  "numberOfElements": 1,
  "first": true,
  "size": 8,
  "number": 0,
  "sort": {
    "sorted": true,
    "unsorted": false,
    "empty": false
  },
  "empty": false
}

์œ„์™€ ๊ฐ™์ด ํŽ˜์ด์ง€ ์ฒ˜๋ฆฌ๋˜์–ด ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ด์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

JSON์— ํฌํ•จ๋œ last, first, pageNumber, pageSize ๋“ฑ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํ™”๋ฉด์„ ๊ตฌํ˜„ํ•  ๋•Œ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.