DTO (Data Trsnfer Object)
데이터 전송객체, 시스템 간 데이터를 주고받을 때 사용하는 객체
주로 계층 간 데이터를 전달하거나 데이터를 캡슐화하여 전송하는데 사용됨
특징
1. 데이터 전송 목적
- 데이터베이스, 서비스, 컨트롤러 등 여러 계층 간 데이터를 전달하기 위해 사용함
2. 필드와 Getter, Setter 만 포함
- 비즈니스 로직은 포함하지 않으며, 단순히 데이터를 저장하고 전달함
3. Immutable 또는 Mutable
- 일반적으로 DTO는 불변객체로 만들어지는 경우가 많다
하지만 필요에 따라 Setter를 제공하여 Mutable하게 구현하기도 한다
사용하는 이유
1. 계층 간 데이터 전달
- 컨트롤러, 서비스, 데이터베이스 등의 계층 간 데이터를 전달하는 표준화된 객체로 사용
2. 보안성 및 안정성
- 도메인(Entity) 개체를 직접 노출하면 내부 비즈니스 로직이나 불필요한 데이터가 외부로 공개될 수 있다
DTO를 사용하면 필요한 데이터만 선택적으로 노출할 수 있다
3. 응집도와 책임 분리
- 엔티티(Entity)는 데이터베이스와 밀접한 관련이 있지만, DTO는 전송 데이터에만 집중하므로 각 클래스의 책임이 분리된다
4. API 요청/응답 데이터 표현
- REST API 에서 클라이언트와 서버 간에 주고받는 데이터를 표현하기 위해 사용된다
DTO, Entity 차이
항목 | DTO | Entity |
역할 | 계층간 데이터 전송 | 데이터베이스와 직접 연관 |
책임 | 데이터 전달 | 데이터 저장 및 비즈니스 로직 포함 |
내용 | 필요한 데이터만 포함 | 모든 데이터와 연관관계 포함 |
영향 범위 | 계층 간 데이터 전달에 한정 | 데이터베이스와 연결된 전체 시스템 |
수명 주기 | 단기적 (요청/응답 단위) | 장기적 (애플리케이션 수명 주기 내내) |
연관 관계 | 일반적으로 없음 | 엔티티 간 연관 관계 포함 |
예제
예제 시나리오
- 사용자 데이터를 저장하고 반환하는 애플리케이션
- Entity 클래스 : 데이터베이스에 직접 매핑되는 객체
- DTO 클래스 : 사용자에게 노출될 데이터만 포함
Entity 클래스 :
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
private String password; // 민감한 정보
// Getter & Setter
}
DTO 클래스 :
public class UserDTO {
private Long id;
private String name;
private String email;
// Getter & Setter
}
Controller에서 DTO 활용 :
@RestController
@RequestMapping("/users")
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping("/{id}")
public UserDTO getUserById(@PathVariable Long id) {
User user = userService.findUserById(id);
return new UserDTO(user.getId(), user.getName(), user.getEmail());
}
}
Service에서 Entity를 DTO로 변환 :
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public UserDTO findUserById(Long id) {
User user = userRepository.findById(id).orElseThrow(() -> new RuntimeException("User not found"));
return new UserDTO(user.getId(), user.getName(), user.getEmail());
}
}
장점
1. 보안성 :
- 민감한 데이터(예: 비밀번호 등)를 숨길 수 있음
2. 유지보수성 :
- 데이터 전송 구조가 변경되어도, DTO만 수정하면 다른 계층에 영향을 주지 않음
3. 테스트 용이성 :
- 단순 데이터 전송 객체이므로, 단위 테스트가 쉽습니다
4. API 응답 최적화 :
- 필요한 데이터만 클라이언트에 반환하여 불필요한 데이터 전송을 줄일 수 있음
단점
1. 추가 작업 :
- DTO를 생성하고, Entity와 변환(매핑)하는 코드가 필요하므로 작업량이 증가할 수 있음
2. 변환 비용 :
- Entity ↔ DTO 간 변환 과정에서 성능 비용이 발생할 수 있음
DTO 변환 자동화 도구
- 수동으로 Entity와 DTO를 변환하는 코드는 많아질 수 있다. 이를 자동화하는 라이브러리를 활용하면 효율성이 증가한다
- ModelMapper : 객체간 매핑을 자동으로 수행
- MapStruct : 컴파일 타임에 매핑 코드를 생성
MapStruct 예시
@Mapper
public interface UserMapper {
UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
UserDTO toDTO(User user);
User toEntity(UserDTO userDTO);
}
출처 : ChatGPT
'BE > Spring & Spring Boot' 카테고리의 다른 글
[Spring Boot] PSA (0) | 2025.01.05 |
---|---|
[Spring Boot] AOP (0) | 2025.01.05 |
[Spring Boot, JPA] 관련 어노테이션 (0) | 2025.01.01 |
[Spring Boot] 관련 어노테이션 (0) | 2025.01.01 |
[Spring Boot] Validation 유효성 검사 (0) | 2024.12.30 |