본문 바로가기

Spring/Spring MVC

스프링 폼태그, 스프링 벨리데이터 를 통한 회원가입 02


스프링 폼태그, 스프링 벨리데이터 를 통한 회원가입 02

예제 코드는 Github에 있습니다. (브랜치별로 분할 하엿습니다.)
1. Message properties을 이용한 custom Error message
2. Custom Vaildation Annotation 만들기
- VO에 Custom Vaildation Annotation 적용
3. Validator interface를 implements 한 Validator.java만들기
- VO에 Annotation없이 .java로 validator분리

1. Message properties을 이용한 custom Error message

http://zero-gravity.tistory.com/298 참고

  • messageSource Bean 등록


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
  <property name="basenames" value="classpath:/messages/message" />
  <property name="cacheSeconds" value="5"/>
  <property name="defaultEncoding" value="UTF-8" />
</bean>

</beans>

Annotaion 에 관련된 Message Properties

Message.properties를 설정하지 않으면 default message가 나타난다.

Ex) @NotEmpty 에 관련된 validation Error message 는 값을 입력하여주세요. 라는 메세지가 나타난다.



2. Custom Vaildation Annotation 만들기

  • VO에 Custom @annotaion 작성


@Phone
private String phoneNumber;

  • Interface 생성 (Custom @annotaion)

    (@annotation == interface)


@Documented
@Constraint(validatedBy = PhoneValidator.class)
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Phone {
  String message() default "전화번호 형식이 맞지 않습니다.";
 
  Class<?>[] groups() default {};
 
  Class<? extends Payload>[] payload() default {};
}

@Documented 문서에도 어노테이션의 정보가 표현됩니다.@Constraint(validatedBy = PhoneValidator.class) 제약 조건을 나타내는 에노테이션 입니다. 구현한 @Target({ElementType.METHOD, ElementType.FIELD}) 어노테이션이 적용할 위치를 결정합니다.@Retention(RetentionPolicy.RUNTIME) 어노테이션의 범위 OR 어떤 시점까지 어노테이션이 영향을 미치는지 결정합니다.

  • Interface 구현 (Annotation구현)


public class PhoneValidator implements ConstraintValidator<Phone, String> {

@Override
public void initialize(Phone arg0) {
}

@Override
public boolean isValid(String phoneNo, ConstraintValidatorContext ctx) {
if (phoneNo == null) {
return false;
}
return phoneNo.matches("^[0-9]*$");
// ^문자열 시작
// [] 문자의 집합이나 범위 - 의 사이값
// 앞 문자가 없을 수도 무한정 많을 수도 있음
// $문자열의 종료
}
}

@NotEmpty 와 같이 @Phone이라는 에노테이션 구현 하였습니다.


3. Validator interface를 implements 한 Validator.java만들기

  • VO의 Vaildation check를 하기 위해 custom annotion을 구현하지 않고 클래스로 분리


    public class PersonValidator implements Validator {

    public boolean supports(Class clazz) {
      return YourVO.class.equals(clazz);
      // supports 는 Java Reflection방식을 통해 해당 검사대상이 오브젝트인지 아닌지 검사함
      // supports 메소드를 통과한후 validate메소드 호출이된다.
    }

    public void validate(Object obj, Errors errors) {
     
    YourVO yourVO = (YourVO) obj;

          String fieldName = "mberId",
          errorCode = Constants.ERROR_REQUIRED,
          propFieldName = getPropMessage(string);

    if(yourVO.get()==null || "".equals(yourVO.get())){
              errors.rejectValue(field, errorCode, new Object[] { message param }, null);
    }

    /*
    rejectValue(
    1. field,(jsp path일치)
    2. errorCode,(context-message.xml 프로퍼티)/
    3. errorArgs(context-message.xml 프로퍼티의 파라미터)
    ex) message.properties 일부
    ex_errors = {0} 는 {1} 형식이 맞지 않습니다.
    4. defaultMessage (메세지 우선순위낮음)
    )
    */
    }
    }

    • supports(Class) - 이 Validator가 제공된 Class의 인스턴스를 유효성검사할 수 있는가?

    • validate(Object, org.springframework.validation.Errors) - 주어진 객체에 유효성검사를 하고 유효성검사에 오류가 있는 경우 주어진 객체에 이 오류들을 등록한다.

    • Validate 메소드 내부는 VO의 각 필드의 Validate Check 를 구현한 메소드들의 집합이 깔끔할것이다.

      Ex)


      public void validate(Object obj, Errors errors) {
       
      YourVO yourVO = (YourVO) obj;

      idValidChk("yourVO.id", yourVO.getId(), yourVO, errors);
      pwddValidChk("yourVO.pwd", yourVO.getPwd(), yourVO, errors);

      }

  • 컨트롤러에서는 validator 객체를 사용하여 Validation Check BindingResult 객체 사용


@Controller
public class yourController {

//custom validator
@Resource(name = "serverSideVOValidator")
private VOValidator voValidator;

@RequestMapping(value = "yourJsp")
public String serverSide((@ModelAttribute YourVO yourVO,
BindingResult result, ModelMap model)) throws Exception {

validator.validate(yourVO, result);

return "yourJsp";
}
}

  • @InitBinder 를 활용한 validator등록 (@Validated 활용)


    @Controller
    public class yourController {

    //custom validator
    @Resource(name = "serverSideVOValidator")
    private VOValidator voValidator;

    @InitBinder
    public void initBinder(WebDataBinder dataBinder) {
    dataBinder.setValidator(validator);
    }

    //@Validated 축가
    @RequestMapping(value = "yourJsp")
    public String serverSide((@ModelAttribute @Validated YourVO yourVO,
    BindingResult result, ModelMap model)) throws Exception {

    //validator.validate(yourVO, result);

    return "yourJsp";
    }
    }

    @Valid = JSR-303의 빈검증기를 이용하여 모델 오브젝트를 검증하는 지시자

    @InitBinder =

    주의사항 : BindingResult가 ModelMap 뒤로 가지 않도록 한다.

    1. InitBinder(WebdataBinder) 를 사용하여 사용하는경우 @ModelAttribute를 사용하지 않아도 @Valid만 사용하여 값들이 자동 binding되는 결과물들을 얻을 수 있다.

    2. WebDataBinder는 web request parameter를 JavaBean 객체에 바인딩하는 특정한 DataBinder이다. WebDataBinder는 웹 환경이 필요하지만, Servlet API에 의존적이지 않다. Servlet API에 의존적인 ServletRequestDataBinder와 같이 특정한 DataBinder를 위한 더 많은 base classs를 제공한다. . Spring Web 환경에서는 기존 Servlet을 이용했을 때의 상황과는 달리, Java의 reflection 기법을 이용하여 parameter 들을 POJO 기반의 Class로 setter 주입을 하여 제공을 하게 된다.

    3. 기본 자료형 변수들이 setter 될때 Type이 일치 하지 않는 경우, 예외가 발생하게 된다. 이런 상황을 방지하기 위하여 initBinder라는 애노테이션을 이용하게 된다.