[Spring Boot] Form 데이터를 위한 객체 설계 VO vs DTO, 무엇을 선택할까?

KUKJIN LEE • 3개월 전 작성
Spring Boot로 웹 애플리케이션을 개발할 때, 사용자가 입력한 Form 데이터를 처리하기 위한 객체를 설계하면서 "VO(Value Object)와 DTO(Data Transfer Object) 중 무엇이 적합할까?"라는 고민을 많이 합니다.
VO (Value Object)
-
정의: VO는 도메인에서 특정 값을 표현하는 객체로, 주로 불변성을 유지하며 동등성(equality) 기반 비교를 지원합니다.
-
특징
-
불변 객체로 설계(Immutable)
-
동일한 값이면 같은 객체로 간주
-
-
사용 목적
-
도메인 내에서 값의 동등성을 비교하거나, 특정 값을 의미 있게 표현할 때 활용
-
DTO (Data Transfer Object)
-
정의: DTO는 계층 간 데이터를 전송하기 위해 사용되는 객체로, 주로 클라이언트-서버 간 데이터 교환에 사용됩니다.
-
특징
-
일반적으로 getter와 setter가 포함
-
직렬화 가능
-
값이 가변(Mutable)하도록 설계
-
-
사용 목적
-
데이터를 입력받거나, 서비스 간 데이터 전송을 위해 활용
-
Form 데이터와 API 응답 데이터를 주고받는 데 중점
-
Spring Boot에서 Form 데이터를 위한 객체 설계
Form 데이터의 특성과 요구사항
Spring Boot에서 Form 데이터 처리는 다음과 같은 특성을 가집니다.
-
사용자 입력 데이터를 서버로 전달.
-
데이터가 가변적이며 검증(validation)이 필요.
-
클라이언트-서버 간 전송 목적.
이러한 요구사항은 DTO의 특징과 일치합니다. 따라서 Form 데이터를 위한 객체로는 DTO 사용이 적합합니다.
DTO를 사용하는 이유
-
데이터 전달 목적에 부합
-
Form 데이터는 주로 데이터를 서버에 전달하거나 저장 및 처리 전 데이터를 변환하는 데 사용됩니다. 이는 DTO의 주된 목적과 같습니다.
-
-
가변성(Mutability)
-
VO는 일반적으로 불변 객체로 설계되지만, Form 데이터는 사용자의 입력에 따라 값이 변경됩니다. 따라서 변경 가능한 DTO가 적합합니다.
-
-
데이터 검증 및 변환 용이
-
DTO는 컨트롤러 계층에서 데이터를 검증하고 비즈니스 로직에 전달하기 전에 필요한 가공 및 변환 작업을 수행하기 쉽습니다.
-
Spring Boot에서 DTO 사용 방법
DTO 클래스 설계
Form 데이터를 수집하기 위한 DTO 클래스는 다음과 같이 정의할 수 있습니다.
public class UserFormDTO {
private String username;
private String email;
private String password;
// Getters and Setters
}
컨트롤러에서 DTO로 데이터 받기
Spring Boot의 컨트롤러에서 DTO 객체를 활용해 Form 데이터를 처리하는 예제
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import jakarta.validation.Valid;
@Controller
public class UserController {
@PostMapping("/register")
public String registerUser(@Valid @ModelAttribute("userForm") UserFormDTO userForm, BindingResult result) {
if (result.hasErrors()) {
return "register"; // 유효성 검증 실패 시 다시 Form 페이지로 리턴
}
// Form 데이터 처리 로직 (e.g., 서비스 호출)
return "redirect:/success"; // 성공 시 리다이렉트
}
}
VO와 DTO의 역할 분리 전략
DTO 사용이 적합한 경우
-
클라이언트-서버 간 데이터를 전송할 때.
-
Form 데이터를 받아 서버에 전달하거나, 비즈니스 로직 처리 전 데이터를 검증할 때.
-
컨트롤러 계층에서 데이터를 처리할 때.
VO 사용이 적합한 경우
-
도메인 계층에서 특정 값을 불변 객체로 표현해야 할 때.
-
값 자체가 비즈니스 의미를 가지며, 동등성 비교가 중요한 경우.
실무 데이터 흐름 예시
-
컨트롤러 계층: Form 데이터를 DTO로 받음.
-
서비스 계층: DTO를 처리하거나 VO/엔티티로 변환.
-
리포지토리 계층: 엔티티(Entity)를 통해 데이터베이스와 상호작용
@Service
public class UserService {
public void registerUser(UserFormDTO userFormDTO) {
User user = new User();
user.setName(userFormDTO.getUsername());
user.setEmail(userFormDTO.getEmail());
user.setPassword(userFormDTO.getPassword());
userRepository.save(user); // Entity 저장
}
}
특징 |
VO |
DTO |
---|---|---|
주요 목적 |
도메인 값 표현 |
데이터 전송 및 검증 |
설계 방식 |
불변 객체(Immutable) |
가변 객체(Mutable) |
적용 계층 |
도메인 계층 |
컨트롤러, 서비스 계층 |
적용 사례 |
|
Form 데이터, API 요청/응답 데이터 |