日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

SpringBoot 如何进行参数校验,老鸟们都这么玩的!

發布時間:2023/12/15 javascript 66 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SpringBoot 如何进行参数校验,老鸟们都这么玩的! 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

大家好,我是飄渺。

前幾天寫了一篇 SpringBoot如何統一后端返回格式?老鳥們都是這樣玩的! 閱讀效果還不錯,而且被很多號主都轉載過,今天我們繼續第二篇,來聊聊在SprinBoot中如何集成參數校驗Validator,以及參數校驗的高階技巧(自定義校驗,分組校驗)。

此文是依賴于前文的代碼基礎,已經在項目中加入了全局異常校驗器。(代碼倉庫在文末)

首先我們來看看什么是Validator參數校驗器,為什么需要參數校驗?

為什么需要參數校驗

在日常的接口開發中,為了防止非法參數對業務造成影響,經常需要對接口的參數做校驗,例如登錄的時候需要校驗用戶名密碼是否為空,創建用戶的時候需要校驗郵件、手機號碼格式是否準確。靠代碼對接口參數一個個校驗的話就太繁瑣了,代碼可讀性極差。

Validator框架就是為了解決開發人員在開發的時候少寫代碼,提升開發效率;Validator專門用來進行接口參數校驗,例如常見的必填校驗,email格式校驗,用戶名必須位于6到12之間 等等…

Validator校驗框架遵循了JSR-303驗證規范(參數校驗規范), JSR是 Java Specification Requests的縮寫。

接下來我們看看在SpringbBoot中如何集成參數校驗框架。

SpringBoot中集成參數校驗

第一步,引入依賴

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId> </dependency>

注:從 springboot-2.3開始,校驗包被獨立成了一個 starter組件,所以需要引入validation和web,而 springboot-2.3之前的版本只需要引入 web 依賴就可以了。

第二步,定義要參數校驗的實體類

@Data public class ValidVO {private String id;@Length(min = 6,max = 12,message = "appId長度必須位于6到12之間")private String appId;@NotBlank(message = "名字為必填項")private String name;@Email(message = "請填寫正確的郵箱地址")private String email;private String sex;@NotEmpty(message = "級別不能為空")private String level; }

在實際開發中對于需要校驗的字段都需要設置對應的業務提示,即message屬性。

常見的約束注解如下:

注解功能
@AssertFalse可以為null,如果不為null的話必須為false
@AssertTrue可以為null,如果不為null的話必須為true
@DecimalMax設置不能超過最大值
@DecimalMin設置不能超過最小值
@Digits設置必須是數字且數字整數的位數和小數的位數必須在指定范圍內
@Future日期必須在當前日期的未來
@Past日期必須在當前日期的過去
@Max最大不得超過此最大值
@Min最大不得小于此最小值
@NotNull不能為null,可以是空
@Null必須為null
@Pattern必須滿足指定的正則表達式
@Size集合、數組、map等的size()值必須在指定范圍內
@Email必須是email格式
@Length長度必須在指定范圍內
@NotBlank字符串不能為null,字符串trim()后也不能等于“”
@NotEmpty不能為null,集合、數組、map等size()不能為0;字符串trim()后可以等于“”
@Range值必須在指定范圍內
@URL必須是一個URL

注:此表格只是簡單的對注解功能的說明,并沒有對每一個注解的屬性進行說明;可詳見源碼。

第三步,定義校驗類進行測試

@RestController @Slf4j @Validated public class ValidController {@ApiOperation("RequestBody校驗")@PostMapping("/valid/test1") public String test1(@Validated @RequestBody ValidVO validVO){log.info("validEntity is {}", validVO);return "test1 valid success";}@ApiOperation("Form校驗")@PostMapping(value = "/valid/test2")public String test2(@Validated ValidVO validVO){log.info("validEntity is {}", validVO);return "test2 valid success";}@ApiOperation("單參數校驗")@PostMapping(value = "/valid/test3")public String test3(@Email String email){log.info("email is {}", email);return "email valid success";} }

這里我們先定義三個方法test1,test2,test3,test1使用了 @RequestBody注解,用于接受前端發送的json數據,test2模擬表單提交,test3模擬單參數提交。注意,當使用單參數校驗時需要在Controller上加上@Validated注解,否則不生效

第四步,體驗效果

  • 調用test1方法,提示的是org.springframework.web.bind.MethodArgumentNotValidException異常
  • POST http://localhost:8080/valid/test1 Content-Type: application/json{"id": 1,"level": "12","email": "47693899","appId": "ab1c" } {"status": 500,"message": "Validation failed for argument [0] in public java.lang.String com.jianzh5.blog.valid.ValidController.test1(com.jianzh5.blog.valid.ValidVO) with 3 errors: [Field error in object 'validVO' on field 'email': rejected value [47693899]; codes [Email.validVO.email,Email.email,Email.java.lang.String,Email]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [validVO.email,email]; arguments []; default message [email],[Ljavax.validation.constraints.Pattern$Flag;@26139123,.*]; default message [不是一個合法的電子郵件地址]]...","data": null,"timestamp": 1628239624332 }
  • 調用test2方法,提示的是org.springframework.validation.BindException異常
  • POST http://localhost:8080/valid/test2 Content-Type: application/x-www-form-urlencodedid=1&level=12&email=476938977&appId=ab1c {"status": 500,"message": "org.springframework.validation.BeanPropertyBindingResult: 3 errors\nField error in object 'validVO' on field 'name': rejected value [null]; codes [NotBlank.validVO.name,NotBlank.name,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [validVO.name,name]; arguments []; default message [name]]; default message [名字為必填項]...","data": null,"timestamp": 1628239301951 }
  • 調用test3方法,提示的是javax.validation.ConstraintViolationException異常
  • POST http://localhost:8080/valid/test3 Content-Type: application/x-www-form-urlencodedemail=476938977 {"status": 500,"message": "test3.email: 不是一個合法的電子郵件地址","data": null,"timestamp": 1628239281022 }

    通過加入 Validator校驗框架可以幫助我們自動實現參數的校驗。

    參數異常加入全局異常處理器

    雖然我們之前定義了全局異常攔截器,也看到了攔截器確實生效了,但是 Validator校驗框架返回的錯誤提示太臃腫了,不便于閱讀,為了方便前端提示,我們需要將其簡化一下。

    直接修改之前定義的 RestExceptionHandler,單獨攔截參數校驗的三個異常:javax.validation.ConstraintViolationException,org.springframework.validation.BindException,org.springframework.web.bind.MethodArgumentNotValidException,代碼如下:

    @ExceptionHandler(value = {BindException.class, ValidationException.class, MethodArgumentNotValidException.class}) public ResponseEntity<ResultData<String>> handleValidatedException(Exception e) {ResultData<String> resp = null;if (e instanceof MethodArgumentNotValidException) {// BeanValidation exceptionMethodArgumentNotValidException ex = (MethodArgumentNotValidException) e;resp = ResultData.fail(HttpStatus.BAD_REQUEST.value(),ex.getBindingResult().getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining("; ")));} else if (e instanceof ConstraintViolationException) {// BeanValidation GET simple paramConstraintViolationException ex = (ConstraintViolationException) e;resp = ResultData.fail(HttpStatus.BAD_REQUEST.value(),ex.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining("; ")));} else if (e instanceof BindException) {// BeanValidation GET object paramBindException ex = (BindException) e;resp = ResultData.fail(HttpStatus.BAD_REQUEST.value(),ex.getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining("; ")));}return new ResponseEntity<>(resp,HttpStatus.BAD_REQUEST); }

    體驗效果

    POST http://localhost:8080/valid/test1 Content-Type: application/json{"id": 1,"level": "12","email": "47693899","appId": "ab1c" } {"status": 400,"message": "名字為必填項; 不是一個合法的電子郵件地址; appId長度必須位于6到12之間","data": null,"timestamp": 1628435116680 }

    是不是感覺清爽多了?

    自定義參數校驗

    雖然Spring Validation 提供的注解基本上夠用,但是面對復雜的定義,我們還是需要自己定義相關注解來實現自動校驗。

    比如上面實體類中的sex性別屬性,只允許前端傳遞傳 M,F 這2個枚舉值,如何實現呢?

    第一步,創建自定義注解

    @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE}) @Retention(RUNTIME) @Repeatable(EnumString.List.class) @Documented @Constraint(validatedBy = EnumStringValidator.class)//標明由哪個類執行校驗邏輯 public @interface EnumString {String message() default "value not in enum values.";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};/*** @return date must in this value array*/String[] value();/*** Defines several {@link EnumString} annotations on the same element.** @see EnumString*/@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})@Retention(RUNTIME)@Documented@interface List {EnumString[] value();} }

    第二步,自定義校驗邏輯

    public class EnumStringValidator implements ConstraintValidator<EnumString, String> {private List<String> enumStringList;@Overridepublic void initialize(EnumString constraintAnnotation) {enumStringList = Arrays.asList(constraintAnnotation.value());}@Overridepublic boolean isValid(String value, ConstraintValidatorContext context) {if(value == null){return true;}return enumStringList.contains(value);} }

    第三步,在字段上增加注解

    @ApiModelProperty(value = "性別") @EnumString(value = {"F","M"}, message="性別只允許為F或M") private String sex;

    第四步,體驗效果

    POST http://localhost:8080/valid/test2 Content-Type: application/x-www-form-urlencodedid=1&name=javadaily&level=12&email=476938977@qq.com&appId=ab1cdddd&sex=N {"status": 400,"message": "性別只允許為F或M","data": null,"timestamp": 1628435243723 }

    分組校驗

    一個VO對象在新增的時候某些字段為必填,在更新的時候又非必填。如上面的 ValidVO中 id 和 appId 屬性在新增操作時都是非必填,而在編輯操作時都為必填,name在新增操作時為必填,面對這種場景你會怎么處理呢?

    在實際開發中我見到很多同學都是建立兩個VO對象,ValidCreateVO,ValidEditVO來處理這種場景,這樣確實也能實現效果,但是會造成類膨脹,而且極其容易被開發老鳥們嘲笑。

    其實 Validator校驗框架已經考慮到了這種場景并且提供了解決方案,就是分組校驗,只不過很多同學不知道而已。要使用分組校驗,只需要三個步驟:

    第一步:定義分組接口

    public interface ValidGroup extends Default {interface Crud extends ValidGroup{interface Create extends Crud{}interface Update extends Crud{}interface Query extends Crud{}interface Delete extends Crud{}} }

    這里我們定義一個分組接口ValidGroup讓其繼承 javax.validation.groups.Default,再在分組接口中定義出多個不同的操作類型,Create,Update,Query,Delete。至于為什么需要繼承Default我們稍后再說。

    第二步,在模型中給參數分配分組

    @Data @ApiModel(value = "參數校驗類") public class ValidVO {@ApiModelProperty("ID")@Null(groups = ValidGroup.Crud.Create.class)@NotNull(groups = ValidGroup.Crud.Update.class, message = "應用ID不能為空")private String id;@Null(groups = ValidGroup.Crud.Create.class)@NotNull(groups = ValidGroup.Crud.Update.class, message = "應用ID不能為空")@ApiModelProperty(value = "應用ID",example = "cloud")private String appId;@ApiModelProperty(value = "名字")@NotBlank(groups = ValidGroup.Crud.Create.class,message = "名字為必填項")private String name;@ApiModelProperty(value = "郵箱")@Email(message = "請填寫正取的郵箱地址")privte String email;...}

    給參數指定分組,對于未指定分組的則使用的是默認分組。

    第三步,給需要參數校驗的方法指定分組

    @RestController @Api("參數校驗") @Slf4j @Validated public class ValidController {@ApiOperation("新增")@PostMapping(value = "/valid/add")public String add(@Validated(value = ValidGroup.Crud.Create.class) ValidVO validVO){log.info("validEntity is {}", validVO);return "test3 valid success";}@ApiOperation("更新")@PostMapping(value = "/valid/update")public String update(@Validated(value = ValidGroup.Crud.Update.class) ValidVO validVO){log.info("validEntity is {}", validVO);return "test4 valid success";} }

    這里我們通過 value屬性給 add()和 update()方法分別指定Create和Update分組。

    第四步,體驗效果

    POST http://localhost:8080/valid/add Content-Type: application/x-www-form-urlencodedname=javadaily&level=12&email=476938977@qq.com&sex=F

    在Create時我們沒有傳遞id和appId參數,校驗通過。

    當我們使用同樣的參數調用update方法時則提示參數校驗錯誤。

    {"status": 400,"message": "ID不能為空; 應用ID不能為空","data": null,"timestamp": 1628492514313 }

    由于email屬于默認分組,而我們的分組接口 ValidGroup已經繼承了 Default分組,所以也是可以對email字段作參數校驗的。如:

    POST http://localhost:8080/valid/add Content-Type: application/x-www-form-urlencodedname=javadaily&level=12&email=476938977&sex=F {"status": 400,"message": "請填寫正取的郵箱地址","data": null,"timestamp": 1628492637305 }

    當然如果你的ValidGroup沒有繼承Default分組,那在代碼屬性上就需要加上 @Validated(value = {ValidGroup.Crud.Create.class, Default.class}才能讓 email字段的校驗生效。

    小結

    參數校驗在實際開發中使用頻率非常高,但是很多同學還只是停留在簡單的使用上,像分組校驗,自定義參數校驗這2個高階技巧基本沒怎么用過,經常出現譬如建立多個VO用于接受Create,Update場景的情況,很容易被老鳥被所鄙視嘲笑,希望大家好好掌握。

    最后,我是飄渺Jam,一名寫代碼的架構師,做架構的程序員,期待您的轉發與關注,當然也可以添加我的個人微信 jianzh5,咱們一起聊技術!

    github地址:https://github.com/jianzh5/cloud-blog/

    總結

    以上是生活随笔為你收集整理的SpringBoot 如何进行参数校验,老鸟们都这么玩的!的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。