SpringBoot 參數(shù)校驗(yàn)/參數(shù)驗(yàn)證,常用方法都給你總結(jié)好了!
1、前言
在控制器類的方法里自己寫校驗(yàn)邏輯代碼當(dāng)然也可以,只是代碼比較丑陋,有點(diǎn)“l(fā)ow”。業(yè)界有更好的處理方法,分別闡述如下。
2、PathVariable校驗(yàn)
@GetMapping("/path/{group:[a-zA-Z0-9_]+}/{userid}")
@ResponseBody
public?String?path(@PathVariable("group")?String?group,?@PathVariable("userid")?Integer?userid)?{
????return?group?+?":"?+?userid;
}
用法是:路徑變量:正則表達(dá)式。當(dāng)請(qǐng)求URI不滿足正則表達(dá)式時(shí),客戶端將收到404錯(cuò)誤碼。不方便的地方是,不能通過(guò)捕獲異常的方式,向前端返回統(tǒng)一的、自定義格式的響應(yīng)參數(shù)。
3、方法參數(shù)校驗(yàn)
@GetMapping("/validate1")
@ResponseBody
public?String?validate1(
????????@Size(min?=?1,max?=?10,message?=?"姓名長(zhǎng)度必須為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來(lái)自validation-api.jar,更多注解參見相關(guān)標(biāo)準(zhǔn)小節(jié)。
4、表單對(duì)象/VO對(duì)象校驗(yàn)
當(dāng)參數(shù)是VO時(shí),可以在VO類的屬性上添加校驗(yàn)注解。
public?class?User?{
????@Size(min?=?1,max?=?10,message?=?"姓名長(zhǎng)度必須為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注解要求必須是相對(duì)當(dāng)前時(shí)間來(lái)講“未來(lái)的”某個(gè)時(shí)間。
@PostMapping("/validate2")
@ResponseBody
public?User?validate2(@Valid?@RequestBody?User?user){
????return?user;
}
5、自定義校驗(yàn)規(guī)則
5.1 自定義注解校驗(yàn)
需要自定義一個(gè)注解類和一個(gè)校驗(yàn)類。
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的有效值,多個(gè)使用,隔開
????String?values();
????//?flag無(wú)效時(shí)的提示內(nèi)容
????String?message()?default?"flag必須是預(yù)定義的那幾個(gè)值,不能隨便寫";
????Class>[]?groups()?default?{};
????Class?extends?Payload>[]?payload()?default?{};
}
import?javax.validation.ConstraintValidator;
import?javax.validation.ConstraintValidatorContext;
public?class?FlagValidatorClass?implements?ConstraintValidator<FlagValidator,Object>?{
????/**
?????*?FlagValidator注解規(guī)定的那些有效值
?????*/
????private?String?values;
????@Override
????public?void?initialize(FlagValidator?flagValidator)?{
????????this.values?=?flagValidator.values();
????}
????/**
?????*?用戶輸入的值,必須是FlagValidator注解規(guī)定的那些值其中之一。
?????*?否則,校驗(yàn)不通過(guò)。
?????*?@param?value?用戶輸入的值,如從前端傳入的某個(gè)值
?????*/
????@Override
????public?boolean?isValid(Object?value,?ConstraintValidatorContext?constraintValidatorContext)?{
????????//?切割獲取值
????????String[]?value_array?=?values.split(",");
????????Boolean?isFlag?=?false;
????????for?(int?i?=?0;?i?????????????//?存在一致就跳出循環(huán)
????????????if?(value_array[i]?.equals(value)){
????????????????isFlag?=?true;?break;
????????????}
????????}
????????return?isFlag;
????}
}
使用我們自定義的注解:
public?class?User?{
????//?前端傳入的flag值必須是1或2或3,否則校驗(yàn)失敗
????@FlagValidator(values?=?"1,2,3")
????private?String?flag?;
????。。。
}
5.2 分組校驗(yàn)
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?長(zhǎng)度必須在?{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分組進(jìn)行驗(yàn)證
?????*?@param?resume
?????*?@return
?????*/
????@PostMapping("/validate5")
????public?String?addUser(@Validated(value?=?Resume.Default.class)?@RequestBody?Resume?resume)?{
????????return?"validate5";
????}
????/**
?????*?使用Default、Update分組進(jìn)行驗(yàn)證
?????*?@param?resume
?????*?@return
?????*/
????@PutMapping("/validate6")
????public?String?updateUser(@Validated(value?=?{Resume.Update.class,?Resume.Default.class})?@RequestBody?Resume?resume)?{
????????return?"validate6";
????}
建立了兩個(gè)分組,名稱分別為Default、Update。POST方法提交時(shí)使用Defaut分組的校驗(yàn)規(guī)則,PUT方法提交時(shí)同時(shí)使用兩個(gè)分組規(guī)則。
6、異常攔截器
通過(guò)設(shè)置全局異常處理器,統(tǒng)一向前端返回校驗(yàn)失敗信息。
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);
????/**
?????*?用來(lái)處理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;
????}
}
7、相關(guān)標(biāo)準(zhǔn)
JSR 303 是Bean驗(yàn)證的規(guī)范 ,Hibernate Validator?是該規(guī)范的參考實(shí)現(xiàn),它除了實(shí)現(xiàn)規(guī)范要求的注解外,還額外實(shí)現(xiàn)了一些注解。
validation-api-1.1.0.jar?包括如下約束注解:

hibernate-validator-5.3.6.jar?包括如下約束注解:

8、同時(shí)校驗(yàn)2個(gè)或更多個(gè)字段/參數(shù)
常見的場(chǎng)景之一是,查詢某信息時(shí)要輸入開始時(shí)間和結(jié)束時(shí)間。顯然,結(jié)束時(shí)間要≥開始時(shí)間??梢栽诓樵?a target="_blank" textvalue="VO類" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" data-linktype="2" wah-hotarea="click" hasload="1" style="outline: 0px;text-decoration: underline;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">VO類上使用自定義注解,下面的例子來(lái)自這里。劃重點(diǎn):@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<ValidAddress,?Address>?{
????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;
????????}
????}
}
來(lái)源:blog.csdn.net/jinjiankang/article/details/89711493
END
推薦閱讀 一鍵生成Springboot & Vue項(xiàng)目!【畢設(shè)神器】
Java可視化編程工具系列(一)
Java可視化編程工具系列(二)
順便給大家推薦一個(gè)GitHub項(xiàng)目,這個(gè) GitHub 整理了上千本常用技術(shù)PDF,絕大部分核心的技術(shù)書籍都可以在這里找到,
GitHub地址:https://github.com/javadevbooks/books
Gitee地址:https://gitee.com/javadevbooks/books
電子書已經(jīng)更新好了,你們需要的可以自行下載了,記得點(diǎn)一個(gè)star,持續(xù)更新中..

