Skip to content

Conversation

@xxxjinn
Copy link
Contributor

@xxxjinn xxxjinn commented May 7, 2025

추가 Q & A

🤔 잘 모르겠거나, 더 궁금한 내용이 있었나요?

집중적으로 리뷰 받고싶은 것이 있나요?

  • comment api 엔드포인트 이름 제대로 지은 것 맞나요?
  • 올려주신 예시 중 Req body에 comment의 CreateCommentRequest에서 postId를 안받고있던데 받게 하는 것 맞을까요?? 일단 저는 받도록 구현해두었습니다!

@xxxjinn xxxjinn changed the title [6주차] 신현진 학습 PR 제출합니다. [7주차] 신현진 학습 PR 제출합니다. May 11, 2025
@xxxjinn xxxjinn changed the title [7주차] 신현진 학습 PR 제출합니다. [8주차] 신현진 학습 PR 제출합니다. May 16, 2025
Copy link

@KoSeonJe KoSeonJe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨어요~

코멘트 남겼는데,,,,, 조금 많네요.
그래도 알아야할 개념만 남겼습니다! 고민해보세요! 답글은 괜찮아요~ㅎㅎ

자신이 작성한 코드에 의문을 계속해서 가져보면 좋을 것 같아요!


@RestController
@RequiredArgsConstructor
@RequestMapping

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 어노테이션은 무슨 역할을 하나요!? 적절하게 사용하고 계시는지 다시 한번 고민해주세요!

Copy link
Contributor Author

@xxxjinn xxxjinn May 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RequestMapping을 클래스 단위로 사용했을 때 그 아래에 있는 메서드들은 @RequestMapping의 url을 공통 경로로 해서 라우팅이 이루어지게 됩니다. 이전에는 따로 경로를 명시해주지 않았기 때문에 모든 메서드가 /를 기준으로 경로를 계산해서 딱히 의미가 없었네요! 수정했습니다 336c6d8

pr 본문에도 적어두었는데, 특정 게시글의 댓글을 조회할 때의 엔드포인트는 /comments/post/{postId}/post/{postId}/comments 중 어느 것이 더 좋은 방식인가요? (저는 게시글 안에 댓글이 있는거라고 생각해서 후자가 더 나은 것 같은데 👀)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

말씀하신것처럼 게시글 안에 댓글이라는 계층이 있으니 posts/{postId}/comments 가 좋아보이네요!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니당 수정했습니다!! 120d959

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아 답장이 늦어졌네요~ 저도 posts/{postId}/comments가 좋아보여요!
아래 글 중 5번을 읽어보면 좋을 것 같네요~!
Restful하기 위한 6가지 원칙

import java.util.List;

@RestController
@RequiredArgsConstructor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 어노테이션은 어떤 필드를 대상으로 생성자를 생성해주나요?
이 외에 생성자를 자동으로 생성하는 어노테이션은 어떤 것들이 있나요!?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RequiredArgsConstructor는 final 또는 @nonnull이 붙은 필드에 대해 자동으로 생성자를 생성해줍니다!
그래서 private final CommentService commentService; 의 생성자를 lombok이 자동으로 생성해주게 됩니다.

생성자를 자동으로 생성해주는 어노테이션은

  • @NoArgsConstructor : 파라미터가 없는 기본 생성자를 생성합니다.
  • @AllArgsConstructor : 모든 필드를 파라미터로 받는 생성자를 생성합니다.
    • 모든 필드를 수동으로 초기화할 필요가 있을 때 사용합니다.


import java.util.List;

@RestController

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RestController@Controller의 차이는 무엇인가요!?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RestController는 이름에서부터 REST API에 적합한 어노테이션임을 알 수 있습니다. 메서드의 리턴값이 http 응답 body로, 보통은 json 형태로 전송됩니다. 해당 어노테이션이 붙은 클래스는 @Controller@ResponseBody가 합쳐진 형태가 되게 됩니다.

@Controller는 리턴값이 view로 처리되게 되며, json 등의 데이터 자체를 응답하기 위해서는 메서드에 @ResponseBody를 추가로 붙여야합니다.

Comment on lines 24 to 25
public List<CommentResponse> getComments(@PathVariable Long postId) {
return commentService.getCommentsByPost(postId);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

메서드명을 다르게 선언하신 이유가 있나요!?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

controller 내부에서는 다른 건 생각하지 않고 기본적인 crud에 맞춰 생각하느라 다르게 지었던 것 같아요!.. 좀 더 명확하게 service 내부 메서드와 메서드명을 getCommentsByPost로 일치시켰습니다! 89124e5

private Long postId;

public Comment toEntity(Member member, Post post) {
return Comment.builder().content(content).member(member).post(post).build();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return Comment.builder().content(content).member(member).post(post).build();
return Comment.builder()
.content(content)
.member(member)
.post(post)
.build();

가독성을 위해 줄바꿈~!

}

public List<CommentResponse> getCommentsByPost(Long postId){
return commentRepository.findByPostId(postId).stream().map(CommentResponse::from).toList();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

줄바꿈 해주세요! 가독성을 위해

Suggested change
return commentRepository.findByPostId(postId).stream().map(CommentResponse::from).toList();
return commentRepository.findByPostId(postId).stream()
.map(CommentResponse::from)
.toList();

Comment on lines +28 to +32
@OneToMany(mappedBy = "member", cascade = CascadeType.ALL)
private List<Post> posts = new ArrayList<>();

@OneToMany(mappedBy = "member", cascade = CascadeType.ALL)
private List<Comment> comments = new ArrayList<>();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

연관관계를 양방향으로 선언해주신 이유가 궁금해요~
어떤 장단점이 있고, 어떤 경우에 써야 할까요??

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

양방향으로 매핑을 해주었을 때, 각각 하나의 테이블을 기준으로 연결되어있는 다른 테이블을 조회할 수 있다고 알고있어서 이런식으로 구현해보았습니다! (ex. 멤버가 작성한 게시글 리스트를 조회하고 싶을 때)

  • 장점

    • 앞서 말한대로 테이블을 조회할 때 편리합니다.
    • 자식 엔티티를 일괄 삭제할 때 관리가 편리합니다.
  • 단점

    • 양쪽 관계를 유지할 때 필요합니다.
    • 연관관계를 설정하는 복잡도가 증가하게 됩니다.
  • 양방향을 써야하는 경우

    • 연관된 데이터를 같이 자주 조회할 때 사용하게 됩니다.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

최고입니다!!ㅎㅎ

Comment on lines 20 to 22
@Column(name="post_id")

private Long id;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@Column(name="post_id")
private Long id;
@Column(name="post_id")
private Long id;

ㅎㅎ

Comment on lines +30 to +31
@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Comment> comments = new ArrayList<>();
Copy link

@KoSeonJe KoSeonJe May 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cascade와 orphanRemoval은 어떤 차이가 있나요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • cascade : 부모와 연결된 자식에게도 똑같은 작업을 한다는 의미가 있습니다.

    • 부모 저장 -> 자식 저장 / 부모 수정 -> 자식 수정 / 부모 삭제 -> 자식 삭제
  • orphanRemoval : true일 때 부모-자식 관계가 끊어진 자식의 경우, 자동으로 삭제되게 한다는 의미가 있습니다.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

최고~

Comment on lines 26 to 31
@ManyToOne
@JoinColumn(name = "member_id", nullable = false)
private Member member;

@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Comment> comments = new ArrayList<>();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ManyToOne@OneToMany의 기본 fetch 전략은 어떻게 될까요?
(지연로딩 혹은 즉시로딩)
알맞게 설정해주면 좋을 것 같아요~

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ManyToOne의 기본 fetch 전략은 즉시로딩으로, post를 조회하면 member도 즉시 조회가 됩니다.
@OneToMany의 기본 fetch 전략은 지연로딩으로, post를 조회할 때 comments는 조회되지 않고, post.getComments()를 하는 시점에 조회할 수 있습니다.

찾아보았을 때 여러 post를 조회했을 때 연관된 member까지 매번 불러오면 불필요한 쿼리가 많아질 수 있기 때문에 ManyToOne의 경우에도 LAZY로 바꾸는 것이 좋다고 하는데 맞나요?.?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

맞아요! 실행해보시면 아시겠지만, 즉시로딩일 때에는 Member와 Join을 하여 member의 정보를 항상 모두 불러옵니다!
그래서 Lazy로 fetch 전략을 바꾸는 것이 좋아요! 즉시 로딩을 관리하기도 힘들기도하니까요~

하지만, Post를 사용할때 항상 Member를 사용한다면, 어떻게 될까?
지연로딩된 객체의 데이터를 조회하기위해 쿼리를 항상 하나 추가로 날리게됩니다. 어쩌면 join보다 더 비용이 많이 들 수 있겠네요
그래서 이를 해결하기위해 fetch join 혹은 entityGraph를 통해 직접 쿼리를 커스텀해줘야합니다!
잘 관리할 수 있다면 EAGER로 선언해도 되구요!

이것도 잘 이해가 안되면 멘토 콜!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fetch join 방식을 사용해 postId로 comment를 찾는 api가 있어야해서 해당 부분을 수정했습니다! 174a9e1

말씀해주셨던 post-member의 관계에서는 memberId로 post를 찾는다는가 그런 api는 없어가지구 @manytoone 에 LAZY를 달아두기만 했습니다!.!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants