SpringMVC使用hibernate-validator進(jìn)行參數(shù)校驗(yàn)最佳實(shí)踐記錄
在我們用Controller接收參數(shù)后,往往需要對(duì)參數(shù)進(jìn)行校驗(yàn)。如果我們手寫校驗(yàn)的話,就會(huì)有一堆的判空代碼,看起來很不優(yōu)雅,寫起來也費(fèi)時(shí)費(fèi)力。下面來看下通過hibernate-validator來進(jìn)行優(yōu)雅的參數(shù)校驗(yàn)。
首先需要引入依賴:
<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.2.0.Final</version> </dependency>
hibernate-validator注解
hibernate-validator提供了很多注解來讓我們進(jìn)行參數(shù)校驗(yàn):
常用的校驗(yàn)注解如下表所示:
注解 | 說明 |
---|---|
@Null | 被注釋的元素必須為null |
@AssertTrue | 被注釋的元素必須為true |
@AssertFalse | 被注釋的元素必須為false |
@DecimalMin(value=,message=) | 被注釋的元素必須是一個(gè)數(shù)字,其值必須大于等于指定的最小值 |
@DecimalMax(value=,message=) | 被注釋的元素必須是一個(gè)數(shù)字,其值必須小于等于指定的最大值 |
@Digits (integer, fraction) | 被注釋的元素必須是一個(gè)數(shù)字,其值必須在可接受的范圍內(nèi) |
@Past | 被注釋的元素必須是一個(gè)過去的日期 |
@Future | 被注釋的元素必須是一個(gè)將來的日期 |
被注釋的元素必須是電子郵箱地址 |
主要區(qū)分下@NotNull、@NotEmpty、@NotBlank 3個(gè)注解的區(qū)別:
(1)@NotNull:任何對(duì)象的value不能為null。
(2)@NotEmpty:集合對(duì)象的元素不為0,即集合不為空,也可以用于字符串不為null。
(3)@NotBlank:只能用于字符串不為null,并且字符串trim()以后length要大于0。
需要注意如下幾點(diǎn):
(1)除了@Empty要求字符串不能全是空格,其他的字符串校驗(yàn)都是允許空格的。
(2)message是可以引用常量的,但是如@Size里max不允許引用對(duì)象常量,基本類型常量是可以的。message是錯(cuò)誤提示信息,是可以返回給前臺(tái)的。
(3)大部分規(guī)則校驗(yàn)都是允許參數(shù)為null,即當(dāng)不存在這個(gè)值時(shí),就不進(jìn)行校驗(yàn)了。
不太常用的校驗(yàn)注解如下表所示:
注解 | 說明 |
---|---|
@Null | 被注釋的元素必須為null |
@AssertTrue | 被注釋的元素必須為true |
@AssertFalse | 被注釋的元素必須為false |
@DecimalMin(value=,message=) | 被注釋的元素必須是一個(gè)數(shù)字,其值必須大于等于指定的最小值 |
@DecimalMax(value=,message=) | 被注釋的元素必須是一個(gè)數(shù)字,其值必須小于等于指定的最大值 |
@Digits (integer, fraction) | 被注釋的元素必須是一個(gè)數(shù)字,其值必須在可接受的范圍內(nèi) |
@Past | 被注釋的元素必須是一個(gè)過去的日期 |
@Future | 被注釋的元素必須是一個(gè)將來的日期 |
被注釋的元素必須是電子郵箱地址 |
代碼實(shí)戰(zhàn)
1.、使用BindingResult獲取檢驗(yàn)結(jié)果
我們可以使用BindingResult獲取檢驗(yàn)結(jié)果,構(gòu)造友好的返回信息
Controller中的代碼如下:
@Api(tags = "校驗(yàn)框架") @RestController @RequestMapping("/validate") public class ValidatedController { @ApiOperation(value = "bindValidate") @PostMapping("bindValidate") public ValidatedVO bindValidate(@RequestBody @Validated(value= {ValidatedGroup.DELET.class}) ValidatedVO validatedVO, BindingResult result) { if (result.hasErrors()) { StringBuilder message = new StringBuilder("參數(shù)校驗(yàn)失敗:"); List<ObjectError> errors = result.getAllErrors(); for (ObjectError error : errors) { message.append(error.getDefaultMessage()).append("."); } throw HttpError.error(111, message.toString()); } return validatedVO; } }
我們用以下實(shí)體類來作為Controller的參數(shù)接收實(shí)體
import lombok.Data; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; @Data public class ValidatedVO { //更新、刪除時(shí)不能為空 @NotNull(message = "id不能為空", groups = {ValidatedGroup.UPDATE.class, ValidatedGroup.DELET.class}) private Long id; //新增、更新時(shí)不能為空 @NotBlank(message = "name不能為空", groups = {ValidatedGroup.CREATE.class ,ValidatedGroup.UPDATE.class}) private String name; //查詢時(shí)不能為空 @NotBlank(message = "queryParam不能為空", groups = {ValidatedGroup.QUERY.class}) private String queryParam; }
分組的類:
public class ValidatedGroup { public interface CREATE{} public interface DELET{} public interface UPDATE{} public interface QUERY{} }
需要注意的是,@Validated支持分組校驗(yàn),即校驗(yàn)注解中的groups屬性。這個(gè)為我們的校驗(yàn)也提供了便利。我們可以在Controller需要校驗(yàn)的參數(shù)前用@Validated的value屬性來表示需要校驗(yàn)的分組,那么就會(huì)只會(huì)校驗(yàn)實(shí)體對(duì)象中擁有相同的分組的屬性。這樣我們就可以只用一個(gè)實(shí)體滿足不同的場景了。
啟動(dòng)項(xiàng)目后,我們?cè)趕wagger上請(qǐng)求,傳遞空的json字符串【{}】,返回結(jié)果:
{
"code": 111,
"message": "參數(shù)校驗(yàn)失?。篿d不能為空."
}
然而每次都需要在請(qǐng)求進(jìn)來時(shí)用BindingResult做處理,很不優(yōu)雅。
2.通過@RestControllerAdvice統(tǒng)一處理參數(shù)校驗(yàn)信息
如果我們不用BindingResult獲取校驗(yàn)結(jié)果,即不做處理,框架就會(huì)拋出異常,響應(yīng)400碼,返回一些不友好的錯(cuò)誤信息。即用如下代碼:
@ApiOperation(value = "bindValidate") @PostMapping("bindValidate") public ValidatedVO bindValidate(@RequestBody @Validated(value= {ValidatedGroup.DELET.class}) ValidatedVO validatedVO/*, BindingResult result*/) { /*if (result.hasErrors()) { StringBuilder message = new StringBuilder("參數(shù)校驗(yàn)失?。?); List<ObjectError> errors = result.getAllErrors(); for (ObjectError error : errors) { message.append(error.getDefaultMessage()).append("."); } throw HttpError.error(111, message.toString()); }*/ return validatedVO; }
那么我們就可以使用@RestControllerAdvice來對(duì)異常進(jìn)行處理,進(jìn)行友好信息的提示
如果對(duì)@RestControllerAdvice和@ControllerAdvice不了解的,可以去查詢學(xué)習(xí),這里不進(jìn)行講述
@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public CommonErrorVO handle(Exception e){ if (e instanceof HttpError) { HttpError error = (HttpError)e; return CommonErrorVO.builder().code(error.getCode()).message(error.getMessage()).build(); } else if (e instanceof MethodArgumentNotValidException) { MethodArgumentNotValidException validException = (MethodArgumentNotValidException) e; StringBuilder message = new StringBuilder(""); validException.getBindingResult().getAllErrors().forEach(err -> { message.append(err.getDefaultMessage()).append("."); }); return CommonErrorVO.builder().code(888).message(message.toString()).build(); } else { return CommonErrorVO.builder().code(999).message(e.getMessage()).build(); } } }
MethodArgumentNotValidException異常即為hibernate-validator校驗(yàn)不通過拋出的異常信息,我們從其中獲取到校驗(yàn)失敗的信息來進(jìn)行組裝。
如上,我們通過@Validated配合@RestControllerAdvice完成了優(yōu)雅的參數(shù)校驗(yàn)。
為了體現(xiàn)分組校驗(yàn)的便利性,我做了如下的測試,如果每個(gè)請(qǐng)求參數(shù)都是空的json字符串【{}】的話,那么返回的信息如下。
@Api(tags = "校驗(yàn)框架") @RestController @RequestMapping("/validate") public class ValidatedController { /** * @Validated注解表示開啟Spring的校驗(yàn)機(jī)制,支持分組校驗(yàn),聲明在入?yún)⑸稀? * @param validatedVO * @return */ @ApiOperation(value = "分組校驗(yàn):QUERY參數(shù)校驗(yàn)")//返回 【queryParam不能為空】 @PostMapping("queryValidate") public ValidatedVO queryValidate(@RequestBody @Validated(value= {ValidatedGroup.QUERY.class}) ValidatedVO validatedVO) { return validatedVO; } @ApiOperation(value = "分組校驗(yàn):CREATE參數(shù)校驗(yàn)")// 返回 【name不能為空】 @PostMapping("createValidate") public ValidatedVO createValidate(@RequestBody @Validated(value= {ValidatedGroup.CREATE.class}) ValidatedVO validatedVO) { return validatedVO; } @ApiOperation(value = "分組校驗(yàn):UPDATE參數(shù)校驗(yàn)") // 返回【id不能為空.name不能為空.】 @PostMapping("updateValidate") public ValidatedVO updateValidate(@RequestBody @Validated(value= {ValidatedGroup.UPDATE.class}) ValidatedVO validatedVO) { return validatedVO; } @ApiOperation(value = "分組校驗(yàn):DELETE參數(shù)校驗(yàn)") //返回 【id不能為空】 @PostMapping("deleteValidate") public ValidatedVO deleteValidate(@RequestBody @Validated(value= {ValidatedGroup.DELET.class}) ValidatedVO validatedVO) { return validatedVO; } }
到此這篇關(guān)于SpringMVC使用hibernate-validator進(jìn)行參數(shù)校驗(yàn)最佳實(shí)踐記錄的文章就介紹到這了,更多相關(guān)SpringMVC參數(shù)校驗(yàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot快速通關(guān)自動(dòng)配置應(yīng)用
在進(jìn)行項(xiàng)目編寫前,我們還需要知道一個(gè)東西,就是SpringBoot對(duì)我們的SpringMVC還做了哪些配置,包括如何擴(kuò)展,如何定制,只有把這些都搞清楚了,我們?cè)谥笫褂貌艜?huì)更加得心應(yīng)手2022-07-07java中CompletableFuture異步執(zhí)行方法
本文主要介紹了java中CompletableFuture異步執(zhí)行方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06LinkedList學(xué)習(xí)示例模擬堆棧與隊(duì)列數(shù)據(jù)結(jié)構(gòu)
這篇文章主要介紹了LinkedList學(xué)習(xí)示例,模擬一個(gè)堆棧與隊(duì)列數(shù)據(jù)結(jié)構(gòu),大家參考使用吧2014-01-01Spring Boot 實(shí)現(xiàn)程序的優(yōu)雅退出(詳細(xì)步驟)
Spring Boot 為我們提供了優(yōu)雅退出的功能,使應(yīng)用程序能夠在關(guān)閉時(shí)正常處理完所有當(dāng)前請(qǐng)求,避免請(qǐng)求被中斷導(dǎo)致數(shù)據(jù)丟失或不一致等問題,本文將全面介紹如何在 Spring Boot 應(yīng)用程序中實(shí)現(xiàn)優(yōu)雅退出,感興趣的朋友跟隨小編一起看看吧2024-03-03Spring Security實(shí)現(xiàn)登錄認(rèn)證實(shí)戰(zhàn)教程
這篇文章主要介紹了Spring Security實(shí)現(xiàn)登錄認(rèn)證實(shí)戰(zhàn)教程,本文通過示例代碼給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧2024-06-06Java的MyBatis框架中Mapper映射配置的使用及原理解析
Mapper用于映射SQL語句,可以說是MyBatis操作數(shù)據(jù)庫的核心特性之一,這里我們來討論Java的MyBatis框架中Mapper映射配置的使用及原理解析,包括對(duì)mapper的xml配置文件的讀取流程解讀.2016-06-06eclipse/intellij idea 查看java源碼和注釋方法
下面小編就為大家?guī)硪黄猠clipse/intellij idea 查看java源碼和注釋方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-05-05