todo 프로젝트의 마지막 기능인 댓글 기능이다.
@Getter
@Entity
@NoArgsConstructor
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column
private String text;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
@ManyToOne
@JoinColumn(name = "todo_id")
private Todo todo;
@Column
private LocalDateTime createDate;
public Comment(CommentRequestDto dto) {
this.text = dto.getText();
this.createDate = LocalDateTime.now();
}
public void setUser(User user) {
this.user = user;
}
public void setTodo(Todo todo) {
this.todo = todo;
todo.getComments().add(this);
}
public void setText(String text) {
this.text = text;
}
}
comment 테이블을 만들어 줘야하기 때문에 Comment.java를 생성해주고 User, Todo 테이블과 다대일 관계이기 때문에 ManyToOne으로 각 테이블의 id와 매핑해준다.
public interface CommentRepository extends JpaRepository<Comment, Long> {
}
@Getter
@Setter
public class CommentRequestDto {
private Long todoId;
private String text;
}
@Getter
@Setter
public class CommentResponseDto extends CommonResponseDto {
private Long id;
private String content;
private UserDto user;
private LocalDateTime createDate;
public CommentResponseDto(Comment comment) {
this.id = comment.getId();
this.content = comment.getText();
this.user = new UserDto(comment.getUser());
this.createDate = comment.getCreateDate();
}
}
Comment를 저장할 수 있도록 CommentRepository를 만들고 CommentRequestDto, CommentResponseDto를 만들어 값 요구와 반환을 할 수 있도록 한다.
@RequestMapping("/api/comments")
@RestController
@RequiredArgsConstructor
public class CommentController {
private final CommentService commentService;
// 댓글 생성
@PostMapping()
public ResponseEntity<CommentResponseDto> postComment(@RequestBody CommentRequestDto commentRequestDto, @AuthenticationPrincipal UserDetailsImpl userDetails) {
CommentResponseDto responseDto = commentService.createComment(commentRequestDto, userDetails.getUser());
return ResponseEntity.status(201).body(responseDto);
}
// 댓글 조회
@GetMapping("/{commentId}")
public ResponseEntity<CommonResponseDto> getComment(@PathVariable Long commentId) {
try {
CommentResponseDto responseDto = commentService.getComment(commentId);
return ResponseEntity.ok().body(responseDto);
} catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().body(new CommonResponseDto(e.getMessage(), HttpStatus.BAD_REQUEST.value()));
}
}
// 댓글 수정(text)
@PutMapping("/{commentId}")
public ResponseEntity<CommonResponseDto> putComment(@AuthenticationPrincipal UserDetailsImpl userDetails, @PathVariable Long commentId, @RequestBody CommentRequestDto commentRequestDto) {
try {
CommentResponseDto responseDto = commentService.updateComment(userDetails.getUser(), commentId, commentRequestDto);
return ResponseEntity.ok().body(responseDto);
} catch (RejectedExecutionException | IllegalArgumentException e) {
return ResponseEntity.badRequest().body(new CommonResponseDto("작성자만 수정할 수 있습니다.", HttpStatus.BAD_REQUEST.value()));
}
}
// 댓글 삭제
@DeleteMapping("/{commentId}")
public ResponseEntity<CommonResponseDto> deleteComment(@AuthenticationPrincipal UserDetailsImpl userDetails, @PathVariable Long commentId) {
try {
commentService.deleteComment(userDetails.getUser(), commentId);
return ResponseEntity.ok().body(new CommonResponseDto("댓글 삭제가 완료되었습니다.", HttpStatus.OK.value()));
} catch (RejectedExecutionException | IllegalArgumentException e){
return ResponseEntity.badRequest().body(new CommonResponseDto("작성자만 삭제할 수 있습니다.", HttpStatus.BAD_REQUEST.value()));
}
}
}
@Service
@RequiredArgsConstructor
public class CommentService {
private final CommentRepository commentRepository;
private final TodoService todoService;
// 댓글 생성
public CommentResponseDto createComment(CommentRequestDto requestDto, User user) {
Todo post = todoService.getTodo(requestDto.getTodoId());
Comment comment = new Comment(requestDto);
comment.setUser(user);
comment.setTodo(post);
Comment saveComment = commentRepository.save(comment);
return new CommentResponseDto(saveComment);
}
// 댓글 단건조회
public CommentResponseDto getComment(Long commentId){
Comment comment = commentRepository.findById(commentId)
.orElseThrow(() -> new IllegalArgumentException("존재하지 않는 댓글 ID 입니다."));
return new CommentResponseDto(comment);
}
// 댓글 수정
@Transactional
public CommentResponseDto updateComment(User user, Long commentId, CommentRequestDto commentRequestDto) {
Comment comment = getComment(user, commentId);
comment.setText(commentRequestDto.getText());
return new CommentResponseDto(comment);
}
// 댓글 삭제
public void deleteComment(User user, Long commentId) {
Comment comment = getComment(user, commentId);
commentRepository.delete(comment);
}
// 검증
public Comment getComment(User user, Long commentId) {
Comment comment = commentRepository.findById(commentId)
.orElseThrow(() -> new IllegalArgumentException("존재하지 않는 댓글 ID 입니다."));
if(!user.getId().equals(comment.getUser().getId())) {
throw new RejectedExecutionException("작성자만 수정할 수 있습니다.");
}
return comment;
}
}
CommentController와 CommentService에는 앞에서 배웠던 CRUD기능과 똑같이 구현했다.
생성

조회

수정


Spring 공부를 하면서, 처음 배우는 걸 너무 많이 배우다보니 내가 지금 뭘 공부하고 있는 건지도 모르겠고 이해도 잘 안되었는데, 이번 프로젝트를 진행하면서 감을 조금씩 잡은 것 같고, 다시 spring입문으로 돌아가서 복습을 하면 처음에는 보이지 않고 이해가 되지 않았던 부분이 보일 것 같다.