728x90
spring data jpa가 제공하는 페이징 & 정렬 기능을 스프링 MVC에서 편하게 사용할 수 있습니다.
이 기능을 통해 실제로 controller에서 page 객체를 응답하는 api를 만들어봅시다.
todolist
1. 기본 클래스 만들기
1. entity 만들기
2. entity를 사용할 spring data jpa repository 만들기
3. controller에서 pageable 사용하기
2. api 호출
1. page 파라미터 없이 api 호출
2. page 파라미터와 함께 api 호출
3. page의 default value 수정
1. 글로벌 설정
2. 개별 설정
4. entity 대신 dto로 응답 반환하기
1-1. Member.kt
@Entity
class Member(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0L,
val username: String,
val age: Int,
val team: String? = null,
)
id(pk), username, age, tema이 있는 간단한 Member 엔티티를 만들었습니다.
1-2. MemberRepository.kt
interface MemberRepository : JpaRepository<Member, Long>
1-3. MemberController.kt
@RestController
class MemberController(
private val memberRepository: MemberRepository,
) {
@GetMapping("members")
fun list(pageable: Pageable): Page<Member> {
return memberRepository.findAll(pageable)
}
// member 데이터 초기화 용도
@PostConstruct
fun init() {
(1..100).forEach { idx ->
memberRepository.save(Member(username = "member${idx}", age = idx))
}
}
}
2-1. api를 parameter 없이 호출해봅시다.
request
curl --request GET --url 'localhost:8080/members'
response
{
"content": [
{"id":1,"username":"member1","age":1,"team":null},
{"id":2,"username":"member2","age":2,"team":null},
...
{"id":19,"username":"member19","age":19,"team":null},
{"id":20,"username":"member20","age":20,"team":null}
],
"pageable":{
"sort": {"empty":true, "sorted":false, "unsorted":true},
"offset":0,
"pageNumber":0,
"pageSize":20,
"paged":true,
"unpaged":false
},
"totalPages":5,
"totalElements":100,
"last":false,
"size":20,
"number":0,
"sort": {"empty":true, "sorted":false, "unsorted":true},
"numberOfElements":20,
"first":true,
"empty":false
}
어떻게 Pageable 파라미터 없이 요청이 성공했을까요?
정답은 SpringDataWebAutoConfiguration
에 있습니다.
SpringDataWebProperties - Pageable
controller의 파라미터가 바인딩될때 Pageable이 있으면 PageRequest 객체를 생성하여 값을 채워넣고 돌려줍니다.
2-2. 물론 request에 파라미터를 추가할수도 있습니다.
request
curl --request GET --url 'localhost:8080/members?page=2&size=3&sort=username,desc'
response
{
"content":[
{"id":93,"username":"member93","age":93,"team":null},
{"id":92,"username":"member92","age":92,"team":null},
{"id":91,"username":"member91","age":91,"team":null}
],
"pageable":{
"sort":{"empty":false,"sorted":true,"unsorted":false},
"offset":6,
"pageNumber":2,
"pageSize":3,
"paged":true,
"unpaged":false
},
"totalPages":34,
"totalElements":100,
"last":false,
"size":3,
"number":2,
"sort":{"empty":false,"sorted":true,"unsorted":false},
"numberOfElements":3,
"first":false,
"empty":false
}
3. 페이징의 default value를 수정할수도 있습니다.
3-1. 글로벌 설정
- application.properties
spring.data.web.pageable.default-page-size=20 /# 기본 페이지 사이즈/
spring.data.web.pageable.max-page-size=2000 /# 최대 페이지 사이즈/
- application.yaml / bootstrap.yaml
spring:
data:
web:
pageable:
default-page-size: 20
max-page-size: 2000
3-2. 개별 설정 in Controller
@GetMapping("members")
fun list(@PageableDefault(
size = 12, sort = ["username"], direction = Sort.Direction.DESC)
pageable: Pageable,
): Page<Member> {
return memberRepository.findAll(pageable)
}
4. entity가 아닌 dto 반환하기
엔티티를 그대로 외부 api로 노출하는건 안좋은 방법입니다.
엔티티의 데이터중 정말 api에 필요한 데이터만 response에 담아주기 위해 Dto를 사용하여 외부에 노출시키는 것이 좋습니다.
따라서 이번에는 MemberDto를 만들어서 response로 반환해보도록 하겠습니다.
MemberDto.kt
data class MemberDto(
val id: Long = 0L,
val username: String,
val age: Int,
) {
companion object {
fun by(member: Member) = MemberDto(
id = member.id,
username = member.username,
age = member.age
)
}
}
MemberController.kt
@GetMapping("members")
fun list(
@PageableDefault(size = 12, sort = ["username"], direction = Sort.Direction.DESC) pageable: Pageable,
): Page<MemberDto> {
return memberRepository.findAll(pageable).map { MemberDto.by(it) }
}