您好,登錄后才能下訂單哦!
這篇文章主要介紹SpringBoot如何實現(xiàn)參數(shù)校驗/參數(shù)驗證,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
在控制器類的方法里自己寫校驗邏輯代碼當然也可以,只是代碼比較丑陋,有點“l(fā)ow”。業(yè)界有更好的處理方法,分別闡述如下。
@GetMapping("/path/{group:[a-zA-Z0-9_]+}/{userid}") @ResponseBody public String path(@PathVariable("group") String group, @PathVariable("userid") Integer userid) { return group + ":" + userid; }
用法是:路徑變量:正則表達式。當請求URI不滿足正則表達式時,客戶端將收到404錯誤碼。不方便的地方是,不能通過捕獲異常的方式,向前端返回統(tǒng)一的、自定義格式的響應參數(shù)。
@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) { return "validate1"; }
如果前端傳遞的參數(shù)不滿足規(guī)則,則拋出異常。注解Size、Min、Max來自validation-api.jar,更多注解參見相關標準小節(jié)。
當參數(shù)是VO時,可以在VO類的屬性上添加校驗注解。
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; 。。。 }
其中,F(xiàn)uture注解要求必須是相對當前時間來講“未來的”某個時間。
@PostMapping("/validate2") @ResponseBody public User validate2(@Valid @RequestBody User user){ return user; }
需要自定義一個注解類和一個校驗類。
import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.*; @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.PARAMETER,ElementType.FIELD}) @Constraint(validatedBy = FlagValidatorClass.class) public @interface FlagValidator { // flag的有效值,多個使用,隔開 String values(); // flag無效時的提示內(nèi)容 String message() default "flag必須是預定義的那幾個值,不能隨便寫"; Class>[] groups() default {}; Class extends Payload>[] payload() default {}; }
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; public class FlagValidatorClass implements ConstraintValidator{ /** * FlagValidator注解規(guī)定的那些有效值 */ private String values; @Override public void initialize(FlagValidator flagValidator) { this.values = flagValidator.values(); } /** * 用戶輸入的值,必須是FlagValidator注解規(guī)定的那些值其中之一。 * 否則,校驗不通過。 * @param value 用戶輸入的值,如從前端傳入的某個值 */ @Override public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) { // 切割獲取值 String[] value_array = values.split(","); Boolean isFlag = false; for (int i = 0; i < value_array.length; i++){ // 存在一致就跳出循環(huán) if (value_array[i] .equals(value)){ isFlag = true; break; } } return isFlag; } }
使用我們自定義的注解:
public class User { // 前端傳入的flag值必須是1或2或3,否則校驗失敗 @FlagValidator(values = "1,2,3") private String flag ; 。。。 }
import org.hibernate.validator.constraints.Length; import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; public class Resume { public interface Default { } public interface Update { } @NotNull(message = "id不能為空", groups = Update.class) private Long id; @NotNull(message = "名字不能為空", groups = Default.class) @Length(min = 4, max = 10, message = "name 長度必須在 {min} - {max} 之間", groups = Default.class) private String name; @NotNull(message = "年齡不能為空", groups = Default.class) @Min(value = 18, message = "年齡不能小于18歲", groups = Default.class) private Integer age; 。。。 }
/** * 使用Defaul分組進行驗證 * @param resume * @return */ @PostMapping("/validate5") public String addUser(@Validated(value = Resume.Default.class) @RequestBody Resume resume) { return "validate5"; } /** * 使用Default、Update分組進行驗證 * @param resume * @return */ @PutMapping("/validate6") public String updateUser(@Validated(value = {Resume.Update.class, Resume.Default.class}) @RequestBody Resume resume) { return "validate6"; }
建立了兩個分組,名稱分別為Default、Update。POST方法提交時使用Defaut分組的校驗規(guī)則,PUT方法提交時同時使用兩個分組規(guī)則。
通過設置全局異常處理器,統(tǒng)一向前端返回校驗失敗信息。
import com.scj.springbootdemo.WebResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.CollectionUtils; import org.springframework.validation.ObjectError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; import java.util.List; import java.util.Set; /** * 全局異常處理器 */ @ControllerAdvice public class GlobalExceptionHandler { private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class); /** * 用來處理bean validation異常 * @param ex * @return */ @ExceptionHandler(ConstraintViolationException.class) @ResponseBody public WebResult resolveConstraintViolationException(ConstraintViolationException ex){ WebResult errorWebResult = new WebResult(WebResult.FAILED); Set> 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 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; } }
JSR 303 是Bean驗證的規(guī)范 ,Hibernate Validator 是該規(guī)范的參考實現(xiàn),它除了實現(xiàn)規(guī)范要求的注解外,還額外實現(xiàn)了一些注解。
validation-api-1.1.0.jar 包括如下約束注解:
約束注解 | 說明 |
---|---|
@AssertFalse | 被注釋的元素必須為 false |
@AssertTrue | 被注釋的元素必須為 true |
@DecimalMax(value) | 被注釋的元素必須是一個數(shù)字,其值必須小于等于指定的最大值 |
@DecimalMin(value) | 被注釋的元素必須是一個數(shù)字,其值必須大于等于指定的最小值 |
@Digits (integer, fraction) | 被注釋的元素必須是一個數(shù)字,其值必須在可接受的范圍內(nèi) |
@Null | 被注釋的元素必須為 null |
@NotNull | 被注釋的元素必須不為 null |
@Min(value) | 被注釋的元素必須是一個數(shù)字,其值必須大于等于指定的最小值 |
@Max(value) | 被注釋的元素必須是一個數(shù)字,其值必須小于等于指定的最大值 |
@Size(max, min) | 被注釋的元素的大小必須在指定的范圍內(nèi) |
@Past | 被注釋的元素必須是一個過去的日期 |
@Future | 被注釋的元素必須是一個將來的日期 |
@Pattern(value) | 被注釋的元素必須符合指定的正則表達式 |
hibernate-validator-5.3.6.jar 包括如下約束注解:
約束注解 | 說明 |
---|---|
被注釋的元素必須是電子郵箱地址 | |
@Length | 被注釋的字符串的大小必須在指定的范圍內(nèi) |
@NotBlank | 被注釋的字符串的必須非空 |
@NotEmpty | 被注釋的字符串、集合、Map、數(shù)組必須非空 |
@Range | 被注釋的元素必須在合適的范圍內(nèi) |
@SafeHtml | 被注釋的元素必須是安全Html |
@URL | 被注釋的元素必須是有效URL |
略 |
公司不讓上傳源碼到GitHub,可以參加這篇文章。
常見的場景之一是,查詢某信息時要輸入開始時間和結(jié)束時間。顯然,結(jié)束時間要≥開始時間??梢栽诓樵僔O類上使用自定義注解,下面的例子來自這里。劃重點:@ValidAddress使用在類上。
@ValidAddress public class Address { @NotNull @Size(max = 50) private String street1; @Size(max = 50) private String street2; @NotNull @Size(max = 10) private String zipCode; @NotNull @Size(max = 20) private String city; @Valid @NotNull private Country country; // Getters and setters }
public class Country { @NotNull @Size(min = 2, max = 2) private String iso2; // Getters and setters }
@Documented @Target(TYPE) @Retention(RUNTIME) @Constraint(validatedBy = { MultiCountryAddressValidator.class }) public @interface ValidAddress { String message() default "{com.example.validation.ValidAddress.message}"; Class>[] groups() default {}; Class extends Payload>[] payload() default {}; }
public class MultiCountryAddressValidator implements ConstraintValidator{ public void initialize(ValidAddress constraintAnnotation) { } @Override public boolean isValid(Address address, ConstraintValidatorContext constraintValidatorContext) { Country country = address.getCountry(); if (country == null || country.getIso2() == null || address.getZipCode() == null) { return true; } switch (country.getIso2()) { case "FR": return // Check if address.getZipCode() is valid for France case "GR": return // Check if address.getZipCode() is valid for Greece default: return true; } } }
以上是SpringBoot如何實現(xiàn)參數(shù)校驗/參數(shù)驗證的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對大家有幫助,更多相關知識,歡迎關注億速云行業(yè)資訊頻道!
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。