Header Banner
GG Logo

Future Engineering

기술의 최전선을 기록합니다.

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

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

BackEnd9개월 전

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를 사용하는 이유

  1. 데이터 전달 목적에 부합

    • Form 데이터는 주로 데이터를 서버에 전달하거나 저장 및 처리 전 데이터를 변환하는 데 사용됩니다. 이는 DTO의 주된 목적과 같습니다.

  2. 가변성(Mutability)

    • VO는 일반적으로 불변 객체로 설계되지만, Form 데이터는 사용자의 입력에 따라 값이 변경됩니다. 따라서 변경 가능한 DTO가 적합합니다.

  3. 데이터 검증 및 변환 용이

    • 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 사용이 적합한 경우

  • 도메인 계층에서 특정 값을 불변 객체로 표현해야 할 때.

  • 값 자체가 비즈니스 의미를 가지며, 동등성 비교가 중요한 경우.

 

실무 데이터 흐름 예시

  1. 컨트롤러 계층: Form 데이터를 DTO로 받음.

  2. 서비스 계층: DTO를 처리하거나 VO/엔티티로 변환.

  3. 리포지토리 계층: 엔티티(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)

적용 계층

도메인 계층

컨트롤러, 서비스 계층

적용 사례

Money, Address 등 값 객체

Form 데이터, API 요청/응답 데이터