1.引言
參數校驗是我們程式開發中必不可少的過程。使用者在前端頁面上填寫表單時,前端js程式會校驗參數的合法性,當資料到了後端,為了防止惡意操作,保持程式的健壯性,後端同樣需要對資料進行校驗。後端參數校驗最簡單的做法是直接在業務方法裡面進行判斷,當判斷成功之後再繼續往下執行。但這樣帶給我們的是代碼的耦合,備援。當我們多個地方需要校驗時,我們就需要在每一個地方調用校驗程式,導緻代碼很備援,且不美觀。
那麼如何優雅的對參數進行校驗呢?JSR303就是為了解決這個問題出現的,本篇文章主要是介紹 JSR303,Hibernate Validator 等校驗工具的使用,以及自定義校驗注解的使用。
2. 校驗架構介紹
JSR303 是一套JavaBean參數校驗的标準,它定義了很多常用的校驗注解,我們可以直接将這些注解加在我們JavaBean的屬性上面,就可以在需要校驗的時候進行校驗了。注解如下:
@NotNull 注解元素必須是非空
@Null 注解元素必須是空
@Digits 驗證數字構成是否合法
@Future 驗證是否在目前系統時間之後
@Past 驗證是否在目前系統時間之前
@Max 驗證值是否小于等于最大指定整數值
@Min 驗證值是否大于等于最小指定整數值
@Pattern 驗證字元串是否比對指定的正規表達式
@Size 驗證元素大小是否在指定範圍内
@DecimalMax 驗證值是否小于等于最大指定小數值
@DecimalMin 驗證值是否大于等于最小指定小數值
@AssertTrue 被注釋的元素必須為true
@AssertFalse 被注釋的元素必須為false
Hibernate validator 在JSR303的基礎上對校驗注解進行了擴充,擴充注解如下:
@Email 被注釋的元素必須是電子郵箱位址
@Length 被注釋的字元串的大小必須在指定的範圍内
@NotEmpty 被注釋的字元串的必須非空
@Range 被注釋的元素必須在合适的範圍内
3.代碼實作
3.1添加JAR包依賴
在pom.xml中添加如下依賴:
<!--jsr 303-->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<!-- hibernate validator-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.0.Final</version>
</dependency>
3.2最簡單的參數校驗
3.2.1、Model 中添加校驗注解
public class Book {
private long id;
@NotEmpty(message = "書名不能為空")
private String bookName;
@NotNull(message = "ISBN号不能為空")
private String bookIsbn;
@DecimalMin(value = "0.1",message = "單價最低為0.1")
private doubleprice; // getter setter ....... }
3.2.2、在controller中使用此校驗
@RequestMapping(value = "/book",method = RequestMethod.POST)
public void addBook(@RequestBody @Valid Book book) {
System.out.println(book.toString());
}
當通路這個post接口時,如果參數不符合Model中定義的話,程式中就回抛出400異常,并提示錯誤資訊。
3.3分組驗證
對同一個Model,我們在增加和修改時對參數的校驗也是不一樣的,這個時候我們就需要定義分組驗證,步驟如下
3.3.1、定義兩個空接口,分别代表Person對象的增加校驗規則和修改校驗規則
public interface PersonAddView {
}
public interface PersonModifyView {
}
3.3.2、Model上添加注解時使用指明所述的分組
public class Person {
private long id;
@NotNull(groups = {PersonAddView.class, PersonModifyView.class}, message= "添加、修改使用者時名字不能為空",payload = ValidateErrorLevel.Info.class)
@ListNotHasNull.List({
@ListNotHasNull(groups = {PersonAddView.class}, message = "添加上Name不能為空"),
@ListNotHasNull(groups = {PersonModifyView.class}, message = "修改時Name不能為空")})
private String name;
@NotNull(groups = {PersonAddView.class}, message = "添加使用者時位址不能為空")
private String address;
@Min(value = 18, groups = {PersonAddView.class}, message = "姓名不能低于18歲")
@Max(value = 30, groups = {PersonModifyView.class}, message = "姓名不能超過30歲")
private int age;
//getter setter 方法......
}
3.3.3、啟用校驗
此時啟用校驗和之前的不同,需要指明啟用哪一組規則
@RequestMapping(value = "/person", method =RequestMethod.POST)
public void addPerson(@RequestBody @Validated({PersonAddView.class,Default.class}) Person person) {
System.out.println(person.toString());
}
@RequestMapping(value = "/person", method = RequestMethod.PUT)
public void modifyPerson(@RequestBody @Validated(value ={PersonModifyView.class}) Person person) {
System.out.println(person.toString());
}
3.4 Spring validator 方法級别的校驗
JSR和Hibernate validator的校驗隻能對Object的屬性進行校驗,不能對單個的參數進行校驗,spring 在此基礎上進行了擴充,添加了MethodValidationPostProcessor攔截器,可以實作對方法參數的校驗,實作如下:
3.4.1、執行個體化MethodValidationPostProcessor
@Bean
public MethodValidationPostProcessormethodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
3.4.2、在所要實作方法參數校驗的類上面添加@Validated,如下
@RestController
@Validated
public class ValidateController {
}
3.4.3、在方法上面添加校驗規則:
@RequestMapping(value = "/test",method = RequestMethod.GET)
public String paramCheck(@Length(min = 10) @RequestParam String name) {
System.out.println(name);
return null;
}
3.5使用BindingResult對象來儲存驗證結果
每一個模型對象後邊都需要跟一個Errors或BindingResult對象來儲存驗證結果,其方法體内部可以使用這兩個驗證結果對象來選擇出錯時跳轉的頁面或處理的邏輯。
@RequestMapping("/validate/multi")
public String multi(@[email protected]("a") A a, BindingResult aErrors, @[email protected]("b") B b, BindingResult bErrors) {
if (aErrors.hasErrors()) { //如果a模型對象驗證失敗
return "validate/error";
}
if (bErrors.hasErrors()) { //如果a模型對象驗證失敗
return "validate/error";
}
return "redirect:/success";
}