目錄
-
-
-
- 簡介
- 內建
- 使用
-
-
- 校驗對象
- 校驗屬性
- 分組校驗
- 自定義限制
- 封裝
- 配合Spring使用
- 注解使用說明
-
-
-
簡介
JSR-303是JAVA EE 6中的一項子規範,叫做 Bean Validation,Hibernate Validator是Bean Validation 的參考實作。實際使用就是通過注解來給字段添加限制,然後校驗字段是否符合規範,如果不符合就會抛出異常,以此來減少校驗資料的代碼,并保證拿到的資料都是符合規範的,也可以和Spring架構配合使用
內建
官方文檔
https://mvnrepository.com/artifact/org.hibernate/hibernate-validator
https://mvnrepository.com/artifact/javax.validation/validation-api
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.10.Final</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>3.0.1-b09</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
使用
校驗對象
public class JsrTest {
@NotNull(message = "id不能為空!")
@Min(value = 1, message = "Id隻能大于等于1")
Integer id;
@NotNull(message = "姓名不能為空!")
String name;
public void validateParams() {
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();//擷取一個驗證器
Set<ConstraintViolation<JsrTest>> violationSet = validator.validate(this);//驗證資料,擷取到錯誤集合
Iterator<ConstraintViolation<JsrTest>> iterator = violationSet.iterator();
if (iterator.hasNext()) {
String errorMessage = iterator.next().getMessage();//擷取到錯誤資訊
throw new ValidationException(errorMessage);
}
}
public static void main(String args[]) {
JsrTest req = new JsrTest();
req.id = 1;
req.validateParams();
}
}
像上面那樣将在屬性上添加注解即可聲明限制
校驗屬性
上面是校驗整個對象,也可以單獨校驗某個字段:
分組校驗
public class JsrTest {
@NotNull(message = "id不能為空!", groups = {ValidationGroup.class})
@Min(value = 1, message = "Id隻能大于等于1")
Integer id;
@NotNull(message = "姓名不能為空!", groups = {ValidationGroup.class})
String name;
@DecimalMin(value = "1.1")
double price;
int date;
public static void validateParams(JsrTest jsrTest) {
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
Set<ConstraintViolation<JsrTest>> violationSet = validator.validate(jsrTest, ValidationGroup.class);
Iterator<ConstraintViolation<JsrTest>> iterator = violationSet.iterator();
if (iterator.hasNext()) {
String errorMessage = iterator.next().getMessage();
throw new ValidationException(errorMessage);
}
}
public static void main(String args[]) {
JsrTest req = new JsrTest();
validateParams(req);
}
public interface ValidationGroup {
}
}
分組校驗所指定的calss必須是一個接口,可以指定多個
自定義限制
通常情況下,架構提供的注解已經可以滿足正常的驗證需求,但是我們也可以自定義注解來滿足我們的需求
我們這裡的例子是所注釋的字元串中不能包含指定字元
@Target(FIELD) //元注解,定義該注解使用在字段上
@Retention(RUNTIME) //定義注解的生命周期
@Constraint(validatedBy = CustomValidator.class)//指明該注解的校驗器
@Documented //表示該注解會被添加到JavaDoc中
public @interface CustomConstraints {
String message() default "預設異常message";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {}; //這個屬性可以用來标注錯誤的嚴重等級,但是并不被API自身所使用
String value() default " ";
}
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
/**
* 需要實作ConstraintValidator接口
* 泛型的第一個參數是自定義的注解,第二個參數注解所注釋的字段的類型
*/
public class CustomValidator implements ConstraintValidator<CustomConstraints, String> {
private String value;
/**
* 初始化調用,拿到注解所指定的value
*
* @param constraintAnnotation
*/
@Override
public void initialize(CustomConstraints constraintAnnotation) {
value = constraintAnnotation.value();
}
/**
* @param value 注釋的字段的值
* @param context
* @return true 通過驗證,false 未通過驗證
*/
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value != null && value.contains(this.value)) {
context.disableDefaultConstraintViolation();//禁用預設的消息
context.buildConstraintViolationWithTemplate("新添加的錯誤消息").addConstraintViolation();
return false;
}
return true;
}
}
然後就可以和其他注解一樣使用它了
封裝
或者是将驗證參數的代碼提取去出來,單獨寫一個方法
public static void validateParams(Object object) {
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();//擷取一個驗證器
Set<ConstraintViolation<Object>> violationSet = validator.validate(object);//驗證資料,擷取到錯誤集合
Iterator<ConstraintViolation<Object>> iterator = violationSet.iterator();
if (iterator.hasNext()) {
String errorMessage = iterator.next().getMessage();//擷取到錯誤資訊
throw new ValidationException(errorMessage);
}
}
當然這裡也可以不抛出異常,而傳回一個boolean值,如何封裝看實際需求
配合Spring使用
@GetMapping("/test")
public Integer lookCanBuyGoods(@Valid JsrTest req, BindingResult result) throws Exception {
if (result.hasErrors()) {
throw new ValidationException(result.getAllErrors().get(0).getDefaultMessage());
}
//do something...
return 1;
}
@Valid添加這個注解之後就會對參數進行驗證,如果在其後沒有跟BindingResult,驗證不通過就會直接抛出異常,如果添加了BindingResult參數,就不會直接抛出異常,而會把異常資訊存儲在BindingResult中,供開發者自行處理
如果想要使用分組可以這樣
@GetMapping("/test")
public Integer test(@Validated (JsrTest.ValidationGroup.class) JsrTest req, BindingResult result) throws Exception {
if (result.hasErrors()) {
throw new ValidationException(result.getAllErrors().get(0).getDefaultMessage());
}
//do something...
return 1;
}
@Validated如果不使用分組其作用和@Valid一緻
注解使用說明
Constraint | 詳細資訊 |
---|---|
@Null | 被注釋的元素必須為 null |
@NotNull | 被注釋的元素必須不為 null |
@AssertTrue | 被注釋的元素必須為 true |
@AssertFalse | 被注釋的元素必須為 false |
@Min(value) | 被注釋的元素必須是一個數字,其值必須大于等于指定的最小值 |
@Max(value) | 被注釋的元素必須是一個數字,其值必須小于等于指定的最大值 |
@DecimalMin(value) | 被注釋的元素必須是一個數字,其值必須大于等于指定的最小值 |
@DecimalMax(value) | 被注釋的元素必須是一個數字,其值必須小于等于指定的最大值 |
@Size(max, min) | 被注釋的元素的大小必須在指定的範圍内 |
@Digits (integer, fraction) | 被注釋的元素必須是一個數字,其值必須在可接受的範圍内 |
@Past | 被注釋的元素必須是一個過去的日期 |
@PastOrPresent | 被注釋的元素必須是過去或現在的日期 |
@Future | 被注釋的元素必須是一個将來的日期 |
@FutureOrPresent | 被注釋的元素必須是将來或現在的日期 |
@Pattern(value) | 被注釋的元素必須符合指定的正規表達式 |
@Digits(integer =, fraction =) | 驗證字元串是否是符合指定格式的數字,interger指定整數精度,fraction指定小數精度 |
驗證是否是郵件位址,如果為null,不進行驗證,算通過驗證 | |
@NotBlank | 字元串不能是Null還有被Trim的長度要大于0 |
@NotEmpty | 不能為null,且長度大于0 |
@Negative | 被注釋的元素必須是負數 |
@NegativeOrZero | 被注釋的元素必須是負數或0 |
@Positive | 必須是正數 |
@PositiveOrZero | 必須是正數或0 |