使用 Spring Validator 介面實現驗證

banq發表於2024-07-16

Spring Validator介面提供了一種靈活且可自定義的方法來驗證物件。在本文中,我們學習如何使用Validator介面在基於 Spring 的應用程式中驗證物件。我們探索了Validator介面的兩種方法supports()和verify(),以及如何實現自定義驗證器來驗證物件。

什麼是Spring Validator介面
Validator介面是Spring 框架的一部分,它提供了一種驗證物件的方法。

它是一個簡單的介面,定義了兩個方法,supports()和verify()。這兩個方法用於確定驗證器是否可以驗證物件並執行驗證邏輯。 

支援(Class<?> clazz)
Validator介面中的 supports() 方法確定驗證器是否可以驗證特定類的例項。此方法接受一個引數Class<?> clazz,該參數列示被驗證物件的類。它是一個通用類 ( Class<?> ),可以靈活地處理不同的物件型別。

具體來說,Spring 使用isAssignableFrom()方法來檢查一個物件是否可以合法地轉換為驗證器支援的類的物件。因此,如果驗證器可以處理提供的clazz的物件,則返回true,否則,返回false以指示應使用另一個驗證器:

@Override
public boolean supports(Class<?> clazz) {
    return User.class.isAssignableFrom(clazz);
}

在此示例中,驗證器配置為僅支援驗證User型別或其子類的物件。方法isAssignableFrom()透過繼承驗證相容性 - 它對 User 及其子類返回true ,對任何其他類型別返回false。

驗證(物件目標,錯誤錯誤)
另一方面,validate()方法在 Spring 的驗證框架中起著至關重要的作用。我們在這裡為驗證器支援的物件定義自定義驗證邏輯。

該方法接收兩個關鍵引數:

  • Object target:此參數列示要驗證的實際物件。Spring MVC會自動將我們要驗證的物件傳遞給此方法。
  • Errors :此引數是Errors介面的一個例項。它提供了向物件新增驗證錯誤的各種方法。

以下是validate()方法的一個示例:

@Override
public void validate(Object target, Errors errors) {
    User user = (User) target;
    if (StringUtils.isEmpty(user.getName())) { 
        errors.rejectValue(<font>"name", "name.required", "Name cannot be empty"); 
    }
}

在此示例中,validate()方法對User物件執行各種驗證,並使用rejectionValue()將特定錯誤訊息新增到Errors物件以識別目標欄位錯誤。值得注意的是,rejectValue()有三個主要引數:
  • field:出現錯誤的欄位名稱,例如“ name ”
  • errorCode:標識錯誤的唯一程式碼,例如“ name.required ”
  • defaultMessage:如果未找到其他訊息,則顯示預設錯誤訊息,例如“名稱不能為空”

實現驗證器
要建立驗證器,我們需要實現Validator介面。下面是驗證User物件的簡單驗證器示例:

public class UserValidator implements Validator {
    @Override
    public boolean supports(Class<?> clazz) {
        return User.class.isAssignableFrom(clazz);
    }
    @Override
    public void validate(Object target, Errors errors) {
        User user = (User) target;
        if (StringUtils.isEmpty(user.getName())) {
            errors.rejectValue(<font>"name", "name.required", "Name cannot be empty");
        }
        if (StringUtils.isEmpty(user.getEmail())) {
            errors.rejectValue(
"email", "email.required", "Invalid email format");
        }
    }
}

建立使用者類
在應用驗證之前,必須定義我們要驗證的物件的結構。以下是User類的一個示例:

public class User {
    private String name;
    private String email;
    <font>// Getters and Setters<i>
}

配置 Spring Bean
接下來,為了將自定義驗證器整合到基於 Spring 的應用程式中,我們可以使用 Spring 配置類將其註冊為應用程式上下文中的 bean。此註冊可確保驗證器在整個應用程式生命週期內可用於依賴項注入:

@Configuration
public class AppConfig implements WebMvcConfigurer{
    @Bean
    public UserValidator userValidator() {
        return new UserValidator();
    }
}

透過用@Bean註釋userValidator()方法,我們確保它返回 Spring 在應用程式上下文中註冊為 bean 的物件。

在 Spring MVC 控制器中整合驗證器
一旦我們註冊了驗證器,我們就可以使用它來驗證Spring MVC 控制器中的使用者物件。

接下來我們建立一個UserController來處理與使用者相關的請求:

@RestController
@RequestMapping(<font>"/api/users")
public class UserController {
    @Autowired
    private UserValidator userValidator;
    @PostMapping
    public ResponseEntity<?> createUser(@RequestBody User user) {
        Errors errors = new BeanPropertyBindingResult(user,
"user");
        userValidator.validate(user, errors);
        if (errors.hasErrors()) {
            return ResponseEntity.badRequest().body(errors.getAllErrors());
        }
       
// Save the user object to the database<i>
        return ResponseEntity.ok(
"User created successfully!");
    }
}

在此示例中,我們使用 Spring 的@RestController註釋來指示此控制器返回JSON響應。此外,我們使用@RequestBody將傳入的 JSON 請求正文繫結到User物件。如果驗證失敗,我們將返回 400 Bad Request 響應,其 JSON 正文包含錯誤訊息。否則,我們將返回 200 OK 響應,其中包含成功訊息。

使用 Curl 進行測試
為了使用 curl 測試此 API,我們可以傳送包含User物件資料的 JSON 請求正文:

curl -X POST \
  http:<font>//localhost:8080/api/users \<i>
  -H 'Content-Type: application/json' \
  -d '{
"name":"","email":""}'

這應該返回一個 400 Bad Request 響應,其 JSON 主體包含錯誤訊息:

[
  {
    <font>"codes": [
     
"name.required.user.name",
     
"name.required.name",
     
"name.required.java.lang.String",
     
"name.required"
    ],
   
"arguments": null,
   
"defaultMessage": "Name cannot be empty",
   
"objectName": "user",
   
"field": "name",
   
"rejectedValue": "",
   
"bindingFailure": false,
   
"code": "name.required"
  },
  {
   
"codes": [
     
"email.required.user.email",
     
"email.required.email",
     
"email.required.java.lang.String",
     
"email.required"
    ],
   
"arguments": null,
   
"defaultMessage": "Invalid email format",
   
"objectName": "user",
   
"field": "email",
   
"rejectedValue": "",
   
"bindingFailure": false,
   
"code": "email.required"
  }
]

如果我們傳送一個帶有姓名和電子郵件的有效使用者物件,API 應該返回 200 OK 響應以及成功訊息:

curl -X POST \
  http:<font>//localhost:8080/api/users \<i>
  -H 'Content-Type: application/json' \
  -d '{
"name":"John Doe","email":"johndoe@example.com"}'

結果,請求返回了帶有成功訊息的響應:

<font>"User created successfully!"


驗證上下文
此外,在某些情況下,我們可能希望將其他上下文傳遞給驗證器。Spring的Validator介面透過validate(Object target, Errors errors, Object…validationHints)方法支援驗證上下文。因此,要使用驗證上下文,我們可以在呼叫validate()方法時傳遞其他物件作為驗證提示。

例如,我們想根據特定場景驗證使用者物件:

public void validate(Object target, Errors errors, Object... validationHints) {
    User user = (User) target;
    if (validationHints.length > 0) {
        if (validationHints[0] == <font>"create") {
            if (StringUtils.isEmpty(user.getName())) {
                errors.rejectValue(
"name", "name.required", "Name cannot be empty");
            }
            if (StringUtils.isEmpty(user.getEmail())) {
                errors.rejectValue(
"email", "email.required", "Invalid email format");
            }
        } else if (validationHints[0] ==
"update") {
           
// Perform update-specific validation<i>
            if (StringUtils.isEmpty(user.getName()) && StringUtils.isEmpty(user.getEmail())) {
                errors.rejectValue(
"name", "name.or.email.required", "Name or email cannot be empty");
            }
        }
    } else {
       
// Perform default validation<i>
    }
}

在此示例中,UserValidator檢查validationHints陣列以確定要使用哪種驗證方案。讓我們更新UserController以使用帶有validationHints的UserValidator:

@PutMapping(<font>"/{id}")
public ResponseEntity<?> updateUser(@PathVariable Long id, @RequestBody User user) {
    Errors errors = new BeanPropertyBindingResult(user,
"user");
    userValidator.validate(user, errors,
"update");
    if (errors.hasErrors()) {
        return ResponseEntity.badRequest().body(errors.getAllErrors());
    }
   
// Update the user object in the database<i>
    return ResponseEntity.ok(
"User updated successfully!");
}

現在,讓我們傳送以下curl命令,其中名稱和電子郵件欄位均為空:

curl -X PUT \
  http:<font>//localhost:8080/api/users/1 \<i>
  -H 'Content-Type: application/json' \
  -d '{
"name":"","email":""}'

UserValidator返回 400 Bad Request 響應並帶有錯誤訊息:

[
  {
    <font>"codes": [
     
"name.or.email.required.user.name",
     
"name.or.email.required.name",
     
"name.or.email.required.java.lang.String",
     
"name.or.email.required"
    ],
   
"arguments": null,
   
"defaultMessage": "Name or email cannot be empty",
   
"objectName": "user",
   
"field": "name",
   
"rejectedValue": "",
   
"bindingFailure": false,
   
"code": "name.or.email.required"
  }
]

如果我們只傳遞其中一個欄位,例如名稱欄位,那麼UserValidator允許更新繼續:

curl -X PUT \
  http:<font>//localhost:8080/api/users/1 \<i>
  -H 'Content-Type: application/json' \
  -d '{
"name":"John Doe"}'

響應是200 OK響應,表示更新成功:

"User updated successfully!"
 

相關文章