[hodolog] 데이터 검증1 - @Vaild, BindingResult[2]

Euiyeon Park·2025년 2월 4일
post-thumbnail

✨ 데이터를 검증하는 이유

  1. 값을 보내는 클라이언트 개발자의 실수 - Human Error
  2. 클라이언트 단 버그로 값이 누락될 수 있음
  3. 외부에서 데이터를 조작할 수 있음
  4. DB에 값을 저장할 때 의도치 않은 오류가 발생할 수 있음
  5. 서버 개발자의 편안함을 위해💖

🌠 데이터 검증에 대해 생각해볼 거리

    @PostMapping("/posts")
    public String post(@RequestBody PostCreate params) throws Exception{
        var title = params.getTitle();
        
        // ✅ title에 대한 데이터 검증 필요
        if(title == null || title.equals("")){
            throw new Exception("title값이 없서용!");
        }
        
        var content = params.getContent();
        
        // ✅ content에 대한 데이터 검증 필요
        if(content == null || content.equals("")){
            throw new Exception("content값이 없서용!");
        }
        
        log.info("params={}", params.toString());
        return "Hello World";
    }
  • 지금은 PostCreate에 필드가 title, content 밖에 없지만,
    수십개의 필드가 있다면 ..? 위와 같은 형태의 검증은 비효율❌(if문 떡칠!)

🌠 어떤 부분이 비효율적인데?

  1. 빡세다(노가다임)
  2. 검증 대상의 필드를 누락할 위험이 있음
  3. 하나의 필드에 대해 생각보다 검증해야될 게 많다(꼼꼼하지 않을 수 있음)
    • {"title" : ""}
    • {"title" : " "}
    • {"title" : "..수십억글자..."}
  4. 간지가 안난다(개발자스럽지않다)

✨ Spring Boot Starter Validator 라이브러리

  • Spring Boot에서 검증 기능을 제공하는 기본 라이브러리
  • spring-boot-starter-validation
  • @NotBlank와 같은 검증 어노테이션을 사용해 DTO 필드 검증을 수행

🌠 검증 어노테이션 사용 방법

1. 검증이 필요한 DTO에 검증 어노테이션 추가(@NotBlank)

📂 PostCreate.java

@Setter
@Getter
@ToString
public class PostCreate {
    @NotBlank
    private String title;
    
    @NotBlank
    private String content;
}

2. 컨트롤러에서 DTO에 대한 유효성을 검증하는 어노테이션 추가(@Vaild)

  • 클라이언트로부터 @RequestBody로 JSON 데이터를 받을 때,
    @Valid를 붙이면 해당 DTO 클래스에 설정된 유효성 검증이 자동으로 수행

📂 PostController.java

@PostMapping("/posts")
    public String post(@RequestBody @Valid PostCreate params) throws Exception{
        ...
    }

🌠 @Valid의 검증 과정(검증 실패와 예외 처리)

  • @Valid는 요청 데이터가 컨트롤러에 도달하기 전에 Spring의 검증 과정을 먼저 수행
  • 유효성 검증에 실패하면,
    1. MethodArgumnetNotValidException 발생 → Spring의 Exception Handler가 이를 처리
    2. Spring Boot는 자동으로 400 Bad Request 응답을 반환

※ 더 세밀한 예외처리가 필요한 경우 @ExceptionHandler를 사용

🌠 잘못된 값이 넘어왔을 때 클라이언트에게 알릴 수 있나?

  • @Vaild는 컨트롤러 실행 전에(컨트롤러 도달 전에) 검증을 수행
  • 검증 실패 시 예외가 발생하면 Spring이 자동으로 400 Bad Reqeust 응답을 반환
  • 즉, 클라이언트에게 오류가 발생했다는 사실을 알릴 수 있지만
    기본적으로 제공되는 오류 메세지가 비직관적이고 사용자 친화적이지 않음
  • BindingResult를 이용해서 해결

✨ BindngResult

  • BindingResult는 Spring에서 유효성 검증 결과를 담는 객체
  • 폼 데이터, JSON 데이터를 DTO 객체로 매핑하거나 유효성 검증을 수행할 때 사용

🌠 BindingResult의 역할 및 기능

  1. 검증 결과 및 저장 : 입력 데이터가 검증 조건을 만족하는지 검사한 결과 저장
  2. 오류 정보 제공 : 어떤 필드에서 오류가 발생했는지, 어떤 메세지를 반환할지 관리
  3. 검증 실패 시 예외 방지 :
    • @Valid만 사용할 경우, 검증 실패시 예외(MethodArgumnetNotValidException)발생
    • BindingResult를 함께 사용하면, 예외가 발생하지 않고 코드 흐름을 계속 진행

🌠 BindingResult의 동작 원리

  1. 요청 데이터가 DTO 객체에 매핑
  2. @Valid 어노테이션이 DTO 유효성 검사를 수행
  3. 검증 결과는 BindingResult 객체에 저장
  4. 컨트롤러 내부에서 검증 결과를 확인하고, 오류가 있으면 사용자 친화적 응답 반환

📂 PostController.java

    @PostMapping("/posts")
    public Map<String, String> post(@RequestBody @Valid PostCreate params, BindingResult result){
    
        // ✅데이터 검증 실패 결과를 클라이언트에게 알리고 싶다면? -> BindingResult
        if(result.hasErrors()){
            List<FieldError> fieldError = result.getFieldErrors();
            FieldError firstFieldError = fieldError.get(0);
            String fieldName = firstFieldError.getField();
            String errorMessage = firstFieldError.getDefaultMessage();

            Map<String, String> error = new HashMap<>();
            error.put(fieldName, errorMessage);
            return error;
        }

        log.info("params={}", params.toString());
        return Map.of();
    }

정리

1. @Valid를 사용한 유효성 검증

  • 컨트롤러 도달 전에 수행
  • 검증 실패 시 Spring이 자동으로 400 Bad Request를 반환
  • 비직관적, 사용자 친화적이지 않은 응답을 반환하게 됨
  1. BindingResult를 사용한 검증 결과 저장
  • @Vaild를 사용한 유효성 검증에 대한 결과를 저장
  • 오류 발생 필드와 메세지를 관리할 수 있어, 오류 정보 제공에 유용

ref

인프런 호돌맨의 요절복통 개발쇼 (SpringBoot, Vue.JS, AWS)

profile
"개발자는 해결사이자 발견자이다✨" - Michael C. Feathers

0개의 댓글