1.Hibernate-Validator 簡介
hibernate-validator是Hibernate項目中的一個數據校驗框架,它能夠將數據校驗從業務代碼中脫離出來,增加代碼可讀性,同時也讓數據校驗變得更加方便、簡單。
官網地址:
http://hibernate.org/validator/documentation
2 項目中為什么要用校驗框架
Java程序開發中,當你要處理一個程序的業務邏輯時,請求參數的數據校驗是必須要處理的。當請求參數格式不正確的時候,需要程序監測到,並且返回對應的錯誤提示,以此來達到數據校驗的目的。對於前后端分離開發過程中,數據校驗還需要返回對應的狀態碼和錯誤提示信息。
3. 添加依賴
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.7.Final</version>
</dependency>
如果使用了springboot,則不需要引用任何依賴,因為spring-boot-starter-web包中已經包含了Hibernate-Validator 依賴。
4.在實體類上添加對應注解
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
@NotBlank(message = "用戶名不能為空")
private String name;
@NotBlank(message = "郵箱不能為空")
private String email;
}
5. POST方法中應用
@RestController
public class StudentController {
@RequestMapping(value = "/addStudent",method = RequestMethod.POST)
public String addStudent(@Valid @RequestBody Student student){
System.out.println("student = [" + student + "]");
return "ok";
}
POST請求必須要加@Valid
@RequestBody 和 @RequestParam區別
@RequestBody獲取的是請求體里面的數據,一般是前端傳給后端的JSON字符串。
@RequestParam 接收的是url里面的查詢參數(比如xxxxxxx?name=admin)
以上面代碼為例,如果去掉@RequestBody那student的屬性就會從查詢參數獲取。
下面以PostMan演示以上兩個注解在調用時的區別
如果方法上面添加@RequestParam注解,應該這樣傳遞傳遞參數。
如果方法上面添加@RequestBody 注解,應該這樣傳遞傳遞參數。
6. GET方法中應用
@RestController
@Validated
public class StudentController {
@RequestMapping(value = "/addStudent1",method = RequestMethod.GET)
public String addStudent1(@NotBlank(message = "name不能為空") String name){
System.out.println("name = [" + name + "]");
return "ok addStudent1";
}
}
Get請求需要在類上添加@Validated
7.利用PostMan調用接口
看到這個結果發現我們添加的校驗框架起作用了,響應信息中存在了"郵箱不能為空"的信息,但是前端用戶一般只關心一個校驗結果和校驗失敗信息,現在返回的這個信息太多了很難讓人接受。所以我們需要定義統一的效驗失敗后返回的格式,這個格式中只包含狀態碼和失敗原因。
7.定義優雅的返回信息
7.1 定義全局異常處理
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public ResultEntity handleBindException(MethodArgumentNotValidException ex) {
FieldError fieldError = ex.getBindingResult().getFieldError();
// 記錄日志。。。
return ResultEntity.faill(211,fieldError.getDefaultMessage(),null);
}
7.2 定義校驗失敗返回模板
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ResultEntity<T> {
private Integer code;
private String message;
private T data;
public static <T> ResultEntity<T> faill(Integer code,String msg,T t){
return new ResultEntity<T>(code,msg,t);
}
}
7.3 測試
8.常用注解
注解 | 說明 |
---|---|
@Nul | 被注釋的元素必須為 null |
@NotNull | 被注釋的元素必須不為 null |
@AssertTrue | 被注釋的元素必須為 true |
@AssertFalse | 被注釋的元素必須為 false |
@Min(value) | 被注釋的元素必須是一個數字,其值必須大於等於指定的最小值 |
@Max(value) | 被注釋的元素必須是一個數字,其值必須小於等於指定的最大值 |
@DecimalMin(value) | 被注釋的元素必須是一個數字,其值必須大於等於指定的最小值 |
@DecimalMax(value) | 被注釋的元素必須是一個數字,其值必須小於等於指定的最大值 |
@Size(max, min) | 被注釋的元素的大小必須在指定的范圍內,元素必須為集合,代表集合個數 |
@Pattern(regexp = ) | 正則表達式校驗 |
@Digits (integer, fraction) | 被注釋的元素必須是一個數字,其值必須在可接受的范圍內 |
@Past | 被注釋的元素必須是一個過去的日期 |
@Future | 被注釋的元素必須是一個將來的日期 |
被注釋的元素必須是電子郵箱地址 | |
@Length(min=, max=) | 被注釋的字符串的大小必須在指定的范圍內,必須為數組或者字符串,若微數組則表示為數組長度,字符串則表示為字符串長度 |
@NotEmpty | 被注釋的字符串的必須非空 |
@Range(min=, max=) | 被注釋的元素必須在合適的范圍內 |
@NotBlank | 被注釋的字符串的必須非空 |
@URI | 字符串是否是一個有效的URL |
注意
- @NotEmpty 用在集合類上面
- @NotBlank 用在String上面
- @NotNull 用在基本類型上
9.Hibernate-Validator校驗模式
普通模式
校驗完所有的屬性,然后返回所有的驗證失敗信息,默認是這個模式
快速失敗返回模式
只要有一個失敗就立馬返回
開啟快速失敗返回模式
@Configuration
public class HibernateValidatorConfiguration {
@Bean
public Validator validator(){
ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
.configure()
// true 快速失敗返回模式 false 普通模式
.addProperty( "hibernate.validator.fail_fast", "true" )
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
return validator;
}
}
測試驗證不通過就會拋出 ConstraintViolationException異常,和之前普通模式下拋出的異常不一樣,所以為了格式統一我還需要自定義的異常處理。
全局異常處理
// 開啟快速失敗返回模式,GET請求校驗不通過會拋出如下異常,在這對它處理
@ExceptionHandler(ConstraintViolationException.class)
@ResponseBody
public ResultEntity handle(ValidationException exception) {
if (exception instanceof ConstraintViolationException) {
ConstraintViolationException exs = (ConstraintViolationException) exception;
Set<ConstraintViolation<?>> violations = exs.getConstraintViolations();
for (ConstraintViolation<?> item : violations) {
System.out.println(item.getMessage());
return ResultEntity.faill(212, item.getMessage(), null);
}
}
return ResultEntity.faill(212, "abc", null);
}
10.對象級聯校驗
Student
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
@NotBlank(message = "用戶名不能為空")
private String name;
@Max(150)
@Min(10)
@NotNull(message = "年齡不能為空")
private Integer age;
@Email
private String email;
@NotNull(message = "user不能為空")
@Valid
private User user;
}
User
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
@NotNull(message = "user對象中的username不能為空")
private String username;
}