이걸 제대로 쓰면 좋은데 말이지...

둘다 인터페이스이다.

컨트롤러에서 커맨드 객체 (간단하게는 form 값을 넘겨받은 클래스를 의미 ) 를 생성한뒤에 Validator 에 넘겨서 검증요청한다.

 인터페이스에는 2가지 메소드가 있는데

ㄱ. boolean supports(Class <?> clazz)
: 해당 클래스에 대한 값 검증을 지원하는 지의 여부를 리턴한다.
ㄴ. void validate (Object target, Errors errors)
: target 객체에 대한 검증을 실행한다. 검증결과 문제가 있을 경우 errors 객체에 어떤 문제인지에 대한 정보를 저장한다.
즉, 리턴은 없고 errors에 담겨온다.


if (memberInfo.getId() == null || memberInfo.getId().trim().isEmpty()) {
errors.rejectValue("id", "required");
}

rejectValue 메소드는 "id" 프로퍼티값이 잘못됐고, 에러코드로 "required"를 남겼다.

Validator 클래스를 작성하면, 다음으로 컨트롤러 클래스에서 Validator를 이용해서 커맨드 객체를 검증하는 것이다. 

검증하는 코드를 추가하는 작업은

ㄱ. @RequestMapping 어노테이션 메소드에서 커맨드 객체 다음 파라미터로 BindingResult 타입이나 , Errors 타입의 파라미터를 추가한다.
ㄴ. 메소드내에 Validator 객체를 생성한뒤 validate() 메소드에서 커맨드객체와 BindingResult 또는 Errors 타입 파라미터를 전달한다.
ㄷ. Errors.hasErrors() 메소드를 이용해서 에러가 존재하는지 확인하고, 에러가 존재할 경우 알맞은 처리를 한다.

사용은 아래와 같이...
@RequestMapping(method = RequestMethod.POST)
public String submit(@ModelAttribute("command") MemberInfo memberInfo,BindingResult result) {
new MemberInfoValidator().validate(memberInfo, result);
if (result.hasErrors()) {
return "account/creationForm";
}
return "account/created";
}


2. Errors / BindingResult 인터페이스
Errors 와 BindingResult 인터페이스의 사용처를 보면,
ㄱ. Errors : 유효성 검증 결과를 저장할때 사용
ㄴ. BindingResult : Errors 인터페이스의 하위 인터페이스로 폼 값을 커맨드객체에 바인딩한 결과로 저장함.

2.1 Errors
값이 올바르지 않을경우 reject() 또는 rejectValue()메소드를 이용해서 어떤 필드가 잘못되었는지, 관련된 에러가 무엇인지 입력받는다.

reject() 메소드는 검증 대상 객체의 전체적인 에러를 설정. (이게 글로벌..을 의미함)
rejectValue() 메소드는 특정 프로퍼티의 검증에러를 설정한다.

책에서 찾아봐라 -ㅅ- 귀찮다


        @RequestMapping(method = RequestMethod.POST)
public String submit(@Valid LoginCommand loginCommand, 
BindingResult result) {
if (result.hasErrors()) {
return formViewName;
}
try {
authenticator.authenticate(loginCommand);
return "redirect:/index.jsp";
} catch (AuthenticationException e) {
// 이 경우의 익셉션은 로그인 실패이지 값이 없거나 하는게 아니다. 즉 깂이 잘못된(아이디나 패스워드가 잘못된) 객체의 문제이다.
//  그러면 아래체럼... reject를 이용해 글로벌에러정보(전체적인 에러정보) 를 추가할 수 있다 
result.reject("invalidIdOrPassword", new Object[] { loginCommand.getUserId() }, null);
return formViewName;
}
}

rejectValue 를 이용하면 객체의 개별 프로퍼티(필드)에 대한 에러정보를 추가할 수 있다.

@Override
public void validate(Object target, Errors errors) {
MemberInfo memberInfo = (MemberInfo) target;
if (memberInfo.getId() == null || memberInfo.getId().trim().isEmpty()) {
errors.rejectValue("id", "required");
}
if (memberInfo.getName() == null
|| memberInfo.getName().trim().isEmpty()) {
errors.rejectValue("name", "required");
}
        ....
        }

rejectValue 는 맵과 달리 계속 추가적으로 에러를 등록할 수 있다. (같은 키값에 말야)
그러면 그 만큼 나중에 확인가능하다. (카운트가 가능한게 이 이유임)

에러가 발견됐다면 페이지 이동시켜버리면된다. 

@RequestMapping(method = RequestMethod.POST)

public String submit(@ModelAttribute("command") MemberInfo memberInfo,

BindingResult result) {

new MemberInfoValidator().validate(memberInfo, result);

if (result.hasErrors()) {

return "account/creationForm";

}

return "account/created";

}



보다시피 return 이 String 이고 주소를 줘서 웹이동을 하게 되는 것임.

BindingResult 인터페이스의 기본 구현클래스(AbstractBindingResult) 클래스는 MessageCodesResolver를 사용하여 에러코드에 대한 에러메시지를 추출한다. 기본적으로 DefaultMessageCodeResolver클래스를 MessageCodesResolver로 사용한다네..

DefaultMessageCodeResolver 를 이용해서 자동으로 에러메시지를 생성하려면 MessageSource를 빈 객체로 등록해야한단다.

에러메시지를 출력할 때에는 스프링이 제공하는 <form:errors> 커스텀 태그를 사용하면된다.

뷰로 jsp를 사용할 경우 2가지 방식으로 에러메시지를 설정한다.
ㄱ. <spring:hashBindErrors> 커스텀 태그를 이용하여 에러정보를 설정
ㄴ, <form:form> 태그를 이용하여 에러정보를 설정

아... 귀찮다 예제는 그냥 책봐라...


ValidationUtils
뭐.. null 이냐 그냥 값없음(whitespace) 이냐를 판단하는 유틸을 제공하더라.
ValidationUtils 이며 메소드로 StringUtils와의 차이는 단순 결과리턴이 아닌 reject등의 데이터가 저장되는거랄까? 즉 rejectValue 등을 호출할 필요가 없다 그거지...

ValidationUtils.rejectEmptyOrWhitespace(errors,"id","required");

위처럼 처리가능하다. ... 나머지는 찾아봐라.. 많다 -ㅅ-;

@Valid 어노테이션 ,  @InitBinder 어노테이션을 이용한 검증

위에서는 Validator 객체를 생성하고 validate를 호출해서 검사했지만 어노테이션으로도 처리 가능하다.

즉... 어노테이션 달고 그냥 자동으로 되는거라 그거지.

@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.setValidator(new LoginCommandValidator());
}

어떤 Validator가 커맨드 객체를 검증할지 여부를 위처럼 설정한다.

그리고 validate() 호출하지 않고 그냥 BindingResult 를 보고 판단한다.
        @RequestMapping(method = RequestMethod.POST)
public String submit(@Valid LoginCommand loginCommand, BindingResult result) {
if (result.hasErrors()) {
return formViewName;
}
try {
authenticator.authenticate(loginCommand);
return "redirect:/index.jsp";
} catch (AuthenticationException e) {
result.reject("invalidIdOrPassword", new Object[] { loginCommand
.getUserId() }, null);
return formViewName;
}
}

만일 @Valid 가 적용된 뒤에 BindingResult 나 Errors 타입이 없다는 의미는... 에러시의 처리를 하지 않겠다는 의미가 된다. (500에러가 나올것임)












 



 




'IT > 스프링' 카테고리의 다른 글

HandlerInterceptor  (0) 2012.01.19
파일 업로드 in spring... 3  (1) 2012.01.18
Ant 경로 패턴 in @RequestMapping  (0) 2012.01.16
PathVariable 어노테이션을 이용한 URI 템플릿...  (0) 2012.01.16
URI 매칭.. (서블릿 맵핑)  (0) 2012.01.13

+ Recent posts