在 RESTful 的接口服務中,存在各種各樣的請求參數。在跳入業務處理環節之前,通常會有一個基礎的數據驗證的機制,待驗證通過,結果無誤后,請求參數才會傳遞到正式的業務處理中。
maven 依賴引入
Spring Boot項目中,Validation校驗需要引入的兩個包:
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.16.Final</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
如何使用javax.validation @Valid注解
Hibernate-Validator的主要使用方式是在Controller的請求參數加@Valid 注解,並且是“零配置”的,無需配置也可以使用。 @Valid 注解表示需要對這個對象的屬性進行驗證:
public String saveUser(@RequestBody **@Valid** User user) {...}
既然是屬性驗證,那么就肯定會有驗證結果,驗證結果可以通過在請求參數那直接添加一個BindingResult變量來獲取。在 User類的屬性上打上如下注解:
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotBlank;
/**
* @author Wiener
* @since 2021/11/7
*/
@Data
public class User {
@NotBlank(
message = "姓名不能為空"
)
@Length(
message = "姓名最長為 {max}個字符"
, min = 1
, max = 20
)
private String name;
@NotBlank(
message = "密碼不能為空"
)
@Length(
message = "密碼最少為{min}個字符,最長為 {max}個字符"
, min = 8
, max = 30
)
private String password;
/** 年齡 */
@NotNull(message = "請輸入年齡")
@Range(message = "年齡大小范圍為 {min} 到 {max} 之間", min = 1, max = 150)
public Integer age;
@NotBlank
@Size(max=32,message="address is null")
private String address;
/**
* 當前時間不能為空(必填)
*/
@NotBlank(message="當前時間不能為空")
@DateTimeStr(format ="yyyy-MM-dd HH:mm:ss", message = "格式錯誤,正確格式為:yyyy-MM-dd HH:mm:ss")
private String currentTime;
}
當輸入不能滿足條件時,就會拋出異常,而后統一由異常中心處理。也可以用BindingResult,但是用了這個后就必須手動處理異常,侵入了正常的業務邏輯,並不推薦。
常用注解
這兒介紹Hibernate和 javax.validation 包下的一些常用校驗注解。
@Null
限制只能為null
@NotNull
限制必須不為null
@AssertFalse
限制必須為false
@AssertTrue
限制必須為true
@DecimalMax(value)
限制必須為一個不大於指定值的數字
@DecimalMin(value)
限制必須為一個不小於指定值的數字
@Digits(integer,fraction)
限制必須為一個小數,且整數部分的位數不能超過integer,小數部分的位數不能超過fraction
@Future
限制必須是一個將來的日期
@Max(value)
限制必須為一個不大於指定值的數字
@Min(value)
限制必須為一個不小於指定值的數字
@Past
限制必須是一個過去的日期
@Pattern(value)
限制必須符合指定的正則表達式
@Size(max,min)
限制字符串長度必須在min到max之間
@Past
驗證注解的元素值(日期類型)比當前時間早
@NotEmpty
驗證注解的元素值不為null且不為空(字符串長度不為0、集合大小不為0)
@NotBlank
驗證注解的元素值不為空(不為null、去除首位空格后長度為0),不同於@NotEmpty,@NotBlank只應用於字符串且在比較時會去除字符串的空格
@Email
驗證注解的元素值是Email,也可以通過正則表達式和flag指定自定義的email格式
嵌套實體驗證和測試用例
溫馨提示:實體類驗證只是針對該實體內第一層的屬性進行驗證,如果被驗證的實體類存在另一個實體類B,那么就需要在B類成員變量上加 @valid 注解。如在Student類中添加班級CurrentTimeDto類型的成員變量並校驗其屬性:
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.Range;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import java.io.Serializable;
@Data
public class Student implements Serializable {
private static final long serialVersionUID = 5285725868010678653L;
@NotNull(
message = "姓名不能為空"
)
@Length(
message = "姓名最長為 {max}個字符"
, min = 1
, max = 20
)
private String name;
@NotNull(
message = "密碼不能為空"
)
@Length(
message = "密碼最少為{min}個字符,最長為 {max}個字符"
, min = 8
, max = 30
)
private String password;
/** 年齡 */
@NotNull(message = "請輸入年齡")
@Range(message = "年齡大小范圍為 {min} 到 {max} 之間", min = 1, max = 150)
public Integer age;
@NotNull(message = "請輸入address")
@Size(max=32,message="address is null")
private String address;
@Pattern(regexp = "\\d{3}-\\d{8}|\\d{4}-\\d{7}|\\d{11}", message = "手機號碼不正確")
private String telephone;
@Valid
private CurrentTimeDto currentTimeDto;
}
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
@Data
public class CurrentTimeDto implements Serializable {
private static final long serialVersionUID = -7831097421296635187L;
/**
* 當前時間不能為空(必填)
*/
//設置時區為上海時區,時間格式自己據需求定。
// @JsonFormat(pattern="yyyy-MM-dd",timezone = "GMT+8")
@NotBlank(message="當前時間不能為空")
private String currentTime;
}
下面是兩個基於Student類的測試用例,在請求參數前加上 @Valid注解即開啟參數校驗:
/**
* 參數校驗結果從bindingResult中讀取
* @param student
* @param bindingResult
* @return
*/
@ApiOperation(value = "bindingResult")
@PostMapping("/bindingResult")
public Object bindingResult(@RequestBody @Valid Student student, BindingResult bindingResult) {
System.out.println("bindingResult---" + student);
if (bindingResult.getErrorCount() > 0) {
return bindingResult.getFieldError();
}
return student;
}
/**
* 參數校驗結果僅僅可以從日志中查看
* @param student
* @return
*/
@ApiOperation(value = "validParam")
@PostMapping("/validParam")
public Object validParam(@RequestBody @Valid Student student) {
System.out.println("validParam---" + student);
return student;
}
小結
願各位新時代農民工不斷打破自己,提升自己,重塑自己,從而讓自己的職業和生活更加璀璨。
