Controller testCode
@Test
@WithMockUser
void 좋아요기능() throws Exception {
mockMvc.perform(post("/api/v1/posts/1/likes")
.contentType(MediaType.APPLICATION_JSON)
).andDo(print())
.andExpect(status().isOk());
}
@Test
@WithAnonymousUser
void 좋아요클릭시_로그인하지_않은경우() throws Exception {
mockMvc.perform(post("/api/v1/posts/1/likes")
.contentType(MediaType.APPLICATION_JSON)
).andDo(print())
.andExpect(status().isUnauthorized());
}
@Test
@WithMockUser
void 좋아요클릭시_게시물이_없는경우() throws Exception {
doThrow(new SimpleSnsApplicationException(ErrorCode.POST_NOT_FOUND)).when(postService).like(any(), any());
mockMvc.perform(post("/api/v1/posts/1/likes")
.contentType(MediaType.APPLICATION_JSON)
).andDo(print())
.andExpect(status().isNotFound());
}
Controller- 좋아요 누르기
@PostMapping("/{postId}/likes")
public Response<Void> like(@PathVariable Integer postId, Authentication authentication) {
postService.like(postId, authentication.getName());
return Response.success();
}
Service- 좋아요 누르기
@Transactional
public void like(Integer postId, String userName) {
//post,user가 존재하는지 확인
PostEntity postEntity = postEntityRepository.findById(postId).orElseThrow(() -> new SimpleSnsApplicationException(ErrorCode.POST_NOT_FOUND, String.format("postId is %d", postId)));
UserEntity userEntity = userEntityRepository.findByUserName(userName)
.orElseThrow(() -> new SimpleSnsApplicationException(ErrorCode.USER_NOT_FOUND, String.format("userName is %s", userName)));
//이 user가 이미 좋아요를 눌렀는지 확인
likeEntityRepository.findByUserAndPost(userEntity, postEntity).ifPresent(it -> {
throw new SimpleSnsApplicationException(ErrorCode.ALREADY_LIKED_POST, String.format("userName %s already like the post %s", userName, postId));
});
likeEntityRepository.save(LikeEntity.of(postEntity, userEntity));
}
Repository- 좋아요 누르기
@Repository
public interface LikeEntityRepository extends JpaRepository<LikeEntity, Integer> {
Optional<LikeEntity> findByUserAndPost(UserEntity user, PostEntity post);
}
LikeEntity
@Setter
@Getter
@Entity
@Table(name = "\"like\"")
@SQLDelete(sql = "UPDATE \"like\" SET removed_at = NOW() WHERE id=?")
@Where(clause = "removed_at is NULL")
@NoArgsConstructor
public class LikeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id = null;
@ManyToOne
@JoinColumn(name = "user_id")
private UserEntity user;
@ManyToOne
@JoinColumn(name = "post_id")
private PostEntity post;
@Column(name = "registered_at")
private Timestamp registeredAt;
@Column(name = "updated_at")
private Timestamp updatedAt;
@Column(name = "removed_at")
private Timestamp removedAt;
@PrePersist
void registeredAt() {
this.registeredAt = Timestamp.from(Instant.now());
}
@PreUpdate
void updatedAt() {
this.updatedAt = Timestamp.from(Instant.now());
}
public static LikeEntity of(PostEntity post, UserEntity user) {
LikeEntity entity = new LikeEntity();
entity.setPost(post);
entity.setUser(user);
return entity;
}
}
이 entity로 user가 어떤 post에 좋아요를 눌렀는지 표현할 수 있음
Controller- 좋아요 가져오기
@GetMapping("/{postId}/likes")
public Response<Integer> getLikes(@PathVariable Integer postId, Authentication authentication) {
return Response.success(postService.getLikeCount(postId));
}
Service- 좋아요 가져오기
public Integer getLikeCount(Integer postId) {
PostEntity postEntity = postEntityRepository.findById(postId).orElseThrow(() -> new SimpleSnsApplicationException(ErrorCode.POST_NOT_FOUND, String.format("postId is %d", postId)));
List<LikeEntity> likes = likeEntityRepository.findAllByPost(postEntity);
return likes.size();
}
Repository- 좋아요 가져오기
List<LikeEntity> findAllByPost(PostEntity post);
좋아요 가져오기 최적화
위 방식대로 진행하여도 post당 좋아요 갯수를 가져올 수 있다.
그러나 위 방식은 필요한건 갯수 뿐인데 entity전체를 db에서 가져온다.
List<LikeEntity> findAllByPost(PostEntity post);
//SELECT * FROM "like" where post_id = 2;
@Query(value = "SELECT COUNT(*) from LikeEntity entity WHERE entity.post = :post")
Integer countByPost(@Param("post") PostEntity post);
다음과 같이 sql을 짜주면 위 문제를 해결할 수 있고 주석과 비교하면 차이를 알 수 있다.
'TIL' 카테고리의 다른 글
[Spring] JWT와 session 기반 인증의 차이점 (0) | 2023.02.08 |
---|---|
[Spring] 알람 기능 추가 (0) | 2023.02.01 |
[Spring] JPA deleteAll (0) | 2023.01.26 |
[Spring] Json 응답처리와 예외처리 (0) | 2023.01.14 |
[Spring] cloudtype에 배포하기 (0) | 2023.01.02 |