JSR-303校验的基本用法可以参考这篇文章:
http://www.cnblogs.com/yangzhilong/p/3724967.html
这里讲一下自定义校验注解的用法;
1.定义一个注解
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = ValidNumChecker.class)
@Documented
public @interface ValidNum {
String message() default "the num is invalid";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
说明:重点在于 :
@Constraint(validatedBy = ValidNumChecker.class)
ValidNumChecker这个类是实际校验的方法;
2.编写实际校验的类
package com.river.jsr.annotation;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
/**
* Created by Administrator on 2017/10/19.
*/
public class ValidNumChecker implements ConstraintValidator<ValidNum, Integer> {
private ValidNum validNum;
@Override
public void initialize(ValidNum validNum) {
this.validNum = validNum;
}
@Override
public boolean isValid(Integer value, ConstraintValidatorContext constraintValidatorContext) {
if (value < 0 || value > 100) {
return false;
}
constraintValidatorContext.disableDefaultConstraintViolation();
constraintValidatorContext.buildConstraintViolationWithTemplate(this.validNum.message()).addConstraintViolation();
return true;
}
}
说明:
这个类ValidNumChecker要实现接口
public interface ConstraintValidator<A extends Annotation, T> { //A为自定义注解ValidNum,T为校验数据的类型; void initialize(A var1); //初始化方法, boolean isValid(T var1, ConstraintValidatorContext var2); //验证的逻辑,返回false则验证不通过 }
3.实体类中应用
package com.river.jsr.entity;
import com.river.jsr.annotation.ValidNum;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* Created by Administrator on 2017/10/18.
*/
@NoArgsConstructor
public class Person {
@Getter
@Setter
@ValidNum(message = "id 超出范围") //在这里实践
private Integer id;
@Getter
@Setter
private Integer age;
@Getter
@Setter
private Integer hight;
@Getter
@Setter
private Integer weight;
}
4.Controller接收参数并验证;
package com.river.jsr.controller; import com.alibaba.fastjson.JSON; import com.river.jsr.entity.Person; import org.springframework.validation.BindingResult; import org.springframework.validation.ObjectError; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; import java.util.Iterator; import java.util.List; /** * Created by Administrator on 2017/10/18. */ @RestController public class PersonController { @RequestMapping(value = "jsr", method = RequestMethod.POST) @ResponseBody public String jsrValid(@Valid Person person, BindingResult result) { List<ObjectError> allErrors = result.getAllErrors(); if (allErrors != null && !allErrors.isEmpty()) { Iterator<ObjectError> errorIterator = allErrors.iterator(); while (errorIterator.hasNext()) { ObjectError error = errorIterator.next(); return error.getDefaultMessage(); } } return person.toString(); } }
说明:BindingResult result为接收错误信息的对象,若没有,则校验不通过直接抛出异常,通过这个对象可以拿到异常信息;
5.页面部分
<form action="/river/jsr" onsubmit="" method="post" enctype="application/x-www-form-urlencoded">
id" <input name="id">
age <input name="age">
hight <input name="hight">
weight <input name="weight">
<input type="submit" value="123">
</form>
6.验证:
当输入参数均为10时,页面返回Person{id=10, age=1, hight=1, weight=1}
当id输入值为1000时,校验不通过,页面得到:id 超出范围
说明:提示信息"id 超出范围"可以在Person的字段加上自定义注解后自定义message属性,也可以使用默认模板在
org\hibernate\hibernate-validator\5.3.5.Final\hibernate-validator-5.3.5.Final.jar!\org\hibernate\validator\ValidationMessages_zh_CN.properties该路径下;
也可以将此文件copy到resource目录下自定义模板;
7.自定义模板
修改自定义注解的message的default,
当default为字符串是被认为是默认提示消息;
当为{"key"}时,被认为引入了模板,在模板中
key = \u9700\u8981\u662F\u4E00\u4E2A\u5408\u6CD5\u7684URL
通过key找到模板中的消息;
8.Validator直接注入
controller里面的校验这样写其实很麻烦,要是有很多很不方便;
我们可以改用这样的方式:
package com.river.jsr.controller; import com.river.jsr.entity.Person; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.BindingResult; import org.springframework.validation.ObjectError; import org.springframework.web.bind.annotation.*; import javax.validation.ConstraintViolation; import javax.validation.Valid; import javax.validation.Validator; import java.util.Iterator; import java.util.List; import java.util.Set; /** * Created by Administrator on 2017/10/18. */ @RestController public class PersonController { @Autowired private Validator validator; @RequestMapping(value = "jsr", method = RequestMethod.POST) @ResponseBody public String jsrValid(Person person) { Set<ConstraintViolation<Person>> validate = validator.validate(person); if (validate !=null &&! validate.isEmpty()){ Iterator<ConstraintViolation<Person>> iterator = validate.iterator(); return iterator.next().getMessage(); } return person.toString(); } }
结果不发生变化;
其中调用校验的方法
Set<ConstraintViolation<Person>> validate = validator.validate(person);
if (validate !=null &&! validate.isEmpty()){
Iterator<ConstraintViolation<Person>> iterator = validate.iterator();
return iterator.next().getMessage();
}
我们可以提出来单独一个方法,每次进入后首先调用校验方法;
9.AOP
这里应该很多人都想到了,进一步的我们可以写成一个aop,前置通知去做这一步的校验,切点打在要加入校验的方法上或者所有有该对象接收的方法上;
好了,就讲到这里吧,有些细节可以参考下面的链接;
这篇文章:http://clongjava.iteye.com/blog/1317649