`

spring 使用hibernate validator

 
阅读更多

ar包引用就不说了,使用也很简单,直接上代码:

public class Customer {
 @NotEmpty //make sure name is not empty
String name;
 @Range(min = 1, max = 150) //age need between 1 and 150
int age;
 //getter and setter methods
 }
 
@Controller
@RequestMapping("/customer")
public class SignUpController {
 
@RequestMapping(value = "/signup", method = RequestMethod.POST)
public String addCustomer(@Valid Customer customer, BindingResult result) {
 if (result.hasErrors()) {
return "SignUpForm";
} else {
return "Done";
}
 }
 
@RequestMapping(method = RequestMethod.GET)
public String displayCustomerForm(ModelMap model) {
 model.addAttribute("customer", new Customer());
return "SignUpForm";
 }
 
}
见:http://www.mkyong.com/spring-mvc/spring-3-mvc-and-jsr303-valid-example/
关于@Valid ,有的地方说用@ModelAttribute,没试过,@Valid可用,并且也很自然,就用@Valid了。
 
      当需要同时校验多个属性来验证一个对象或者一个属性在验证的时候需要另外的属性的信息的时候, 类级别的约束会很有用.。首先这个注解要标注在类上面
@OrderIdDateValid(message = "...")
public class HotelOrderParam {
@NotNull
...
@NotBlank
...
public boolean isParam_valid() {
...//验证逻辑
}
}
hibernate validator对属性的验证,是每设一个就验证一个,而且是通过反射获得属性值,因此修改相应的getter方面是没法控制的。一开始想着另外加个boolean类型的属性,然后这个boolean属性值就由isParam_valid()方法来赋值,结合@AssertTrue来验证。这个思路行不通,在给这个boolean属性赋值的时候,其他属性全部为null,根本无法使用。
      自定义注解如下:
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
import javax.validation.Constraint;
import javax.validation.Payload;
 
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = OrderIdDateValidValidator.class)
@Documented
public @interface OrderIdDateValid {
String message() default "";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
在hibernate_validator_reference 文档中有说明
message属性, 这个属性被用来定义默认得消息模版, 当这个约束条件被验证失败的时候,通过此属性来输出错误信息.
groups 属性, 用于指定这个约束条件属于哪(些)个校验组(请参考第 2.3 节 “校验组”). 这个的默认值必须是Class<?>类型到空到数组.
payload 属性, Bean Validation API 的使用者可以通过此属性来给约束条件指定严重级别. 这个属性并不被API自身所使用.
      在上面那个注解下面还可以加上
Class<?> value();
注解的方法返回值只能是String、Class、基本类型、注解、枚举。不过当前不需要value()。验证器代码如下:
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
 
public class OrderIdDateValidValidator implements ConstraintValidator<OrderIdDateValid, HotelOrderParam> {
@Override
public void initialize(OrderIdDateValid constraintAnnotation) {
}
 
@Override
public boolean isValid(HotelOrderParam value, ConstraintValidatorContext context) {
if (value == null) {
return true;
} else {
return value.isParam_valid();
}
}
}
 
ConstraintValidator接口泛型的后一个,是验证对象类型,很多例子是String,不过这个例子是HotelOrderParam。如果这个参数类型错误,会报如下错误:
javax.validation.UnexpectedTypeException: HV000030: No validator could be found for type
      这里是调用param自己的方法来实现验证逻辑,这样比较符合自己负责自己的事。
 
      hibernate validator默认提供了一些注解,有时候某些属性上标注有多个验证注解,如果多个位置有这样的重复设置,可以自定义个注解来组合那些注解,然进行统一标注。使用复合注解可以使用
@ReportAsSingleViolation //javax.validation.ReportAsSingleViolation;
将提示进行组合,具体说明在这里有:
http://docs.oracle.com/javaee/6/api/javax/validation/ReportAsSingleViolation.html
 
javax.validation 
Annotation Type ReportAsSingleViolation
 
@Target(value=ANNOTATION_TYPE)
@Retention(value=RUNTIME)
public @interface ReportAsSingleViolation
A constraint annotation hosting this annotation will return the composed annotation error report if any of the composing annotations fail. The error reports of each individual composing constraint is ignored.

 
      这个验证方式是spring mvc支持的,很自然,方便使用。之前还使用了一种方式,虽然没这种好,还是记录一下吧。在spring中配置
    <mvc:annotation-driven validator="validator"/>
 
    <bean name="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
        <property name="traversableResolver">
            <bean class="com.xxx.utils.xxxTraversableResolver"></bean>
        </property>
    </bean>
      自定义的xxxTraversableResolver中的实现方法直接返回true,就可以了。hibernate validator中org.hibernate.validator.internal.engine.resolver下面的三个实现类DefaultTraversableResolver,JPATraversableResolver,SingleThreadCachedTraversableResolver虽然对接口有部分实现,但看起来都返回true的情况居多
import java.lang.annotation.ElementType;
import javax.validation.Path;
import javax.validation.TraversableResolver;
 
public class xxxTraversableResolver implements TraversableResolver {
 
public final boolean isReachable(Object traversableObject, Path.Node traversableProperty, Class<?> rootBeanType, Path pathToTraversableObject, ElementType elementType) {
return true;
}
 
public final boolean isCascadable(Object traversableObject, Path.Node traversableProperty, Class<?> rootBeanType, Path pathToTraversableObject, ElementType elementType) {
return true;
}
}
      然后有个工具类
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import com.xxx.utils.ValidateException;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
 
@Component
public class ValidateUtil {
 
    static Validator validator;
 
    @Resource
    public void setValidator(LocalValidatorFactoryBean validatorFactory) {//使用spring中定义的factory
        validator = validatorFactory.getValidator();
    }
 
    public static <T> void validate(T t) {
        Set<ConstraintViolation<T>> constraintViolations = validator.validate(t);
        if (constraintViolations.size() > 0) {
            String validateError = "";
            for (ConstraintViolation<T> constraintViolation : constraintViolations) {
                validateError += constraintViolation.getMessage() + ";";
            }
            throw new ValidateException(validateError);
        }
    }
}
其中ValidateException是自定义的异常。在controller里要手动使用ValidateUtil。这种方法在controller里没上一种方法方便,但在service层,可以用来进行手工测试。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics