쌓고 쌓다
Entity와 DTO의 분리 필요성 및 방법 본문
Entity 자체를 요청과 응답을 처리하는데 그대로 사용하니 다음과 같은 문제 또는 비효율적인 부분이 발생했다...
먼저 회원 엔티티를 보자.
@Entity
@Data
public class Member {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String loginId;
private String loginPwd;
private String name;
@Enumerated(EnumType.STRING)
private Role role;
@CreationTimestamp
private LocalDateTime regDate;
@Enumerated(EnumType.STRING)
private MemberType type;
private Long snsId;
}
이제 발생한 문제들을 간단히 보자.
1. 의도하지 않은 데이터 저장
회원가입시 다음과 같이 컨트롤러에서 Member 엔티티를 그대로 받아 가입을 진행했더니...
회원가입 요청시 유저 권한을 나타내는 role이나 소셜가입시 발급되는 snsId 컬럼에 값을 넣을 수 있다.
{
"name" : "TESTNAME6",
"loginId" : "test6",
"loginPwd" : "1234",
"snsId" : 7777,
"type" : "ADMIN"
}
의도하지 않은 snsId, type이 그대로 디비에 넣어가버린다.
물론 값을 초기화시켜주면 해결할 수 있지만 근본적으로 문제가 있다는게... 문제다!
2. 순환 참조 및 불필요한 응답 데이터 처리
JPA를 사용하다보면 양방향 순환 참조가 발생할 수 있다.
예를 들어 게시글에 회원을 참조하고있고 회원은 게시글을 참조하고있다고하자.
이때 한 엔티티를 그대로 응답으로 보낸다면
게시글 -> 회원 -> 게시글 -> 회원 -> 무한반복
으로 순환 참조가 발생하여 문제가 된다.
실제로 예전에 직접 문제를 겪으며 굳이 DTO를 만들어야할까 싶어
직렬화, 역직렬화를 막는 어노테이션을 사용했지만
역시나 DTO를 만들게 되었다.
https://non-stop.tistory.com/560
또한 응답으로 불필요한 데이터가 들어가 있다.
하나의 게시글 엔티티를 그대로 응답으로 보냈더니 참조되는 작성자 필드까지 JSON으로 변환하여
Member 클래스 또한 직렬화하여 모든 필드가 응답으로 보내지게 된다.
3. 엔티티 구조
엔티티에 @NotBlank와 같은 Validation을 위한 코드, @ManyToOne과 같은 연관관계 매핑,
직렬화 역직렬화 방지를 위한 @JsonIgnore 코드,,, 엔티티가 어질어질해진다.
DTO를 분리하여 검증과 모델링 코드를 분리할 수 있다.
그래서 이제 다음과 같은 디렉토리 구조로 DTO를 분리할 것이다.
MemberRequest
package com.example.spotserver.dto.request;
import com.example.spotserver.domain.Member;
import lombok.Setter;
import lombok.ToString;
@ToString
@Setter
public class MemberRequest {
private String loginId;
private String loginPwd;
private String name;
public Member toEntity(MemberRequest memberRequest) {
Member member = new Member();
member.setLoginId(memberRequest.loginId);
member.setLoginPwd(memberRequest.loginPwd);
member.setName(memberRequest.name);
return member;
}
}
DTO에서 엔티티로 저장하는 과정이 필요하므로 요청Dto에 엔티티로 변화하는 메서드를 작성했다.
@Setter는 JSON으로 바디에 들어온 요청을 스프링이 HttpMessageConverter로
객체로 변환하는데 set 메서드를 사용하기에 필요하다.
MemberResponse
package com.example.spotserver.dto.response;
import com.example.spotserver.domain.Member;
import com.example.spotserver.domain.Role;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
public class MemberResponse {
private Long id;
private String name;
private Role role;
public MemberResponse toDto(Member member) {
MemberResponse memberResponse = new MemberResponse();
memberResponse.id = member.getId();
memberResponse.name = member.getName();
memberResponse.role = member.getRole();
return memberResponse;
}
}
Entity를 응답DTO로 변환하는 과정을 거치므로 응답DTO에 DTO로 변환하는 메서드를 작성했다.
@Getter는 HttpMessageConverter가 JSON으로 응답을 보내기위해 get 메서드를 사용하기에 Getter가 필요하다.
'프로그래밍 > spring' 카테고리의 다른 글
Enum 타입으로 에러 메시지 및 응답 관리하기 (0) | 2024.01.24 |
---|---|
REST API에서 DTO 유효성 검사와 예외 처리 응답 방법 (1) | 2024.01.22 |
BCryptPasswordEncoder.encode 값이 매번 달라지는 이유 및 비교방법 (0) | 2024.01.20 |
@AuthenticationPrincipal로 컨트롤러에서 회원 정보 받기 (0) | 2024.01.19 |
Spring Security JWT 토큰 발급 및 서버 구축 (0) | 2024.01.19 |