一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專(zhuān)注于服務(wù)器技術(shù)及軟件下載分享
分類(lèi)導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|JavaScript|易語(yǔ)言|

服務(wù)器之家 - 編程語(yǔ)言 - Java教程 - Spring Boot參數(shù)校驗(yàn)以及分組校驗(yàn)的使用

Spring Boot參數(shù)校驗(yàn)以及分組校驗(yàn)的使用

2021-08-11 01:31阿里技術(shù) Java教程

做web開(kāi)發(fā)有一點(diǎn)很煩人就是要對(duì)前端輸入?yún)?shù)進(jìn)行校驗(yàn),基本上每個(gè)接口都要對(duì)參數(shù)進(jìn)行校驗(yàn),比如一些非空校驗(yàn)、格式校驗(yàn)等。如果參數(shù)比較少的話還是容易處理的一但參數(shù)比較多了的話代碼中就會(huì)出現(xiàn)大量的if-else語(yǔ)句。

Spring Boot參數(shù)校驗(yàn)以及分組校驗(yàn)的使用

一 前言

做web開(kāi)發(fā)有一點(diǎn)很煩人就是要對(duì)前端輸入?yún)?shù)進(jìn)行校驗(yàn),基本上每個(gè)接口都要對(duì)參數(shù)進(jìn)行校驗(yàn),比如一些非空校驗(yàn)、格式校驗(yàn)等。如果參數(shù)比較少的話還是容易處理的一但參數(shù)比較多了的話代碼中就會(huì)出現(xiàn)大量的if-else語(yǔ)句。

使用這種方式雖然簡(jiǎn)單直接,但是也有不好的地方,一是降低了開(kāi)發(fā)效率,因?yàn)槲覀冃枰r?yàn)的參數(shù)會(huì)存在很多地方,并且不同地方會(huì)有重復(fù)校驗(yàn),其次降低了代碼可讀性,因?yàn)樵跇I(yè)務(wù)代碼中摻雜了太多額外工作的代碼。

所以我們可以使用validator組件來(lái)代替我們進(jìn)行不必要的coding操作。本文基于validator的介紹資料,也結(jié)合自己在項(xiàng)目中的實(shí)際使用經(jīng)驗(yàn)進(jìn)行了總結(jié),希望能幫到大家。

1 什么是validator

Bean Validation是Java定義的一套基于注解的數(shù)據(jù)校驗(yàn)規(guī)范,目前已經(jīng)從JSR 303的1.0版本升級(jí)到JSR 349的1.1版本,再到JSR 380的2.0版本(2.0完成于2017.08),已經(jīng)經(jīng)歷了三個(gè)版本 。需要注意的是,JSR只是一項(xiàng)標(biāo)準(zhǔn),它規(guī)定了一些校驗(yàn)注解的規(guī)范,但沒(méi)有實(shí)現(xiàn),比如@Null、@NotNull、@Pattern等,它們位于 javax.validation.constraints這個(gè)包下。而hibernate validator是對(duì)這個(gè)規(guī)范的實(shí)現(xiàn),并增加了一些其他校驗(yàn)注解,如 @NotBlank、@NotEmpty、@Length等,它們位于org.hibernate.validator.constraints這個(gè)包下。

如果我們的項(xiàng)目使用了Spring Boot,hibernate validator框架已經(jīng)集成在 spring-boot-starter-web中,所以無(wú)需再添加其他依賴(lài)。如果不是Spring Boot項(xiàng)目,需要添加如下依賴(lài)。

  1. <dependency> 
  2.     <groupId>org.hibernate.validator</groupId> 
  3.     <artifactId>hibernate-validator</artifactId> 
  4.     <version>6.0.8.Final</version> 
  5. </dependency> 

二 注解介紹

1 validator內(nèi)置注解

 

 

 

注解 說(shuō)明
@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(value) 被注釋的元素必須符合指定的正則表達(dá)式

hibernate validator中擴(kuò)展定義了如下注解:

注解 說(shuō)明
@NotBlank 被注釋的元素不能為null,且長(zhǎng)度必須大于0,只能用于注解字符串
@Email 被注釋的元素必須是電子郵箱地址
@Length(min=,max=) 被注釋的字符串的大小必須在指定的范圍內(nèi)
@NotEmpty 被注釋的元素值不為null且不為空,支持字符串、集合、Map和數(shù)組類(lèi)型
@Range 被注釋的元素必須在規(guī)定的范圍內(nèi)
 

三 使用

使用起來(lái)比較簡(jiǎn)單,都是使用注解方式使用。具體來(lái)說(shuō)分為單參數(shù)校驗(yàn)、對(duì)象參數(shù)校驗(yàn),單參數(shù)校驗(yàn)就是controller接口按照單參數(shù)接收前端傳值,沒(méi)有封裝對(duì)象進(jìn)行接收,如果有封裝對(duì)象那就是對(duì)象參數(shù)校驗(yàn)。

1 單參數(shù)校驗(yàn)

單參數(shù)校驗(yàn)只需要在參數(shù)前添加注解即可,如下所示:

  1. public Result deleteUser(@NotNull(message = "id不能為空") Long id) { 
  2.   // do something 

但有一點(diǎn)需要注意,如果使用單參數(shù)校驗(yàn),controller類(lèi)上必須添加@Validated注解,如下所示:

  1. @RestController 
  2. @RequestMapping("/user"
  3. @Validated // 單參數(shù)校驗(yàn)需要加的注解 
  4. public class UserController { 
  5.   // do something 

2 對(duì)象參數(shù)校驗(yàn)

對(duì)象參數(shù)校驗(yàn)使用時(shí),需要先在對(duì)象的校驗(yàn)屬性上添加注解,然后在Controller方法的對(duì)象參數(shù)前添加@Validated 注解,如下所示:

  1. public Result addUser(@Validated UserAO userAo) { 
  2.     // do something 
  3.  
  4. public class UserAO { 
  5.   @NotBlank 
  6.   private String name
  7.  
  8.   @NotNull 
  9.   private Integer age; 
  10.    
  11.   …… 

注解分組

在對(duì)象參數(shù)校驗(yàn)場(chǎng)景下,有一種特殊場(chǎng)景,同一個(gè)參數(shù)對(duì)象在不同的場(chǎng)景下有不同的校驗(yàn)規(guī)則。比如,在創(chuàng)建對(duì)象時(shí)不需要傳入id字段(id字段是主鍵,由系統(tǒng)生成,不由用戶指定),但是在修改對(duì)象時(shí)就必須要傳入id字段。在這樣的場(chǎng)景下就需要對(duì)注解進(jìn)行分組。

1)組件有個(gè)默認(rèn)分組Default.class, 所以我們可以再創(chuàng)建一個(gè)分組UpdateAction.class,如下所示:

  1. public interface UpdateAction { 

2)在參數(shù)類(lèi)中需要校驗(yàn)的屬性上,在注解中添加groups屬性:

  1. public class UserAO { 
  2.  
  3.     @NotNull(groups = UpdateAction.class, message = "id不能為空"
  4.     private Long id; 
  5.      
  6.     @NotBlank 
  7.     private String name
  8.  
  9.     @NotNull 
  10.     private Integer age; 
  11.      
  12.     …… 

如上所示,就表示只在UpdateAction分組下校驗(yàn)id字段,在默認(rèn)情況下就會(huì)校驗(yàn)name字段和age字段。

然后在controller的方法中,在@Validated注解里指定哪種場(chǎng)景即可,沒(méi)有指定就代表采用Default.class,采用其他分組就需要顯示指定。如下代碼便表示在addUser()接口中按照默認(rèn)情況進(jìn)行參數(shù)校驗(yàn),在updateUser()接口中按照默認(rèn)情況和UpdateAction分組對(duì)參數(shù)進(jìn)行共同校驗(yàn)。

  1. public Result addUser(@Validated UserAO userAo) { 
  2.   // do something 
  1. public Result updateUser(@Validated({Default.class, UpdateAction.class}) UserAO userAo) { 
  2.   // do something 

對(duì)象嵌套

如果需要校驗(yàn)的參數(shù)對(duì)象中還嵌套有一個(gè)對(duì)象屬性,而該嵌套的對(duì)象屬性也需要校驗(yàn),那么就需要在該對(duì)象屬性上增加@Valid注解。

  1. public class UserAO { 
  2.  
  3.     @NotNull(groups = UpdateAction.class, message = "id不能為空"
  4.     private Long id; 
  5.      
  6.     @NotBlank 
  7.     private String name
  8.  
  9.     @NotNull 
  10.     private Integer age; 
  11.      
  12.     @Valid 
  13.     private Phone phone; 
  14.      
  15.     …… 
  16.  
  17. public class Phone { 
  18.     @NotBlank 
  19.     private String operatorType; 
  20.      
  21.     @NotBlank 
  22.     private String phoneNum; 

3 錯(cuò)誤消息的捕獲

參數(shù)校驗(yàn)失敗后會(huì)拋出異常,我們只需要在全局異常處理類(lèi)中捕獲參數(shù)校驗(yàn)的失敗異常,然后將錯(cuò)誤消息添加到返回值中即可。捕獲異常的方法如下所示,返回值Result是我們系統(tǒng)自定義的返回值類(lèi)。

  1. @RestControllerAdvice(basePackages= {"com.alibaba.dc.controller","com.alibaba.dc.service"}) 
  2. public class GlobalExceptionHandler { 
  3.  
  4.   @ExceptionHandler(value = {Throwable.class}) 
  5.   Result handleException(Throwable e, HttpServletRequest request){ 
  6.     // 異常處理 
  7.         } 

需要注意的是,如果缺少參數(shù)拋出的異常是MissingServletRequestParameterException,單參數(shù)校驗(yàn)失敗后拋出的異常是ConstraintViolationException,get請(qǐng)求的對(duì)象參數(shù)校驗(yàn)失敗后拋出的異常是BindException,post請(qǐng)求的對(duì)象參數(shù)校驗(yàn)失敗后拋出的異常是MethodArgumentNotValidException,不同異常對(duì)象的結(jié)構(gòu)不同,對(duì)異常消息的提取方式也就不同。如下圖所示:

1)MissingServletRequestParameterException

  1. if(e instanceof MissingServletRequestParameterException){ 
  2.     Result result = Result.buildErrorResult(ErrorCodeEnum.PARAM_ILLEGAL); 
  3.     String msg = MessageFormat.format("缺少參數(shù){0}", ((MissingServletRequestParameterException) e).getParameterName()); 
  4.     result.setMessage(msg); 
  5.     return result; 

2)ConstraintViolationException異常

  1. if(e instanceof ConstraintViolationException){ 
  2.   // 單個(gè)參數(shù)校驗(yàn)異常 
  3.   Result result = Result.buildErrorResult(ErrorCodeEnum.PARAM_ILLEGAL); 
  4.   Set<ConstraintViolation<?>> sets = ((ConstraintViolationException) e).getConstraintViolations(); 
  5.   if(CollectionUtils.isNotEmpty(sets)){ 
  6.     StringBuilder sb = new StringBuilder(); 
  7.     sets.forEach(error -> { 
  8.                     if (error instanceof FieldError) { 
  9.                         sb.append(((FieldError)error).getField()).append(":"); 
  10.                     } 
  11.                     sb.append(error.getMessage()).append(";"); 
  12.                 }); 
  13.     String msg = sb.toString(); 
  14.     msg = StringUtils.substring(msg, 0, msg.length() -1); 
  15.     result.setMessage(msg); 
  16.   } 
  17.   return result; 

3)BindException異常

  1. if (e instanceof BindException){ 
  2.       // get請(qǐng)求的對(duì)象參數(shù)校驗(yàn)異常 
  3.       Result result = Result.buildErrorResult(ErrorCodeEnum.PARAM_ILLEGAL); 
  4.       List<ObjectError> errors = ((BindException) e).getBindingResult().getAllErrors(); 
  5.       String msg = getValidExceptionMsg(errors); 
  6.       if (StringUtils.isNotBlank(msg)){ 
  7.         result.setMessage(msg); 
  8.       } 
  9.       return result; 
  1. private String getValidExceptionMsg(List<ObjectError> errors) { 
  2.   if(CollectionUtils.isNotEmpty(errors)){ 
  3.     StringBuilder sb = new StringBuilder(); 
  4.     errors.forEach(error -> { 
  5.                     if (error instanceof FieldError) { 
  6.                        sb.append(((FieldError)error).getField()).append(":"); 
  7.                     } 
  8.                     sb.append(error.getDefaultMessage()).append(";"); 
  9.                 }); 
  10.     String msg = sb.toString(); 
  11.     msg = StringUtils.substring(msg, 0, msg.length() -1); 
  12.     return msg; 
  13.   } 
  14.   return null

4)MethodArgumentNotValidException異常

  1. if (e instanceof MethodArgumentNotValidException){ 
  2.       // post請(qǐng)求的對(duì)象參數(shù)校驗(yàn)異常 
  3.       Result result = Result.buildErrorResult(ErrorCodeEnum.PARAM_ILLEGAL); 
  4.       List<ObjectError> errors = ((MethodArgumentNotValidException) e).getBindingResult().getAllErrors(); 
  5.       String msg = getValidExceptionMsg(errors); 
  6.       if (StringUtils.isNotBlank(msg)){ 
  7.         result.setMessage(msg); 
  8.       } 
  9.       return result; 

【本文為51CTO專(zhuān)欄作者“阿里巴巴官方技術(shù)”原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)聯(lián)系原作者】

原文地址:https://zhuanlan.51cto.com/art/202108/677315.htm

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 亚洲不卡视频 | 午夜人妻理论片天堂影院 | 忘忧草研究院一二三 | 国产欧美亚洲精品第一页青草 | 青春草视频在线免费观看 | 把内裤拔到一边高h1v1 | 亚洲激情 欧美 | 欧美kkk4444在线观看 | 欧美黑人成人免费全部 | 韩国男女做性全过程视频 | 欧美日韩国产在线人成 | 初尝黑人巨大h文 | 国产最新精品视频 | 国产欧美视频高清va在线观看 | aa一级护士医生毛片 | 国产haodiaose最新 | 欧美日韩国产在线一区 | 99re热这里只有精品视频 | 无码国产成人午夜在线观看不卡 | 欧美三级不卡视频 | 亚洲高清色图 | 91九色丨porny丨制服 | 亚洲国产成人超福利久久精品 | 国产一区二区三区在线看片 | 朝鲜女人free性hu | 欧美精品久久一区二区三区 | 亚洲AV久久无码精品九号 | 色女的乖男人 | 国产精品玖玖玖影院 | 四虎影视入口 | 精品日韩二区三区精品视频 | 美女脱了内裤打开腿让你桶爽 | 亚偷熟乱区视频在线观看 | 亚洲国产货青视觉盛宴 | 数学老师扒开腿让我爽快 | 久久久精品国产免费A片胖妇女 | 欧美精品99久久久久久人 | 亚洲国产精品综合久久一线 | 国产精品久久久久久网站 | 成人久久久 | 国产日韩一区二区三区 |