前言
后端開發(fā)API的時(shí)候經(jīng)常遇到要驗(yàn)證前端傳過來的參數(shù)太抓。一個(gè)一個(gè)的校驗(yàn)未免太不優(yōu)雅了。那么使用springboot怎么優(yōu)雅解決呢掉丽?
傳統(tǒng)的校驗(yàn)參數(shù)的方法
傳統(tǒng)的方式,會(huì)將前端傳過來的參數(shù)一一校驗(yàn)项炼,雖然也能達(dá)到效果,但是耗費(fèi)了精力,代碼也比較長
@RequestMapping("add")
public R<String> add( @RequestBody Banner banner){
R<String> r =new R<>();
if (StringUtils.isEmpty(banner.getName())) {
return r.fail("名字不能為空");
}
if (StringUtils.isEmpty(banner.getUrl())) {
return r.fail("url不能為空");
}
//假裝有業(yè)務(wù)操作
return r.success("ok");
}
更簡潔的校驗(yàn)方式
我們可以使用spring提供的validation組件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
首先需要設(shè)計(jì)一個(gè)入?yún)⒌膶?duì)象
@Data
public class Banner implements Serializable {
/**
* 名字
*/
private String name;
/**
* 鏈接
*/
private String url;
}
當(dāng)我們需要對(duì)指定的入?yún)⑦M(jìn)行校驗(yàn)的時(shí)候摄杂,使用注解就能指定校驗(yàn)規(guī)則(支持多個(gè))
下面是封裝好的規(guī)則墨坚,找到需要的直接使用就可以了
注解 | 規(guī)則 |
---|---|
@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è)過去的日期 |
@Future | 被注釋的元素必須是一個(gè)將來的日期 |
@Pattern (value) | 被注釋的元素必須符合指定的正則表達(dá)式 |
當(dāng)我們需要name、url這兩個(gè)參數(shù)不能為空時(shí)责嚷,選擇加上@NotNull
注解就可以了
然后再完善下controller,在入?yún)⒌牡胤郊由?code>@Vaild,就代表需要做參數(shù)校驗(yàn)
@RequestMapping("banner")
@RestController
public class BannerController {
@RequestMapping("add")
public R<String> add(@Valid @RequestBody Banner banner){
R<String> r =new R<>();
//假裝有業(yè)務(wù)邏輯代碼在這里調(diào)用
return r.success("ok");
}
}
參數(shù)校驗(yàn)效果
當(dāng)我們把參數(shù)設(shè)置為不能為空,就可以啟動(dòng)web服務(wù)試試效果了
上面圖片展示了雨涛,有參數(shù)校驗(yàn)通過的情況凉泄,和參數(shù)校驗(yàn)不通過的情況。我們能看到,在校驗(yàn)不通過的時(shí)候,響應(yīng)的code 是
400
锥债。這樣雖然參數(shù)校驗(yàn)到位了,但是報(bào)錯(cuò)也不夠友好,不利于后續(xù)排查問題涣楷。所以我們希望當(dāng)參數(shù)不合規(guī)時(shí),把錯(cuò)誤的的原因通過接口返回。
優(yōu)化返回參數(shù)
我們?cè)诳刂婆_(tái)發(fā)現(xiàn)剛剛出現(xiàn)參數(shù)校驗(yàn)不通過的時(shí)候,實(shí)際上是拋出了一個(gè)異常
我們可以試試將這個(gè)異常捕獲,然后將錯(cuò)誤信息抓出來返回給客戶端
首先來看下異常里面有哪些我們可以使用的信息
1. 全局異常控制
@ControllerAdvice
@ResponseBody
public class ExceptionHandle {
@ExceptionHandler
public R ParamExceptionHandle(MethodArgumentNotValidException e){
System.out.println(e);//這里打斷點(diǎn),看看異常類里有什么東西
return null;
}
}
通過將異常捕獲器,看看異常里面的內(nèi)容
從錯(cuò)誤消息中我們可以看到有校驗(yàn)不通過的字段名和默認(rèn)的錯(cuò)誤消息
那我們把這兩個(gè)字段組合一下,就變成了"url"+"字段"+"不能為null”
2. 下面進(jìn)行對(duì)全局異常捕獲的改造
@Slf4j
@ControllerAdvice
@ResponseBody
public class ExceptionHandle {
@ExceptionHandler
public R ParamExceptionHandle(MethodArgumentNotValidException e){
log.info("捕獲參數(shù)校驗(yàn)異常",e);
List<String> failError= new ArrayList<>();
for (FieldError fieldError : e.getBindingResult().getFieldErrors()) {
String field = fieldError.getField();//字段名
String defaultMessage = fieldError.getDefaultMessage();
StringBuilder sb=new StringBuilder();
sb.append("參數(shù):").append(field).append(",校驗(yàn)異常宪睹。").append("原因:").append(defaultMessage);
failError.add(sb.toString());
}
R<List<String>> r=new R<>();
return r.fail(failError.toString());
}
}
3.重啟服務(wù)看看效果
尾巴
spring提供的validate工具結(jié)合全局異常管理嘶居,可以讓控制器瘦身邮屁,減少代碼量的同時(shí),在設(shè)計(jì)入?yún)⒆侄蔚耐瑫r(shí)設(shè)計(jì)校驗(yàn)規(guī)則葬项,更符合直覺民珍,不容易出錯(cuò)嚷量。感謝閱讀蝶溶!如果覺得我內(nèi)容還不錯(cuò)的話抖所,記得關(guān)注和點(diǎn)贊