설명
LocalValidatorFactoryBean
으로 스프링이 글로벌 Validator로 자동등록하여 작동한다.(Validator 등록에 대해서는 뒤에서 설명)관련 문서 : Reference(Hibernate 애노테이션 종류)
일반적인 경우 사용하는 방법으로 빠르고 쉽게 입력값 검증을 진행할 수 있다.
사용방법
파라미터 앞에 @Valid
or @Validated
선언
*@Valid는 java 표준, @Validated는 Hibernate 구현 애노테이션
다음 파라미터로 BindingResult
선언
이때 BindingResult는 검증하고자 하는 값 뒤에 선언해야 한다.
* BindingResult를 선언하지 않으면 Exception을 발생시키며 이때는 ExceptionHandler
이용 처리 필요
객체 각 필드에 검증 애노테이션 선언
예시
//DTO
public RequestDto{
@Email //이메일 형식 검증
private String email;
@Max(10) // 최대 10까지만 입력 가능
private int peopleLimit;
@size(min = 10, message = "10자 이상 입력 필요") //message를 입력하면 defaultMessage가 설정된다.
String content;
}
//Controller
@Controller
public ArticleController{
/*검증하고자 하는 값에 @Valid 또는 @Validated를 붙여준다.
그리고 검증하고자 하는 값 뒤에 BindingResult를 선언한다.
*/
@GetMapping("/")
public String getArticles(@Valid @ModelAttribute RequestDto requestDto, BindingResult bindingResult){
// 오류 검증값은 bindingResult 변수에 담긴다.
if(bindingResult.hasErrors()){
에러가 있을 경우 진행하는 logic
}
/* RequestBody에도 사용할 수 있다.
*/
@GetMapping("/")
@ResponseBody
public ResponseEntity getArticles(@Valid @RequestBody RequestDto requestDto, BindingResult bindingResult){
// 오류 검증값은 bindingResult 변수에 담긴다.
if(bindingResult.hasErrors()){
에러가 있을 경우 진행하는 logic
}
}
주의할 점 : ParsingError가 발생했을 때 @ModealAttribute
와 @RequestBody
일 때 결과가 다르다. (예시 : Integer 필드에 String값 입력했을 경우)
@ModelAttribute
의 경우 ParsingError가 발생한 필드는 default 값(보통 null)로 할당하고 객체를 생성한다. 해당 필드에 typeMismatch코드로 오류 정보가 생성되어 BindingResult에 저장된다. 이후 다른 필드에 대한 Validation을 계속 진행한다.@RequestBody
의 경우 HttpMessageConverter
가 객체 생성을 중단하고 예외를 발생시키기 때문에 Validation 및 Controller 로직이 진행되지 않는다.MethodValidationPostProcessor
빈을 등록해주어야 한다(Springboot는 기본으로 등록하기 때문에 별도 설정 불필요)@Controller
public UserController{
//@RequestParam은 생략 가능
@GetMapping("/login")
public String login(@email String email, String password){
}
}
Validator
인터페이스를 이용하면 된다. Validator
인터페이스 구현@Init
을 선언하여 구현체를 해당 Controller에 등록LocalValidatorFactoryBean
가 작동하지 않을 수 있다.예시
//customValidator 생성
public class CustomValidator implements Validator{
//특정 파라미터가 검증 대상인지 체크하는 메소드
//return 반환값이 true일 경우 검증 대상이 된다.
@Override
public boolean supports(Class<?> class){
return RequestDto.class.isAssingnableFrom(clazz);
}
/*검증로직 구현 및 error에 오류내용 입력
Error는 BindingResult의 부모 클래스이다.
Spring은 Errors에 앞서 Controller에 선언한 BindingResult를 validate의 매개변수로 전달한다.
*/
@Override
public void validate(Object target, Errors errors) {
RequestDto requestDto = (RequestDto) target;
//필드 오류 검증로직
if(requestDto.getCotent() == null){
errors.rejectValue(에러 필드 및 입력 값 설정); //특정 필드 오류로 지정하고 싶은 경우
}
//글로벌 오류(객체 오류) 검증로직
if(검증로직){
errors.reject(입력 값 설정); //target Object 자체가 오류라고 지정하고 싶은 경우
}
}
}
//Controller에 CustomValidator 등록
@RequiredArgsConstructor
public class ArticlController{
private final Validator customValidator; //빈 주입 필요
@Init
public void init(WebDatBinder databinder){
databinder.addValidators(customValidator);
}
@GetMapping("/")
public String getArticles(@Valid @ModelAttribute RequestDto requestDto, BindingResult bindingResult){
// 오류 검증값은 bindingResult 변수에 담긴다.
if(bindingResult.hasErrors()){
에러가 있을 경우 진행하는 logic
}
}
}
여러 개의 Validator를 동시에 적용할 수도 있다(다중 Validator 등록). 이때 기본적으로 등록되는 LocalValidatorFactoryBean
도 같이 적용된다.
//Controller에 CustomValidator 등록
@RequiredArgsConstructor
public class ArticlController{
private final CustomValidator1 customValidator1; //빈 주입 필요
private final CustomValidator2 customValidator2; //빈 주입 필요
@InitBinder
public void init(WebDatBinder databinder){
//validator 여러 건 등록
databinder.addValidators(customValidator1, customValidator2);
}
@GetMapping("/")
public String getArticles(@Valid @ModelAttribute RequestDto requestDto, BindingResult bindingResult){
// 오류 검증값은 bindingResult 변수에 담긴다.
if(bindingResult.hasErrors()){
에러가 있을 경우 진행하는 logic
}
}
}
//Controller에 CustomValidator 등록
@RequiredArgsConstructor
public class ArticlController{
private final CustomValidator1 customValidator1; //빈 주입 필요
private final CustomValidator2 customValidator2; //빈 주입 필요
//검증하려는 클래스이름(첫글자는 소문자)
@InitBinder("requestDto")
public void init(WebDatBinder databinder){
//validator 여러 건 등록
databinder.addValidators(customValidator1);
}
@InitBinder("postRequestDto")
public void init(WebDatBinder databinder){
//validator 여러 건 등록
databinder.addValidators(customValidator2);
}
@GetMapping("/")
public String getArticles(@Valid @ModelAttribute RequestDto requestDto, BindingResult bindingResult){
// 오류 검증값은 bindingResult 변수에 담긴다.
if(bindingResult.hasErrors()){
에러가 있을 경우 진행하는 logic
}
}
@GetMapping("/")
public String postArticles(@Valid @ModelAttribute PostRequestDto postRequestDto, BindingResult bindingResult){
// 오류 검증값은 bindingResult 변수에 담긴다.
if(bindingResult.hasErrors()){
에러가 있을 경우 진행하는 logic
}
}
}
LocalValidatorFactoryBean
를 이용한 방법이다. Validator
인터페이스를 구현 및 등록(Cotroller에 @Init 등록 메소드 추가)하여 사용할 수 있다. 다양한 Validator를 1개의 DTO에 적용할 수 있으며, DTO 타입별로도 Validator를 구분 적용할 수 있다.