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