코딩/자바

[Spring] Validation

yoney 2025. 2. 5. 11:15

[ 목차 ]


    ✏️Validation

    특정 데이터의 값이 유효한지 확인하는 단계


    🔍Validation의 역할

    1. 검증을 통해 적절한 메세지를 유저에게 보여주어야 한다.
    2. 검증 오류로 인해 정상적인 동작을 하지 못하는 경우는 없어야 한다.
    3. 사용자가 입력한 데이터는 유지된 상태여야 한다.

    🔍검증의 종류

    1. 프론트 검증
      • 해당 검증은 유저가 조작할 수 있음으로 보안에 취약하다.
      • 보안에 취약하지만 그럼에도 꼭 필요하다
      • ex) 비밀번호에 특수문자가 포함되어야 한다면 즉각적인 alert 가능 → 유저 사용성 증가
    2. 서버 검증
      • 프론트 검증없이 서버에서만 검증한다면 유저 사용성이 떨어진다.
      • API Spec을 정의해서 Validation 오류를 Response 예시에 남겨주어야 한다.
        • API 명세서를 잘 만들어야 그에 맞는 대응을 할 수 있다.
      • 서버 검증은 선택이 아닌 필수이다.
    3. 데이터베이스 검증
      • Not Null, Default와 같은 제약조건을 설정한다.
      • 최종 방어선의 역할을 수행한다.

    ✏️BindingResult

    Spring에서 기본적으로 제공되는 Validation 오류를 보관하는 객체이다. 주로 사용자 입력 폼을 검증할 때 많이 쓰이고 Field Error와 ObjectError를 보관한다.

    • Errors 인터페이스를 상속받은 인터페이스이다.
    • Errors 인터페이스는 에러의 저장과 조회 기능을 제공한다.
    • BindingResult는 addError() 와 같은 추가적인 기능을 제공한다.
    • Spring이 기본적으로 사용하는 구현체는 BeanPropertyBindingResult 이다.
    • BindingResult 파라미터는 검증대상 파라미터 뒤에 위치해야만 한다.

    @Controller
    public class BindingResultController {
    
        @PostMapping("/v2/member")
        public String createMemberV2(
                // 1. @ModelAttribute 뒤에 2. BindingResult가 위치한다.
                @ModelAttribute MemberCreateRequestDto request,
                BindingResult bindingResult,
                Model model
        ) {
    
            System.out.println("/V2/member API가 호출되었습니다.");
    
            // BindingResult의 에러 출력
            List<ObjectError> allErrors = bindingResult.getAllErrors();
            System.out.println("allErrors = " + allErrors);
    
            // Model에 저장
            model.addAttribute("point", request.getPoint());
            model.addAttribute("name", request.getName());
            model.addAttribute("age", request.getAge());
    
            return "complete";
        }
        
    }

    @ModelAttribute는 파라미터를 필드 하나하나에 바인딩한다. 파라미터에 Binding Result가 함께 있는 경우 만약 그중 하나의 필드에 오류가 발생하면 해당 필드를 제외하고 나머지 필드들만 바인딩 된 후 Controller가 호출된다.


    ✏️bean validation

    BindingResult처럼 번거롭게 구현하지 않고 간단하게 변경한 방법.

     

    1. 의존성 추가

    implementation 'org.springframework.boot:spring-boot-starter-validation'

     

    2. 어노테이션 사용

    • 사용된 Annotation 정리
      • @NotBlank
        1. null을 허용하지 않는다.
        2. 공백(” “)을 허용하지 않는다. 하나 이상의 문자를 포함해야한다.
        3. 빈값(””)을 허용하지 않는다.
        4. CharSequence 타입 허용
          • String은 CharSequence(Interface)의 구현체이다.
      • @NotNull
        1. null을 허용하지 않는다.
        2. 모든 타입을 허용한다.
      • @NotEmpty
        1. null을 허용하지 않는다.
        2. 빈값(””)을 허용하지 않는다.
        3. CharSequence, Collection, Map, Array 허용
      • @Max
      • @Range(min= ,max= )
      • @Valid, @Validated

     

    • @Valid, @Validated 차이점
      1. @Valid 는 JAVA 표준이고 @Validated 는 Spring 에서 제공하는 Annotation이다.
      2. @Validated 를 통해 Group Validation 혹은 Controller 이외 계층에서 Validation이 가능하다.
      3. @Valid 는 MethodArgumentNotValidException 예외를 발생시킨다.
      4. @Validated 는 ConstraintViolationException 예외를 발생시킨다.

     

    Bean Validation의 충돌이 일어날 수 있으니 request dto를 분리하는 것을 추천한다.
    보통 save, update dto는 무조건 분리!!

     

     

     

     

     

    • @ModelAttribute와 @RequestBody 차이점
      1. @ModelAttribute
        • 각각의 필드 단위로 바인딩한다.
        • 특정 필드 바인딩이 실패하여도 나머지 필드는 정상적으로 검증 처리할 수 있다.
        • 특정필드 변환 실패
          • 컨트롤러 호출, 나머지 필드 Validation 적용
      2. @RequestBody
        • 필드별로 적용되는것이 아니라 객체 단위로 적용된다.
        • MessageConverter가 정상적으로 동작하여 Object로 변환하여야 Validation이 동작한다.
        • 특정필드 변환 실패
          • 컨트롤러 미호출, Validation 미적용