라티의 작은 일기장

패스트캠퍼스 환급챌린지 9일차 미션 (2월 9일) : 10개 프로젝트로 시작하는 백엔드 웹개발 : 신입 개발자 취업 집중반 강의 후기 본문

Spring(Java)

패스트캠퍼스 환급챌린지 9일차 미션 (2월 9일) : 10개 프로젝트로 시작하는 백엔드 웹개발 : 신입 개발자 취업 집중반 강의 후기

코드라티 2025. 2. 9. 23:26

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성하였습니다.

https://bit.ly/4gL1f1o

 

오늘은 입력값 검사에 관한 내용을 공부했다. (나는 입력값 검증이라는 표현이 좀 더 익숙한듯?)

 

Spring Framework에서는 어노테이션을 기반으로 입력값에 대한 검사를 쉽게 진행할 수 있고, 이를 위한 의존성을 Spring Framework에서 제공해주고 있다. (spring-boot-starter-validation)

 

이메일과 이름으로 회원가입하는 경우를 예로 들어보자. 일반적으로 생각해봤을 때 이메일은 유효한 이메일의 형식이 있고, 이름은 아무리 짧아도 2자, 또 너무 길어도 20자를 넘지 않는 경우가 많다고 할 수 있다.

이런 제약 조건 하에 회원 가입 요청을 받는 api를 만들어보자.

 

1. DTO 정의

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

public class UserRequest {

    @NotBlank(message = "이름은 필수 입력 항목입니다.")
    @Size(min = 2, max = 20, message = "이름은 2자 이상 20자 이하로 입력해주세요.")
    private String name;

    @NotBlank(message = "이메일은 필수 입력 항목입니다.")
    @Email(message = "올바른 이메일 형식을 입력해주세요.")
    private String email;

    public UserRequest() {}

    public UserRequest(String name, String email) {
        this.name = name;
        this.email = email;
    }

    // Getter & Setter
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

 

이름과 이메일은 필수 입력 사항이므로 @NotBlank 어노테이션을 활용했고, 값의 길이에 대한 제약조건을 적용하기 위해 @Size를 활용했다. 마지막으로 이메일의 형식을 검증하기 위해 @Email 어노테이션을 활용했다.

그리고 각 어노테이션에는 해당 제약조건이 만족하지 않았을 때 반환할 message를 지정해줄 수 있다.

 

2. Controller에서 @Valid 적용

이런 입력값 검증 어노테이션은 검증하는 쪽에서 @Valid 어노테이션을 사용해줘야 검증을 할 수 있다.

import jakarta.validation.Valid;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/users")
public class UserController {

    @PostMapping("/register")
    public ResponseEntity<String> registerUser(@Valid @RequestBody UserRequest userRequest) {
        return ResponseEntity.ok("사용자 등록 성공: " + userRequest.getName());
    }
}

 

제약조건에 만족하지 않는 값으로 요청이 들어오면 기본적으로 400 에러를 반환(by DefaultHandlerExceptionResolver)한다.

 

@Valid, @Validated 어노테이션의 차이에 대해서도 공부했다.

@Valid는 자바 진영의 표준 스펙이고, @Validated는 Spring Framework에서 제공해주는 AOP 기반의 어노테이션이다.

 

어제 클라이언트의 요청이 Spring MVC에서, 특히 Front Controller에서 어떤 흐름으로 처리되는지에 대해 공부했었는데, @Valid는 Controller의 메소드가 탐색된 후 ArgumentResolver가 해당 메소드의 매개변수를 생성하고 바인딩을 진행할 때, 바로 이때 @Valid가 ArgumentResolver 내부에서 실행되는 것이다.

이 때 유효성 검사가 실패하면 예외가 발생하고, @ControllerAdvice에서 처리하게 된다.

 

도메인 계층에서는 @Valid를 활용한 입력값 검사를 진행하지만, 만약 서비스 등 다른 계층에서 입력값 검사를 진행해야한다면 앞서 언급한 Spring AOP 기반의 @Validated 어노테이션을 활용할 수 있다.
Spring에서 제공하는 기능이기 때문에, 스프링 빈의 경우에는 @Validated로 유효성 검증을 수행할 수 있는 것이다.

 

@Validated는 @Valid가 지원하지 않는 기능을 하나 더 사용할 수 있는데, 입력값 검증 상황을 그룹화하여 관리할 수 있다.

위의 UserRequest 클래스에 age 필드를 추가한 예시를 한번 살펴보자.

import jakarta.validation.constraints.*;

public class UserRequest {

    @NotBlank(message = "이름은 필수 입력 항목입니다.")
    @Size(min = 2, max = 20, message = "이름은 2자 이상 20자 이하로 입력해주세요.")
    private String name;

    @NotBlank(message = "이메일은 필수 입력 항목입니다.", groups = CreateUser.class)
    @Email(message = "올바른 이메일 형식을 입력해주세요.", groups = CreateUser.class)
    private String email;

    @Min(value = 18, message = "나이는 최소 18세 이상이어야 합니다.", groups = CreateUser.class)
    private int age;

    public UserRequest() {}

    public UserRequest(String name, String email, int age) {
        this.name = name;
        this.email = email;
        this.age = age;
    }

    // Getter & Setter
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    // 검증 그룹 인터페이스 정의
    public interface CreateUser {}  // 회원가입용 검증 그룹
    public interface UpdateUser {}  // 수정용 검증 그룹
}

 

이렇게 작성하면 이메일 검증 제약조건과 나이 검증 제약조건은 CreateUser라고 하는 인터페이스의 구현체에 대해서만 검증을 수행한다.

 

학습 시작 인증

 

학습 종료 인증

 

첫 번째 클립 수강 인증

 

두 번째 클립 수강 인증

 

학습 인증