springboot 參數校驗詳解


https://www.jianshu.com/p/89a675b7c900

在日常開發寫rest接口時,接口參數校驗這一部分是必須的,但是如果全部用代碼去做,顯得十分麻煩,spring也提供了這部分功能,本文來探究一下如何實現

1.配置

spring-boot-starter-web包自動依賴hibernate-validator,不用再重復引入,直接開搞

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.3.1.Final</version> </dependency> 

聲明一個bean注冊到spring容器,這個bean是一個容器后處理器,會把校驗的邏輯通過AOP織入有@Validated注解的class,具體可以看這個類的源碼

這一步在springboot其實也不用做,ValidationAutoConfiguration這個配置類自動幫我們做了

 @Bean public MethodValidationPostProcessor methodValidationPostProcessor(){ return new MethodValidationPostProcessor(); } 

驗證不通過會產生異常,因為我們項目提供rest接口,所以通過全局捕獲異常,然后轉換為json給前台


@ControllerAdvice public class GlobalExceptionHandler { /** * 用來處理bean validation異常 * @param ex * @return */ @ExceptionHandler(ConstraintViolationException.class) @ResponseBody public WebResult resolveConstraintViolationException(ConstraintViolationException ex){ WebResult errorWebResult = new WebResult(WebResult.FAILED); Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations(); if(!CollectionUtils.isEmpty(constraintViolations)){ StringBuilder msgBuilder = new StringBuilder(); for(ConstraintViolation constraintViolation :constraintViolations){ msgBuilder.append(constraintViolation.getMessage()).append(","); } String errorMessage = msgBuilder.toString(); if(errorMessage.length()>1){ errorMessage = errorMessage.substring(0,errorMessage.length()-1); } errorWebResult.setInfo(errorMessage); return errorWebResult; } errorWebResult.setInfo(ex.getMessage()); return errorWebResult; } @ExceptionHandler(MethodArgumentNotValidException.class) @ResponseBody public WebResult resolveMethodArgumentNotValidException(MethodArgumentNotValidException ex){ WebResult errorWebResult = new WebResult(WebResult.FAILED); List<ObjectError> objectErrors = ex.getBindingResult().getAllErrors(); if(!CollectionUtils.isEmpty(objectErrors)) { StringBuilder msgBuilder = new StringBuilder(); for (ObjectError objectError : objectErrors) { msgBuilder.append(objectError.getDefaultMessage()).append(","); } String errorMessage = msgBuilder.toString(); if (errorMessage.length() > 1) { errorMessage = errorMessage.substring(0, errorMessage.length() - 1); } errorWebResult.setInfo(errorMessage); return errorWebResult; } errorWebResult.setInfo(ex.getMessage()); return errorWebResult; } } 

這兩個異常分別對應校驗的兩種使用方式

  1. 在方法里面校驗
  2. 在bean對象里面校驗
    經過測試,以上兩種形式的數據驗證不僅僅對controller層有用,在service層也行,只要這個類在spring ioc容器里面

2.使用

2.1常用校驗注解

@AssertFalse 校驗false @AssertTrue 校驗true @DecimalMax(value=,inclusive=) 小於等於value, inclusive=true,是小於等於 @DecimalMin(value=,inclusive=) 與上類似 @Max(value=) 小於等於value @Min(value=) 大於等於value @NotNull 檢查Null @Past 檢查日期 @Pattern(regex=,flag=) 正則 @Size(min=, max=) 字符串,集合,map限制大小 @Valid 對po實體類進行校驗 

這篇文章介紹的注解更全一點

2.2在方法參數上使用

@Controller
@Validated
public class ValidationController { @GetMapping("/validate1") @ResponseBody public String validate1( @Size(min = 1,max = 10,message = "姓名長度必須為1到10")@RequestParam("name") String name, @Min(value = 10,message = "年齡最小為10")@Max(value = 100,message = "年齡最大為100") @RequestParam("age") Integer age, @Future @RequestParam("birth")@DateTimeFormat(pattern = "yyyy-MM-dd hh:mm:ss") Date birth){ return "validate1"; } } 

注意類名需要加注解@Validated
校驗失敗會拋出ConstraintViolationException異常
然后我們在全局異常捕獲類捕獲這個異常,返回給前台對應的錯誤json

2.3在bean內屬性上使用

給model類增加校驗注解

public class User { @Size(min = 1,max = 10,message = "姓名長度必須為1到10") private String name; @NotEmpty private String firstName; @Min(value = 10,message = "年齡最小為10")@Max(value = 100,message = "年齡最大為100") private Integer age; @Future @JSONField(format="yyyy-MM-dd HH:mm:ss") private Date birth; ...getter setter } 

在controller對應User實體前增加@Valid注解

@PostMapping("/validate2") @ResponseBody public User validate2(@Valid @RequestBody User user){ return user; } 

3.擴展

除了默認提供的校驗注解外,我們可以定義自己的校驗注解

3.1.創建約束注解類

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER }) @Retention(RUNTIME) @Documented @Constraint(validatedBy = { HandsomeBoyValidator.class}) public @interface HandsomeBoy { String message() default "盛超傑最帥"; String name(); Class<?>[] groups() default { }; Class<? extends Payload>[] payload() default {}; } 

注意:message用於顯示錯誤信息這個字段是必須的,groups和payload也是必須的
@Constraint(validatedBy = { HandsomeBoyValidator.class})用來指定處理這個注解邏輯的類

一開始寫了這個自定義注解和驗證類,發現沒有生效,最后發現是@Constraint這個注解里的類沒有配置,還跟了很多源碼,蛋疼,總的來講,這個配置還是挺方便的

外國人寫的一篇博客,介紹自定義驗證配置,挺全的

3.2.創建驗證器類

public class HandsomeBoyValidator implements ConstraintValidator<HandsomeBoy, User> { private String name; /** * 用於初始化注解上的值到這個validator * @param constraintAnnotation */ @Override public void initialize(HandsomeBoy constraintAnnotation) { name =constraintAnnotation.name(); } /** * 具體的校驗邏輯 * @param value * @param context * @return */ @Override public boolean isValid(User value, ConstraintValidatorContext context) { return name ==null || name.equals(value.getName()); } } 

這邊的功能是user類里面的name字段必須和配置的一樣,否則輸出一個事實

3.3. 測試

@PostMapping("/validate3") @ResponseBody public User validate3(@Valid @HandsomeBoy(name = "scj",message = "盛超傑第二帥") @RequestBody User user){ return user; } 

如果驗證不通過,會輸出盛超傑第二帥,全局異常處理器不要忘記配置

4.demo源碼下載

https://github.com/shengchaojie/springboot-validation-demo

小禮物走一走,來簡書關注我


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM