51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

在 Spring 应用中的 Service 层进行验证

1、概览 {#1概览}

本文将带你了解如何在 Spring 应用的 Service 层中使用 Spring Validation 进行校验。

2、应用分层 {#2应用分层}

Spring Web 应用通常分为如下几层:

Java Web 应用的分层架构

Consumer 层或 Web 层是 Web 应用程序的最上层。它负责解析用户的输入并提供适当的响应。其他层抛出的异常也必须由 Web 层处理。由于 Web 层是应用程序的入口点,因此它负责身份认证,是防止未授权用户的第一道防线。

在 Web 层之下是 Service 层。它充当事务屏障,同时承载应用和基础设施服务。Service 层的公共 API 由应用服务提供。它们通常作为事务边界,并负责授权事务。基础设施服务提供与外部工具(包括文件系统、数据库和电子邮件服务器)连接的 "管道代码"。这些方法通常被多个应用服务使用。

Web 应用的最底层是持久层。换句话说,它负责与数据存储进行交互。

3、Service 层的验证 {#3service-层的验证}

Service 层是应用中的一个层,用于在 Controller 和持久层之间进行通信。此外,业务逻辑也存储在 Service 层中。其中特别包括验证逻辑。Model 状态用于 Controller 层和 Service 层之间的通信。

在业务层进行验证逻辑有其优点和缺点。Spring 的验证(和数据绑定)架构并不排除任何一种方式。验证未绑定在 Web 层,这易于本地化,并且允许使用任何可用的 Validator。

此外,客户端输入数据并不总是通过 REST Controller 处理,如果不在 Service 层进行验证,非法数据可能会通过,引发多个问题。

在这种情况下,可以使用标准的 Java JSR-303 验证方案。

4、示例 {#4示例}

使用 Spring Boot 开发一个简单的用户注册应用。

4.1、Domain {#41domain}

只有 nameagephonepassword 属性:

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;
    
    //构造函数、get、set 方法省略
}

在上述类中,使用了 @NotNull@Size@NotBlank@Min 这四个注解来确保输入属性既不是空的,也不是空白的,并且符合大小要求。

4.2、在 Service 层实现验证 {#42在-service-层实现验证}

有许多可用的验证解决方案。手动验证也是一个可行的选择,在将验证集成到应用的适当部分时,这提供了很大的灵活性。

在 service 类中实现验证:

@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());
            }
            throw new ConstraintViolationException("Error occurred: " + sb.toString(), violations);
        }

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

Validator 是 Bean Validation API 的一部分,负责验证 Java 对象。Spring 自动提供了一个 Validator 实例,可以将其注入到 UserAccountService 中。

Validator 通过 validate(...) 函数验证传递的对象。验证结果是一组 ConstraintViolation

如果没有违反验证约束(对象有效),则集合为空。否则,会抛出一个 ConstraintViolationException 异常。

4.3、实现 REST Controller {#43实现-rest-controller}

之后,构建 Spring REST Controller 类,将服务暴露给客户端,并对输入进行验证:

@RestController
public class UserAccountController {

    @Autowired
    private UserAccountService service;

    @PostMapping("/addUserAccount")
    public Object addUserAccount(@RequestBody UserAccount userAccount) {
        return service.addUserAccount(userAccount);
    }
}

在上述 REST Controller 中,没有使用 @Valid 注解来进行任何验证。

4.4、测试 Controller {#44测试-controller}

启动应用,使用 Postman 或其他 API 测试工具,将如下 JSON POSTlocalhost:8080/addUserAccount 端点:

{
   "name":"Baeldung",
   "age":25,
   "phone":"1234567890",
   "password":"test",
   "useraddress":{
      "countryCode":"UK"
   }
}

测试 OK,接着尝试 POST 一个包含非法参数值的 JSON,如下:

{
   "name":"",
   "age":25,
   "phone":"1234567890",
   "password":"",
   "useraddress":{
      "countryCode":"UK"
   }
}

参数校验失败,响应如下:

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

5、总结 {#5总结}

本文介绍了 Java Web 应用的分层,以及如何在 Service 层对参数进行手动验证。

在 Service / Business 层中,这种验证方法并不局限于方法参数,还可以应用于各种对象。例如,可以从数据库加载一个对象,对其进行更改,然后在继续之前对其进行验证。


Ref:https://www.baeldung.com/spring-service-layer-validation

赞(4)
未经允许不得转载:工具盒子 » 在 Spring 应用中的 Service 层进行验证