Ch12. MVC 2 : Validator의 범위
스프링 MVC에는 모든 컨트롤러에 적용할 수 있는 글로벌 범위 Validator 와 단일 컨트롤러에 적용할 수 있는 Validator를 설정하는 방법이 있다.
글로벌 범위 Validator (@Valid)
글로벌 범위 Validator는 모든 컨트롤러에 적용할수 있는 Validator 이다.
글로벌 범위 Validator를 적용하려면 다음 두 가지를 설정해야 한다.
1. 설정 클래스에서 WebMvcConfigurer의 getValidator() 메서드가 Validator 구현 객체를 리턴하도록 구현
package config;
// ..
// Spring MVC 설정
@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer
{
// .. 생략
// 스프링은 getValidator()가 리턴한 객체를 글로벌 범위 Validator로 사용
@Override
public Validator getValidator()
{
return new RegisterRequestValidator();
}
}
2. 글로벌 범위 Validator가 검증할 커맨드 객체에 @Valid 애노테이션 적용
package controller;
// ..
@Controller
public class RegisterController
{
// ..
// 회원가입 form 데이터 받아서 처리하고 step3 (회원가입 완료 페이지) 이동
@PostMapping("/register/step3")
public String handleStep3(@Valid RegisterRequest regReq, Errors errors)
{
// 에러 있다면 step2 로 되돌아감
// @Valid에서 처리
// new RegisterRequestValidator().validate(regReq, errors);
if(errors.hasErrors()) return "register/step2";
// ..
}
}
커맨드 객체 ReigsterRequest 앞에 @Valid 애노테이션을 붙여 적용했다.
이렇게 되면 @Valid 애노테이션에 의해 Validator가 해당 타입을 검증할수 있는지 확인하고 (RegisterRequestValidator의 supports 메서드), 에러가 있는지 확인한다 (validate 메서드) .
위 과정은 요청 처리 메서드 (handleStep3) 실행 전에 수행된다.
컨트롤러 범위 Validator (@InitBinder)
특정 컨트롤러를 검사할 Validator의 설정은 다음과 같이 할수 있다.
package controller;
// ...
@Controller
public class RegisterController
{
// ...
// 회원가입 form 데이터 받아서 처리하고 step3 (회원가입 완료 페이지) 이동
@PostMapping("/register/step3")
public String handleStep3(@Valid RegisterRequest regReq, Errors errors)
{
// 에러 있다면 step2 로 되돌아감
// @Valid에서 처리
// new RegisterRequestValidator().validate(regReq, errors);
if(errors.hasErrors()) return "register/step2";
try
{
memberRegisterService.regist(regReq);
return "register/step3";
} catch(DuplicateMemberException ex)
{
errors.rejectValue("email", "duplicate");
return "register/step2";
}
}
// @Valid 가 붙은 커맨드 객체 검사할 Validator 설정
// 컨트롤러의 요청 처리 메서드 실행 전 매번 실행
@InitBinder
protected void initBinder(WebDataBinder binder)
{
binder.setValidator(new RegisterRequestValidator());
}
}
handleStep3 메서드의 파라미터에 커맨드 객체 RegisterRequest 앞에 @Valid 애노테이션을 붙였다.
그리고 @InitBinder가 붙은 initBinder 메서드에서 WebDataBinder#setValidator()로 RegisterRequestValidator를 등록하고 있다.
이것은 RegisterReqeust 객체를 검사할 Validator를 RegisterRequestValidator로 지정하겠다는 의미이다.
@InitBinder가 붙은 메서드는 컨트롤러의 요청 처리 메서드 (handleStep1, handleStep3 등 @Mapping이 붙은 메서드들)들이 실행되기 전 매번 실행되어 initBinder 메서드를 호출해 WebDataBinder를 초기화 한다.
글로벌 범위, 컨트롤러 범위 Validator의 우선 순위
만약 어떤 컨트롤러가 글로벌 범위와 컨트롤러 범위 두 개의 Validator가 검사하도록 되어 있고, WebDataBinder#setValidator()로 컨트롤러 범위 Validator를 지정했다면, 컨트롤러 범위 Validator로 검사하게 된다.
WebDataBinder는 내부적으로 Validator 목록을 갖고 있고 여기에는 글로벌 Validator도 포함되는데, WebDataBinder#setValidator()로 Validator를 추가할때 기존에 있던 Validator를 삭제하고 추가하기 때문이다.
출처 : 스프링5 프로그래밍 입문 (최범균 저)