Entity 끼리 연관관계를 설정할 경우 무한궤도에 들어갈 수 있다.
ORM이 Entity를 매핑할 때 Entity 안의 연관관계에 있는 다른 Entity를 생성하고
다른 Entity에서 처음 Entity를 다시 만듦으로써 무한 루프에 들어가서 오류가 발생한다.
(아래 코드에서 추가설명)
해결책은 @JsonIgnore 어노테이션을 엔티티 속성 중 다른 엔티티를 생성하는 필드에 붙이는 방법,
또한 로그를 찍을 때 toString 과정에서도 무한루프가 발생하여 @ToString.Exclude 어노테이션도 붙여 방지하는 방법이 있다.
하지만 이 방법은 데이터를 요청하였을 때 어노테이션을 붙인 필드가 제외된 JSON 데이터를 받게 된다. 즉 근본적인 해결책이 아니다.
따라서 Entity를 직접적으로 view까지 내리지 않기 위해서
Entity에 해당하는 Dto를 만들어 대신 값을 내린다. (값 변환)
값변환은 converter를 따로 만들어 관련 로직을 통일성 있게 관리하도록 한다. (오류 수정 용이)
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString
@Entity(name="board") //연결할 table 이름
public class BoardEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String board_name;
private String status;
@OneToMany(
mappedBy = "boardEntity"
)
private List<PostEntity> postList = List.of();
}
public class PostEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JsonIgnore // Json 생성으로 인한 무한 루프 방지 //이제는 dto로 리턴하기 때문에 있으나 없으나
@ToString.Exclude // ToString 사용시 무한 루프 방지
@JoinColumn(name = "board_id")
private BoardEntity boardEntity; // 시스템상으로 뒤에 +_id
private String user_name;
다음 코드와 같이 BoardEntity를 생성할 때 List<PostEntity>를 생성하게 되고
PostEntity를 생성하기 위해서 boardEntity를 생성하게 되는데 이때 무한루프를 돌게된다.
@Service
@RequiredArgsConstructor
public class BoardConverter { // 데이터 변환의 역할
private final PostConverter postConverter;
public BoardDto toDto(BoardEntity boardEntity){
var postList=boardEntity.getPostList().stream() // 스트림으로 변환
.map(postEntity -> {
return postConverter.toDto(postEntity);
}).collect(Collectors.toList()); // 변환된 PostDto 객체 리스트로 수집
return BoardDto.builder()
.id(boardEntity.getId())
.board_name(boardEntity.getBoard_name())
.status(boardEntity.getStatus())
.postList(postList) //boardEntity.getPostList()
.build()
;
}
}
@Service
public class PostConverter { // 데이터 변환
public PostDto toDto(PostEntity postEntity) {
return PostDto.builder()
.id(postEntity.getId())
.user_name(postEntity.getUser_name())
.status(postEntity.getStatus())
.email(postEntity.getEmail())
.password(postEntity.getPassword())
.title(postEntity.getTitle())
.content(postEntity.getContent())
.posted_at(postEntity.getPosted_at())
.boardId(postEntity.getBoardEntity().getId())
.build();
}
}
따라서 다음 코드와 같이 Converter 클래스를 만들어 Entity에 대응하는 Dto로 값을 변환한다.
'Springboot' 카테고리의 다른 글
[스프링 부트] 인터셉터 (0) | 2024.07.04 |
---|---|
[스프링 부트] 페이지네이션 정보 응답 받기 (0) | 2024.07.01 |
[스프링 부트] DispatcherSevlet의 역할 (0) | 2024.06.29 |
[스프링 부트] Object Mapper (0) | 2024.06.25 |
스프링 부트2 (view 환경설정) (0) | 2024.06.21 |