- 도메인 클래스 컨버터
- 도메인 클래스 컨버터 사용 전
@GetMapping("/members/{id}")
public String findMember(@PathVariable("id") Long id) {
Member member = memberRepository.findById(id).get();
return member.getUsername();
- 도메인 클래스 컨버터 사용 후
@GetMapping("/members2/{id}")
public String findMember(@PathVariable("id") Member member) {
return member.getUsername();
}
- 위와 같이 HTTP 파라미터로 넘어온 엔티티의 아이디로 엔티티 객체를 찾아서 바인딩하거나 엔티티 객체 자체를 바인딩 해서 찾을 수 있다.
- 단 컨버터로 엔티티를 파라미터로 받으면, 이 엔티티는 단순 조회용으로만 사용해야 한다. (트랜잭션이 없는 범위에서 엔티티를 조회했으므로, 엔티티를 변경해도 DB에 반영되지 않는다.)
- 페이징과 정렬
@GetMapping("/members")
public Page<Member> list(Pageable pageable) {
Page<Member> page = memberRepository.findAll(pageable);
return page;
}
- 파라미터로 Pageable 인터페이스를 받고 구현체로 PageRequest를 사용한다.
Page<T> findAll(Pageable pageable);
}
- findAll 파라미터로 pageable을 받는 메서드가 작성되어 있다.
@PostConstruct
public void init() {
for (int i = 0; i < 100; i++) {
memberRepository.save(new Member("user" + i, i));
}
}
- 위의 코드를 통해 임의의 Member 엔티티 100개를 생성했다고 가정한다.
{
"content": [
{
"createdDate": "2023-07-26T14:36:04.609312",
"lastModifiedDate": "2023-07-26T14:36:04.609312",
"createdBy": "d44c3a91-4cb3-453d-b788-1b536a85e2bb",
"lastModifiedBy": "d44c3a91-4cb3-453d-b788-1b536a85e2bb",
"id": 1,
"username": "user0",
"age": 0,
"team": null
},
{
"createdDate": "2023-07-26T14:36:04.638226",
"lastModifiedDate": "2023-07-26T14:36:04.638226",
"createdBy": "f617d7e2-62ef-45c6-8c5a-517536af8cc8",
"lastModifiedBy": "f617d7e2-62ef-45c6-8c5a-517536af8cc8",
"id": 2,
"username": "user1",
"age": 1,
"team": null
},
{
"createdDate": "2023-07-26T14:36:04.64061",
"lastModifiedDate": "2023-07-26T14:36:04.64061",
"createdBy": "bbc56e86-96c1-4359-93de-d3883b2f7ee6",
"lastModifiedBy": "bbc56e86-96c1-4359-93de-d3883b2f7ee6",
"id": 3,
"username": "user2",
"age": 2,
"team": null
},
...
],
"pageable": {
"sort": {
"empty": true,
"sorted": false,
"unsorted": true
},
"offset": 0,
"pageSize": 5,
"pageNumber": 0,
"paged": true,
"unpaged": false
},
"last": false,
"totalPages": 20,
"totalElements": 100,
"size": 5,
"number": 0,
"sort": {
"empty": true,
"sorted": false,
"unsorted": true
},
"first": true,
"numberOfElements": 5,
"empty": false
}
- pageable 객체를 통해 스프링 데이터 JPA가 페이징과 관련된 데이터를 전부 알아서 가져온다.
{
"content": [
{
"createdDate": "2023-07-26T14:36:04.64912",
"lastModifiedDate": "2023-07-26T14:36:04.64912",
"createdBy": "0ad70158-c53d-4efe-a81d-aad234caae6e",
"lastModifiedBy": "0ad70158-c53d-4efe-a81d-aad234caae6e",
"id": 6,
"username": "user5",
"age": 5,
"team": null
},
{
"createdDate": "2023-07-26T14:36:04.651125",
"lastModifiedDate": "2023-07-26T14:36:04.651125",
"createdBy": "1972d971-2522-4d3a-86d2-428a9c4ac9d4",
"lastModifiedBy": "1972d971-2522-4d3a-86d2-428a9c4ac9d4",
"id": 7,
"username": "user6",
"age": 6,
"team": null
},
...
"pageable": {
"sort": {
"empty": true,
"sorted": false,
"unsorted": true
},
"offset": 5,
"pageSize": 5,
"pageNumber": 1,
"paged": true,
"unpaged": false
},
"last": false,
"totalPages": 20,
"totalElements": 100,
"size": 5,
"number": 1,
"sort": {
"empty": true,
"sorted": false,
"unsorted": true
},
"first": false,
"numberOfElements": 5,
"empty": false
}
- /members?page=1 과 같은 요청을 받았을 때 Spring MVC는 'page' 등... 요청 파라미터를 Pageable 객체로 변환하여 list 메서드의 pageable 파라미터에 전달한다. 이렇게 함으로써 list 메서드 내에서 페이징과 정렬을 쉽게 처리할 수 있게 된다.
- 스프링 데이터 JPA의 기능을 스프링 부트가 알아서 Pagealbe 인터페스의 구현체로 pageRequest를 알아서 넣고, 데이터를 주입한다.
- application.yml (글로벌 설정)
data:
web:
pageable:
default-page-size: 10
max-page-size: 2000
- 설정 파일을 통해 기본값을 변경할 수 있다.
- 개별 설정
@GetMapping("/members")
public Page<MemberDto> list(@PageableDefault(size=5) Pageable pageable) {
- @PageableDefault(...)를 통해 개별 설정을 할 수도 있다.
- Page 내용을 DTO로 변환하기
1. 엔티티를 API로 노출하면 다양한 문제가 발생한다.
2. 그래서 엔티티를 꼭 DTO로 변환해서 반환해야 한다. Page는 map() 을 지원해서 내부 데이터를 다른 것으로 변경할 수 있다.
- MemberDto
@Data
public class MemberDto {
private Long id;
private String username;
private String teamName;
public MemberDto(Long id, String username, String teamName) {
this.id = id;
this.username = username;
this.teamName = teamName;
}
}
- Controller에 DTO 변환 코드 추가
@GetMapping("/members")
public Page<MemberDto> list(@PageableDefault(size=5) Pageable pageable) {
Page<Member> page = memberRepository.findAll(pageable);
Page<MemberDto> map = page.map(member -> new MemberDto(member.getId(), member.getUsername(), null));
return map;
}
{
"content": [
{
"id": 6,
"username": "user5",
"teamName": null
},
{
"id": 7,
"username": "user6",
"teamName": null
},
{
"id": 8,
"username": "user7",
"teamName": null
},
{
"id": 9,
"username": "user8",
"teamName": null
},
{
"id": 10,
"username": "user9",
"teamName": null
}
...
"pageable": {
"sort": {
"empty": true,
"sorted": false,
"unsorted": true
},
"offset": 5,
"pageNumber": 1,
"pageSize": 5,
"paged": true,
"unpaged": false
},
"last": false,
"totalElements": 100,
"totalPages": 20,
"size": 5,
"number": 1,
"sort": {
"empty": true,
"sorted": false,
"unsorted": true
},
"first": false,
"numberOfElements": 5,
"empty": false
}
- DTO를 사용하여 원하는 데이터만 가져오는 것이 가능해진다.
* 참고
- MemberDto
@Data
public class MemberDto {
private Long id;
private String username;
private String teamName;
public MemberDto(Long id, String username, String teamName) {
this.id = id;
this.username = username;
this.teamName = teamName;
}
public MemberDto(Member member) {
this.id = member.getId();
this.username = member.getUsername();
}
}
- Controller
@GetMapping("/members")
public Page<MemberDto> list(@PageableDefault(size=5) Pageable pageable) {
// Page<Member> page = memberRepository.findAll(pageable);
// Page<MemberDto> map = page.map(member -> new MemberDto(member.getId(), member.getUsername(), null));
// return map;
// return memberRepository.findAll(pageable)
// .map(member -> new MemberDto(member));
return memberRepository.findAll(pageable)
.map(MemberDto::new);
}
- DTO로 변환하는 코드를 위와 같이 줄일 수 있다.
출처 : 인프런 - 김영한(실전! 스프링 데이터 JPA)
'Programming > Spring' 카테고리의 다른 글
JPA - 기본 동작 방식, 아키텍처 (0) | 2023.08.01 |
---|---|
Spring Data JPA - 새로운 엔티티 구별하기 (0) | 2023.07.26 |
Spring Data JPA - Auditing (0) | 2023.07.26 |
Spring Data JPA - 사용자 정의 리포지토리 (0) | 2023.07.26 |
Spring Data JPA - @EntityGraph (0) | 2023.07.26 |