參數校驗是咱們程序開發中必不可少的過程。用戶在前端頁面上填寫表單時,前端js程序會校驗參數的合法性,當數據到了後端,爲了防止惡意操做,保持程序的健壯性,後端一樣須要對數據進行校驗。後端參數校驗最簡單的作法是直接在業務方法裏面進行判斷,當判斷成功以後再繼續往下執行。但這樣帶給咱們的是代碼的耦合,冗餘。當咱們多個地方須要校驗時,咱們就須要在每個地方調用校驗程序,致使代碼很冗餘,且不美觀。html
那麼如何優雅的對參數進行校驗呢?JSR303就是爲了解決這個問題出現的,本篇文章主要是介紹 JSR303,Hibernate Validator 等校驗工具的使用,以及自定義校驗註解的使用。前端
JSR303 是一套JavaBean參數校驗的標準,它定義了不少經常使用的校驗註解,咱們能夠直接將這些註解加在咱們JavaBean的屬性上面,就能夠在須要校驗的時候進行校驗了。註解以下:java
Hibernate validator 在JSR303的基礎上對校驗註解進行了擴展,擴展註解以下:git
Spring validtor 一樣擴展了jsr303,並實現了方法參數和返回值的校驗spring
Spring 提供了MethodValidationPostProcessor類,用於對方法的校驗後端
在pom.xml中添加以下依賴:api
<!--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>
一、Model 中添加校驗註解數組
public class Book { private long id; /** * 書名 */ @NotEmpty(message = "書名不能爲空") private String bookName; /** * ISBN號 */ @NotNull(message = "ISBN號不能爲空") private String bookIsbn; /** * 單價 */ @DecimalMin(value = "0.1",message = "單價最低爲0.1")
private double price; // getter setter ....... }
二、在controller中使用此校驗app
/** * 添加Book對象 * @param book */ @RequestMapping(value = "/book", method = RequestMethod.POST) public void addBook(@RequestBody @Valid Book book) { System.out.println(book.toString()); }
當訪問這個post接口時,若是參數不符合Model中定義的話,程序中就回拋出400異常,並提示錯誤信息。框架
雖然jSR303和Hibernate Validtor 已經提供了不少校驗註解,可是當面對複雜參數校驗時,仍是不能知足咱們的要求,這時候咱們就須要 自定義校驗註解。
下面以「List數組中不能含有null元素」爲實例自定義校驗註解
一、註解定義以下:
package com.beiyan.validate.annotation; import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.*; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** * 自定義參數校驗註解 * 校驗 List 集合中是否有null 元素 */ @Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Constraint(validatedBy = ListNotHasNullValidatorImpl.class)////此處指定了註解的實現類爲ListNotHasNullValidatorImpl public @interface ListNotHasNull { /** * 添加value屬性,能夠做爲校驗時的條件,若不須要,可去掉此處定義 */ int value() default 0; String message() default "List集合中不能含有null元素"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; /** * 定義List,爲了讓Bean的一個屬性上能夠添加多套規則 */ @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER}) @Retention(RUNTIME) @Documented @interface List { ListNotHasNull[] value(); } }
二、註解實現類:
package com.beiyan.validate.annotation; import org.springframework.stereotype.Service; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; import java.util.List; /** * 自定義註解ListNotHasNull 的實現類 * 用於判斷List集合中是否含有null元素 */ @Service public class ListNotHasNullValidatorImpl implements ConstraintValidator<ListNotHasNull, List> { private int value; @Override public void initialize(ListNotHasNull constraintAnnotation) { //傳入value 值,能夠在校驗中使用 this.value = constraintAnnotation.value(); } public boolean isValid(List list, ConstraintValidatorContext constraintValidatorContext) { for (Object object : list) { if (object == null) { //若是List集合中含有Null元素,校驗失敗 return false; } } return true; } }
三、model添加註解:
public class User {
//其餘參數 ....... /** * 所擁有的書籍列表 */ @NotEmpty(message = "所擁有書籍不能爲空") @ListNotHasNull(message = "List 中不能含有null元素") @Valid private List<Book> books; //getter setter 方法....... }
使用方法同上,在在須要校驗的Model上面加上@Valid 便可
對同一個Model,咱們在增長和修改時對參數的校驗也是不同的,這個時候咱們就須要定義分組驗證,步驟以下
一、定義兩個空接口,分別表明Person對象的增長校驗規則和修改校驗規則
/** * 能夠在一個Model上面添加多套參數驗證規則,此接口定義添加Person模型新增時的參數校驗規則 */ public interface PersonAddView { } /** * 能夠在一個Model上面添加多套參數驗證規則,此接口定義添加Person模型修改時的參數校驗規則 */ public interface PersonModifyView { }
二、Model上添加註解時使用指明所述的分組
public class Person { private long id; /** * 添加groups 屬性,說明只在特定的驗證規則裏面起做用,不加則表示在使用Deafault規則時起做用 */ @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 方法...... }
三、啓用校驗
此時啓用校驗和以前的不一樣,須要指明啓用哪一組規則
/** * 添加一個Person對象 * 此處啓用PersonAddView 這個驗證規則 * 備註:此處@Validated(PersonAddView.class) 表示使用PersonAndView這套校驗規則,若使用@Valid 則表示使用默認校驗規則, * 若兩個規則同時加上去,則只有第一套起做用 */ @RequestMapping(value = "/person", method = RequestMethod.POST) public void addPerson(@RequestBody @Validated({PersonAddView.class, Default.class}) Person person) { System.out.println(person.toString()); } /** * 修改Person對象 * 此處啓用PersonModifyView 這個驗證規則 */ @RequestMapping(value = "/person", method = RequestMethod.PUT) public void modifyPerson(@RequestBody @Validated(value = {PersonModifyView.class}) Person person) { System.out.println(person.toString()); }
JSR和Hibernate validator的校驗只能對Object的屬性進行校驗,不能對單個的參數進行校驗,spring 在此基礎上進行了擴展,添加了MethodValidationPostProcessor攔截器,能夠實現對方法參數的校驗,實現以下:
一、實例化MethodValidationPostProcessor
@Bean public MethodValidationPostProcessor methodValidationPostProcessor() { return new MethodValidationPostProcessor(); }
二、在所要實現方法參數校驗的類上面添加@Validated,以下
@RestController @Validated public class ValidateController { }
三、在方法上面添加校驗規則:
@RequestMapping(value = "/test", method = RequestMethod.GET) public String paramCheck(@Length(min = 10) @RequestParam String name) { System.out.println(name); return null; }
當方法上面的參數校驗失敗,spring 框架就回拋出異常
{ "timestamp": 1476108200558, "status": 500, "error": "Internal Server Error", "exception": "javax.validation.ConstraintViolationException", "message": "No message available", "path": "/test" }
今後能夠優雅的對參數進行校驗了
本篇文章只列舉了經常使用的幾種校驗方法,其實關於校驗的內容還有不少:
校驗信息的國際化顯示,
組合參數校驗,
message中使用EL表達式,
將校驗信息綁定到ModelAndView等,這裏就不一一列出了,下面這幾篇文章寫的也不錯,讀者能夠參考:
將校驗信息綁定到ModelAndView http://www.voidcn.com/blog/983836259/article/p-5794496.html
集成Bean Validation 1.1(JSR-349)到SpringMVC https://my.oschina.net/qjx1208/blog/200946
本文的所有代碼已上傳開源中國git倉庫: http://git.oschina.net/beiyan/Validate