1.为什么使用hibernate validate

​ 在开发http接口的时候,参数校验是必须有的一个环节,当参数校验较少的时候,一般是直接按照校验条件做校验,校验不通过,返回错误信息。比如以下校验用户名不为空的校验:

  1. if (userName == null || "".equals(userName)) {
  2. response.setCode(10001);
  3. response.setMessage("用户名不能为空!");
  4. return response;
  5. }

但是当接口参数很多,并且参数校验很负责的时候,如果继续使用这种校验的方式,校验代码会非常多,并且难以维护。那么在这种情况下可以考虑使用hibernate validate做参数校验。

2.hibernate validate简介

hibernate validate是基于注解来实现的参数校验框架,并且有很好的扩展性,使用者可以通过自定义约束条件来实现自定义的校验条件。以下为添加注解的一个小例子:

  1. public class Car {
  2. @NotNull
  3. private String manufacturer;
  4. @NotNull
  5. @Size(min = 2, max = 14)
  6. private String licensePlate;
  7. @Min(2)
  8. private int seatCount;
  9. }
2.1 springboot项目做基本校验

​ 新建springboot项目,并且在项目中添加hibernate validate依赖,在springboot2.0版本中的spring-boot-starter-web已经包含了此jar包,不需要再重复添加,但是在spring-boot-starter-web2.0以上版本中不包含此jar包,需要手动添加,依赖信息如下:

  1. <!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
  2. <dependency>
  3. <groupId>org.hibernate.validator</groupId>
  4. <artifactId>hibernate-validator</artifactId>
  5. <version>6.1.5.Final</version>
  6. </dependency>

添加Validator的bean配置,配置内容如下:

  1. @Configuration
  2. public class ValidatorConfiguration {
  3. @Bean
  4. public Validator validator(){
  5. ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
  6. .configure()
  7. .addProperty( "hibernate.validator.fail_fast", "true" )
  8. .buildValidatorFactory();
  9. Validator validator = validatorFactory.getValidator();
  10. return validator;
  11. }
  12. }

Validator的实现必须是线程安全的,因此可以配置了bean之后,在全项目中使用,并且能多次使用.

创建对象:

  1. public class Company {
  2. @NotBlank(message = "商品名称不能为空")
  3. private String name;
  4. @Size(min = 2, max = 10, message = "税号长度必须在2到10位之前")
  5. private String taxNum;
  6. @Min(13)
  7. @Pattern(regexp = "[+-]?[0-9.]+$", message = "手机号码只能是数字")
  8. private String phoneNum;
  9. public String getName() {
  10. return name;
  11. }
  12. ....(相关getset方法)
  13. }

运行以下测试类:

  1. @SpringBootTest
  2. class HibernateValidateDemoApplicationTests {
  3. @Autowired
  4. protected Validator validator;
  5. @Test
  6. void contextLoads() {
  7. Company company = buildCompany();
  8. Set<ConstraintViolation<Company>> validResultSet = validator.validate(company);
  9. for (ConstraintViolation<Company> validResult : validResultSet) {
  10. System.out.println(validResult.getMessage());
  11. }
  12. }
  13. private Company buildCompany() {
  14. Company company = new Company();
  15. company.setName("中国石化(浙江石油分公司)");
  16. company.setTaxNum("123123123123");
  17. company.setPhoneNum("13333333333");
  18. return company;
  19. }
  20. }

输出结果为:税号长度必须在2到10位之前

以上例子中的注解比较简单,通过添加

  1. @NotBlank(message = "商品名称不能为空")
  2. @Size(min = 2, max = 10, message = "税号长度必须在2到10位之前")
  3. @Min(13)
  4. @Pattern(regexp = "[+-]?[0-9.]+$", message = "手机号码只能是数字") 通过正则表达式校验字符窜

来做一些字符串非空、长度的校验.常用的校验注解有以下几种:

注解 校验规则
AssertFalse、AssertTrue 判断值是否为false或者true
DecimalMax、DecimalMin 必须为数字,并且值小于最大值、大于最小值
Digits 必须是数字
Email 必须是邮箱
Max、Min、NotBlank、NotEmpty、Size 最大最小长度校验
Negative、NegativeOrZero 数值校验
Pattern 正则表达式校验
2.2 自定义校验规则

除了上面框架提供的校验规则, 我们也可以自定义校验规则,比如当我们要校验字符个数的时候,可以使用一下自定义规则。

首先定义注解:

  1. @Target( { ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Constraint(validatedBy = CharacterValidator.class)
  4. @Documented
  5. public @interface CharLength {
  6. int min() default 0;
  7. int max() default Integer.MAX_VALUE;
  8. String message() default "{org.hibernate.validator.constraints.Length.message}";
  9. Class<?>[] groups() default { };
  10. Class<? extends Payload>[] payload() default { };
  11. }

定义此注解对应的校验实现类:

  1. public class CharacterValidator implements ConstraintValidator<CharLength, String> {
  2. private static final Log log = LoggerFactory.make(MethodHandles.lookup());
  3. private int min;
  4. private int max;
  5. @Override
  6. public void initialize(CharLength constraintAnnotation) {
  7. min = constraintAnnotation.min();
  8. max = constraintAnnotation.max();
  9. validateParameters();
  10. }
  11. @Override
  12. public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
  13. //为具体的校验规则
  14. if ( value == null ) {
  15. return true;
  16. }
  17. int length = CharUtil.getStringLength(value);
  18. return length >= min && length <= max;
  19. }
  20. private void validateParameters() {
  21. if ( min < 0 ) {
  22. throw log.getMinCannotBeNegativeException();
  23. }
  24. if ( max < 0 ) {
  25. throw log.getMaxCannotBeNegativeException();
  26. }
  27. if ( max < min ) {
  28. throw log.getLengthCannotBeNegativeException();
  29. }
  30. }
  31. }

定义完成之后,对Company的定义修改如下:

  1. @NotBlank(message = "公司名称不能为空")
  2. @CharLength(max = 12, message = "公司名称不能超过12个字符")
  3. private String name;

再次运行测试用例,输出内容如下:公司名称不能超过12个字符

2.3 使用@ScriptAssert校验参数

但是当我们的校验规则更加复杂的时候,只是用注解可能不能完成我们的需求,这个时候就可以使用@ScriptAssert注解来实现运行方法的方式来实现复杂校验。

在Company类上添加以下注解:

  1. @ScriptAssert(lang = "javascript", script = "com.zjut.hibernate.validate.business.CompanyValidateScript.checkCombineLength(_this.name,_this.taxNum, 30)",
  2. message = "名称和税号不能超过30位")

并定义校验方法:

  1. public static boolean checkCombineLength(int maxLength, String... params) {
  2. int length = 0;
  3. for (String param : params) {
  4. if (StringUtils.isEmpty(param)) {
  5. continue;
  6. }
  7. length += CharUtil.getStringLength(param);
  8. }
  9. return length <= maxLength;
  10. }

除此之外,hibernater validate还支持分组校验、校验集合等功能,具体可参考官方文档:

http://hibernate.org/validator/

使用hibernate validate做参数校验的更多相关文章

  1. 寻找写代码感觉(十六)之 集成Validation做参数校验

    写在前面 今天是大年初五了... 不知不觉,又要上班了,美好的假期只剩一天了,有点不舍呢! 也不知道为什么,总感觉像在做梦一样,像没睡醒一样,并不是因为眼睛小,更多应该是自寻烦恼,想得多罢了. 参数校 ...

  2. 如何在 Spring/Spring Boot 中做参数校验?你需要了解的都在这里!

    本文为作者原创,如需转载请在文首著名地址,公众号转载请申请开白. springboot-guide : 适合新手入门以及有经验的开发人员查阅的 Spring Boot 教程(业余时间维护中,欢迎一起维 ...

  3. 如何在 Spring/Spring Boot 中做参数校验

    数据的校验的重要性就不用说了,即使在前端对数据进行校验的情况下,我们还是要对传入后端的数据再进行一遍校验,避免用户绕过浏览器直接通过一些 HTTP 工具直接向后端请求一些违法数据. 本文结合自己在项目 ...

  4. 如何优雅的做参数校验-JSR330

    前言: 本文不是讲@Validate.@Valid是如何使用的.区别是什么,想看这些内容的请换篇文章. 背景: 当前端传过来的参数是进行对称性加密.base64加密等处理后过的参数时,在control ...

  5. hibernate validation 手动参数校验 不经过spring

    /** * 校验工具类 * @author wdmcygah * */ public class ValidationUtils { private static Validator validato ...

  6. spring mvc +@Valid +@RequestBody 来做参数校验返回400,并且不显示具体message 如何解决

    参考文档: https://www.oschina.net/question/115867_2282711   谢谢原作者

  7. Spring Validation最佳实践及其实现原理,参数校验没那么简单!

    之前也写过一篇关于Spring Validation使用的文章,不过自我感觉还是浮于表面,本次打算彻底搞懂Spring Validation.本文会详细介绍Spring Validation各种场景下 ...

  8. eggjs的参数校验模块egg-validate的使用和进一步定制化升级

    简单讲一下这个egg-validate egg-validate是基于parameter的. 安装 npm install --save egg-validate 启用 // config/plugi ...

  9. 全栈项目|小书架|服务器开发-Koa2 参数校验处理

    为什么需要做参数校验 在开发中,无论是App开发还是服务器接口开发, 我们无法去预测用户传入的数据,因此参数(数据)校验是开发中不可或缺的一环. 例如像App的注册登录表单提交页面,就要做好多层的判断 ...

随机推荐

  1. Mister B and PR Shifts,题解

    题目链接 分析: 题意很明白,不再多说了,直接分析题目,首先想一想暴力,直接枚举起点,然后求出来,时间复杂度n*n,显然不太好,所以我们考虑换一种方法枚举,当然本质还是枚举,其实你会发现变化i次和i+ ...

  2. Python-自动用0补取长度

    描述 Python zfill() 方法返回指定长度的字符串,原字符串右对齐,前面填充0. 语法 zfill()方法语法: str.zfill(width) 参数 width -- 指定字符串的长度. ...

  3. day74 bbs项目☞点赞与评论

    目录 一.文章详情展示 1 将侧边栏做成inclusion_tag 二.点赞点踩功能 三.评论功能 整体总结: 在出现bug的时候,先判断是前端bug还是后端bug,再判断bug错误类型,以及报错信息 ...

  4. day47 数据库进阶

    目录 一.select查询扩展 1 几个重要关键字的执行顺序 2 where筛选条件 3 group by分组 4 having 分组之后的筛选条件 5 distinct去重 6 order by 排 ...

  5. day15 作业

    day15 作业 目录 day15 作业 第一题 第二题 第三题 第四题 第五题 第六题 第七题 第一题 ===================题目一=================== input ...

  6. 初学linux常见问题

    学习视频:<Linux从入门到精通> 1.Linux系统与我们常用的windows系统有什么相同与不同之处? 相同之处:都是操作系统,可以安装其他的软件 不同之处:从使用方式上来看,win ...

  7. redis(二十四):Redis分布式锁以及实现(python)

    阅读目录 什么事分布式锁 基于redis实现分布式锁 一.什么是分布式锁 我们在开发应用的时候,如果需要对某一个共享变量进行多线程同步访问的时候,可以使用我们学到的锁进行处理,并且可以完美的运行,毫无 ...

  8. 面试软件测试工程师——盘点HR的那些黑话

    当疫情过后,应该有很多测试实习生寻找测试岗或者已从业测试岗的群体进行跳槽:最近也收到很多测试新生的咨询,在这里简单分享一下!老铁们走起!今天在这里就简单做跟大家聊一聊面试过程中你与面试官/HR聊天过程 ...

  9. OSCP Learning Notes - Capstone(2)

    BTRSys v2.1 Walkthrough Preparation: Download the BTRSys virtual machine from the following website: ...

  10. P1100 高低位切换

    这个题很简单 直接用左移位(<<)和右移位(>>)就可以过了 #include<iostream> #include<cstdio> using nam ...