下下下周健蕊,爭取做只水煮魚~~~
算了吧缩功,買現(xiàn)成的調(diào)料吧~~~
1 場景
JavaWeb后臺應(yīng)用程序,具體的執(zhí)行方法势木,收到請求跟压,需要對請求的數(shù)據(jù)
進行基礎(chǔ)校驗
,如字符串長度限制查剖、正則校驗笋庄、數(shù)字區(qū)間校驗等。
推薦在springMVC中對前臺的請求參數(shù)進行統(tǒng)一校驗静暂,校驗方式建議采用JSR30標準
進行校驗洽蛀。
1.1 普通校驗方式
最簡單的校驗方式是郊供,對請求的參數(shù)手動一個個進行校驗
鲫寄,如下代碼:
@GetMapping("saveWithOld")
public JSONObject saveWithOld(User user) {
JSONObject result = new JSONObject();
if (user.getUserCode() == null || user.getUserCode() == "") {
result.put("success", true);
result.put("message", "用戶代碼不可為空");
return result;
}
if (user.getUserName() == null || user.getUserName() == "") {
result.put("success", true);
result.put("message", "用戶名稱不可為空");
return result;
}
// do something ......
result.put("success", true);
return result;
}
這種方式塔拳,代碼量非常大
量九,代碼非常不友好
类浪。
1.2 springMVC校驗方式
springMVC费就,在執(zhí)行后臺方法之前
,可以對請求的數(shù)據(jù)通過注解
進行校驗眠蚂。此校驗方式基于JSR303規(guī)范
。
如下代碼所示:
@Data
public class User {
@NotNull(message = "用戶代碼不可為空")
private String userCode;
}
@GetMapping("saveWithNormal")
public JSONObject saveWithNormal(@Valid User user) {
JSONObject result = new JSONObject();
result.put("success", true);
result.put("message", user.toString());
return result;
}
@PostMapping("saveWithRequestParam")
public JSONObject saveWithRequestParam(@NotNull(message = "用戶代碼不可為空") String userCode) {
JSONObject result = new JSONObject();
result.put("success", true);
result.put("message", userCode);
return result;
}
此種方式笛臣,可以使用注解,已更簡單的方式對請求參數(shù)進行校驗踱蛀。
3 版本說明
本文中代碼涉及到的相關(guān)版本如下:
3.1 JDK
JDK1.8
3.2 maven依賴
spring-boot-starter-web中已包含了我們需要的依賴崩泡。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.7 </version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.18</version>
<scope>provided</scope>
</dependency>
2 名詞關(guān)系說明
這里講下springMVC中使用JSR303進行參數(shù)校驗,相關(guān)的名詞含義
及名詞之間的關(guān)系說明
谒所。
2.1 基本說明
springMVC基于JSR303
規(guī)范進行校驗劣领。
官網(wǎng)說明:https://jcp.org/en/jsr/detail?id=303
規(guī)范的相關(guān)說明如下:
JSR是Java Specification Requests的縮寫著觉,意思是Java 規(guī)范提案 趁桃。
JSR-303 是JAVA EE 6 中的一項子規(guī)范,叫做Bean Validation
忽肛。
Hibernate Validator是 Bean Validation的參考實現(xiàn)
。
Hibernate Validator提供了JSR 303 規(guī)范中所有內(nèi)置 constrain(約束)的實現(xiàn)罕模,除此之外還有一些附加的constraint(約束)
。
2.2 詳細說明
關(guān)于springMVC請求參數(shù)校驗抛腕,涉及幾個對應(yīng)的名詞摔敛,如下是:
名詞 | 說明 |
---|---|
constraint(約束) | 對參數(shù)的校驗約束 注解,如@NotNull 表示參數(shù)不可以為Null |
校驗注解 | 為元素加上約束后行楞,有時候 需要在參數(shù)前加上校驗注解 來開啟驗證。相關(guān)注解有 @Valid 和@Validated 池颈,如沒有用到注解獨有的特性 (分組、嵌套)等每币,用哪個注解 都一樣携丁。需注意不是所有的校驗都需要開啟校驗,如下不需要加上校驗注解: saveWithRequestParam(@NotNull(message = "用戶代碼不可為空") String userCode) 但是需要在 Controller類上 加上注解@Valid或@Validated |
JSR303規(guī)范 | 行業(yè)規(guī)范標準 兰怠,包括校驗的constraint(約束梦鉴,如@NotNull) 和開啟校驗注解@Valid 等體現(xiàn):代碼中體現(xiàn)為 注解、接口 揭保,無具體實現(xiàn)代碼 jar包:jakarta.validation-api-2.0.2.jar 約束注解:javax.validation.constraints包下注解+hibernate增強注解org.hibernate.validator.constraints 校驗注解: javax.validation.Valid
|
Hibernate Validator | Hibernate對JSR303規(guī)范中的約束constraint 的具體代碼實現(xiàn) jar包:hibernate-validator-6.0.20.Final.jar 增強:在原有JSR303的 constraint(約束) 中增加了約束(如@Range)
|
spring JSR303 | spring對JSR303 的包裝肥橙,對原有的校驗進行了增強 增強: 分組校驗 椭坚、順序校驗 缺點: 不支持嵌套校驗 約束注解:javax.validation.constraints包下注解+hibernate增強注解org.hibernate.validator.constraints 校驗注解: org.springframework.validation.annotation.Validated 增強說明:所謂的包裝和增強烁焙,只是將 @Valid 注解擴展為@Validated 注解乞榨。約束注解和JSR303一樣。 |
2.3 關(guān)系圖
一圖勝千言媒楼。參數(shù)校驗的相關(guān)說明夺颤,關(guān)系圖如下:
3 校驗流程
3.1 對象參數(shù)
3.1.1 說明
在對象參數(shù)
中進行約束校驗抚恒。需滿足以下條件:
(1)在mapping方法
中通過注解@Valid或@Validated指定要校驗的參數(shù)對象
如下:
@GetMapping("saveWithNormal")
public JSONObject saveWithNormal(@Valid User user) {......}
(2)在對象參數(shù)
對應(yīng)的類中,對需要校驗的參數(shù)加上約束注解
如下:
@Data
public class User {
/**
* 用戶代碼
*/
@NotNull(message = "用戶代碼不可為空")
private String userCode;
}
3.1.2 校驗流程
校驗失敗后,需要對失敗的異常信息進行處理,處理方式有兩種:
1榆俺、在mapping方法上加上參數(shù)BindingResult bindingResult
此種方式,校驗失敗后,會將異常信息封裝到參數(shù)對象bindingResult
中,可以自行
對其中的異常信息進行處理装获,封裝錯位信息,返回請求結(jié)果
习柠。
這種情況,需要每個請求露久,都對參數(shù)BindingResult
進行處理臊泰,較為繁瑣,不建議此種方式莽鸭。
如下:
@GetMapping("saveWithBind")
public JSONObject saveWithBind(@Valid User user, BindingResult bindingResult) {
// --------------------[手動檢測驗證是否通過]--------------------
if (bindingResult.hasErrors()) {
for (FieldError fieldError : bindingResult.getFieldErrors()) {
JSONObject result = new JSONObject();
result.put("success", false);
result.put("message", fieldError.getDefaultMessage());
return result;
}
}
// --------------------[驗證檢測通過后執(zhí)行其他操作]--------------------
// ......
JSONObject result = new JSONObject();
result.put("success", true);
result.put("message", user.toString());
return result;
}
2、定義spring全局異常處理,捕捉對應(yīng)的異常信息官地,進行統(tǒng)一處理
mapping方法上不加參數(shù)BindingResult bindingResult
修陡,校驗失敗后魄鸦,會拋出異常
,異常信息,通過spring全局異常管理
图仓,統(tǒng)一對拋出的異常信息進行處理狸臣,處理后統(tǒng)一封裝錯位信息丹诀。這種方式钝的,代碼量較少翁垂,且處理錯誤信息集中,推薦此種方式硝桩。
如下代碼:
@Data
public class User {
/**
* 用戶代碼
*/
@NotNull(message = "用戶代碼不可為空")
private String userCode;
}
// 參數(shù)校驗失敗沿猜,拋出異常:org.springframework.validation.BindException
@GetMapping("saveWithNormal")
public JSONObject saveWithNormal(@Valid User user) {
JSONObject result = new JSONObject();
result.put("success", true);
result.put("message", user.toString());
return result;
}
/**
* 捕捉全局異常:org.springframework.validation.BindException
* <div>普通請求的參數(shù),校驗失敗碗脊,拋出此異常</div>
* <div>如:(@Valid User user)</div>
*
* @param exception
* @return
*/
@ExceptionHandler(BindException.class)
public JSONObject handlerBindException(BindException exception) {
log.info("全局異常[BindException]:" + exception.getMessage());
JSONObject result = new JSONObject();
result.put("success", false);
if (exception != null) {
String message = exception.getBindingResult().getFieldErrors().stream().filter(e -> e != null).map(FieldError::getDefaultMessage).collect(Collectors.joining(","));
result.put("message", message);
}
return result;
}
需注意:參數(shù)上@Valid和@Validated使用方式的不同
啼肩,校驗失敗后,會拋出不同的異常
:
如下:
/**
* 捕捉全局異常:org.springframework.validation.BindException
* <div>普通請求的參數(shù)望薄,校驗失敗疟游,拋出此異常</div>
* <div>如:(@Valid User user)</div>
* @param exception
* @return
*/
@ExceptionHandler(BindException.class)
public JSONObject handlerBindException(BindException exception) {......}
/**
* 捕捉全局異常:org.springframework.web.bind.MethodArgumentNotValidException
* <div>@RequestBody修飾的參數(shù),校驗失敗痕支,拋出此異常</div>
* <div>如:(@RequestBody @Valid User user)</div>
* @param exception
* @return
*/
@ExceptionHandler({MethodArgumentNotValidException.class})
public JSONObject handleMethodArgumentNotValidException(MethodArgumentNotValidException exception) {......}
總結(jié)校驗流程圖如下:
3.2 普通類型參數(shù)
3.2.1 說明
在普通類型參數(shù)
中進行約束校驗颁虐。需滿足以下條件:
(1)在Controller類
上通過注解@Validated
開啟校驗
注意:需為@Validated注解,而不是@Valid注解
如下:
@Validated
@RestController
@RequestMapping("user")
public class UserController {......}
(2)在mapping方法
的普通類型
參數(shù)前面加上約束注解
如下:
// 參數(shù)校驗失敗卧须,拋出異常:javax.validation.ConstraintViolationException
@PostMapping("saveWithRequestParam")
public JSONObject saveWithRequestParam(@NotNull(message="用戶代碼不可為空") String userCode){......}
// 參數(shù)校驗失敗另绩,拋出異常:org.springframework.web.bind.ConstraintViolationException
@GetMapping("saveWithRestful/{userCode}")
public JSONObject saveWithRest(@PathVariable("userCode") @Length(max = 10,message="用戶代碼不可超過10位") String userCode) {......}
3.2.1 校驗流程
校驗結(jié)果的處理流程同《3.1對象參數(shù)》
需注意:如使用全局異常捕捉,校驗失敗后拋出的異常
如下:
/**
* 捕捉全局異常:javax.validation.ConstraintViolationException
* <div>直接在參數(shù)上加的校驗花嘶,校驗失敗笋籽,拋出此異常</div>
* <div>如:(@NotNull(message = "用戶代碼不可為空") String userCode)</div>
*
* @param exception
* @return
*/
@ExceptionHandler(ConstraintViolationException.class)
public JSONObject handlerConstraintViolationException(ConstraintViolationException exception) {......}
總結(jié)校驗流程圖如下:
4 嵌套校驗
嵌套校驗,準確來說椭员,是對象內(nèi)約束的嵌套校驗
车海。指的是校驗A對象,A對象內(nèi)有個屬性B是對象
隘击,B對象內(nèi)部屬性仍然有約束侍芝。需要對A對象的約束
+A對象內(nèi)B對象的約束
進行校驗,這種就是嵌套約束埋同。
4.1 代碼示例
這里既校驗參數(shù)user中的userCode約束
又需要校驗user中的屬性對象department
中的departmentCode的約束
州叠。
- 實體定義
@Data
public class Department {
@NotNull(message = "部門代碼不可為空")
private String departmentCode;
}
@Data
public class User {
@NotNull(message = "用戶代碼不可為空")
private String userCode;
@Valid
@NotNull(message = "部門不可為空")
private Department department;
private String userName;
}
- mapping方法
@GetMapping("saveWithLevel")
public JSONObject saveWithLevel(@Valid User user) {
JSONObject result = new JSONObject();
result.put("success", true);
result.put("message", user.toString());
return result;
}
- 異常處理
@ExceptionHandler(BindException.class)
public JSONObject handlerBindException(BindException exception) {
log.info("全局異常[BindException]:" + exception.getMessage());
JSONObject result = new JSONObject();
result.put("success", false);
if (exception != null) {
String message = exception.getBindingResult().getFieldErrors().stream().filter(e -> e != null).map(FieldError::getDefaultMessage).collect(Collectors.joining(","));
result.put("message", message);
}
return result;
}
4.2 代碼測試
- 請求信息
http://localhost:8080/user/saveWithLevel?department.departmentCode=001
- 返回結(jié)果
{"success":false,"message":"部門代碼長度需在5~10之間,用戶代碼不可為空"}
可見嵌套校驗起作用了,對象user的內(nèi)部普通屬性userCode和內(nèi)部對象department的自己的約束都起作用了凶赁。
4.3 總結(jié)
實現(xiàn)嵌套校驗咧栗,在被校驗對象的
內(nèi)部屬性對象上
,必須加上@Valid注解
mapping方法參數(shù)前虱肄,用
@Valid注解和@Validated沒有區(qū)別
5 分組校驗
同一個javaBean致板,我們加上約束注解后,這個javaBean作為請求參數(shù)的對象類型咏窿,其中的約束注解斟或,會對參數(shù)對象的內(nèi)容進行校驗。
有時候翰灾,不同的請求我們會使用相同的javaBean作為對象的參數(shù)類型
缕粹,如新增用戶
和更新用戶
我們都會使用用戶
這個JavaBean作為請求參數(shù)的封裝對象。
5.1 代碼示例
比如纸淮,我們新增用戶平斩,需要設(shè)置密碼;更新用戶咽块,不需要設(shè)置密碼绘面。
代碼如下:
- 分組類型
分組接口不需要有實現(xiàn),僅僅作為一個分組類型
public interface Add {
}
public interface Edit {
}
- 實體定義
通過約束中的group參數(shù)
侈沪,來指定對應(yīng)的分組類型揭璃,可以指定多個
@Data
public class User {
@NotNull(message = "用戶代碼不可為空", groups = {Add.class, Edit.class})
private String userCode;
@NotNull(message = "密碼不可為空", groups = {Add.class})
private String password;
}
- mapping方法
校驗方式,只能指定@Validated
亭罪,其中的value為這個參數(shù)的分組類型
瘦馍,和類中約束注解的groups屬性相對性
,可以指定多個
应役。
@GetMapping("groupAdd")
public JSONObject groupAdd(@Validated(Add.class) User user) {
JSONObject result = new JSONObject();
result.put("success", true);
result.put("message", user.toString());
return result;
}
@GetMapping("groupEdit")
public JSONObject groupEdit(@Validated(Edit.class) User user) {
JSONObject result = new JSONObject();
result.put("success", true);
result.put("message", user.toString());
return result;
}
- 異常處理
同4.1
5.2 代碼測試
-
新增
-
請求
-
結(jié)果
{"success":false,"message":"用戶代碼不可為空,密碼不可為空"}
-
-
編輯
-
請求
-
結(jié)果
{"success":false,"message":"用戶代碼不可為空"}
-
5.3 總結(jié)
(1)分組校驗中情组,定義的分組類型
接口,不需要有實現(xiàn)內(nèi)容箩祥,僅僅是作為分組的一個類型
存在院崇,不同的業(yè)務(wù),可以共用相同的類型袍祖。
(2)約束中的分組類型底瓣,可以定義多個。
(3)@Validated中的分組類型蕉陋,也可以指定多個捐凭。
(4)校驗的時候,根據(jù)@Validated中指定分組類型寺滚,
柑营,去找校驗對象中的對應(yīng)有此分組類型的約束
,進行校驗村视。
(5)指定分組后官套,不滿足分組的約束
(不加分組的約束為默認分組,也是一種分組)蚁孔,不會進行校驗
6 順序校驗
如不進行順序校驗配置奶赔,校驗對象內(nèi)的屬性,校驗順序是隨機
的杠氢。
有時候想先校驗比較簡單的約束站刑,再校驗復(fù)雜的,因此需要指定約束的校驗順序鼻百〗事茫可以結(jié)合《7 驗證將檢測到第一個約束違例時停止
》一起使用摆尝。
6.1 代碼示例
- 分組類型
// 分組類型:第一個執(zhí)行
public interface FirstCheck {
}
// 分組類型:第二個執(zhí)行
public interface SecondCheck {
}
// 待順序的分組類型組
@GroupSequence({FirstCheck.class, SecondCheck.class})
public interface UserGroupCheck {
}
- 實體定義
@Data
public class User {
@NotNull(message = "用戶代碼不可為空", groups = {FirstCheck.class})
private String userCode;
@NotNull(message = "密碼不可為空", groups = {SecondCheck.class})
private String password;
@NotNull(message = "用戶名不可為空")
private String userName;
}
- mapping方法
@GetMapping("orderCheck")
public JSONObject orderCheck(@Validated(UserGroupCheck.class) User user) {
JSONObject result = new JSONObject();
result.put("success", true);
result.put("message", user.toString());
return result;
}
- 異常處理
同4.1
6.2 代碼測試
-
請求1
- 請求
http://localhost:8080/user/orderCheck
- 結(jié)果
{"success":false,"message":"用戶代碼不可為空"}
-
請求2
- 請求
http://localhost:8080/user/orderCheck?userCode=001
- 結(jié)果
{"success":false,"message":"密碼不可為空"}
請求3
-
- 請求
http://localhost:8080/user/orderCheck?userCode=001&password=123456
- 結(jié)果
{"success":true,"message":"User(userCode=001, password=123456, userName=null)"}
-
特殊請求
-
變更
將實體類進行變更,userName上的約束也加上分組為FirstCheck因悲。此時userCode和userName的約束分組均為FirstCheck堕汞。
如下:
@Data public class User { @NotNull(message = "用戶代碼不可為空", groups = {FirstCheck.class}) private String userCode; @NotNull(message = "密碼不可為空", groups = {SecondCheck.class}) private String password; @NotNull(message = "用戶名不可為空", groups = {FirstCheck.class}) private String userName; }
-
請求
結(jié)果
-
{"success":false,"message":"用戶代碼不可為空,用戶名不可為空"}
或
```json
{"success":false,"message":"用戶名不可為空,用戶代碼不可為空"}
可以看出,當一個分組內(nèi)有多個約束晃琳,約束的校驗順序仍然是隨機的
6.3 總結(jié)
(1)根據(jù)參數(shù)中的分組對應(yīng)的接口中@GroupSequence
指定的分組類型
的順序進行加校驗
(2)只有當一個分組內(nèi)的所有約束都校驗通過后
讯检,才會進入下一個分組
進行校驗。
(3)順序校驗卫旱,指的是@GroupSequence
內(nèi)配置的分組的順序人灼,當一個分組
內(nèi)有多個約束
,這個分組內(nèi)約束
的校驗順序仍然隨機
7 驗證將檢測到第一個約束違例時停止
默認顾翼,有多個約束的情況下
投放,將會對所有參數(shù)進行校驗
,如果存在校驗失敗的約束适贸,返回的校驗結(jié)果(BindingResult或?qū)?yīng)Exception)中會有所有的參數(shù)校驗錯誤信息
跪呈。即如果多個不滿足約束,則返回結(jié)果中會有多個失敗信息
取逾。
有時候耗绿,我們只需要返回第一個
一個校驗失敗的約束信息就好,校驗到一個約束失敗后砾隅,沒有必要再花費代價
進行其他約束校驗误阻。
springBoot中,參數(shù)校驗的實現(xiàn)晴埂,基于MethodValidationPostProcessor
:
@Bean
@ConditionalOnMissingBean
public static MethodValidationPostProcessor methodValidationPostProcessor(Environment environment,
@Lazy Validator validator) {
MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
boolean proxyTargetClass = environment.getProperty("spring.aop.proxy-target-class", Boolean.class, true);
processor.setProxyTargetClass(proxyTargetClass);
processor.setValidator(validator);
return processor;
}
這個postProcessor的校驗配置基于spring中的beanValidator
究反,我們創(chuàng)建自己的Validator的bean,配置failFast
儒洛,即可實現(xiàn)驗證將檢測到第一個約束違例時停止
這個要求精耐。
實現(xiàn)代碼如下:
@Bean
public Validator validator() {
HibernateValidatorConfiguration configuration = Validation.byProvider(HibernateValidator.class).configure();
//驗證將檢測到第一個約束違例時停止
configuration.failFast(true);
ValidatorFactory validatorFactory = configuration.buildValidatorFactory();
return validatorFactory.getValidator();
}
或使用更簡潔的寫法:
@Bean
public Validator validator() {
ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
.configure()
//驗證將檢測到第一個約束違例時停止
.failFast(true)
.buildValidatorFactory();
return validatorFactory.getValidator();
}
failFast
是HibernateValidatorConfiguration
中的一個屬性配置,配置中還有其他配置屬性
琅锻,可以定制我們的校驗器
卦停。
8 自定義校驗器
自定義校驗器,注意點比較多恼蓬,不是本文的重點惊完,暫時不進行記錄,后續(xù)有時間會有專門的文章進行分析处硬。
9 生產(chǎn)環(huán)境配置
前面說的都是原理和使用細節(jié)小槐,這里記錄下生產(chǎn)環(huán)境,需要進行哪些全局配置荷辕。
9.1 全局異常處理
建議使用全局異常處理凿跳,對請求的異常信息進行統(tǒng)一處理件豌。
代碼如下:
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.stream.Collectors;
/**
* 統(tǒng)一異常處理
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 捕捉全局異常:org.springframework.web.bind.MethodArgumentNotValidException
* <div>@RequestBody修飾的參數(shù),校驗失敗控嗜,拋出此異常</div>
* <div>如:xxxAction(@RequestBody @Valid User user)</div>
* @param exception
* @return
*/
@ExceptionHandler({MethodArgumentNotValidException.class})
public JSONObject handleMethodArgumentNotValidException(MethodArgumentNotValidException exception) {
log.info("全局異常[MethodArgumentNotValidException]:" + exception.getMessage());
JSONObject result = new JSONObject();
result.put("success", false);
if (exception != null) {
String message = exception.getBindingResult().getFieldErrors().stream().filter(e -> e != null).map(FieldError::getDefaultMessage).collect(Collectors.joining(","));
result.put("message", message);
}
return result;
}
/**
* 捕捉全局異常:org.springframework.validation.BindException
* <div>普通請求的參數(shù)苟径,校驗失敗,拋出此異常</div>
* <div>如:xxxAction(@Valid User user)</div>
* @param exception
* @return
*/
@ExceptionHandler(BindException.class)
public JSONObject handlerBindException(BindException exception) {
log.info("全局異常[BindException]:" + exception.getMessage());
JSONObject result = new JSONObject();
result.put("success", false);
if (exception != null) {
String message = exception.getBindingResult().getFieldErrors().stream().filter(e -> e != null).map(FieldError::getDefaultMessage).collect(Collectors.joining(","));
result.put("message", message);
}
return result;
}
/**
* 捕捉全局異常:javax.validation.ConstraintViolationException
* <div>直接在參數(shù)上加的校驗躬审,校驗失敗,拋出此異常</div>
* <div>如:xxxAction(@NotNull(message = "用戶代碼不可為空") String userCode)</div>
* <div>如:xxxAction(@PathVariable("userCode") @Length(max = 10,message="用戶代碼不可超過10位") String userCode)</div>
* @param exception
* @return
*/
@ExceptionHandler(ConstraintViolationException.class)
public JSONObject handlerConstraintViolationException(ConstraintViolationException exception) {
log.info("全局異常[ConstraintViolationException]:" + exception.getMessage());
JSONObject result = new JSONObject();
result.put("success", false);
if (exception != null) {
result.put("message", exception.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining(";")));
}
return result;
}
}
參數(shù)校驗失敗蟆盐,返回的錯誤json信息如下承边,可以根據(jù)項目的實際情況進行定制:
{"success":false,"message":"用戶代碼不可超過10位"}
9.2 驗證將檢測到第一個約束違例時停止
import org.hibernate.validator.HibernateValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
@Configuration
public class ValidConfig {
@Bean
public Validator validator() {
ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
.configure()
//驗證將檢測到第一個約束違例時停止
.failFast(true)
.buildValidatorFactory();
return validatorFactory.getValidator();
}
}
10 補充
10.1 校驗限制
@Valid支持嵌套驗證
、@Validated支持分組驗證
石挂、排序驗證
(準確來說博助,排序驗證也是分組驗證的一種)。
故無法實現(xiàn)
:“嵌套驗證+分組驗證
”和“嵌套驗證+排序驗證
”這種組合形式的驗證痹愚。
10.2 建議
雖然JSR303支持自定義校驗器富岳,筆者不建議將太復(fù)雜的校驗交給JSR303的標準進行校驗
。
如果是參數(shù)基本的屬性校驗(是否為空拯腮、長度窖式、大小、枚舉动壤、正則格式)萝喘,可以以這種形式進行校驗。
但是如果是太復(fù)雜的校驗
琼懊,如需要連接數(shù)據(jù)庫進行業(yè)務(wù)判斷的校驗阁簸,筆者仍然建議在具體的業(yè)務(wù)代碼
中進行校驗。
10.2 校驗順序的隨機性
如不使用@Validated指定約束的校驗順序哼丈,所有約束的校驗順序是隨機的启妹,即相同的情況,返回的校驗結(jié)果的順序可能不一樣醉旦。
10.3 一個字段多個約束
同一個字段可以加多個約束注解饶米,并不是只能有一個約束注解。如下:
@NotNull(message = "用戶代碼不可為空")
@Length(min = 5, max = 10, message = "用戶代碼長度需在5~10之間")
private String userCode;
如userCode為空车胡,則拋出異常:用戶代碼不可為空
如userCode不為空咙崎,則校驗約束:用戶代碼長度需在5~10之間