1、說(shuō)明
后端接口設(shè)計(jì)時(shí)候胸囱,需要對(duì)前端請(qǐng)求參數(shù)進(jìn)行'先校驗(yàn)后處理業(yè)務(wù)'情況妹卿,如果在業(yè)務(wù)代碼中通過(guò)類(lèi)似if這里逐個(gè)校驗(yàn)蔑鹦,會(huì)使得代碼變得繁瑣嚎朽,開(kāi)發(fā)工作者都是愛(ài)偷懶的柬帕。java中,Bean Validation
為JavaBean
的驗(yàn)證定義了相關(guān)的元數(shù)據(jù)模型和API陷寝》锱埽基于Bean-Validation
封裝,提供了更加豐富的Hibernate-Validation
的校驗(yàn)包仔引。也有開(kāi)發(fā)會(huì)把這類(lèi)校驗(yàn)交給前端來(lái)處理咖耘,但是接口暴露外網(wǎng)會(huì)存在直接調(diào)用情況(黃牛)。畢竟:前端校驗(yàn)是為了提高用戶的體驗(yàn)度版保,后端校驗(yàn)則是為了保證數(shù)據(jù)的安全性
優(yōu)點(diǎn)
1.驗(yàn)證邏輯與業(yè)務(wù)邏輯之間進(jìn)行了分離夫否,降低了程序耦合度
2.統(tǒng)一且規(guī)范的驗(yàn)證方式,無(wú)需你再次編寫(xiě)重復(fù)的驗(yàn)證代碼
3.你將更專(zhuān)注于你的業(yè)務(wù)凰慈,將這些繁瑣的事情統(tǒng)統(tǒng)丟在一邊
2溉瓶、Bean Validation與Hibernate Validation
2.1 Bean Validation中內(nèi)置的constraint
包位置路徑:javax.validation.constraints
注解 | 說(shuō)明 |
---|---|
@AssertFalse | 注釋的元素必須為False |
@AssertTrue | 注釋的元素必須為T(mén)rue |
注釋的元素必須郵箱 | |
@NotBlank | 注釋的元素不能為空堰酿,张足!null && size>0 |
@NotEmpty | 注釋的元素不能為空,數(shù)組哼绑,集合等 |
@NotNull | 注釋的元素必須為空,但可以為""字符串 |
@DecimalMin | 注釋的元素?cái)?shù)字抖韩,最小不得小于Min |
@DecimalMax | 注釋的元素為數(shù)字茂浮,最大不超過(guò)Max值 |
其中NotNull、NotEmpty席揽、NotBlank區(qū)別
-
@NotNull
適用于基本數(shù)據(jù)類(lèi)型(Integer幌羞,Long,Double等等)属桦,當(dāng) @NotNull 注解被使用在 String 類(lèi)型的數(shù)據(jù)上地啰,則表示該數(shù)據(jù)不能為 Null(但是可以為 Empty) -
@NotBlank
適用于 String 類(lèi)型的數(shù)據(jù)上,加了@NotBlank 注解的參數(shù)不能為 Null 且 trim() 之后 size > 0 -
@NotEmpty
適用于 String亏吝、Collection集合蔚鸥、Map、數(shù)組等等止喷,加了@NotEmpty 注解的參數(shù)不能為 Null 或者 長(zhǎng)度為 0
2.1 Hibernate Validation中添加的constraint
注解 | 說(shuō)明 |
---|---|
@Length | 注釋的元素字符串長(zhǎng)度必須為制定返回內(nèi) |
@Range | 注釋的元素必須在指定范圍內(nèi) |
@URL | 注釋的元素必須為鏈接 |
3弹谁、基于Hibernate Validation的實(shí)現(xiàn)
(1)pom包引用
查看spring-boot-start-web
中已經(jīng)集成了Hibernate Validation
,所以可以不用額外引用包沟于。同時(shí)spring-boot-start-validation
也完成了Hibernate Validation
的start
封裝(校驗(yàn)機(jī)制更加全面)植康。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
(2)Bean
對(duì)象中使用注解注釋
...
@ApiModelProperty(value = "收貨人所在省",required = true)
@NotNull(message = "省不能為空")
private String recipientProvince;
@ApiModelProperty(value = "收貨人所在市")
@NotNull(message = "市不能為空")
private String recipientCity;
@ApiModelProperty(value = "收貨人所在區(qū)")
@NotNull(message = "區(qū)不能為空")
private String recipientDistrict;
...
(3)Controller
層使用@Valid
或者@Validated
@PostMapping("/add")
public UniformResultTemplate<Boolean> addAddress(@RequestBody @Validated AddressReqDto reqDto, HttpServletRequest request){
return null;
}
注意:Post請(qǐng)求方式區(qū)別,Get@Validated注解需要加在 所在方法類(lèi)前
@RestController
@RequestMapping("/api/address")
@Validated
public class AddressController extends BaseController{
@ApiOperation("收獲地址詳情")
@GetMapping("/detail")
public UniformResultTemplate<AddressDetailRespDto> queryAddressList(@NotNull(message = "地址Id不能為空")
@RequestParam(value = "addressId") Long addressId, HttpServletRequest request){
return null;
}
}
(4)使用@ControllerAdvice
統(tǒng)一異常處理返回存崖。
@Component
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
// Post請(qǐng)求Bean中的校驗(yàn)拋出:MethodArgumentNotValidException
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public UniformResultTemplate handleBindException(MethodArgumentNotValidException ex) {
FieldError fieldError = ex.getBindingResult().getFieldError();
log.warn("參數(shù)校驗(yàn)異常:{}({})", fieldError.getDefaultMessage(),fieldError.getField());
return new UniformResultTemplate("10002",fieldError.getDefaultMessage());
}
// Get請(qǐng)求的參數(shù)校驗(yàn)睡毒,拋出的是ConstraintViolationException
@ExceptionHandler(ConstraintViolationException.class)
@ResponseBody
public UniformResultTemplate handleGetBindException(ConstraintViolationException ex) {
Set<ConstraintViolation<?>> eSet = ex.getConstraintViolations();
StringBuffer sb = new StringBuffer();
if(!CollectionUtils.isEmpty(eSet)) {
Iterator<ConstraintViolation<?>> iterator = eSet.iterator();
while (iterator.hasNext()) {
log.warn("參數(shù)校驗(yàn)異常:{}({})", iterator.next().getMessage());
sb.append(iterator.next().getMessage()).append("::");
}
}
return new UniformResultTemplate("10002",sb.toString());
}
// 方法簽名參數(shù)錯(cuò)誤
@ExceptionHandler(MissingServletRequestParameterException.class)
@ResponseBody
public UniformResultTemplate handleGetBindException(MissingServletRequestParameterException ex) {
log.warn("參數(shù)校驗(yàn)異常:{}", ex.getMessage());
return new UniformResultTemplate("10002",ex.getMessage());
}
}
(5)結(jié)果現(xiàn)象
{
"code": "10002",
"message": "市不能為空",
"result": null,
"totalTimes": null,
"interfaceTimes": null
}
4吕嘀、編譯器校驗(yàn)工具
防止因使用錯(cuò)誤Hibernate-Validation注解而導(dǎo)致程序運(yùn)行時(shí)報(bào)錯(cuò)偶房,增加編譯器校驗(yàn)工具,進(jìn)行友好提示棕洋。
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator-annotation-processor</artifactId>
<version>6.1.5.Final</version>
</dependency>