服務層中的Spring Validation

1.**概述**

在本教程中,我們將討論 Java 應用程序服務層中的 Spring 驗證。儘管Spring Boot 支持與自定義驗證器的無縫集成,但執行驗證的事實上的標準是Hibernate Validator

在這裡,我們將學習如何將我們的驗證邏輯從控制器中移到一個單獨的服務層中。此外,我們將在 Spring 應用程序的服務層中實現驗證。

2. 應用分層

根據需求,Java 業務應用程序可以採用多種不同的形式和類型。例如,我們必鬚根據這些標準確定我們的應用程序需要哪些層。除非有特定需求,否則許多應用程序不會從服務或存儲庫層增加的複雜性和維護成本中受益。

我們可以通過使用多層來解決所有這些問題。這些層是:

服務層中的Spring

消費者層或 Web 層是 Web 應用程序的最頂層。它負責解釋用戶的輸入並提供適當的響應。其他層拋出的異常也必須由 web 層處理。由於 web 層是我們應用程序的入口點,它負責身份驗證並作為防止未經授權用戶的第一道防線。

web層下面是Service層。它充當事務屏障並容納應用程序和基礎設施服務。此外,服務層的公共 API 由應用服務提供。它們通常作為交易邊界並負責授權交易。基礎設施服務提供連接到外部工具(包括文件系統、數據庫和電子郵件服務器)的“管道代碼”。這些方法通常由多個應用程序服務使用。

Web 應用程序的最低層是持久層。換句話說,它負責與用戶的數據存儲進行交互。

3.**服務層驗證**

服務層是應用程序中促進控制器和持久層之間通信的層。此外,業務邏輯存儲在服務層中。它特別包括驗證邏輯。模型狀態用於在控制器和服務層之間進行通信。

將驗證視為業務邏輯有利有弊,Spring 的驗證(和數據綁定)架構也不排除這兩種情況。驗證尤其不應綁定到 Web 層,應易於本地化,並應允許使用任何可用的驗證器。

此外,客戶端輸入數據並不總是通過 REST 控制器進程,如果我們不在服務層進行驗證,不可接受的數據可能會通過,從而導致幾個問題。在這種情況下,我們將使用標準的 Java JSR-303 驗證方案

4.**例子**

讓我們考慮一個使用 Spring Boot 開發的簡單用戶帳戶註冊表。

4.1.簡單域類

首先,我們將只有姓名、年齡、電話和密碼屬性:

public class UserAccount {



 @NotNull(message = "Password must be between 4 to 15 characters")

 @Size(min = 4, max = 15)

 private String password;



 @NotBlank(message = "Name must not be blank")

 private String name;



 @Min(value = 18, message = "Age should not be less than 18")

 private int age;



 @NotBlank(message = "Phone must not be blank")

 private String phone;



 // standard constructors / setters / getters / toString

 }

在這裡,在上面的類中,我們使用了四個批註- @NotNull@Size@NotBlank@Min -確保輸入的屬性既不是空也不空,堅持尺寸要求。

4.2.在服務層實現驗證

有許多驗證解決方案可用,Spring 或 Hibernate 處理實際驗證。另一方面,手動驗證是一種可行的替代方法。在將驗證集成到我們應用程序的正確部分時,這為我們提供了很大的靈活性。

接下來,讓我們在服務類中實現我們的驗證:

@Service

 public class UserAccountService {



 @Autowired

 private Validator validator;



 @Autowired

 private UserAccountDao dao;



 public String addUserAccount(UserAccount useraccount) {



 Set<ConstraintViolation<UserAccount>> violations = validator.validate(useraccount);



 if (!violations.isEmpty()) {

 StringBuilder sb = new StringBuilder();

 for (ConstraintViolation<UserAccount> constraintViolation : violations) {

 sb.append(constraintViolation.getMessage());

 }

 dao.addUserAccount(useraccount);

 throw new ConstraintViolationException("Error occurred: " + sb.toString(), violations);

 }

 return "Account for " + useraccount.getName() + " Added!";

 }

 }

Validator是 Bean Validation API 的一部分,負責驗證 Java 對象。此外,Spring 自動提供了一個Validator實例,我們可以將其註入到我們的UserAccountServiceValidator validate(..)函數中傳遞的對象。結果是一Set ConstraintViolation

如果沒有違反驗證約束(對像有效),則Set為空。否則,我們會拋出ConstraintViolationException

4.3.實現 REST 控制器

在此之後,讓我們構建 Spring REST Controller 類以向客戶端或最終用戶顯示服務並評估應用程序的輸入驗證:

@RestController

 public class UserAccountController {



 @Autowired

 private UserAccountService service;



 @PostMapping("/addUserAccount")

 public Object addUserAccount(@RequestBody UserAccount userAccount) {

 return service.addUserAccount(userAccount);

 }

 }

我們沒有在上面的 REST 控制器表單中@Valid

4.4.測試 REST 控制器

現在,讓我們通過運行 Spring Boot 應用程序來測試這個方法。之後,使用 Postman 或任何其他 API 測試工具,我們將 JSON 輸入發佈到localhost:8080/addUserAccount URL:

{

 "name":"Baeldung",

 "age":25,

 "phone":"1234567890",

 "password":"test",

 "useraddress":{

 "countryCode":"UK"

 }

 }

在確認測試成功運行後,讓我們現在檢查驗證是否按預期工作。下一個合乎邏輯的步驟是使用少量無效輸入來測試應用程序。因此,我們將使用無效值更新我們的輸入 JSON:

{

 "name":"",

 "age":25,

 "phone":"1234567890",

 "password":"",

 "useraddress":{

 "countryCode":"UK"

 }

 }

控制台現在顯示錯誤消息,因此, 我們可以看到 Validator 的使用對於驗證是多麼重要

Error occurred: Password must be between 4 to 15 characters, Name must not be blank

5. 優點和缺點

在服務/業務層,這通常是一種成功的驗證方法。它不限於方法參數,可以應用於各種對象。例如,我們可以從數據庫加載一個對象,更改它,然後在繼續之前驗證它。

我們也可以使用這個方法進行單元測試,這樣我們就可以實際模擬 Service 類。為了便於在單元測試中進行真正的驗證,我們可以手動生成必要的Validator實例

這兩種情況都不需要在我們的測試中引導 Spring 應用程序上下文。

六,結論

在本快速教程中,我們探索了 Java 業務應用程序的不同層。我們學習瞭如何將我們的驗證邏輯從控制器中移到一個單獨的服務層中。此外,我們實現了一種在 Spring 應用程序的服務層中執行驗證的方法。