1. 양방향 연관관계에서 발생하는 순환참조
JPA에서 엔티티 간 양방향 관계를 사용하면 순환참조 문제가 발생할 수 있다.
예를 들어 Post와 Comment가 다음과 같이 서로를 참조한다고 가정한다.
// Post
@OneToMany(mappedBy = "post")
private List<Comment> comments;
// Comment
@ManyToOne
private Post post;
Post를 JSON으로 변환하면 Post 안의 comments를 조회하게 된다.
그런데 Comment에는 다시 post가 존재한다.
Post
└─ comments
└─ Comment
└─ post
└─ comments
└─ Comment
...
서로를 계속 참조하면서 무한 루프가 발생할 수 있다.
2. DTO를 사용하는 이유
이러한 문제를 해결하는 방법 중 하나가 DTO(Data Transfer Object)를 사용하는 것이다.
엔티티를 그대로 API 응답으로 반환하지 않고, API에 필요한 데이터만 DTO에 담아서 반환한다.
@Getter
public class PostDto {
private int id;
private String title;
private String body;
private LocalDateTime createDate;
private LocalDateTime modifyDate;
public PostDto(Post post) {
this.id = post.getId();
this.title = post.getTitle();
this.body = post.getContent();
this.createDate = post.getCreateDate();
this.modifyDate = post.getModifyDate();
}
}
컨트롤러에서는 엔티티를 DTO로 변환한 후 반환한다.
@GetMapping("/posts")
@ResponseBody
public List<PostDto> list() {
List<Post> postList = postService.findAll();
return postList.stream()
.map(PostDto::new)
.toList();
}
여기서
.map(PostDto::new)
은 다음 코드와 같은 의미이다.
.map(post -> new PostDto(post))
즉, Post 객체 하나를 PostDto 객체 하나로 변환하는 것이다.
이렇게 하면 엔티티 구조를 외부에 그대로 노출하지 않고 필요한 데이터만 API 응답으로 제공할 수 있다.
또한 API 응답의 필드 이름을 변경해야 할 때도 엔티티를 수정하지 않고 DTO만 수정하면 된다.
DTO에 Setter를 사용하지 않는 이유
응답용 DTO는 일반적으로 조회할 데이터를 전달하는 역할만 하기 때문에 Setter를 제공하지 않는 것이 좋다.
필요한 값은 생성자를 통해 전달하고, @Getter를 통해 조회하도록 구성할 수 있다.
3. Record를 이용한 DTO
Java의 record를 사용하면 데이터를 전달하기 위한 DTO를 더욱 간결하게 작성할 수 있다.
public record PostDto(
int id,
String title,
String body,
LocalDateTime createDate,
LocalDateTime modifyDate
) {
public PostDto(Post post) {
this(
post.getId(),
post.getTitle(),
post.getContent(),
post.getCreateDate(),
post.getModifyDate()
);
}
}
Record는 기본적으로 데이터를 변경하지 않는 불변 객체로 사용하기 적합하다.
또한 Getter를 별도로 작성하지 않아도 된다.
postDto.title()
postDto.body()
와 같은 형태로 값을 조회할 수 있다.
'BackEnd > Spring' 카테고리의 다른 글
| REST API 응답 형식 통일하기 - HTTP 상태 코드와 RsData (0) | 2026.08.12 |
|---|---|
| [Spring] REST API 버저닝과 @RequestMapping (0) | 2026.08.12 |
| [Spring] Java Record란? DTO를 간결하게 만드는 방법 (0) | 2026.08.11 |
| [Spring] orphanRemoval (0) | 2026.08.11 |
| [Spring] REST API란? SSR과 CSR 차이부터 JSON 응답까지 (0) | 2026.08.11 |
댓글