來咯來咯!2021年,開發者對SpringBoot中實現約束驗證,你懂得多少|牛氣沖天新年徵文

前言

首先呢,先祝你們新年快樂!!牛年大吉!!html

咱們如今開啓咱們新一年的學習吧。今天,咱們將聊一下在Springboot應用程序中驗證數據的經常使用實現。java

Hibernate驗證器

通常實現是經過使用Bean驗證API進行驗證。Bean驗證API的參考實現是Hibernate驗證器。spring

全部必需的依賴項都打包在springbootstarter POM springbootstarter驗證中。所以,一般您只須要開始如下依賴關係:數據庫

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>
複製代碼

驗證約束是經過使用適當的Bean驗證註解對字段進行註解來定義的。例如:編程

public class Address {
 
    @NotBlank
    @Size(max = 50)
    private String street;
 
    @NotBlank
    @Size(max = 50)
    private String city;
 
    @NotBlank
    @Size(max = 10)
    private String zipCode;
     
    @NotBlank
    @Size(max = 3)
    private String countryCOde;
 
    // getters + setters
}
複製代碼

對於這些註解的做用是顯而易見的。咱們將在下面的許多示例中使用到這個Address類。springboot

能夠在Bean驗證文檔中找到內置約束註解的完整列表。markdown

若是有須要,經過建立自定義約束驗證器來定義本身的驗證約束。app

請求數據驗證

在使用Springboot構建RestAPI接口時,大多時候須要驗證傳入的請求數據。這能夠經過簡單地將@Valid註解添加到@RequestBody方法參數來完成。框架

例如:函數

@RestController
public class AddressController {
 
    @PostMapping("/address")
    public void createAddress(@Valid @RequestBody Address address) {
        // ..
    }
}
複製代碼

經過@Valid註解,就開啓了數據約束驗證。

Spring如今根據先前定義的約束自動驗證傳遞的Address對象。

這種類型的驗證一般用於確保客戶端發送的數據語法正確。若是驗證失敗,則不調用控制器方法,並向客戶端返回HTTP 400(錯誤請求)響應。更復雜的特定於業務的驗證約束一般應該稍後在業務層中檢查。

持久層數據驗證

在Springboot應用程序中使用關係數據庫時,持久層採用了Hibernate框架,也會支持驗證。Hibernate支持Bean驗證。若是實體包含Bean驗證註解,則在持久化實體時會自動檢查這些註解。

請注意,持久層絕對不該該是驗證的惟一位置。若是驗證在這裏失敗,一般意味着其餘應用程序組件中缺乏某種驗證。持久層驗證應該被視爲最後一道防線。除此以外,持久性層對於與業務相關的驗證來講一般爲時已晚。

方法參數驗證

Spring提供了對於方法參數的數據約束驗證。經過向方法參數添加Bean驗證註解。而後,Spring使用AOP攔截器在調用實際方法以前驗證參數。

例如:

@Service
@Validated
public class CustomerService {
 
    public void updateAddress( @Pattern(regexp = "\\w{2}\\d{8}") String customerId, @Valid Address newAddress ) {
        // ..
    }
}
複製代碼

另外,這種方法對於驗證進入服務層的數據很是有用。可是,在使用這種方法以前,應該瞭解它的侷限性,由於這種類型的驗證只有在涉及Spring代理時纔有效。

同時須要注意,這種方法會使單元測試變得更困難。

編程方式觸發Bean驗證

在上述的驗證方案中,實際的驗證是由Spring或Hibernate觸發的。不少時候,咱們須要根據合適時機,靈活觸發Bean驗證。

下面,咱們嘗試用編程方式,觸發對於Bean驗證。

咱們首先建立一個驗證Facade bean:

@Component
public class ValidationFacade {
 
    private final Validator validator;
 
    public ValidationFacade(Validator validator) {
        this.validator = validator;
    }
 
    public <T> void validate(T object, Class<?>... groups) {
        Set<ConstraintViolation<T>> violations = validator.validate(object, groups);
        if (!violations.isEmpty()) {
            throw new ConstraintViolationException(violations);
        }
    }
}
複製代碼

這個bean接受一個驗證器做爲有參構造函數。驗證器是Bean驗證API的一部分,負責驗證Java對象。

在validate(..)方法中,咱們使用驗證器來驗證傳遞的對象。結果是一組約束衝突。若是未違反任何驗證約束(=對象有效),則集合爲空。不然,咱們拋出一個約束衝突異常。

咱們如今能夠將咱們的驗證門面注入到其餘bean中。例如:

@Service
public class CustomerService {
 
    private final ValidationFacade validationFacade;
 
    public CustomerService(ValidationFacade validationFacade) {
        this.validationFacade = validationFacade;
    }
 
    public void updateAddress(String customerId, Address newAddress) {
        validationFacade.validate(newAddress);
        // ...
    }
}

複製代碼

爲了驗證一個對象Address(這裏是新地址),咱們只需調用validate(..)方法。固然,咱們也能夠將驗證器直接注入到咱們的客戶服務中。可是,在驗證錯誤的狀況下,咱們一般不但願處理返回的約束衝突集。相反,咱們可能只想拋出一個異常,這正是驗證門面所作的。

一般,這是在服務/業務層進行驗證的好的一種實現。它不只限於方法參數,並且能夠用於不一樣類型的對象。例如,咱們能夠從數據庫中加載一個對象,修改它,而後在繼續以前驗證它。

這種方法對於單元測試也很好,由於咱們能夠簡單地模擬驗證門面。若是咱們想在單元測試中進行真正的驗證,能夠手動建立所需的驗證器實例。

驗證內部業務類

咱們能夠對實際的業務Bean對象進行建立時的動態驗證。

在DDD領域驅動設計開發時,採用動態驗證比較重要。例如,在建立地址實例時,構造函數能夠確保咱們不能構造無效的對象:

public class Address {
 
    @NotBlank
    @Size(max = 50)
    private String street;
 
    @NotBlank
    @Size(max = 50)
    private String city;
 
    ...
     
    public Address(String street, String city) {
        this.street = street;
        this.city = city;
        ValidationHelper.validate(this);
    }
}

複製代碼

在這裏,構造函數調用靜態validate(..)方法來驗證對象狀態。這個靜態validate(..)方法與前面在ValidationFacade中顯示的方法相似:

這裏的區別是,咱們沒有經過Spring檢索驗證程序實例。相反,咱們使用如下方法手動建立:

Validation.buildDefaultValidatorFactory().getValidator()
複製代碼

經過這種方式,咱們能夠直接將驗證集成到域對象中,而無需依賴外部人員來驗證對象。

總結

今天咱們聊了下,在Springboot應用程序中處理驗證的不一樣方法。

不一樣的使用,根據具體的業務須要,咱們實際去作本身的開發策略。

好了,今天聊天結束。新的一年,你們也要好好學習哦!

相關文章
相關標籤/搜索