Spring Validation 校驗


概述

在 Web 應用中,客戶端提交數據之前都會進行數據的校驗,比如用戶注冊時填寫的郵箱地址是否符合規范、用戶名長度的限制等等,不過這並不意味着服務端的代碼可以免去數據驗證的工作,用戶也可能使用 HTTP 工具直接發送違法數據。為了保證數據的安全性,服務端的數據校驗是必須的。

先理清概念:

  • JSR-303 是 JavaEE 6 中的一項子規范,又稱作 Bean Validation,提供了針對 Java Bean 字段的一些校驗注解,如@NotNull@Min等。JSR-349 是其升級版本,添加了一些新特性。
  • Hibernate Validator 是對這個規范的實現(與 ORM 框架無關),並在它的基礎上增加了一些新的校驗注解。
  • Spring 本身也有一個校驗接口Validator,位於 org.springframework.validation 包下,但是使用這個接口需要進行硬編碼,也就是手動校驗,沒有提供注解進行簡化。為了給開發者提供便捷,Spring 也全面支持 JSR-303、JSR-349 規范,對 Hibernate Validation 進行二次封裝,在 SpringMVC 模塊中添加了自動校驗機制,可以利用注解對 Java Bean 的字段的值進行校驗,並將校驗信息封裝進特定的類中。

下面將介紹如何在 Spring 應用中使用 JSR-303 校驗規范。

校驗注解

1. JSR-303 包含的注解

注解名稱 說明
@Null 被注解元素必須為 null
@NonNull 被注解元素必須不為 null
@AssertTrue 被注解元素必須為 true
@AssertFalse 被注解元素必須為 false
@Min(value) 被注解元素必須是一個值,並且不能小於指定的值
@Max(value) 被注解元素必須是一個值,並且不能大於指定的值
@DecimalMin(value) 被注解元素必須是一個數字,並且不能小於指定的值
@DecimalMax(value) 被注解元素必須是一個數字,並且不能大於指定的值
@Size(max=,min=) 被注解元素的大小必須在指定范圍內
@Digits(integer,fraction) 被注解元素必須是一個數字,其值必須在指定范圍內
@Past 被注解元素必須是一個過去的日期
@Future 被注解元素必須是一個將來的日期
@Pattern(regex=,flag=) 被注解元素必須符合指定的正則表達式

2. Hibernate Validator 擴展的注解

注解名稱 說明
@NotBlank(message=) 被注解的字符串必須非 null 且trim()后長度大於 0
@Email 被注解元素必須是電子郵箱地址
@Length(min=,max=) 被注解的字符串的長度必須在指定范圍內
@NotEmpty 被注解元素(字符串、數組、集合等)必須非 null 且長度大於 0
@Range(min=,max=,message=) 被注解元素必須在合適的范圍內
@URL 被注解元素必須是合法的 URL

用法

1. 依賴

pom.xml中引入 Hibernate Validator 需要的依賴包:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.0.10.Final</version>
</dependency>

 

如果你使用的是 SpringBoot,那么只需引入spring-boot-starter-web即可,它的子依賴中包含了hibernate-validator和必要的數據綁定組件。

2. 實體類

public class Student {
    private Long id;

    @NotBlank(message = "名稱不能為空")  
    private String name;

    @Range(min = 10, max = 25, message = "年齡必須在10~25之間 ")
    private Integer age;

    @Pattern(regexp = "^1(3|4|5|7|8)\\d{9}$", message = "手機號碼格式錯誤")
    @NotBlank(message = "手機號碼不能為空")
    private String phone;

    @Email(message = "郵箱格式錯誤")
    private String email;

    // Getter/Setter
}

 

每一個注解都包含了message字段,用於校驗失敗時作為提示信息。

3. 處理器方法

在處理器方法需要校驗的參數上添加@Valid注解,就可以“激活”對它的校驗操作,后面傳入一個 BindingResult 類型的參數,用於獲取校驗失敗情況下的反饋信息。

@PostMapping("/student")
public ApiResult addStudent(@RequestBody @Valid Student student, BindingResult result) {
    if (result.hasErrors()) {
        for (ObjectError error : result.getAllErrors()) {
            System.out.println(error.getDefaultMessage();
        }
        return ApiResult.error();
    }
    studentService.insert(student);
    return ApiResult.success();
}

 

@Valid注解的參數和 BindingResult 參數必須是成對出現的,並且一前一后。

發送數據,進入上面的處理器:

控制台輸出:

自定義校驗

假如現在有一個需求是學生名字的內部不能含有空格,我們要如何自定義一個滿足該要求的校驗呢?

1. 自定義注解

@Target({FIELD, METHOD, PARAMETER})
@Retention(RUNTIME)
@Constraint(validatedBy = NotContainSpaceValidator.class)
public @interface NotContainSpace {
    //默認錯誤消息
    String message() default "不能包含空格";

    //分組
    Class<?>[] groups() default {};

    //負載
    Class<? extends Payload>[] payload() default {};

    //指定多個時使用,從而支持重復注解
    @Target({FIELD, METHOD, PARAMETER})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @interface List {
        NotContainSpace[] value();
    }
}

 

@Constraint指定這個注解真正的校驗者類。

2. 校驗者類

實現ConstraintValidator接口:

public class NotContainSpaceValidator implements ConstraintValidator<NotContainSpace, String> {
    @Override
    public void initialize(NotContainSpace notContainSpace) {
    }

    @Override
    public boolean isValid(String s, ConstraintValidatorContext context) {
        if (s != null && s.trim().contains(" ")) {
            // 獲取默認提示信息
            String constraintMessageTemplate = context.getDefaultConstraintMessageTemplate();
            System.out.println(constraintMessageTemplate);

            // 禁用默認提示信息
            context.disableDefaultConstraintViolation();

            // 設置提示語
            context.buildConstraintViolationWithTemplate("Can not contain space").addConstraintViolation();
            return false;
        }
        return true;
    }
}

 

第一個泛型參數是表明校驗的注解類型,第二個泛型參數是需要被校驗的類型。

  • initialize:初始化事件方法
  • isValid:判斷是否合法的方法

ConstraintValidatorContext這個上下文包含了校驗中所有的信息,我們可以利用這個對象進行獲取默認錯誤提示信息,禁用錯誤提示信息,改寫錯誤提示信息等操作。

4. 使用

@NotContainSpace
private String name;

 

發送數據:

控制台輸出:

可以看到NotContainSpaceValidator的執行是先於處理器方法的,並且禁用默認提示語、設置新的提示語等操作都是有效的。

分組校驗

如果對同一個類,在不同的使用場景下有不同的校驗規則,就可以使用分組校驗。比如更新一條學生記錄時,要求 id 不為 null 且大於 0:

我們上面在對方法參數添加自動校驗時用的是@Valid注解,它是由 javax 提供的,其實 Spring Validation 校驗框架還提供了@Validated注解。在檢驗 Controller 的入參是否符合規范時,它們的基本驗證功能並沒有多大區別。但是,現在要進行分組校驗,就必須使用@Validated:

@PutMapping("/student")
public ApiResult updateStudent(@RequestBody @Validated({Student.Update.class}) Student student, BindingResult result) {
    if (result.hasErrors()) {
        for (ObjectError error : result.getAllErrors()) {
            // do stuff
        }
        return ApiResult.error();
    }
    studentService.update(student);
    return ApiResult.success();
}

 

不過注意,在@Validated中指定了分組,那么其他未分組的校驗將會被忽略。

關於更多 @Valid 和 @Validated 的區別,可見文末參考鏈接。

END

 

 

參考文章:https://www.cnblogs.com/zzzt20/p/12482979.html


免責聲明!

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



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