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還支援分組校驗、校驗集合等功能,具體可參考官方文件: