经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring » 查看文章
Spring 校验(validator,JSR-303)简单实现方式
来源:jb51  时间:2021/10/19 17:14:56  对本文有异议

Spring 校验(validator,JSR-303)实现

什么是JSR-303规范

JSR 303是Java EE 6中的一项子规范,叫做Bean Validation,官方参考实现是hibernate Validator,此实现与Hibernate ORM没有任何关系。JSR 303用于对Java Bean中的字段的值进行验证。

与Spring MVC结合

Spring-mvc.xml配置:

  1. <!--JSR-303-->
  2. <mvc:annotation-driven validator="validator"/>
  3. <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
  4. <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
  5. <property name="validationMessageSource" ref="messageSource"/>
  6. </bean>
  7. <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
  8. <property name="basename" value="validatemessage"/>
  9. <property name="useCodeAsDefaultMessage" value="false"/>
  10. <property name="defaultEncoding" value="UTF-8"/>
  11. <property name="cacheSeconds" value="60"/>
  12. </bean>
  13. <bean id="webBindingInitializer" class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
  14. <property name="conversionService">
  15. <bean class="org.springframework.format.support.FormattingConversionServiceFactoryBean"></bean>
  16. </property>
  17. <property name="validator" ref="validator"/>
  18. </bean>

实体类添加验证注解

这里贴出部分代码,知道如何加注解即可:

  1. import com.lemontree.common.utils.AjaxResult;
  2. import com.lemontree.common.utils.StringUtil;
  3. import com.lemontree.common.utils.email.EmailUtils;
  4. import org.hibernate.validator.constraints.NotEmpty;
  5. import java.util.Date;
  6. public class User {
  7. /**
  8. * This field was generated by MyBatis Generator.
  9. * This field corresponds to the database column user.id
  10. *
  11. * @mbg.generated Thu Mar 16 13:27:38 CST 2017
  12. */
  13. private Integer id;
  14. /**
  15. * This field was generated by MyBatis Generator.
  16. * This field corresponds to the database column user.user_name
  17. *
  18. * @mbg.generated Thu Mar 16 13:27:38 CST 2017
  19. */
  20. @NotEmpty(message = "用户名不能为空")
  21. private String userName;
  22. /**
  23. * This field was generated by MyBatis Generator.
  24. * This field corresponds to the database column user.password
  25. *
  26. * @mbg.generated Thu Mar 16 13:27:38 CST 2017
  27. */
  28. @NotEmpty(message = "密码不能为空")
  29. private String password;
  30. }

控制器验证注解添加

将@Validated 注解跟在实体类前面,BindingResult紧跟其后:

  1. @RequestMapping(value = "/login.htm", method = RequestMethod.POST)
  2. public @ResponseBody AjaxResult login(@Validated User user, BindingResult bindingResult,
  3. HttpServletRequest request, HttpServletResponse response) {
  4. if (bindingResult.hasErrors()){
  5. List<FieldError> errorses = bindingResult.getFieldErrors();
  6. if (CollectionUtils.isNotEmpty(errorses)){
  7. errorses.forEach(item->{
  8. System.out.println(item.getDefaultMessage());
  9. });
  10. }
  11. }
  12. }

Java Hibernate Validator JSR-303验证

JSR-303是JAVA EE 6中的一项子规范,叫做 Bean Validation,Hibernate Validator是Bean Validation 的参考实现。

实际使用就是通过注解来给字段添加约束,然后校验字段是否符合规范,如果不符合就会抛出异常,以此来减少校验数据的代码,并保证拿到的数据都是符合规范的,也可以和Spring框架配合使用

集成

官方文档

https://mvnrepository.com/artifact/org.hibernate/hibernate-validator

https://mvnrepository.com/artifact/javax.validation/validation-api

  1. <dependency>
  2. <groupId>org.hibernate</groupId>
  3. <artifactId>hibernate-validator</artifactId>
  4. <version>6.0.10.Final</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.glassfish</groupId>
  8. <artifactId>javax.el</artifactId>
  9. <version>3.0.1-b09</version>
  10. </dependency>
  11. <dependency>
  12. <groupId>javax.validation</groupId>
  13. <artifactId>validation-api</artifactId>
  14. <version>2.0.1.Final</version>
  15. </dependency>

使用

校验对象

  1. public class JsrTest {
  2. @NotNull(message = "id不能为空!")
  3. @Min(value = 1, message = "Id只能大于等于1")
  4. Integer id;
  5. @NotNull(message = "姓名不能为空!")
  6. String name;
  7. public void validateParams() {
  8. Validator validator = Validation.buildDefaultValidatorFactory().getValidator();//获取一个验证器
  9. Set<ConstraintViolation<JsrTest>> violationSet = validator.validate(this);//验证数据,获取到错误集合
  10. Iterator<ConstraintViolation<JsrTest>> iterator = violationSet.iterator();
  11. if (iterator.hasNext()) {
  12. String errorMessage = iterator.next().getMessage();//获取到错误信息
  13. throw new ValidationException(errorMessage);
  14. }
  15. }
  16. public static void main(String args[]) {
  17. JsrTest req = new JsrTest();
  18. req.id = 1;
  19. req.validateParams();
  20. }
  21. }

像上面那样将在属性上添加注解即可声明约束

校验属性

上面是校验整个对象,也可以单独校验某个字段:

  1. validator.validateProperty(object, "name");

分组校验

  1. public class JsrTest {
  2. @NotNull(message = "id不能为空!", groups = {ValidationGroup.class})
  3. @Min(value = 1, message = "Id只能大于等于1")
  4. Integer id;
  5. @NotNull(message = "姓名不能为空!", groups = {ValidationGroup.class})
  6. String name;
  7. @DecimalMin(value = "1.1")
  8. double price;
  9. int date;
  10. public static void validateParams(JsrTest jsrTest) {
  11. Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
  12. Set<ConstraintViolation<JsrTest>> violationSet = validator.validate(jsrTest, ValidationGroup.class);
  13. Iterator<ConstraintViolation<JsrTest>> iterator = violationSet.iterator();
  14. if (iterator.hasNext()) {
  15. String errorMessage = iterator.next().getMessage();
  16. throw new ValidationException(errorMessage);
  17. }
  18. }
  19. public static void main(String args[]) {
  20. JsrTest req = new JsrTest();
  21. validateParams(req);
  22. }
  23. public interface ValidationGroup {
  24. }
  25. }

分组校验所指定的calss必须是一个接口,可以指定多个

自定义约束

通常情况下,框架提供的注解已经可以满足正常的验证需求,但是我们也可以自定义注解来满足我们的需求

我们这里的例子是所注释的字符串中不能包含指定字符

  1. @Target(FIELD) //元注解,定义该注解使用在字段上
  2. @Retention(RUNTIME) //定义注解的生命周期
  3. @Constraint(validatedBy = CustomValidator.class)//指明该注解的校验器
  4. @Documented //表示该注解会被添加到JavaDoc中
  5. public @interface CustomConstraints {
  6. String message() default "默认异常message";
  7. Class<?>[] groups() default {};
  8. Class<? extends Payload>[] payload() default {}; //这个属性可以用来标注错误的严重等级,但是并不被API自身所使用
  9. String value() default " ";
  10. }
  1. import javax.validation.ConstraintValidator;
  2. import javax.validation.ConstraintValidatorContext;
  3. /**
  4. * 需要实现ConstraintValidator接口
  5. * 泛型的第一个参数是自定义的注解,第二个参数注解所注释的字段的类型
  6. */
  7. public class CustomValidator implements ConstraintValidator<CustomConstraints, String> {
  8. private String value;
  9. /**
  10. * 初始化调用,拿到注解所指定的value
  11. *
  12. * @param constraintAnnotation
  13. */
  14. @Override
  15. public void initialize(CustomConstraints constraintAnnotation) {
  16. value = constraintAnnotation.value();
  17. }
  18. /**
  19. * @param value 注释的字段的值
  20. * @param context
  21. * @return true 通过验证,false 未通过验证
  22. */
  23. @Override
  24. public boolean isValid(String value, ConstraintValidatorContext context) {
  25. if (value != null && value.contains(this.value)) {
  26. context.disableDefaultConstraintViolation();//禁用默认的消息
  27. context.buildConstraintViolationWithTemplate("新添加的错误消息").addConstraintViolation();
  28. return false;
  29. }
  30. return true;
  31. }
  32. }

然后就可以和其他注解一样使用它了

封装

或者是将验证参数的代码提取去出来,单独写一个方法

  1. public static void validateParams(Object object) {
  2. Validator validator = Validation.buildDefaultValidatorFactory().getValidator();//获取一个验证器
  3. Set<ConstraintViolation<Object>> violationSet = validator.validate(object);//验证数据,获取到错误集合
  4. Iterator<ConstraintViolation<Object>> iterator = violationSet.iterator();
  5. if (iterator.hasNext()) {
  6. String errorMessage = iterator.next().getMessage();//获取到错误信息
  7. throw new ValidationException(errorMessage);
  8. }
  9. }

当然这里也可以不抛出异常,而返回一个boolean值,如何封装看实际需求

配合Spring使用

  1. @GetMapping("/test")
  2. public Integer lookCanBuyGoods(@Valid JsrTest req, BindingResult result) throws Exception {
  3. if (result.hasErrors()) {
  4. throw new ValidationException(result.getAllErrors().get(0).getDefaultMessage());
  5. }
  6. //do something...
  7. return 1;
  8. }

@Valid添加这个注解之后就会对参数进行验证,如果在其后没有跟BindingResult,验证不通过就会直接抛出异常,如果添加了BindingResult参数,就不会直接抛出异常,而会把异常信息存储在BindingResult中,供开发者自行处理

如果想要使用分组可以这样

  1. @GetMapping("/test")
  2. public Integer test(@Validated (JsrTest.ValidationGroup.class) JsrTest req, BindingResult result) throws Exception {
  3. if (result.hasErrors()) {
  4. throw new ValidationException(result.getAllErrors().get(0).getDefaultMessage());
  5. }
  6. //do something...
  7. return 1;
  8. }

@Validated如果不使用分组其作用和@Valid一致

注解使用说明

Constraint 详细信息
@Null 被注释的元素必须为 null
@NotNull 被注释的元素必须不为 null
@AssertTrue 被注释的元素必须为 true
@AssertFalse 被注释的元素必须为 false
@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max, min) 被注释的元素的大小必须在指定的范围内
@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past 被注释的元素必须是一个过去的日期
@PastOrPresent 被注释的元素必须是过去或现在的日期
@Future 被注释的元素必须是一个将来的日期
@FutureOrPresent 被注释的元素必须是将来或现在的日期
@Pattern(value) 被注释的元素必须符合指定的正则表达式
@Digits(integer =, fraction =) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度
@Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证
@NotBlank 字符串不能是Null还有被Trim的长度要大于0
@NotEmpty 不能为null,且长度大于0
@Negative 被注释的元素必须是负数
@NegativeOrZero 被注释的元素必须是负数或0
@Positive 必须是正数
@PositiveOrZero 必须是正数或0

以上为个人经验,希望能给大家一个参考,也希望大家多多支持w3xue。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号