在開發業務時,不可避免的須要處理一些校驗, 若是是寫 if-else 這種代碼去校驗, 那會有一大段這樣的代碼。不過還好有個校驗插件: javax.validation.validation-api ,不過通常會引用hibernate的校驗組件: org.hibernate.hibernate-validator , 它已經引用了validation-api組件。java
1.基礎校驗類型git
JSR303 是一套JavaBean參數校驗的標準,它定義了不少經常使用的校驗註解,咱們能夠直接將這些註解加在咱們JavaBean的屬性上面,就能夠在須要校驗的時候進行校驗了。註解以下:
建立須要被校驗的實體類,使用一些比較經常使用的校驗註解,仍是比較淺顯易懂的,字段上的註解名稱便可推斷出校驗內容,每個註解都包含了message字段,用於校驗失敗時做爲提示信息,
特殊的校驗註解,如Pattern(正則校驗),還能夠本身添加正則表達式,在實體類上加上@notnull @size等驗證,例如:正則表達式
1 @Entity 2 @Table(name = "userinfo", uniqueConstraints = @UniqueConstraint(columnNames = "username")) 3 public class User { 4 private Integer id; 5 @Size(min = 4, max = 15, message = "用戶名長度爲4-15位") 6 private String username; 7 @Size(min = 6, max = 18, message = "密碼長度爲6-18位") 8 private String password; 9 @Pattern(regexp = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$", message = "郵箱格式不正確") 10 private String email; 11 @Pattern(regexp = "^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$", message = "手機號填寫錯誤") 12 private String phone; 13 @NotEmpty(message = "性別不能爲空") 14 private String sex; 15 private Date creat_time; 16 private Date update_time; 17 @Id 18 @GeneratedValue 19 public Integer getId() { 20 return id; 21 }
//省略後面set和get方法
說明:spring
@null 被註釋的元素必須爲空
@notnull 被註釋的元素必須不爲空
@AssertTrue 被註釋的元素必須爲true
@AssertFalse 被註釋的元素必須爲false
@Min 被註釋的元素必須是一個數字,其值必須大於等於指定的最小數
@Max 被註釋的元素必須是一個數字,其值必須小於等於指定的最大數
@DecimalMin 被註釋的元素必須是一個數字,其值必須大於等於指定的最小數
@DecimalMax 被註釋的元素必須是一個數字,其值必須小於等於指定的最大數
@Size(min,max) 被註釋的元素的大小必須在指定的範圍內
@Digits(integer,fraction) 被註釋的元素必須是一個數字,其值必須在可接受的範圍內
@past 被註釋的元素必須是一個過去的日期
@Future 被註釋的元素必須是一個未來的日期
@Pattern(value) 被註釋的元素必須符合指定的正則表達式
@Email 被註釋的元素必須是電子郵箱
@Length 被註釋的字符串的大小必須在指定的範圍內
@NotEmpty 被註釋的字符串必須非空
@Range 被註釋的元素必須在合適的範圍內api
@NotNull 和 @NotEmpty 和 @NotBlank 區別:app
@NotEmpty 用在集合類上面,@NotBlank 用在String上面, @NotNull 用在基本類型上。ide
咱們能夠看到咱們在username、password和age對應的get方法上都加上了一個註解,這些註解就是JSR-303裏面定義的限制,把對應的校驗錯誤信息放到Spring的Errors對象中。ui
2.在@Controller中校驗數據 spa
接着咱們來定義一個使用User對象做爲參數接收者的Controller,其代碼以下所示:hibernate
1 @Controller 2 public class FooController { 3 @RequestMapping("/foo") 4 public String foo(@Validated Foo foo <1>, BindingResult bindingResult <2>) { 5 if(bindingResult.hasErrors()){ 6 for (FieldError fieldError : bindingResult.getFieldErrors()) { 7 //... 8 } 9 return "fail"; 10 } 11 return "success"; 12 } 13 }
<1> 參數Foo前須要加上 @Validated 註解,代表須要spring對其進行校驗,而校驗的信息會存放到其後的 BindingResult 中。注意,必須相鄰,若是有多個參數須要校驗,形式能夠以下。 foo(@Validated Foo foo, BindingResult fooBindingResult ,@Validated Bar bar, BindingResult barBindingResult){ //*** } ;即一個校驗類對應一個校驗結果。
<2> 校驗結果會被自動填充,在controller中能夠根據業務邏輯來決定具體的操做,如跳轉到錯誤頁面。
3.頁面獲取message裏的錯誤信息
現、在Form裏 th:Object 裏添加實體的對象,經過 #fields.hasErrors('字段名') 判斷該字段是否有錯誤,若是有錯誤,經過 th:errors=「*{字段名}」 顯示messages裏的錯誤信息提示。例如:
<p th:if="${#fields.hasErrors('username')} " th:errors="*{username}" class="text-danger"></p>
4.分組校驗
例如:
1 Class Foo{ 2 @Min(value = 18,groups = {Adult.class}) 3 private Integer age; 4 public interface Adult{} 5 public interface Minor{} 6 }
這個裏的age只有在Adult的分組下才會背校驗,例如:
1 @RequestMapping("/drink") 2 public String drink(@Validated({Foo.Adult.class}) Foo foo, BindingResult bindingResult) { 3 if(bindingResult.hasErrors()){ 4 for (FieldError fieldError : bindingResult.getFieldErrors()) {}......
5.自定義校驗
(1)咱們嘗試添加一個「字符串不能包含空格」的限制。
1 @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER}) 2 @Retention(RUNTIME) 3 @Documented 4 @Constraint(validatedBy = {CannotHaveBlankValidator.class})<1> 5 public @interface CannotHaveBlank { 6 //默認錯誤消息 7 String message() default "不能包含空格"; 8 //分組 9 Class<?>[] groups() default {}; 10 //負載 11 Class<? extends Payload>[] payload() default {}; 12 //指定多個時使用 13 @Target({FIELD, METHOD, PARAMETER, ANNOTATION_TYPE}) 14 @Retention(RUNTIME) 15 @Documented 16 @interface List { 17 CannotHaveBlank[] value(); 18 } 19 }
咱們不須要關注太多東西,使用spring validation的原則即是便捷咱們的開發,例如payload,List ,groups,均可以忽略。
<1>自定義註解中指定了這個註解真正的驗證者類。
(2)編寫真正的校驗者類
1 public class CannotHaveBlankValidator implements <1> ConstraintValidator<CannotHaveBlank, String> { 2 @Override 3 public void initialize(CannotHaveBlank constraintAnnotation) { 4 } 5 @Override 6 public boolean isValid(String value, ConstraintValidatorContext context <2>) { 7 //null時不進行校驗 8 if (value != null && value.contains(" ")) { 9 <3> 10 //獲取默認提示信息 11 String defaultConstraintMessageTemplate = context.getDefaultConstraintMessageTemplate(); 12 System.out.println("default message :" + defaultConstraintMessageTemplate); 13 //禁用默認提示信息 14 context.disableDefaultConstraintViolation(); 15 //設置提示語 16 context.buildConstraintViolationWithTemplate("can not contains blank").addConstraintViolation(); 17 return false; 18 } 19 return true; 20 } 21 }
<1> 全部的驗證者都須要實現ConstraintValidator接口,它的接口也很形象,包含一個初始化事件方法,和一個判斷是否合法的方法。
1 public interface ConstraintValidator<A extends Annotation, T> { 2 3 void initialize(A constraintAnnotation); 4 5 boolean isValid(T value, ConstraintValidatorContext context); 6 }
<2> ConstraintValidatorContext 這個上下文包含了認證中全部的信息,咱們能夠利用這個上下文實現獲取默認錯誤提示信息,禁用錯誤提示信息,改寫錯誤提示信息等操做。
<3> 一些典型校驗操做,或許能夠對你產生啓示做用。
值得注意的一點是,自定義註解能夠用在METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER之上, ConstraintValidator 的第二個泛型參數T,是須要被校驗的類型。