前言
在開發中經常需要寫一些字段校驗的代碼,比如字段非空,字段長度限制,郵箱格式驗證等等,寫這些與業務邏輯關系不大的代碼個人感覺有點麻煩:
驗證代碼繁瑣,重復勞動
方法內代碼顯得冗長
每次要看哪些參數驗證是否完整,需要去翻閱驗證邏輯代碼
敘述
Bean Validation是一個通過配置注解來驗證參數的框架,它包含兩部分Bean Validation API和Hibernate Validator。
Bean Validation API是Java定義的一個驗證參數的規范。
Hibernate Validator是Bean Validation API的一個實現。
@Valid和Validated的比較
Spring Validation驗證框架對參數的驗證機制提供了@Validated(Spring's JSR-303規范,是標準JSR-303的一個變種),javax提供了@Valid(標準JSR-303規范),配合BindingResult可以直接提供參數驗證結果。
@Valid : 沒有分組功能,可以用在方法、構造函數、方法參數和成員屬性(field)上,如果一個待驗證的pojo類,其中還包含了待驗證的對象,需要在待驗證對象上注解@valid,才能驗證待驗證對象中的成員屬性
@Validated :提供分組功能,可以在入參驗證時,根據不同的分組采用不同的驗證機制,用在類型、方法和方法參數上。但不能用于成員屬性(field)。
兩者都可以用在方法入參上,但都無法單獨提供嵌套驗證功能,都能配合嵌套驗證注解@Valid進行嵌套驗證。
嵌套驗證示例:
1
2
3
4
5
6
7
8
|
public class ClassRoom{ @NotNull String name; @Valid // 嵌套校驗,校驗參數內部的屬性 @NotNull Student student; } |
1
2
3
4
5
6
7
|
@GetMapping ( "/room" ) // 此處可使用 @Valid 或 @Validated, 將會進行嵌套校驗 public String validator( @Validated ClassRoom classRoom, BindingResult result) { if (result.hasErrors()) { return result.getFieldError().getDefaultMessage(); } return "ok" ; } |
BindingResult 的使用
BindingResult必須跟在被校驗參數之后,若被校驗參數之后沒有BindingResult對象,將會拋出BindException。
1
2
3
4
5
6
7
|
@GetMapping ( "/room" ) public String validator( @Validated ClassRoom classRoom, BindingResult result) { if (result.hasErrors()) { return result.getFieldError().getDefaultMessage(); } return "ok" ; } |
不要使用 BindingResult 接收String等簡單對象的錯誤信息。簡單對象校驗失敗,會拋出 ConstraintViolationException。主要就是接不著,你要寫也算是沒關系…
1
2
3
4
5
6
7
8
9
|
// ? 錯誤用法,也沒有特別的錯,只是 result 是接不到值。 @GetMapping ( "/room" ) @Validated // 啟用校驗 public String validator( @NotNull String name, BindingResult result) { if (result.hasErrors()) { return result.getFieldError().getDefaultMessage(); } return "ok" ; } |
修改校驗失敗的提示信息
可以通過各個校驗注解的message屬性設置更友好的提示信息。
1
2
3
4
5
6
7
8
|
public class ClassRoom{ @NotNull (message = "Classroom name must not be null" ) String name; @Valid @NotNull Student student; } |
1
2
3
4
5
6
7
8
|
@GetMapping ( "/room" ) @Validated public String validator(ClassRoom classRoom, BindingResult result, @NotNull (message = "姓名不能為空" ) String name) { if (result.hasErrors()) { return result.getFieldError().getDefaultMessage(); } return "ok" ; } |
message屬性配置國際化的消息也可以的,message中填寫國際化消息的code,在拋出異常時根據code處理一下就好了。
1
2
3
4
5
6
7
8
|
@GetMapping ( "/room" ) @Validated public String validator( @NotNull (message = "demo.message.notnull" ) String name) { if (result.hasErrors()) { return result.getFieldError().getDefaultMessage(); } return "ok" ; } |
1
2
3
4
5
|
// message_zh_CN.properties demo.message.notnull=xxx消息不能為空 // message_en_US.properties demo.message.notnull=xxx message must no be null |
hibernate-validator 的使用
1.引入pom
1
2
3
4
5
|
< dependency > < groupId >org.hibernate</ groupId > < artifactId >hibernate-validator</ artifactId > < version >5.3.1.Final</ version > </ dependency > |
2.dto入參對象屬性加入注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
@Data public class UserModel implements Serializable { private String id; @NotBlank (message = "用戶名不能為空" ) private String name; @NotNull (message = "性別不能不填" ) private Byte gender; @NotNull (message = "年齡不能不填" ) @Min (value = 0 ,message = "年齡必須大于0歲" ) @Max (value = 150 ,message = "年齡必須小于150歲" ) private Integer age; @NotBlank (message = "手機號不能不填" ) private String telphone; private String registerMode; private String thirdPartyId; private String encrptPassward; } |
方法一:3.controller方法入參加入校驗(@Validated )
1
2
3
4
5
6
7
|
@GetMapping ( "/getUser" ) public String validator( @Validated UserModel userModel , BindingResult result) { if (result.hasErrors()) { return result.getFieldError().getDefaultMessage(); } return "ok" ; } |
方法二:3.自定義封裝ValidatorImpl類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
@Component public class ValidatorImpl implements InitializingBean{ private Validator validator; //實現校驗方法并返回校驗結果 public ValidationResult validate(Object bean){ final ValidationResult result= new ValidationResult(); Set<ConstraintViolation<Object>> validate = validator.validate(bean); if (validate.size()> 0 ) { result.setHasError( true ); validate.forEach(constraintViolation->{ String errMsg=constraintViolation.getMessage(); String propertyName=constraintViolation.getPropertyPath().toString(); result.getErrorMsgMap().put(propertyName,errMsg); }); } return result; } @Override public void afterPropertiesSet() throws Exception { this .validator= Validation.buildDefaultValidatorFactory().getValidator(); } } |
方法二:4.自定義封裝ValidationResult 類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
public class ValidationResult { public boolean hasError= false ; private Map<String,String> errorMsgMap= new HashMap<>(); //實現通用的通過格式化字符串信息獲取錯誤結果的msg方法 public String getErrMsg(){ return StringUtils.join(errorMsgMap.values().toArray(), "," ); } public boolean isHasError() { return hasError; } public void setHasError( boolean hasError) { this .hasError = hasError; } public Map<String, String> getErrorMsgMap() { return errorMsgMap; } public void setErrorMsgMap(Map<String, String> errorMsgMap) { this .errorMsgMap = errorMsgMap; } } |
5.controller方法入參加入校驗
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@Autowired private ValidatorImpl validator; @Override @Transactional (rollbackFor = Exception. class ) public void register(UserModel userModel) throws BusinessException { UserDo userDo= new UserDo(); if (userModel == null ) { throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR); } //validate進行入參校驗 ValidationResult validate = validator.validate(userModel); if (validate.isHasError()){ throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR,validate.getErrMsg()); } } |
Bean Validation 的約束
-
@Null
被注釋的元素必須為 null -
@NotNull
被注釋的元素必須不為 null -
@AssertTrue
被注釋的元素必須為 true -
@AssertFalse
被注釋的元素必須為 false -
@Min(value)
被注釋的元素必須是一個數字,其值必須大于等于指定的最小值 -
@Max(value)
被注釋的元素必須是一個數字,其值必須小于等于指定的最大值 -
@DecimalMin(value)
被注釋的元素必須是一個數字,其值必須大于等于指定的最小值 -
@DecimalMax(value)
被注釋的元素必須是一個數字,其值必須小于等于指定的最大值 -
@Size(max, min)
被注釋的元素的大小必須在指定的范圍內 -
@Digits (integer, fraction)
被注釋的元素必須是一個數字,其值必須在可接受的范圍內 -
@Past
被注釋的元素必須是一個過去的日期 -
@Future
被注釋的元素必須是一個將來的日期 -
@Pattern(value)
被注釋的元素必須符合指定的正則表達式
Hibernate Validator 附加的約束
Hibernate Validator 附加的 constraint:
-
@Email
被注釋的元素必須是電子郵箱地址 -
@Length
被注釋的字符串的大小必須在指定的范圍內 -
@NotEmpty
被注釋的字符串的必須非空 -
@Range
被注釋的元素必須在合適的范圍內
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持服務器之家。
原文鏈接:https://blog.csdn.net/zmh458/article/details/96173583