본문 바로가기
Back-End/Spring MVC

DTO(Data Transfer Object)

by 달의 조각 2022. 8. 22.

 

HTTP 요청/응답에서의 DTO

Data Transfer Object

 

 

마틴 파울러(Martin Fowler)가 ‘Patterns of Enterprise Application Architecture’라는 책에서 처음 소개한 엔터프라이즈 애플리케이션 아키텍처 패턴의 하나이다.

주로 클라이언트와 서버 사이에서 데이터를 주고받을 때 사용한다. 클라이언트의 Request Body를 하나의 객체로 전달받을 수 있기 때문에 코드가 간결해지며, Request Body의 데이터 유효성 검증이 단순해진다.

중요한 목적은 비용이 많이 드는 작업인 HTTP 요청의 수를 줄이고, 도메인 객체와 분리하기 위함이다.

 

🍑 코드의 간결성

@RestController
@RequestMapping("/v1/members")
public class MemberController {
    @PostMapping
    public ResponseEntity postMember(@RequestParam("email") String email,
                                     @RequestParam("name") String name,
                                     @RequestParam("phone") String phone) {
        Map<String, String> map = new HashMap<>();
        map.put("email", email);
        map.put("name", name);
        map.put("phone", phone);

        return new ResponseEntity<Map>(map, HttpStatus.CREATED);
    }
		...
}
@RestController
@RequestMapping("/v1/members")
public class MemberController {
    @PostMapping
    public ResponseEntity postMember(MemberDto memberDto) {
        return new ResponseEntity<MemberDto>(memberDto, HttpStatus.CREATED);
    }
		...
}

 

 

🍑 데이터 유효성 검증의 단순화

유효성 검증이란 서버 쪽에서 유효한 데이터를 전달받기 위해 데이터를 검증하는 것이다.

public class MemberDto {
    @Email //유효한 이메일 주소가 포함되어 있지 않으면 클라이언트의 요청이 거부된다
    private String email;
    private String name;
    private String phone;

    // . . .
}
@RestController
@RequestMapping("/v1/members")
public class MemberController {
    @PostMapping
    //@Valid: MemberDto 객체에 유효성 검증을 적용한다.
    public ResponseEntity postMember(@Valid MemberDto memberDto) {
        return new ResponseEntity<MemberDto>(memberDto, HttpStatus.CREATED);
    }
		...
}

 

 

🍑 적용하기

  1. Reqeust Body에 담겨서 JSON 형식으로 전달될 데이터를 다룰 DTO 클래스를 생성한다.
    DTO 클래스에는 전달받는 각 데이터 항목을 멤버 변수로 추가한다.
  2. 클라이언트의 요청 데이터를 @RequestParam 애너테이션으로 전달받는 핸들러 메서드를 찾는다.
    Request Body를 사용하는 핸들러는 POST, PATCH, PUT 같이 리소스의 추가나 변경이 발생할 때이다.
  3. @RequestParam 코드를 DTO 클래스의 객체로 수정한다.
  4. Map 객체로 작성되어 있는 메서드 바디를 DTO 클래스의 객체로 변경한다.

 

@RequestBody: JSON 형식의 Request Body → DTO 클래스의 객체로 변환
@ResponseBody: 클라이언트에게 전달하기 위해 DTO 클래스의 객체 → Response Body로 변환

핸들러 메서드에 @ResponseBody 애너테이션이 붙거나, 리턴 값이 ResponseEntity이면
Spring MVC는 내부적으로 HttpMessageConverter가 동작하게 되어 응답 객체를 JSON 형식으로 바꿔 준다.

JSON → DTO : 역직렬화(Deserialization)
DTO → JSON : 직렬화(Serialization)

 

 

DTO 유효성 검증(Validation)

 

//build.gradle
dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-validation'
	...
	...
}
public class MemberPostDto {
    @NotBlank
    @Email
    private String email;

    @NotBlank(message = "이름은 공백이 아니어야 합니다.")
    private String name;

    @Pattern(regexp = "^010-\\d{3,4}-\\d{4}$",
            message = "휴대폰 번호는 010으로 시작하는 11자리 숫자와 '-'로 구성되어야 합니다.")
    private String phone;
@PostMapping
public ResponseEntity postMember(@Valid @RequestBody MemberPostDto memberPostDto) {

    return new ResponseEntity<>(memberPostDto, HttpStatus.CREATED);
}

@NotBlank: null 값이나 공백(””), 스페이스(” “) 같은 값들을 모두 허용하지 않는다.
유효성 검증에 실패하면 message 애트리뷰트에 지정한 문자열이 에러 메시지로 콘솔에 출력된다.

@Email: 유효한 이메일 주소인지를 검증한다.

@Pattern: 정규 표힌식에 매치되는지 검증한다.

 

쿼리 파라미터 및 Pathvariable 검증

@RestController
@RequestMapping("/v1/members")
@Validated //쿼리 파라미터 검증 애너테이션 넣기
public class MemberController {

    @PatchMapping("/{member-id}")
    //파라미터의 memberId는 최소값이 1이다
    public ResponseEntity patchMember(@PathVariable("member-id") @Min(1) long memberId,
                                      @Valid @RequestBody MemberPatchDto memberPatchDto) {

 

Jakarta Bean Validation

유효성 검증을 위한 표준 스펙에서 지원하는 내장 애너테이션 모음
라이브러리처럼 사용할 수 있는 API가 아닌 스펙(사양, Specification) 자체

구현체: Hibernate Validator

 

 

Custom Validator

원하는 목적에 맞는 애너테이션을 직접 만들어서 적용할 수 있다.
모든 로직을 정규 표현식로 작성하는 것은 좋은 개발 방식이 아니다.

  1. Custom Validator를 사용하기 위한 Custom Annotation을 정의한다.
  2. 정의한 Custom Annotation에 바인딩 되는 Custom Validator를 구현한다.
  3. 유효성 검증이 필요한 DTO 클래스의 멤버 변수에 Custom Annotation을 추가한다.

댓글