Spring-Validation 后端數(shù)據(jù)校驗(yàn)的實(shí)現(xiàn)
前言
最近看到很多童鞋在項(xiàng)目中的對(duì)請(qǐng)求參數(shù)的校驗(yàn)都用的if來(lái)判斷各參數(shù)的屬性,如:
if(StringUtils.isBlank(username)){ return RR.exception("賬號(hào)不能為空"); } if(StringUtils.isBlank(password)){ return RR.exception("密碼不能為空"); } if(StringUtils.isBlank(realName)){ return RR.exception("姓名不能為空"); } ......
每個(gè)參數(shù)都需要這樣一個(gè)個(gè)去校驗(yàn)null,返回對(duì)應(yīng)信息,代碼就像疊羅漢一樣~~,在此,樓主強(qiáng)烈推薦一個(gè)神器:Validation,有了它,再也不用這樣去校驗(yàn)參數(shù)啦,可以讓我們?cè)陧?xiàng)目中不用太關(guān)注其他東西,專注于業(yè)務(wù)邏輯的編寫。
引入核心依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
使用示例-添加用戶
需要校驗(yàn)的實(shí)體類,在此使用了一些常用的校驗(yàn)注解,基本上能夠見名知意,每個(gè)注解中都有message屬性,就是校驗(yàn)不通過(guò)后的提示信息
@Data @AllArgsConstructor @NoArgsConstructor @ApiModel(value = "Account", description = "用戶實(shí)體類") public class Account implements Serializable { private static final long serialVersionUID = -6310331730721778951L; private Long id; @NotBlank(message = "用戶名不能為空") @Length(max = 10, message = "用戶名最長(zhǎng)為10位") private String name; @Pattern(regexp = PatternUtil.PASSWORDREGEX, message = "密碼為6-20位數(shù)字加字母組合") private String pwd; @NotBlank(message = "姓名不能為空") @Length(max = 8, message = "姓名最長(zhǎng)為8位") private String realName; @Pattern(regexp = PatternUtil.PHONENOREGEX, message = "手機(jī)號(hào)碼格式不正確") private String phone; @NotNull(message = "用戶性別不能為空") @Max(value = 1,message = "性別 0:男 1:女") @Min(value = 0,message = "性別 0:男 1:女") private Integer sex; @NotNull(message = "用戶狀態(tài)不能為空") @Max(value = 1,message = "用戶狀態(tài) 0:啟用 1:禁用") @Min(value = 0,message = "用戶狀態(tài) 0:啟用 1:禁用") private Integer status; @Length(max = 200, message = "備注最長(zhǎng)為200個(gè)字符") private String rmk; }
controller接口,注意在接收參數(shù)前需加上@Validated注解,這樣就會(huì)逐個(gè)去校驗(yàn)實(shí)體類中需要加了校驗(yàn)注解的的屬性,完全通過(guò)才進(jìn)入下一步業(yè)務(wù)處理,否則拋出MethodArgumentNotValidException異常,在這里我們直接將異常拋出,交給全局異常處理類來(lái)處理。
@SysLog(menu = "用戶管理", function = "添加",filterParams = {"pwd","password","salt"}) @PermissionCheck("account:manager:add") @PostMapping(value = "/add", produces = BaseConsts.REQUEST_HEADERS_CONTENT_TYPE) @ApiOperation(value = "用戶管理-添加用戶接口", notes = "用戶管理-添加用戶接口", httpMethod = BaseConsts.REQUEST_METHOD, response = RR.class) public RR add(@Validated @RequestBody Account account) throws Exception { return RR.success("添加用戶成功"); }
聲明全局異常處理類,處理所有異常,可以隨業(yè)務(wù)需要將異常種類細(xì)分,返回錯(cuò)誤碼,返回提示信息可自由定義... 這里只需關(guān)注MethodArgumentNotValidException異常。
@RestControllerAdvice public class GlobalExceptionHandle { /** * @param e * @return * @Description 未知異常處理 */ @ExceptionHandler(Exception.class) public RR handleException(Exception e) { e.printStackTrace(); return RR.exception("系統(tǒng)異常,請(qǐng)聯(lián)系管理員"); } /** * @param e * @return * @Description 請(qǐng)求參數(shù)異常 */ @ExceptionHandler(MethodArgumentNotValidException.class) public RR handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { return RR.exception("請(qǐng)求參數(shù)錯(cuò)誤:[" + e.getBindingResult().getFieldError().getDefaultMessage() + "]"); } /** * @param e * @return * @Description 系統(tǒng)業(yè)務(wù)服務(wù)異常 */ @ExceptionHandler(ServerException.class) public RR handleServerException(ServerException e) { return RR.exception(e.getMessage()); } /** * @param e * @return * @Description 令牌校驗(yàn)異常 */ @ExceptionHandler(ExpireException.class) public RR handleExpireException(ExpireException e) { return RR.expire(e.getMessage()); } /** * @param e * @return * @Description 無(wú)權(quán)訪問(wèn)異常 */ @ExceptionHandler(AccessDeniedException.class) public RR handleAccessDeniedException(AccessDeniedException e) { return RR.forbidden(e.getMessage()); } /** * @param e * @return * @Description 自定義重復(fù)操作異常 */ public RR handleRepeatHandleException(RepeatHandleException e) { return RR.exception("您的請(qǐng)求已發(fā)送,請(qǐng)勿重復(fù)操作!"); } /** * @param e * @return * @Description 登錄異常處理 */ @ExceptionHandler(AuthenticationException.class) public RR handleAuthenticationException(AuthenticationException e) { return RR.exception(e.getMessage()); } }
然后我們用Swagger來(lái)測(cè)試一下接口
1.用戶名為空
2.手機(jī)號(hào)格式錯(cuò)誤
通過(guò)返回結(jié)果可以看到,我們的校驗(yàn)注解已經(jīng)幫我們按照指定的校驗(yàn)方式校驗(yàn)了指定的字段屬性,我們?cè)诮y(tǒng)一的全局異常處理類中將提示信息封裝成需要的返回結(jié)果就可以了。
分組校驗(yàn)
有的童鞋在此可能有疑問(wèn)了,上述方法雖然可行,但我在新增用戶和修改用戶兩個(gè)接口中,新增用戶的用戶id是自動(dòng)生成的,無(wú)需校驗(yàn);修改用戶的用戶id是必傳的,則需校驗(yàn)。在此業(yè)務(wù)場(chǎng)景中,那豈不是需要聲明兩個(gè)實(shí)體類,但這兩個(gè)實(shí)體類中的屬性又大致相同,這不是增加麻煩嗎?其實(shí)不然,在此我們可以用到 groups 屬性來(lái)解決此場(chǎng)景下的問(wèn)題。
聲明分組
注意:在聲明分組的時(shí)候盡量加上 extend javax.validation.groups.Default 否則,在你聲明@Validated(Update.class)的時(shí)候,就會(huì)出現(xiàn)你在默認(rèn)沒添加groups = {}的時(shí)候的校驗(yàn)組@Email(message = "郵箱格式不對(duì)"),會(huì)不去校驗(yàn),因?yàn)槟J(rèn)的校驗(yàn)組是groups = {Default.class}。
/** * 數(shù)據(jù)新增分組 */ public interface Create extends Default { } /** * 數(shù)據(jù)更新分組 */ public interface Update extends Default { }
校驗(yàn)注解中添加分組,groups 為一個(gè)數(shù)組,可以添加多個(gè)分組
@NotNull(message = "id不能為空" , groups = Update.class) private Long id; @NotBlank(message = "用戶名不能為空" , groups = {Create.class, Update.class}) @Length(max = 10, message = "用戶名最長(zhǎng)為10位") private String name;
修改Controller中的@Validated注解,聲明校驗(yàn)分組
@PermissionCheck("account:manager:add") @PostMapping(value = "/add", produces = BaseConsts.REQUEST_HEADERS_CONTENT_TYPE) @ApiOperation(value = "用戶管理-添加用戶接口", notes = "用戶管理-添加用戶接口", httpMethod = BaseConsts.REQUEST_METHOD, response = RR.class) public RR add(@Validated(Create.class) @RequestBody Account account) throws Exception { return RR.success("添加用戶成功"); } @PermissionCheck("account:manager:edit") @PostMapping(value = "/edit", produces = BaseConsts.REQUEST_HEADERS_CONTENT_TYPE) @ApiOperation(value = "用戶管理-修改用戶接口", notes = "用戶管理-修改用戶接口", httpMethod = BaseConsts.REQUEST_METHOD, response = RR.class) public RR edit(@Validated(Update.class) @RequestBody Account account) throws Exception { return RR.success("編輯用戶成功"); }
使用相同的請(qǐng)求參數(shù)測(cè)試一下添加用戶和修改用戶的接口
測(cè)試添加接口
測(cè)試修改接口
通過(guò)接口的返回結(jié)果可以看到,新增用戶的接口并沒有校驗(yàn)id這個(gè)參數(shù)了,而修改用戶的接口中則校驗(yàn)了id不能為空。
常用校驗(yàn)注解
以上就是樓主在項(xiàng)目中使用validation的總結(jié)歸納,下面收集了一些常用注解,紅色的標(biāo)注則是樓主在項(xiàng)目中用的比較多的。
JSR提供的校驗(yàn)注解:
@Null 被注釋的元素必須為 null
@NotNull 被注釋的元素必須不為 null
@AssertTrue 被注釋的元素必須為 true
@AssertFalse 被注釋的元素必須為 false
@Min(value) 被注釋的元素必須是一個(gè)數(shù)字,其值必須大于等于指定的最小值
@Max(value) 被注釋的元素必須是一個(gè)數(shù)字,其值必須小于等于指定的最大值
@DecimalMin(value) 被注釋的元素必須是一個(gè)數(shù)字,其值必須大于等于指定的最小值
@DecimalMax(value) 被注釋的元素必須是一個(gè)數(shù)字,其值必須小于等于指定的最大值
@Size(max=, min=) 被注釋的元素的大小必須在指定的范圍內(nèi)
@Digits (integer, fraction) 被注釋的元素必須是一個(gè)數(shù)字,其值必須在可接受的范圍內(nèi)
@Past 被注釋的元素必須是一個(gè)過(guò)去的日期
@Future 被注釋的元素必須是一個(gè)將來(lái)的日期
@Pattern(regex) 被注釋的元素必須符合指定的正則表達(dá)式
Hibernate Validator提供的校驗(yàn)注解:
@NotBlank() 驗(yàn)證字符串非null且非空格,長(zhǎng)度必須大于0
@Email 被注釋的元素必須是電子郵箱地址
@Length(min=,max=) 被注釋的字符串的大小必須在指定的范圍內(nèi)
@NotEmpty 被注釋的字符串的必須非空
@Range(min=,max=,message=) 被注釋的元素必須在合適的范圍內(nèi)
參考博文: http://www.dbjr.com.cn/article/157604.htm
到此這篇關(guān)于Spring-Validation 后端數(shù)據(jù)校驗(yàn)的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Spring Validation數(shù)據(jù)校驗(yàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot使用Redis實(shí)現(xiàn)分布式緩存
這篇文章主要介紹了SpringBoot redis分布式緩存實(shí)現(xiàn)過(guò)程解析,文中通過(guò)示例代碼解析的非常詳細(xì),感興趣的同學(xué)可以參考閱讀2023-04-04Idea中添加Maven項(xiàng)目支持scala的詳細(xì)步驟
這篇文章主要介紹了Idea中添加Maven項(xiàng)目支持scala,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-03-03springboot實(shí)現(xiàn)maven多模塊和打包部署
本文主要介紹了springboot實(shí)現(xiàn)maven多模塊和打包部署,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04spring?webClient配置及使用簡(jiǎn)單代碼示例
WebClient是Spring框架5.0引入的基于響應(yīng)式編程模型的HTTP客戶端,它提供一種簡(jiǎn)便的方式來(lái)處理HTTP請(qǐng)求和響應(yīng),支持異步和非阻塞式的請(qǐng)求和響應(yīng)處理,下面這篇文章主要給大家介紹了關(guān)于spring?webClient配置及使用的相關(guān)資料,需要的朋友可以參考下2024-03-03Java 中如何使用 JavaFx 庫(kù)標(biāo)注文本顏色
這篇文章主要介紹了在 Java 中用 JavaFx 庫(kù)標(biāo)注文本顏色,在本文中,我們將了解如何更改標(biāo)簽的文本顏色,并且我們還將看到一個(gè)必要的示例和適當(dāng)?shù)慕忉專员愀菀桌斫庠撝黝},需要的朋友可以參考下2023-05-05