SpringBoot 數據校驗

數據校驗是開發過程中一個常見的環節,一般來說,爲了提高系統運行效率,都會在前端進行數據校驗,但是這並不意味着不必在後端做數據校驗了,因爲用戶還是可能在獲取數據接口後手動傳入非法數據,所以後端還是需要做數據校驗。 Spring Boot 對此也提供了相關的自動化配置解決方案。

普通校驗

添加依賴:

<dependency>-->
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

項目創建成功後,查看 LocalValidatorFactoryBean 類的源碼,發現默認的 ValidationMessageSource (校驗出錯時的提示文件) 是 resources 目錄下的 ValidationMessages.properties 文件,因此在 resource 目錄下創建該文件:

user.name.size=用戶名長度介於 5 到 10 個字符之間
user.address.notnull=用戶地址不能爲空
user.age.size=年齡輸入不正確
user.email.notnull=郵箱不能爲空
user.email.pattern=郵箱格式不正確

接下來創建 User 類,配置數據校驗:

import javax.validation.constraints.*;

public class User {

    private Integer id;

    @Size(min = 5, max = 10, message = "{user.name.size}")
    private String name;

    @NotNull(message = "{user.address.notnull}")
    private String address;

    @DecimalMax(value = "200", message = "{user.age.size}")
    @DecimalMin(value = "1", message = "{user.age.size}")
    private Integer age;

    @Email(message = "{user.email.pattern}")
    @NotNull(message = "{user.email.notnull}")
    private String email;

    // 省略 getter / setter
}

代碼解釋:

  • @Size 表示一個字符串的長度或者一個集合的大小必須在某一個範圍中。min 參數表示範圍的下限,max參數表示範圍的上限,message 表示校驗失敗時的提示信息。
  • @NotNull 註解表示該字段不能爲空。
  • @DecimalMin 註解表示對應屬性值的下限,@DecimalMax 阻註解表示對應屬性值的上限。
  • @Email 註解表示對應屬性格式是一個 Email。

配置完成後,接下來創建 Controlle:

import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import xyz.ther.boot.validation.User;

import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("/validation")
public class UserValidationController {

    @PostMapping("/user")
    public List<String> addUser(@Validated User user, BindingResult bindingResult) {
        List<String> errors = new ArrayList<>();
        if (bindingResult.hasErrors()) {
            List<ObjectError> allErrors = bindingResult.getAllErrors();
            for (ObjectError error : allErrors) {
                errors.add(error.getDefaultMessage());
            }
        }
        return errors;
    }
}

代碼解釋:

  • 給 User 參數添加 @Validated 註解,表示需要對該參數做校驗,BindingResult 參數表示在校驗出錯時保存的出錯信息。
  • 如果 BindingResult 中的 hasErrors 方法返回 true,表示有錯誤信息,此時遍歷錯誤信息並返回給前端。

使用 Postman 進行測試,直接訪問接口:

[
    "郵箱不能爲空",
    "用戶地址不能爲空"
]

分組校驗

有的時候開發者在某一個實體類中定義了很多校驗規則 ,但是在某一次業務處理中並不需要這麼多校驗規時就可以使用分組校驗。步驟如下:

首先創建兩個分組接口:

public interface ValidationGroup1 {
}

public interface ValidationGroup2 {
}

然後在實體類中添加分組信息:

import javax.validation.constraints.*;

public class User {

    private Integer id;

    @Size(min = 5, max = 10, message = "{user.name.size}", groups = ValidationGroup1.class)
    private String name;

    @NotNull(message = "{user.address.notnull}", groups = ValidationGroup2.class)
    private String address;

    @DecimalMax(value = "200", message = "{user.age.size}")
    @DecimalMin(value = "1", message = "{user.age.size}")
    private Integer age;

    @Email(message = "{user.email.pattern}")
    @NotNull(message = "{user.email.notnull}", groups = ValidationGroup2.class)
    private String email;

    // 省略 getter / setter
}

這次在部分註解中添加了 groups 屬性,表示該校驗規則所屬的分組, 接下來在 @Validated 註解中指定校驗分組:

import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import xyz.ther.boot.validation.User;
import xyz.ther.boot.validation.ValidationGroup1;

import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("/validation")
public class UserValidationController {

    @PostMapping("/user")
    public List<String> addUser(@Validated(ValidationGroup1.class) User user, BindingResult bindingResult) {
        List<String> errors = new ArrayList<>();
        if (bindingResult.hasErrors()) {
            List<ObjectError> allErrors = bindingResult.getAllErrors();
            for (ObjectError error : allErrors) {
                errors.add(error.getDefaultMessage());
            }
        }
        return errors;
    }
}

測試請求中不包含 address 和 email 也不會產生錯誤信息。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章