Hateoas를 써보자!
Hasteoas는 Spring에서 Restful하게 반환하기 위해 사용하는 라이브러리입니다.
원래는 interface를 만들고 해야하지만 그냥 class로 하겠습니다.
@Service
@RequiredArgsConstructor
public class PostService {
private final PostRepository postRepository;
public Page<Post> getPostList(Pageable pageable){
pageable = PageRequest.of(pageable.getPageNumber() <=0 ? 0: pageable.getPageNumber()-1,pageable.getPageSize());
Page<Post> postList = postRepository.findAll(pageable);
return postList;
}
}
Pageable은 Hateoas에서 page를 나타냅니다. 우리가 흔히 생각하는 page입니다. getPageNumber() 메소드는 현재 페이지를 반환하는 메소드입니다. 시작이 0이기 때문에 1페이지 요청을 보낼 때 1로 받기 위하여 삼항연산자를 사용해 -1을 해준 것 입니다.
PostService에서 반환받은 PageModel에 링크를 추가하여 반환합니다.
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
@RestController
@RequiredArgsConstructor
@RequestMapping("/post")
public class PostController {
private final PostService postService;
@GetMapping
public ResponseEntity<?> getPost(@PageableDefault Pageable pageable){
PagedModel<Post> body = Page<Post> postList = postService.getPostList(pageable);
PageMetadata pageMetadata = new PageMetadata(pageable.getPageSize(),postList.getNumber(),postList.getTotalElements());
PagedModel<Post> body = PagedModel.of(postList.getContent(),pageMetadata);
body.add(linkTo(methodOn(PostController.class).getPost(pageable)).withSelfRel());
return ResponseEntity.ok(body);
}
}
@PageableDefault는 Pageable의 기본 설정을 하는 Annotation입니다. 아무것도 하지 않아 size 10의 Pageable이 생성이 됩니다.
PageMetadata는 그 페이지의 정보를 담고 있습니다. 페이지가 한번에 몇 개씩 가져오는지, 총 몇 개의 원소가 있는지, 현재 몇 번째 페이지인지, 총 몇 개의 페이지가 있는지 정보를 가지고 있습니다.
PageModel은 내용과 메타데이터를 감싸는 객체입니다.
linkTo()는 링크를 남길 때 사용하는 메소드입니다.
methodOn()은 어떤 클래스의 메소드로 요청을 보냈는지 남길 때 사용합니다.
withSelfRel()은 반환하는 자원이 어떤 링크로 요청을 보내 얻은 자원인지 남기기 위해 사용합니다.
/post?page=1로 요청을 해봅니다.
"_embedded": {
"postList": [
{
"id": 1,
"title": "test",
"content": "test",
"user": {
"id": 1,
"name": "test",
"email": "test"
},
"fileList": [
{
"id": 1,
"name": "test",
"uuid": "afabd05c-d0ab-4f9b-b7b4-7b3401c92ec2",
"upload_path": "/"
}
]
}
]
},
"_links": {
"self": {
"href": "http://localhost:8080/post"
}
},
"page": {
"size": 10,
"totalElements": 1,
"totalPages": 1,
"number": 0
}