모모프로젝트의 댓글기능을 구현하다가 JSON응답 형식을 보니 프론트분들이 보기 힘들겠다는 생각이 들어 변경하고 싶었다. 내가 원했던 방식은 이차배열로 객체 안에 배열이 들어가 보기 좋게 나열되는 형태였다
저 댓글 객체 안에 topic , post 정보가 들어가길 원했다
프로젝트 ERD를 보면 Topic - Post가 서로 양방향 연관관계이다
Topic안에는 PostEntityList가 들어가 있는데 이게 무한 참조되어 값이 불러와진것을 볼 수 있었다
@Builder
@Entity
@AllArgsConstructor
@NoArgsConstructor
@Data
@Table(name = "topic")
public class TopicEntity extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long tid;
private String title;
@OneToMany(
fetch = FetchType.LAZY,
targetEntity = PostEntity.class,
mappedBy = "topicEntity"
)
private List<PostEntity> postEntityList = new ArrayList<>();
--> postEntityList가 계속 참조되어서 에러
}
원래는 단일로 Long타입의 PostId를 반환값으로 나타내주었는데 객체를 반환해 주기 위해 PostDto타입으로 변경하였다
@Builder //package-private 생성자가 자동으로 생성
@AllArgsConstructor //모든 필드 값을 파라미터로 받는 생성자를 만들어준다
@NoArgsConstructor //파라미터가 없는 기본 생성자를 생성
@Data
public class CommentDto {
@ApiModelProperty(value = "고유 id")
private Long id;
@ApiModelProperty(value = "댓글" , example = "댓글: 정말 좋아보여요")
private String comment;
private Instant createAt;
private Long userId;
private PostDto postDto; // 원래는 Long postId; 였다
}
@Override
public CommentDto create(Long postId, CommentDto dto) {
if (!this.postRepository.existsById(postId))
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
if (!this.userRepository.existsById(dto.getUserId()))
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
PostEntity postEntity = this.postRepository.findById(postId).get();
UserEntity userEntity = this.userRepository.findById(dto.getUserId()).get();
CommentEntity commentEntity = new CommentEntity();
commentEntity.setComment(dto.getComment());
commentEntity.setWriter(userEntity);
commentEntity.setPostEntity(postEntity);
commentEntity = this.commentRepository.save(commentEntity);
return new CommentDto(
commentEntity.getCid(),
commentEntity.getComment(),
commentEntity.getCreateAt(),
commentEntity.getPostEntity(),
commentEntity.getWriter().getUid()
);
}
CommentService 코드에 PostEntity를 바로 반환시키지 않고 PostDto객체를 만들어 반환하고자 하는 값을 넣어 원하는 형태로 반환시켜준다
commentEntity.setPostEntity(postEntity); 부분을 없애고 DTO객체를 만들어 값을 넣어준다
@Override
public CommentDto create(Long postId, CommentDto dto) {
if (!this.postRepository.existsById(postId))
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
if (!this.userRepository.existsById(dto.getUserId()))
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
PostEntity postEntity = this.postRepository.findById(postId).get();
UserEntity userEntity = this.userRepository.findById(dto.getUserId()).get();
CommentEntity commentEntity = new CommentEntity();
commentEntity.setComment(dto.getComment());
commentEntity.setWriter(userEntity);
// commentEntity.setPostEntity(postEntity); -> 원래는 이 방식이었지만 JSON 2차 배열방식으로 반환되길 원해서 수정
commentEntity = this.commentRepository.save(commentEntity);
/**
JSON 2차 배열로 POST객체 값을 배열형태로 가져오고 싶음!
Topic Entity의 PostEntitiyList가 계속 무한 참조됨으로
Entity를 가져오지 말고 DTO에 담아서 가져오자
* */
PostDto postDto = new PostDto();
postDto.setId(postEntity.getPid());
postDto.setContent(postEntity.getContent());
postDto.setUserId(postEntity.getWriter().getUid());
postDto.setTopicId(postEntity.getTopicEntity().getTid());
postDto.setTopicTitle(postEntity.getTopicEntity().getTitle());
postDto.setCreateAt(postEntity.getCreateAt());
return new CommentDto(
commentEntity.getCid(),
commentEntity.getComment(),
commentEntity.getCreateAt(),
commentEntity.getWriter().getUid(),
postDto
);
}
위의 코드를 고치면서 코드가 너무 길다 비효율적으로 보인다 라는 생각이 들었다. 언뜻 듣기만하고 제대로 사용해본적 없는 builder패턴이라는 것을 적용해보자!
빌더 패턴은 복잡한 객체를 생성하는 클래스와 표현하는 클래스를 분리하여, 동일한 절차에서도 서로 다른 표현을 생성하는 방법을 제공한다.
원래는 클래스를 분리해서 사용하는 것인데 현재 클래스 자체를 변경하기에는 시간적 여유와 대공사가 될것임을 깨닫고 아쉬운대로 빌더 부분만 적용시키기로 했다
/**
JSON 2차 배열로 POST객체 값을 배열형태로 가져오고 싶음!
Topic Entity의 PostEntitiyList가 계속 무한 참조됨으로
Entity를 가져오지 말고 DTO에 담아서 가져오자
* */
// 빌더 적용 전
PostDto postDto = new PostDto();
postDto.setId(postEntity.getPid());
postDto.setContent(postEntity.getContent());
postDto.setUserId(postEntity.getWriter().getUid());
postDto.setTopicId(postEntity.getTopicEntity().getTid());
postDto.setTopicTitle(postEntity.getTopicEntity().getTitle());
postDto.setCreateAt(postEntity.getCreateAt());
// 빌더 적용
PostDto postDto = PostDto.builder()
.id(postEntity.getPid())
.content(postEntity.getContent())
.userId(postEntity.getWriter().getUid())
.topicId(postEntity.getTopicEntity().getTid())
.topicTitle(postEntity.getTopicEntity().getTitle())
.build();
return new CommentDto(
commentEntity.getCid(),
commentEntity.getComment(),
commentEntity.getCreateAt(),
commentEntity.getWriter().getUid(),
postDto
);
코드가 더 깔끔해진것을 볼 수 있다!
새벽 1시까지 같이 공부하고 의견을 주신 스터디 메이트님께 영광을...!