현재까지 구현한 리뷰 기능은 C,R 기능만 있고 U,D 기능이 존재하지 않았기 때문에 리뷰의 수정, 삭제 기능을 추가했다. 수정과 삭제 모두 로그인한 회원 정보와 수정/삭제 하려는 리뷰를 findById
로 찾아오고, Member
에 정의해 놓은 isWrittenBy
메서드를 통해 작성자가 맞는지 체크하여 작성자가 아닐 경우 403 Forbidden
을 반환하도록 구현했다.
그 외에 수정 과정에서 수정을 하는 방법으로 JPA의 변경 감지를 쓰거나 엔티티 매니저의 병합 기능을 쓰는 방법이 있어 어떤 방식으로 할 지 고민했는데, 병합 기능은 정말 그럴 일은 없겠지만 혹시나 id가 null일 경우 수정이 아니라 저장이 될 수 있기도 하고, 굳이 메서드 호출 없이 도메인의 필드 값을 변경만 해주고 더티 체킹으로 update 쿼리를 날리는 편이 더 좋은 것 같아 변경 감지를 사용하였다.
@Transactional
public void update(final Long reviewId, final Long memberId, final ReviewRequest updateRequest) {
final Review target = findTarget(reviewId, memberId);
final Review updateReview = updateRequest.toReview(target.getKeyboard(), target.getMember());
target.update(updateReview);
}
@Transactional
public void delete(final Long reviewId, final Long memberId) {
final Review target = findTarget(reviewId, memberId);
reviewRepository.delete(target);
}
private Review findTarget(final Long reviewId, final Long memberId) {
final Member member = memberRepository.findById(memberId)
.orElseThrow(MemberNotFoundException::new);
final Review target = reviewRepository.findById(reviewId)
.orElseThrow(ReviewNotFoundException::new);
validateAuthor(member, target);
return target;
}
private void validateAuthor(final Member member, final Review target) {
if (!target.isWrittenBy(member)) {
throw new NotAuthorException();
}
}
Review
와 Member
는 @ManyToOne(fetch = FetchType.LAZY)
로 연관관계를 맺고 있다. 때문에 Review
조회 시 Member
를 프록시 객체로 조회해온다. 그런데 리뷰 수정 및 삭제 과정에서 Member.equals
를 사용하는 리뷰의 작성자인지 확인하는 로직이 들어갔는데, 여기서 예상치 못한 버그가 발생했다. 분명히 같은 Member
객체인데 동등성 비교에 실패하는 것이었다. 이는 프록시로 인한 문제였는데, JPA의 프록시에 대해 자세히 알아보면서 해결할 수 있었다.
JPA 프록시에 대한 정리는 JPA-프록시의-사실과-오해 참고
이번 스프린트의 마지막 기능으로 제품에 대해 리뷰를 작성하면 해당 제품이 자동으로 사용자의 인벤토리에 추가되도록 하는 기능을 기획했다. 인벤토리에 대한 대부분의 기능이 완료되었고, 리뷰 CRUD도 완료되었기 때문에 해당 기능을 추가하여 전체 기능을 마무리 하는 것이 내일의 목표다.