빡코

[스프링데이터 JPA] Web 확장 - 도메인클래스컨버터, 페이징과 정렬 본문

Java/JPA

[스프링데이터 JPA] Web 확장 - 도메인클래스컨버터, 페이징과 정렬

chris.djang 2023. 5. 12. 12:03

도메인클래스컨버터

*조회용으로만 사용할 것 

HTTP  파라미터로 넘어온 엔티티의 아이디로 엔티티 객체를 찾아서 바인딩

package study.datajpa.controller;

import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import study.datajpa.entity.Member;
import study.datajpa.repository.MemberRepository;

import javax.annotation.PostConstruct;

@RestController
@RequiredArgsConstructor
public class MemberController {

    private final MemberRepository memberRepository;

	//도메인 클래스 컨버터 사용 전
    @GetMapping("/members/{id}")
    public String findMember(@PathVariable("id") Long id) {
        Member member = memberRepository.findById(id).get();
        return member.getUsername();
    }
 
	//도메인 클래스 컨버터 사용 후
    @GetMapping("/members2/{id}")
    public String findMember2(@PathVariable("id") Member member) {
        return member.getUsername();
    }

    @PostConstruct
    public void init(){
        memberRepository.save(new Member("userA"));
    }

}

HTTP 요청은 회원 id를 받지만 도메인클래스컨버터가 중간에 동작해서 회원 엔티티 객체를 반환 
도메인클래스컨버터도 리파지토리를 사용해서 엔티티를 찾음> 
주의:도메인클래스컨버터로 엔티티를 파라미터로 받으면, 이엔티티는 단순조회용으로만 사용해야 한다. 
(트랜잭션이 없는 범위에서 엔티티를 조회했으므로, 엔티티를 변경해도 DB에 반영되지 않는다.)

 

페이징과 정렬 

스프링데이터가 제공하는 페이징과 정렬 기능을 스프링  MVC에서 편리하게 사용할 있다.

@GetMapping("/members")
public Page<Member>list(Pageable pageable){    
	Page<Member> page = memberRepository.findAll(pageable);
    return page;
}

파라미터로 Pageable을 받을 수 있다.

Pageable은 인터페이스, 실제는 org.springframework.data.domain.PageRequest 객체생성

 

요청 파라미터

예) /members? page=0&size=3&sort=id, desc&sort=username, descpage:

현재페이지, 0부터 시작한다.

size: 한 페이지에 노출할 데이터건수

sort: 정렬조건을 정의한다.

예) 정렬속성, 정렬속성...(ASC | DESC), 정렬방향을 변경하고 싶으면 sort 파라미터 추가(asc생략가능)

 

Paging 기본값  그로벌 설정(스프링부트)

spring:
  data:
    web:
      pageable:
        default-page-size: 20 # 기본페이지사이즈
        max-page-size: 2000 # 최대페이지사이즈

 

개별설정

@PageableDefault 어노테이션을 사용

entity 모델을 반화하면 안되며, 별도의 DTO로 반환한다.

 @GetMapping("/members")
    public Page<MemberDto> list(@PageableDefault(size = 5, sort = "username",direction = Sort.Direction.DESC) Pageable pageable) {
        Page<Member> page = memberRepository.findAll(pageable);
        Page<MemberDto> map = page.map(member -> new MemberDto(member.getId(), member.getUsername(), null));
        return map;
        
        //Page<MemberDto> map = memberRepository.findAll(pageable).map(member -> new MemberDto(member.getId(), member.getUsername(), null));
    }

DTO  또다른 방법 

package study.datajpa.dto;

import lombok.Data;
import study.datajpa.entity.Member;

@Data
public class MemberDto {

    private Long id;
    private String username;
    private String name;

    public MemberDto(Long id, String username, String name) {
        this.id = id;
        this.username = username;
        this.name = name;
    }

    public MemberDto(Member member) {
        this.id = member.getId();
        this.username = member.getUsername();
    }
}
@GetMapping("/members")
public Page<MemberDto> list(
		@PageableDefault(size = 5, sort = "username",direction = Sort.Direction.DESC) Pageable pageable) {
        return memberRepository.findAll(pageable)
           .map(MemberDto::new);

}

결과 

{
    "content": [
        {
            "id": 100,
            "username": "user99",
            "name": null
        },
        {
            "id": 99,
            "username": "user98",
            "name": null
        },
        {
            "id": 98,
            "username": "user97",
            "name": null
        },
        {
            "id": 97,
            "username": "user96",
            "name": null
        },
        {
            "id": 96,
            "username": "user95",
            "name": null
        }
    ],
 
 
 

접두사

페이징 정보가 이상이면 접두사로 구분

@Qualifier접두사명 추가

"{접두사명}_xxx”

예제:/members?member_page=0&order_page=1

public String list(
    @Qualifier("member") Pageable memberPageable,
    @Qualifier("order") Pageable orderPageable,..

 

Page를 1부터 시작하기 
스프링데이터는 Page를 0부터 시작한다. 

만약 1부터 시작하려면? 

 

1. Pageable, Page를 파리미터와 응답값으로 사용히지 않고, 직접클래스를 만들어서 처리한다. 그리고 직접 PageRequest(Pageable 구현체)를생성해서리포지토리에 넘긴다. 물론응답값도 Page 대신에 직접 만들어서 제공해야 한다. 

2.spring.data.web.pageable.one-indexed-parameters를 true로 설정한다. 그런데 이 방법은 web에서 page파라미터를-1 처리할 뿐이다. 따라서 응답값인 Page에 모두 0 페이지인덱스를 사용하는 한계가 있다