쌓고 쌓다

[스프링 부트] 유효성 검사 @Validator - 27 본문

프로그래밍/spring

[스프링 부트] 유효성 검사 @Validator - 27

승민아 2023. 9. 9. 21:13

기존의 유효성 검사를 위한 코드들을 보자.

 

컨트롤러에서 유효성 검사를 위한 로직이 차지하는 부분이 크다.

이런 경우는 별도의 클래스로 분리하는 것이 좋다고한다.!

 

Validator 등록

스프링에서 제공하는 Validator 인터페이스를 살펴보자.

public interface Validator {
    boolean supports(Class<?> clazz);
    void validate(Object target, Errors errors);
}
  • supports : 해당 검증기를 지원하는가 여부 결정
  • validate : 검증 대상 target을 통해 유효성 검사 로직을 통해 errors에 담음

 

PosterValidation

package com.example.board.validation;

import com.example.board.domain.Poster;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

@Component
public class PosterValidation implements Validator {

    @Override
    public boolean supports(Class<?> clazz) {
        return Poster.class.isAssignableFrom(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
        Poster poster = (Poster) target;

        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "title", "require");
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "writer", "require");
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "content", "require");

        if(poster.getHeight()==null || poster.getHeight()<100)
            errors.rejectValue("height", "min", new Object[]{100}, null);

        if(poster.getWeight()==null || poster.getWeight()<40)
            errors.rejectValue("weight", "min", new Object[]{40}, null);

        if(poster.getHeight()!=null && poster.getWeight()!=null){
            Long height = poster.getHeight();
            Long weight = poster.getWeight();

            if(height+weight<150)
                errors.reject("heightWeightSumMin", new Object[]{150, height+weight}, null);
        }

    }

}

 

Validator 사용

PosterValidator를 만들었으니

Controller에서 PosterValidator(검증기)를 직접 호출하여 사용할 수 있다.

@PostMapping("/posters/{category}")
public String write(@PathVariable("category") Category category,
                    @ModelAttribute Poster poster, BindingResult bindingResult) throws IOException {

    // 검증기 직접 호출
    posterValidation.validate(poster, bindingResult);
    if(bindingResult.hasErrors()) {
        return "posters/createPosterForm";
    }
}

 

InitBinder와 WebDataBinder로 사용

Validator를 직접 호출하는 코드를 지울 수 있으며 대신 검증 대상 객체 앞에 @Validated를 붙인다.

 

@Slf4j
@Controller
@RequiredArgsConstructor
public class PosterController {

    private final PosterValidation posterValidation;

    @InitBinder("poster")
    public void init(WebDataBinder webDataBinder) {
        webDataBinder.addValidators(posterValidation);
    }

    @PostMapping("/posters/{category}")
    public String write(@PathVariable("category") Category category,
                        @Validated @ModelAttribute Poster poster, BindingResult bindingResult) throws IOException {

        //posterValidation.validate(poster, bindingResult);
        if(bindingResult.hasErrors()) {
            System.out.println("bindingResult = " + bindingResult);
            return "posters/createPosterForm";
        }
    }
}
  • @InitBinder("poster") : @InitBinder는 해당 컨트롤러에만 영향을 주며 name 속성에 모델명을 주어 검증 객체를 지정한다.
  • WebDataBinder : 해당 컨트롤러에서 검증기를 자동으로 적용할 수 있다.
  • @Validated : 검증기를 실행하라는 어노테이션으로 검증할 객체에 붙여주자.
    • @Validated 어노테이션이 붙어있으면 WebDataBinder에서 검증기를 찾아 supports()를 통해 찾아 수행한다.
    • @Validated 대신 @Valid를 사용해도 된다.
      • @Validated는 스프링 전용 어노테이션이고, @Valid는 자바 표준 검증 어노테이션이다.
  • 검증기 또한 글로벌 설정으로 모든 컨트롤러에 적용 가능하다.
Comments