- Entity
- Entity 클래스는 실제 DB 테이블과 매핑되는 클래스
- 데이터베이스 영속성의 목적으로 사용되는 객체이며, 때문에 요청(Request)이나 응답(Response) 값을 전달하는 클래스로 사용하는 것은 좋지 않다.
- 서비스 클래스와 비즈니스 로직들이 Entity 클래스를 기준으로 동작하기 때문에 Entity 클래스가 변경되면 여러 클래스에 영향을 줄 수 있다
영속성이 있는 특징으로 Constructor(생성자) 또는 Builder를 사용한다
- 생성자(Constructor)를 이용해서 초기화하는 경우 불변 객체로 활용
- Builder를 사용하면 멤버 변수가 많아지더라도 어떤 값을 어떤 필드에 넣는지 코드를 통해 확인할 수 있고
, 필요한 값만 넣는 것이 가능하다
- @Setter 사용을 지양하되, 사용할 경우 private 로 제한
- DTO (Data Transfer Object)
- 목적 자체가 계층(Layer) 간 데이터 교환이므로 읽고, 쓰는 것이 모두 가능하고, 일회성으로 사용
- 데이터 전달용이므로 Getter와 Setter만 존재하며, 로직이 없다.
데이터 변경 방지를 위해서 Setter 역할은 생성자를 이용한 불변 객체로 활용한다. - DAO(Data Access Object) 패턴에서 유래되어 DAO에서 DB 처리 로직을 숨기고
DTO라는 결괏값을 내보내는 용도로 활용
§ DAO : DB에 직접 접근하여, CRUD기능을 수행
- VO
- 값 그 자체를 표현하는 객체
- equals, hashCode를 Overring하여
, 값 자체가 동일하면 객체끼리 서로 다른 이름을 가졌다 하더라도 같은 객체라고 판단 - 객체의 불변성을 보장
- 로직을 포함할 수 있음
'Entity와 DTO를 분리하는 이유는 DB와 View 사이의 역할 분리를 위해서'
활용성 높은 Layer
Controller ↔ View 사이에서 데이터를 주고받을 때 활용성이 높음 |
관심사의 분리
Entity는 핵심 비지니스 로직을 담는 비지니스 도메인 영역이며,
DTO는 클라이언트와의 데이터 교환을 위해서 사용된다.
Entity와 DTO를 분리함으로써 관심사를 분리하고 각각의 역할에 집중할 수 있다.
유연성과 확장성
Entity의 값이 변경되는 경우 DB에 변경값이 반영된다. ( Repository 클래스의 Entity Manager의 flush가 호출될 때 )
DTO를 사용하여, Entity의 변경으로 인한 영향을 최소화할 수 있고
클라이언트에게 전달되는 데이터를 쉽게 조정하고 확장할 수 있다.
데이터 은닉
DTO를 사용하면 클라이언트에게 필요한 데이터만을 선택하여 전달하므로, 불필요한 정보 노출을 방지하고 데이터 은닉을 보장할 수 있다.
변환방법 : Service Layer에서 변환
DTO <-> Entity
(1) Request DTO : PostRequest는 toEntity() 메서드를 통해 Entity로 변환이 가능하다.
@Getter
@Builder
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class PostRequest {
private String title;
private String content;
private String writer;
public Post toEntity() {
return Post.builder()
.title(title)
.content(content)
.writer(writer)
.build();
}
}
(2) Response DTO : PostResponse에서는 Builder 생성자를 통해 Entity를 DTO로 변환 가능하다.
(@Builder의 생성자에서 entity를 파라미터로 받으면서 Entity to DTO 작업을 할 수 있습니다.)
@Getter
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class PostResponse {
private Long id;
private String title;
private String content;
private String writer;
@Builder
public PostResponse(Post post) {
this.id = post.getId();
this.title = post.getTitle();
this.content = post.getContent();
this.writer = post.getWriter();
}
}
(3) Service Layer 에서 변환
- Controller Layer
@PostMapping
public ResponseEntity<Long> create(@RequestBody PostRequest PostRequest) {
return ResponseEntity.ok().body(postService.create(PostRequest));
}
@GetMapping("/{postId}")
public ResponseEntity<PostResponse> getPost(@PathVariable Long postId) {
return ResponseEntity.ok().body(postService.getPost(postId));
}
- Service Layer
public PostRequest create(PostRequest PostRequest) {
return postMapper.insert(PostRequest.toEntity()));
}
public PostResponse getPost(PostResponse postResponse) {
Post post = postService.getPost(postId);
return postMapper.find(PostResponse.builder().post(post).build());
}
※ @Builder
빌더 패턴을 사용하여 객체를 생성할 경우 장점
- 불필요한 생성자를 제거할 수 있다.
- 생성자의 인자 순서에 상관없이 객체 생성이 가능하다.
- setter 메서드가 없으므로 변경 불가능한 객체를 만들 수 있다.
- 객체 생성 시 어떤 데이터를 셋팅하는지 파악 가능하여 가독성을 높여준다.
클래스 레벨
⇒ 클래스 레벨에 @Builder 어노테이션을 선언하면, @AllArgsConstructor(access=AccessLevel.PACKAGE) 와 동일하게 생성자를 생성한다.
⇒ 주의: 다른 생성자가 이미 있을 경우 제대로 동작하지 않을 수 있다.
@NoArgsConstructor을 사용하는 이유
내가 @NoArgsConstructor (access = AccessLevel.PROTECTED)를 작성했던 이유
그 때 당시에는 Spring은 물론 Java에 대한 개념도 매우 약할 때라 지금도 약하지만레퍼런스의 코드를 가져다 사용하기에 급급했다.당시의 나는 해당 개념에 대한 정확한 이해보다는 기능 구현이
velog.io
참고자료
https://hudi.blog/data-transfer-object/
DTO의 개념과 사용범위
DTO는 우테코 과정 중 정말 많이 들어봤고, 나름 사용도 많이 했지만 이상하게 바람직하게 사용하고 있다는 확신이 들지 않는 개념이다. DTO에 대한 내용은 항상 새롭게 알아가는데, 이러다간 DTO
hudi.blog
DTO의 사용 이유와 범위
개발을 하다가 굳이 domain과 DTO를 왜 같이 써야할까?라는 의문점이 생겼다. 내가 배운 DTO는 client와 controller, controller와 service 사이의 객체 전달을 위해 사용하는 것이라 생각했는데 굳이 객체 전
velog.io
빌더 패턴(Builder) + @Build 어노테이션
빌더 패턴이란? > The builder pattern is used in software development to construct complex objects in a step-by-step manner, without having to specify the complex details of object creation in the main code...
velog.io
https://blossom6729.tistory.com/32 :
[Mybatis] Mybatis에서 DTO로 분리하기
[Mybatis] Mybatis에서 DTO로 분리하기
개요 현재 회사에서는 하나의 객체를 만들어 모든 레이어에서 사용하거나 Controller Layer에서 HashMap으로 받고 있습니다. 추가적으로 제약조건으로 Post Method만 허용합니다. 회원 (코멘트) API를 예로
blossom6729.tistory.com
'SPRING' 카테고리의 다른 글
[Spring Sequrity] 구동원리과 간략한 구현 (0) | 2025.02.12 |
---|---|
AOP (작성중) (0) | 2025.01.31 |
스프링 컨테이너와 싱글톤 컨테이너 (0) | 2024.12.29 |
Spring Bean과 빈 조회하기 (0) | 2024.12.25 |
ApplicationContext(스프링 컨테이너)가 작동하는 과정 (0) | 2024.12.22 |