【问题标题】:SpringBoot Bean Validation annotationSpring Boot Bean 验证注解
【发布时间】:2020-10-19 09:13:18
【问题描述】:

我目前正在为服务中的 bean 验证编写一些 @SpringBootTest。

@Data
@Document
public final class Supplier {

    @Id
    @NotEmpty
    private String supplierId;
    ...
    @NotEmpty
    private String hash;
    ....
}

测试

注释:

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = {Application.class}, webEnvironment = SpringBootTest.WebEnvironment.MOCK)

 @Test
    void testValidation() {
        Supplier invalidSupplier = SupplierTestDataUtil.createSupplier("1234");
        invalidSupplier.setSupplierId(null);

        //works
        assertThrows(ConstraintViolationException.class, () -> supplierService.publish(invalidSupplier));

        //works
        assertThrows(ConstraintViolationException.class, () -> supplierService.persist(invalidSupplier));
        
        //works not
        assertThrows(ConstraintViolationException.class, () -> supplierService.saveAndPublish(invalidSupplier));

        //works
        assertThrows(ConstraintViolationException.class, () -> supplierService.delete(invalidSupplier));
    }

服务:

@Transactional
public Supplier saveAndPublish(@NotNull Supplier supplier) {
    supplier.setHash(messageDigester.digest(supplier));
    Supplier persisted = persist(supplier);
    publish(supplier);
    return persisted;
}

@Transactional
public Supplier persist(@Valid @NotNull Supplier supplier) {
    return repository.save(supplier);
}

此时 saveAndFlush 的供应商必须无效,因为将在该方法中生成并设置所需的哈希值。 尽管如此,我的期望是 ConstraintViolationException 也会被抛出,因为我还调用了 persist 和 publish 方法并传递了该无效文档。

我的意思是你可以在同一个类中绕过 BeanValidation。

【问题讨论】:

    标签: java spring spring-boot bean-validation


    【解决方案1】:

    ConstraintViolationException 将由 Spring Validator 抛出,如果您“手动”调用 persist,则不会使用该 persist。如果从 Spring 上下文调用 persist@Valid 注释将告诉 Spring 根据类的验证约束来验证对象。

    你可以:

    1. 始终“手动”验证hash(不带@NotEmpty 注释)
    2. 在调用saveAndPublish之前调用supplier.setHash(messageDigester.digest(supplier));并将@Valid注解添加到Supplier参数saveAndPublish
    3. 将 Validator 实例作为字段添加到您的服务中,并在要验证的供应商上手动调用它(当然,在设置哈希后是 saveAndPublish
    4. 实现两种不同类型的Supplier,例如AddSupplier(未验证hash;由saveAndPublish使用)和EditSupplier(已验证hash;由persist使用)

    (这可能是一个不完整的列表)

    【讨论】:

    • 这真的让基于注释的验证对我来说毫无用处。我想实现始终验证输入参数的“安全”方法,并且我不想关心这个方法是从我的类内部还是外部调用的。所以我认为我需要使用注入的验证器手动验证。可惜
    • 好吧,如果您使用两个不同的供应商实现以及相关案例的特定验证约束 (4.),那么您确实有安全的方法。您可以定义一个通用接口、一个抽象类或一个非抽象、非最终基类,并在此基础上实现或扩展不同的实现。
    • 是的 - 这个特定问题有多种解决方案。如果你使用基于注解的 bean 验证,我仍然不满意我发现你可以绕过类内部的验证。
    • 我认为最好的解决方案是手动触发验证,正如您在 3 中提到的那样。仍然对这种混合解决方案(基于注释和手动)不满意,但我认为它最适合这种情况。
    猜你喜欢
    • 1970-01-01
    • 2020-12-21
    • 1970-01-01
    • 2022-01-01
    • 2022-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-14
    相关资源
    最近更新 更多