摘要:所以就有今天的话题利用注解对进行校验。利用注解对进行校验,主要是利用框架,实现了的接口关于校验的接口,直接使用非常方便,省时省力。
最近写业务代码,因为页面复杂,导致对应的Bean属性非常多,而产品大佬又提出各种校验要求。
emmmmmm......如果写if条件来校验,那简直是又臭又长。
所以就有今天的话题——利用注解对Bean进行校验。
利用注解对Bean进行校验,主要是利用hibernate-validator框架,hibernate-validator实现了validation-api的接口关于Bean校验的接口,直接使用hibernate-validator非常方便,省时省力。
1.hibernate-validato简介此hibernate-validator+SpringMVC可以实现以下功能:
注解java bean声明校验规则;
添加message错误信息源实现国际化配置;
结合spring form中的errors标签展现错误信息。
优势:
代码简洁、处理校验可以更加优雅。
实现要求:
使用hibernate validator至少要引入两个jar包:
org.hibernate.validator hibernate-validator 6.0.1.Final org.glassfish javax.el 3.0.1-b08
java bean中使用注解添加检验规则。
2.注解及用法hibernate validator使用的注解定义在hibernate-validator-6.0.1.Final.jar、validation-api-1.1.0.Final.jar两个包中,
@AssertFalse 验证注解的元素值是false @AssertTrue 验证注解的元素值是true @DecimalMax(value=x) 验证注解的元素值小于等于@ DecimalMax指定的value值 @DecimalMin(value=x) 验证注解的元素值小于等于@ DecimalMin指定的value值 @Digits(integer=整数位数, fraction=小数位数) 验证注解的元素值的整数位数和小数位数上限 @Future 验证注解的元素值(日期类型)比当前时间晚 @Max(value=x) 验证注解的元素值小于等于@Max指定的value值 @Min(value=x) 验证注解的元素值大于等于@Min指定的value值 @NotNull 验证注解的元素值不是null @Null 验证注解的元素值是null @Past 验证注解的元素值(日期类型)比当前时间早 @Pattern(regex=正则表达式, flag=) 验证注解的元素值与指定的正则表达式匹配 @Size(min=最小值, max=最大值) 验证注解的元素值的在min和max(包含)指定区间之内,如字符长度、集合大小 @Valid 验证关联的对象,如账户对象里有一个订单对象,指定验证订单对象 @NotEmpty 验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0) @Range(min=最小值, max=最大值) 验证注解的元素值在最小值和最大值之间 @NotBlank 验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格 @Length(min=下限, max=上限) 验证注解的元素值长度在min和max区间内 @Email 验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式3.校验demo
利用hibernate validator实现Bean校验,一般有两种做法:
利用@ModelAttribute和@Valid注解;
利用validate()、validateValue()、validateProperty()等方法在需要之处直接调用。
Bean对象:
import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; public class Car { @NotNull private String manufacturer; @NotNull @Size(min = 2, max = 14) private String licensePlate; @Min(2) private int seatCount; public Car(String manufacturer, String licencePlate, int seatCount) { this.manufacturer = manufacturer; this.licensePlate = licencePlate; this.seatCount = seatCount; } //getters and setters ... }3.1.利用Validator的validate()方法
验证器
import org.apache.commons.collections4.CollectionUtils; import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.Validator; import java.util.Set; public class ValidateTest { /** * 验证器 */ private static Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); public static void main(String[] args) { Car car = new Car(null, "12", 1); //执行验证 Set> constraintViolations = validator.validate(car); //打印校验信息 if (CollectionUtils.isNotEmpty(constraintViolations)) { for (ConstraintViolation constraintViolation : constraintViolations) { System.out.println(constraintViolation.getPropertyPath().toString() + ": " + constraintViolation.getMessage()); } } } }
输出结果:
seatCount: 最小不能小于2 manufacturer: 不能为null3.2.利用@ModelAttribute和@Valid注解和BindingResult对象
校验demo
import org.springframework.stereotype.Controller; import org.springframework.validation.BindingResult; import org.springframework.validation.ObjectError; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import javax.validation.Valid; @Controller("/Validate") public class ValidateTestController { @RequestMapping("/demo1") public void validateDemo(@Valid @ModelAttribute("car") Car car, BindingResult result) { if(result.hasErrors()){ for (ObjectError error : result.getAllErrors()) { System.out.println(error.getDefaultMessage()); } } } }
测试数据:
{ "manufacturer": null, "licensePlate": "", "seatCount": 1 }
结果:
不能为null 个数必须在2和14之间 最小不能小于2
注意,需要加上@ModelAttribute注解,否则会报错: An Error/BindingResult argument is3.3.利用@Valid注解和统一异常处理
expected to be declared immediately after the model attribute
校验demo
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import javax.validation.Valid; @Controller @RequestMapping("/validate") public class ValidateTestController { @RequestMapping("/demo1") public void validateDemo(@Valid Car car) { } }
测试数据:
{ "manufacturer": null, "licensePlate": "", "seatCount": 1 }
统一异常处理类:
@Component public class ExceptionResolver implements HandlerExceptionResolver { /** * 日志 */ private static final Logger LOG = LoggerFactory.getLogger(AuditCommonExceptionResolver.class); @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { if (ex instanceof BindException) { BindException exs = (BindException) ex; for (ObjectError o : exs.getAllErrors()) { System.out.println(o.getDefaultMessage()); } } else if (ex instanceof ConstraintViolationException) { ConstraintViolationException exs = (ConstraintViolationException) ex; Set> violations = exs.getConstraintViolations(); for (ConstraintViolation> item : violations) { System.out.println(item.getMessage()); } } else { LOG.error("捕获未处理异常,异常信息:{}", ex.getMessage()); } return new ModelAndView("/sys/errorPage.jsp"); } }
结果:
不能为null 个数必须在2和14之间 最小不能小于2
注意:我自己测试的时候,捕获的是BindException异常,但是看网上好多文章写的都是捕获ConstraintViolationException异常,
比较以上三种校验方式(准确的说应该是三种hibernate validator的使用方式),可以发现2、3大同小异,使用@Valid可以不用再自己写校验的处理方法,但是方式1可以更加灵活,可以按照自己需求处理和组织校验的返回信息。
4.hibernate validator更详细的使用文档hibernate validator的更详细的使用说明,可以参考官方文档,以前没关注,这次认真的看了一下,发现hibernate validator的功能还是很强大的,最新的5.0、6.0版本只有英文文档,4.0版本有中文文档。地址如下:https://docs.jboss.org/hibern...
5.使用过程中遇到的问题使用方式1,在我自己电脑注解没有添加message信息时,默认返回的是中文,如@NotNull:不能为null,@NotEmpty:不能为空等等,但是,当部署到服务器以后,就变成英文,如@NotNull:may not be null,@NotEmpty:may not be empty等等,很是诡异。后来研读源码发现,hibernate validator通过messageInterpolator字段来实现国际化的,messageInterpolator字段中存放着当前操作系统的语言环境参数,然后根据语言环境参数去对应的配置文档中读取默认提示信息,而messageInterpolator则会在项目启动时初始化,因为我自己的电脑是中文环境,而公司的系统环境是英文的,所以导致这个问题。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/75290.html
摘要:如果说要使用数据校验,我十分相信小伙伴们都能够使用,但估计大都是有个前提的环境。具体使用可参考小家让支持对平铺参数执行数据校验默认使用只能对进行校验级联校验什么叫级联校验,其实就是带校验的成员里存在级联对象时,也要对它完成校验。 每篇一句 NBA里有两大笑话:一是科比没天赋,二是詹姆斯没技术 相关阅读 【小家Java】深入了解数据校验:Java Bean Validation 2.0(...
摘要:我们可不可以提供一个公共的入口进行统一的异常处理呢当然可以。一般我们可以在地址上带上版本号,也可以在参数上带上版本号,还可以再里带上版本号,这里我们在地址上带上版本号,大致的地址如,其中,即代表的是版本号。 上一篇带领大家初步了解了如何使用 Spring Boot 搭建框架,通过 Spring Boot 和传统的 SpringMVC 架构的对比,我们清晰地发现 Spring Boot ...
摘要:和上标注的约束都会被执行注意如果子类覆盖了父类的方法,那么子类和父类的约束都会被校验。 每篇一句 没有任何技术方案会是一种银弹,任何东西都是有利弊的 相关阅读 【小家Java】深入了解数据校验:Java Bean Validation 2.0(JSR303、JSR349、JSR380)Hibernate-Validation 6.x使用案例【小家Spring】Spring方法级别数据校...
摘要:动态代理的核心是接口和类。以上结果说明它生成的代理类为,说明是代理。测试前提实现接口测试类使用接口方式注入代理方式必须以接口方式注入测试配置为,运行结果如下实际校验逻辑。。。。 本文也同步发布至简书,地址:https://www.jianshu.com/p/f70... AOP设计模式通常运用在日志,校验等业务场景,本文将简单介绍基于Spring的AOP代理模式的运用。 1. 代理模...
摘要:前言估计很多朋友都认为参数校验是客户端的职责,不关服务端的事。轻则导致服务器宕机,重则泄露数据。所以,这时就需要设置第二道关卡,服务端验证了。老项目的服务端校验不能为空不能为空看以上代码,就一个的校验就如此麻烦。 前言 估计很多朋友都认为参数校验是客户端的职责,不关服务端的事。其实这是错误的,学过 Web 安全的都知道,客户端的验证只是第一道关卡。它的参数验证并不是安全的,一旦被有心人...
阅读 1741·2021-09-22 15:10
阅读 1228·2021-09-07 09:58
阅读 2318·2019-08-30 15:44
阅读 1616·2019-08-26 18:29
阅读 2011·2019-08-26 13:35
阅读 735·2019-08-26 13:31
阅读 660·2019-08-26 11:42
阅读 1050·2019-08-23 18:39