可以說(shuō)幾乎所有的應(yīng)用場(chǎng)景中,參數(shù)驗(yàn)證都在編寫(xiě)業(yè)務(wù)邏輯前完成,嚴(yán)格確保進(jìn)來(lái)的數(shù)據(jù)是合法且符合要求的。
Java Web 開(kāi)發(fā)領(lǐng)域,也早有較為完善的 Bean Validation 為 Java Bean 驗(yàn)證定義了相應(yīng)的元數(shù)據(jù)模型和 API。首先,在項(xiàng)目中引入 web 模塊的依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Hibernate Validator 是 Bean Validation 的一種實(shí)現(xiàn) . Hibernate Validator 提供了 JSR 303 規(guī)范中所有內(nèi)置 constraint 的實(shí)現(xiàn),以及一些附加的 constraint。如果想了解更多請(qǐng)查看 http://www.hibernate.org/subprojects/validator.html
具體以及常用的 constraint 包含如下:
@Data
public class Validate {
// 空和非空檢查: @Null、@NotNull、@NotBlank、@NotEmpty
@Null(message = "驗(yàn)證是否為 null")
private Integer isNull;
@NotNull(message = "驗(yàn)證是否不為 null, 但無(wú)法查檢長(zhǎng)度為0的空字符串")
private Integer id;
@NotBlank(message = "檢查字符串是不是為 null,以及去除空格后長(zhǎng)度是否大于0")
private String name;
@NotEmpty(message = "檢查是否為 NULL 或者是 EMPTY")
private List<String> stringList;
// Boolean值檢查: @AssertTrue、@AssertFalse
@AssertTrue(message = " 驗(yàn)證 Boolean參數(shù)是否為 true")
private Boolean isTrue;
@AssertFalse(message = "驗(yàn)證 Boolean 參數(shù)是否為 false ")
private Boolean isFalse;
// 長(zhǎng)度檢查: @Size、@Length
@Size(min = 1, max = 2, message = "驗(yàn)證(Array,Collection,Map,String)長(zhǎng)度是否在給定范圍內(nèi)")
private List<Integer> integerList;
@Length(min = 8, max = 30, message = "驗(yàn)證字符串長(zhǎng)度是否在給定范圍內(nèi)")
private String address;
// 日期檢查: @Future、@FutureOrPresent、@Past、@PastOrPresent
@Future(message = "驗(yàn)證日期是否在當(dāng)前時(shí)間之后")
private Date futureDate;
@FutureOrPresent(message = "驗(yàn)證日期是否為當(dāng)前時(shí)間或之后")
private Date futureOrPresentDate;
@Past(message = "驗(yàn)證日期是否在當(dāng)前時(shí)間之前")
private Date pastDate;
@PastOrPresent(message = "驗(yàn)證日期是否為當(dāng)前時(shí)間或之前")
private Date pastOrPresentDate;
// 其它檢查: @Email、@CreditCardNumber、@URL、@Pattern、@ScriptAssert、@UniqueElements
@Email(message = "校驗(yàn)是否為正確的郵箱格式")
private String email;
@CreditCardNumber(message = "校驗(yàn)是否為正確的信用卡號(hào)")
private String creditCardNumber;
@URL(protocol = "http", host = "127.0.0.1", port = 8080, message = "校驗(yàn)是否為正確的URL地址")
private String url;
@Pattern(regexp = "^1[3|4|5|7|8][0-9]{9}$", message = "正則校驗(yàn)是否為正確的手機(jī)號(hào)")
private String phone;
// 對(duì)關(guān)聯(lián)對(duì)象元素進(jìn)行遞歸校驗(yàn)檢查
@Valid
@UniqueElements(message = "校驗(yàn)集合中的元素是否唯一")
private List<CalendarEvent> calendarEvent;
@Data
@ScriptAssert(lang = "javascript", script = "_this.startDate.before(_this.endDate)",
message = "通過(guò)腳本表達(dá)式校驗(yàn)參數(shù)")
private class CalendarEvent {
private Date startDate;
private Date endDate;
}
// 數(shù)值檢查: @Min、@Max、@Range、@DecimalMin、@DecimalMax、@Digits
@Min(value = 0, message = "驗(yàn)證數(shù)值是否大于等于指定值")
@Max(value = 100, message = "驗(yàn)證數(shù)值是否小于等于指定值")
@Range(min = 0, max = 100, message = "驗(yàn)證數(shù)值是否在指定值區(qū)間范圍內(nèi)")
private Integer score;
@DecimalMin(value = "10.01", inclusive = false, message = "驗(yàn)證數(shù)值是否大于等于指定值")
@DecimalMax(value = "199.99", message = "驗(yàn)證數(shù)值是否小于等于指定值")
@Digits(integer = 3, fraction = 2, message = "限制整數(shù)位最多為3,小數(shù)位最多為2")
private BigDecimal money;
}
常見(jiàn)的前后端分離開(kāi)發(fā)模式,數(shù)據(jù)通信通常以 JSON 為主。針對(duì) POST 和 PUT 請(qǐng)求,一般通過(guò)新建域(對(duì)象)模型來(lái)進(jìn)行數(shù)據(jù)綁定和校驗(yàn),constraint 通常附加在這些域模型的字段上(如上):
/**
* Valid注解標(biāo)明要對(duì)參數(shù)對(duì)象進(jìn)行數(shù)據(jù)校驗(yàn)
*/
@PutMapping
@PostMapping
public Map<String, Object> test01(@RequestBody @Valid Validate validate, BindingResult bindingResult) {
Map<String, Object> map = new HashMap<>(4);
if (bindingResult.hasErrors()) {
String errorMsg = bindingResult.getFieldErrors().stream().map(FieldError::getDefaultMessage)
.collect(Collectors.joining(","));
map.put("errorMsg", errorMsg);
}
map.put("params", validate.toString());
return map;
}
此外,對(duì)于 GET 和 DELETE 請(qǐng)求,參數(shù)通常為 key1=value1&key2=value2 這種形式。默認(rèn)情況下,Hibernate Validator 只能對(duì) Object 屬性進(jìn)行校驗(yàn),并不能對(duì)單個(gè)參數(shù)進(jìn)行校驗(yàn),Spring 在此基礎(chǔ)上進(jìn)行了擴(kuò)展,通過(guò)配置 MethodValidationPostProcessor 處理器,可以實(shí)現(xiàn)對(duì)方法參數(shù)的攔截校驗(yàn)。
@Configuration
public class ValidateConfig {
/**
* 配置MethodValidationPostProcessor攔截器,以實(shí)現(xiàn)對(duì)方法參數(shù)的校驗(yàn)
*/
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
}
注意,要在 Controller 類上明確標(biāo)明 @Validated:
@Validated
@RestController
@RequestMapping("validate")
public class ValidateController {
@GetMapping
@DeleteMapping
public Map<String, Object> test02(@NotNull(message = "id不能為空") @Range(min = 1, max = 100, message = "id最小為1最大為100") Integer id,
@NotBlank(message = "email不能為空") @Email(message = "郵箱格式錯(cuò)誤") String email,
@ModelAttribute @Valid Validate validate) {
Map<String, Object> map = new HashMap<>(4);
map.put("id", id);
map.put("email", email);
map.put("params", validate.toString());
return map;
}
}
上述這種形式的參數(shù)要是校驗(yàn)失敗,錯(cuò)誤提示明顯并不友好,通過(guò)捕獲此類異常就可以解決,這里就不再介紹了。
參考鏈接
JSR 303 - Bean Validation 介紹及最佳實(shí)踐
SpringBoot-服務(wù)端參數(shù)驗(yàn)證-JSR-303驗(yàn)證框架
文章已授權(quán)轉(zhuǎn)載,原文鏈接:Spring Boot 項(xiàng)目參數(shù)校驗(yàn)的常見(jiàn)使用場(chǎng)景