1. 程式人生 > >使用hibernate validate做引數校驗

使用hibernate validate做引數校驗

#### 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包,需要手動新增,依賴資訊如下: ``` org.hibernate.validator hibernate-validator 6.1.5.Final ``` 新增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> validResultSet = validator.validate(company); for (ConstraintViolation 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 | 必須是數字 | | Email | 必須是郵箱 | | 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[] payload() default { }; } ``` 定義此註解對應的校驗實現類: ``` public class CharacterValidator implements ConstraintValidator { 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/val