이번 포스트에서는 포스트를 등록하고 수정하고 삭제하고 읽는 포스트 관련 CRUD API를 개발할 것이다. 이를 통해 블로그 개발에 있어 아주 기본적인 기능을 추가하게 되고 react를 통해 개발하는 프론트엔드와 연동하여 유의미한 화면을 만들 수 있을 것이다.
1. PostDto 객체 생성
- Post와 관련된 데이터를 CRUD를 통해 받을 때는 기존에 생성한 Post 도메인 객체를 사용하지 않을 것이다. 물론 @jsonIgnore 어노테이션을 이용하는 방법으로 원하는 데이터만 노출할 수도 있겠지만 Post 객체를 직접 이용하기 보단 데이터 이동간의 필수 필드만 가지고 있는 DTO 객체를 별도로 생성하여 사용할 것이다.
@Data
public class PostDto {
private Long id;
private String title;
private String body;
private Long userId;
private String userName;
private String createdBy;
private LocalDateTime createdDate;
private String lastModifiedBy;
private LocalDateTime lastModifiedDate;
public PostDto () {}
public PostDto (Post post) {
this.id = post.getId();
this.title = post.getTitle();
this.body = post.getBody();
this.createdBy = post.getCreatedBy();
this.createdDate = post.getCreatedDate();
this.lastModifiedBy = post.getLastModifiedBy();
this.lastModifiedDate = post.getLastModifiedDate();
this.userId = post.getUser().getId();
this.userName = post.getUser().getUserName();
}
}
2. PostService 클래스 생성
- 이전 포스트에서 만든 PostRepository를 이용하여 포스트를 등록하고 수정하고 조회하고 삭제하는 코드를 작성하였다. 아직 User 관련 코드를 작성하지 않은 관계를 post 등록시 User는 임의로 생성하였다.
@Service
@Transactional
public class PostService {
@Autowired
private PostRepository postRepository;
public Optional<Post> findForId(Long id) {
return postRepository.findById(id);
}
public PostDto registerPost(PostDto postDto) {
Post newPost = new Post();
newPost.setTitle(postDto.getTitle());
newPost.setBody(postDto.getBody());
newPost.setUser(new User(1L)); // temporary code
return new PostDto(postRepository.saveAndFlush(newPost));
}
public Optional<PostDto> editPost(PostDto editPostDto) {
return this.findForId(editPostDto.getId())
.map(p -> {
p.setTitle(editPostDto.getTitle());
p.setBody(editPostDto.getBody());
return p;
})
.map(PostDto::new);
}
public Page<Post> findByUserOrderedByCreatedDatePageable(User user, Pageable pageable) {
return postRepository.findByUserOrderByCreatedDateDesc(user, pageable);
}
public Page<Post> findAllByOrderByCreatedDateDescPageable(Pageable pageable) {
return postRepository.findAllByOrderByCreatedDateDesc(pageable);
}
public void delete(Post post) {
postRepository.delete(post);
}
}
3. PostController 생성
- Post와 관련된 CRUD를 위한 컨트롤러를 작성하였다. API 행동에 맞는 HTTP 메소드를 선언하고 stateless 한 REST API 형태로 작성였고 기본적인 데이터 교환은 PostDto 객체를 이용하였다. 그리고 getPostList 메소드에서는 스프링의 Pageable 객체를 이용하여 손쉽게 페이징을 구현한 것을 확인할 수 있다. 기본적으로 모든 Response는 Spring의 ResponseEntity를 사용하였는데 ResponseEntity를 사용하면 body 메시지와 함께 명시적으로 적절한 HTTP 상태코드를 지정할 수 있기 때문이다.
@RestController
@RequestMapping("/api")
public class PostController {
private final Logger log = LoggerFactory.getLogger(PostController.class);
@Autowired
private PostService postService;
@GetMapping(value = "/posts/{id}")
public ResponseEntity<PostDto> getPost(@PathVariable Long id) {
log.debug("REST request to get Post : {}", id);
Post post = postService.findForId(id).orElseThrow(() -> new ApiException("Post does not exist", HttpStatus.NOT_FOUND));
return new ResponseEntity<>(new PostDto(post), HttpStatus.OK);
}
@GetMapping(value = "/posts")
public ResponseEntity<List<PostDto>> getPostList(Pageable pageable) {
log.debug("REST request to get Posts : {}", pageable);
Page<Post> posts = postService.findAllByOrderByCreatedDateDescPageable(pageable);
Page<PostDto> postDto = posts.map(post -> new PostDto((post)));
return new ResponseEntity<>(postDto.getContent(), HttpStatus.OK);
}
@PostMapping(value = "/posts")
public ResponseEntity<PostDto> registerPost(@RequestBody PostDto postDto) {
log.debug("REST request to save Post : {}", postDto);
if (postDto.getId() != null) {
throw new ApiException("A new post cannot already have an ID", HttpStatus.CONFLICT);
} else {
PostDto returnPost = postService.registerPost(postDto);
return new ResponseEntity<PostDto>(returnPost, HttpStatus.CREATED);
}
}
@PutMapping(value = "/posts/{id}")
public ResponseEntity<PostDto> editPost(@PathVariable Long id,
@RequestBody PostDto postDto) {
log.debug("REST request to edit Post : {}", postDto);
Optional<Post> post = postService.findForId(id);
if (!post.isPresent()) {
throw new ApiException("Post could not be found", HttpStatus.NOT_FOUND);
}
Optional<PostDto> returnPost = postService.editPost(postDto);
return returnPost.map(response -> {
return new ResponseEntity<PostDto>(response, HttpStatus.OK);
}).orElse(new ResponseEntity(HttpStatus.NOT_FOUND));
}
}
NEXT
- 다음 포스트에서는 create-react-app을 통해 프론트엔드 프로젝트를 생성하고 기본 UI를 작성할 것이다.
프로젝트 github
'Project' 카테고리의 다른 글
Spring boot, react 이용한 블로그 개발 (3) - ConfigurationProperties 프로퍼티 설정 (0) | 2018.10.14 |
---|---|
Spring boot, react 이용한 블로그 개발 (2) - JPA + hibernate 연동 (0) | 2018.10.13 |
Spring boot, react 이용한 블로그 개발 (1) - 프로젝트 구조 설정 (0) | 2018.10.08 |
Spring boot, react 이용한 블로그 개발 (0) - 프로젝트 시작 (1) | 2018.10.02 |