1. 为什么使用 hibernate validate
在开发 http 接口的时候, 参数校验是必须有的一个环节, 当参数校验较少的时候, 一般是直接按照校验条件做校验, 校验不通过, 返回错误信息. 比如以下校验用户名不为空的校验:
- if (userName == null || "".equals(userName)) {
- response.setCode(10001);
- response.setMessage("用户名不能为空!");
- return response;
- }
但是当接口参数很多, 并且参数校验很负责的时候, 如果继续使用这种校验的方式, 校验代码会非常多, 并且难以维护. 那么在这种情况下可以考虑使用 hibernate validate 做参数校验.
2.hibernate validate 简介
hibernate validate 是基于注解来实现的参数校验框架, 并且有很好的扩展性, 使用者可以通过自定义约束条件来实现自定义的校验条件. 以下为添加注解的一个小例子:
- public class Car {
- @NotNull
- private String manufacturer;
- @NotNull
- @Size(min = 2, max = 14)
- private String licensePlate;
- @Min(2)
- private int seatCount;
- }
2.1 springboot 项目做基本校验
新建 springboot 项目, 并且在项目中添加 hibernate validate 依赖, 在 springboot2.0 版本中的 spring-boot-starter-web 已经包含了此 jar 包, 不需要再重复添加, 但是在 spring-boot-starter-web2.0 以上版本中不包含此 jar 包, 需要手动添加, 依赖信息如下:
- <!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
- <dependency>
- <groupId>org.hibernate.validator</groupId>
- <artifactId>hibernate-validator</artifactId>
- <version>6.1.5.Final</version>
- </dependency>
添加 Validator 的 bean 配置, 配置内容如下:
- @Configuration
- public class ValidatorConfiguration {
- @Bean
- public Validator validator(){
- ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
- .configure()
- .addProperty( "hibernate.validator.fail_fast", "true" )
- .buildValidatorFactory();
- Validator validator = validatorFactory.getValidator();
- return validator;
- }
- }
Validator 的实现必须是线程安全的, 因此可以配置了 bean 之后, 在全项目中使用, 并且能多次使用.
创建对象:
- public class Company {
- @NotBlank(message = "商品名称不能为空")
- private String name;
- @Size(min = 2, max = 10, message = "税号长度必须在 2 到 10 位之前")
- private String taxNum;
- @Min(13)
- @Pattern(regexp = "[+-]?[0-9.]+$", message = "手机号码只能是数字")
- private String phoneNum;
- public String getName() {
- return name;
- }
- ....(相关 get 和 set 方法)
- }
运行以下测试类:
- @SpringBootTest
- class HibernateValidateDemoApplicationTests {
- @Autowired
- protected Validator validator;
- @Test
- void contextLoads() {
- Company company = buildCompany();
- Set<ConstraintViolation<Company>> validResultSet = validator.validate(company);
- for (ConstraintViolation<Company> validResult : validResultSet) {
- System.out.println(validResult.getMessage());
- }
- }
- private Company buildCompany() {
- Company company = new Company();
- company.setName("中国石化 (浙江石油分公司)");
- company.setTaxNum("123123123123");
- company.setPhoneNum("13333333333");
- return company;
- }
- }
输出结果为: 税号长度必须在 2 到 10 位之前
以上例子中的注解比较简单, 通过添加
- @NotBlank(message = "商品名称不能为空")
- @Size(min = 2, max = 10, message = "税号长度必须在 2 到 10 位之前")
- @Min(13)
@Pattern(regexp = "[+-]?[0-9.]+$", message = "手机号码只能是数字") 通过正则表达式校验字符窜
来做一些字符串非空, 长度的校验. 常用的校验注解有以下几种:
注解 | 校验规则 |
---|---|
AssertFalse、AssertTrue | 判断值是否为 false 或者 true |
DecimalMax、DecimalMin | 必须为数字,并且值小于最大值、大于最小值 |
Digits | 必须是数字 |
必须是邮箱 | |
Max、Min、NotBlank、NotEmpty、Size | 最大最小长度校验 |
Negative、NegativeOrZero | 数值校验 |
Pattern | 正则表达式校验 |
2.2 自定义校验规则
除了上面框架提供的校验规则, 我们也可以自定义校验规则, 比如当我们要校验字符个数的时候, 可以使用一下自定义规则.
首先定义注解:
- @Target( { ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
- @Retention(RetentionPolicy.RUNTIME)
- @Constraint(validatedBy = CharacterValidator.class)
- @Documented
- public @interface CharLength {
- int min() default 0;
- int max() default Integer.MAX_VALUE;
- String message() default "{org.hibernate.validator.constraints.Length.message}";
- Class<?>[] groups() default { };
- Class<? extends Payload>[] payload() default { };
- }
定义此注解对应的校验实现类:
- public class CharacterValidator implements ConstraintValidator<CharLength, String> {
- private static final Log log = LoggerFactory.make(MethodHandles.lookup());
- private int min;
- private int max;
- @Override
- public void initialize(CharLength constraintAnnotation) {
- min = constraintAnnotation.min();
- max = constraintAnnotation.max();
- validateParameters();
- }
- @Override
- public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
- // 为具体的校验规则
- if ( value == null ) {
- return true;
- }
- int length = CharUtil.getStringLength(value);
- return length>= min && length <= max;
- }
- private void validateParameters() {
- if ( min < 0 ) {
- throw log.getMinCannotBeNegativeException();
- }
- if ( max < 0 ) {
- throw log.getMaxCannotBeNegativeException();
- }
- if ( max < min ) {
- throw log.getLengthCannotBeNegativeException();
- }
- }
- }
定义完成之后, 对 Company 的定义修改如下:
- @NotBlank(message = "公司名称不能为空")
- @CharLength(max = 12, message = "公司名称不能超过 12 个字符")
- private String name;
再次运行测试用例, 输出内容如下: 公司名称不能超过 12 个字符
2.3 使用 @ScriptAssert 校验参数
但是当我们的校验规则更加复杂的时候, 只是用注解可能不能完成我们的需求, 这个时候就可以使用 @ScriptAssert 注解来实现运行方法的方式来实现复杂校验.
在 Company 类上添加以下注解:
- @ScriptAssert(lang = "javascript", script = "com.zjut.hibernate.validate.business.CompanyValidateScript.checkCombineLength(_this.name,_this.taxNum, 30)",
- message = "名称和税号不能超过 30 位")
并定义校验方法:
- public static boolean checkCombineLength(int maxLength, String... params) {
- int length = 0;
- for (String param : params) {
- if (StringUtils.isEmpty(param)) {
- continue;
- }
- length += CharUtil.getStringLength(param);
- }
- return length <= maxLength;
- }
除此之外, hibernater validate 还支持分组校验, 校验集合等功能, 具体可参考官方文档:
http://hibernate.org/validator/
来源: https://www.cnblogs.com/vitasyuan/p/13414249.html