SpringBoot + Thymeleaf + Validate驗證


  

  在開發業務時,不可避免的需要處理一些校驗, 如果是寫 if-else 這種代碼去校驗, 那會有一大段這樣的代碼。不過還好有個校驗插件: javax.validation.validation-api ,不過一般會引用hibernate的校驗組件: org.hibernate.hibernate-validator , 它已經引用了validation-api組件。

1.基礎校驗類型

  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方法

  說明:

 @null  被注釋的元素必須為空
 @notnull  被注釋的元素必須不為空
 @AssertTrue  被注釋的元素必須為true
 @AssertFalse  被注釋的元素必須為false
 @Min  被注釋的元素必須是一個數字,其值必須大於等於指定的最小數
 @Max  被注釋的元素必須是一個數字,其值必須小於等於指定的最大數
 @DecimalMin  被注釋的元素必須是一個數字,其值必須大於等於指定的最小數
 @DecimalMax  被注釋的元素必須是一個數字,其值必須小於等於指定的最大數
 @Size(min,max)  被注釋的元素的大小必須在指定的范圍內
 @Digits(integer,fraction) 被注釋的元素必須是一個數字,其值必須在可接受的范圍內
 @past  被注釋的元素必須是一個過去的日期
 @Future  被注釋的元素必須是一個將來的日期
 @Pattern(value)  被注釋的元素必須符合指定的正則表達式
 @Email  被注釋的元素必須是電子郵箱
 @Length  被注釋的字符串的大小必須在指定的范圍內
 @NotEmpty  被注釋的字符串必須非空
 @Range  被注釋的元素必須在合適的范圍內

   @NotNull  和  @NotEmpty   和 @NotBlank  區別:

   @NotEmpty  用在集合類上面,@NotBlank  用在String上面, @NotNull  用在基本類型上。

我們可以看到我們在username、password和age對應的get方法上都加上了一個注解,這些注解就是JSR-303里面定義的限制,把對應的校驗錯誤信息放到Spring的Errors對象中。

2.在@Controller中校驗數據 

   接着我們來定義一個使用User對象作為參數接收者的Controller,其代碼如下所示:

 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,是需要被校驗的類型。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM