来咯来咯!2021年,开发者对SpringBoot中实现约束验证,你懂得多少

前言

首先呢,先祝大家新年快乐!!牛年大吉!!

我们现在开启我们新一年的学习吧。今天,我们将聊一下在Springboot应用程序中验证数据的常用实现。

Hibernate验证器

一般实现是通过使用Bean验证API进行验证。Bean验证API的参考实现是Hibernate验证器。

所有必需的依赖项都打包在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类。

可以在Bean验证文档中找到内置约束注解的完整列表。

如果有需要,通过创建自定义约束验证器来定义自己的验证约束。

请求数据验证

在使用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应用程序中处理验证的不同方法。

不同的使用,根据具体的业务需要,我们实际去做自己的开发策略。

好了,今天聊天结束。新的一年,大家也要好好学习哦!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小隐乐乐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值