java - 如何将@ConvertGroup与@GroupSequenceProvider一起使用

标签 java spring spring-boot bean-validation hibernate-validator

我正在尝试使用 @ConvertGroup 对我的 Spring Boot 项目进行一些级联验证,但它似乎不起作用。谁能告诉我我做错了什么?

我已经为这个问题创建了一个精简的项目。

您可以在这里查看: https://github.com/ericbv/cascadingValidationConvertGroupSpringBoot

我的表单有以下 DTO:

父Dto

@GroupSequenceProvider(ParentGroupSequenceProvider.class)
public class ParentDto {

    @Valid
    @ConvertGroup(from= CreateChild.class , to = Creation.class)
    private ChildDto childDto;

    private boolean createChild;

    public ChildDto getChildDto() {
        return childDto;
    }

    public void setChildDto(ChildDto childDto) {
        this.childDto = childDto;
    }

    public boolean isCreateChild() {
        return createChild;
    }

    public void setCreateChild(boolean createChild) {
        this.createChild = createChild;
    }
}

根据我的理解,如果在验证父项时存在 CreateGroup 组,则 ConvertGroup 注释应该在子项验证中通过 CreationGroup。 (该组将由 ParentGroupSequenceProvider 提供。

以及子对象:

public class ChildDto {
    @NotEmpty(groups = Creation.class)
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

如果创建组存在,则名称不能为空。我通过将 @GroupSequence({ChildDto.class,Creation.class}) 添加到此类的顶部来对此进行了测试,这导致了验证错误。

父 DTO 具有以下组序列提供程序:

public class ParentGroupSequenceProvider implements DefaultGroupSequenceProvider<ParentDto> {

    static Logger log = Logger.getLogger(ParentGroupSequenceProvider.class.getName());
    @Override
    public List<Class<?>> getValidationGroups(ParentDto parentDto) {
        List<Class<?>> sequence = new ArrayList<Class<?>>();

      /*
       * must be added to the returned list so that the validator gets to know
       * the default validation rules, at the very least.
       */
        sequence.add(ParentDto.class);

        if (parentDto == null)
            return sequence;
      /*
       *  Here, we can implement a certain logic to determine what are the additional group of rules
       *  that must be applied.
       */
        if(parentDto.isCreateChild()){
            sequence.add(CreateChild.class);
            log.info("Added CreateChild to groups");

        }

        return sequence;
    }
}

如果创建 boolean 值为 true,则该序列提供程序将添加 creatChild 组。

我通过使用@NotEmpty(groups = CreateChild.class)向parentDto添加字符串属性来测试groupSequenceProvider。这引发了验证错误,因此我知道已提供该组。

Controller 方法:

@RequestMapping(value = "/test",method = RequestMethod.POST)
public String doPost(@Valid ParentDto parentDto, BindingResult bindingResult){
    if(bindingResult.hasErrors()){
        bindingResult.getAllErrors().forEach( error-> log.error(error));
        return "redirect: /error";
    }else{
        return "redirect: /";
    }

}

问题是当表单提交并且 createChild 为 true 时,childDto 中的 name 属性未经过验证。

我错过了什么?

Pom 文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.test</groupId>
    <artifactId>valid-testing</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>valid-testing</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-el</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

最佳答案

Documentation bean 验证的 @GroupSequence 状态:

The Default group sequence overriding is local to the class it is defined on and is not propagated to associated objects. For the example this means that adding DriverChecks to the default group sequence of RentalCar would not have any effects. Only the group Default will be propagated to the driver association.

Note that you can control the propagated group(s) by declaring a group conversion rule

@GroupSequenceProvider 也是如此。在您的示例中,@GroupSequenceProvider 仅影响其目标 ParentDto 类,而不影响 ChildDto。因此 ChildDto 只能看到默认组。所以组转换规则必须是:

@Valid
@ConvertGroup(from= Default.class , to = Creation.class)
private ChildDto childDto;

这解决了当前场景的问题,但产生了另一个问题:在另一个场景中,当您使用 Default 组验证 ParentDto 时(当 createChild为 false),它仍然会转换为 ChildDtoCreation 组。结果,只有用 groups = Creation.class 注释的验证才会得到验证,我认为这不是您打算做的(在这种情况下)。

一般来说,我不推荐您当前尝试验证类(class)的方式。要么使用 Validator 并根据 createChild 字段的值手动调用不同组的验证,或者在 ParentController 中编写两个不同的方法(一个用于当子进程时)应该创建一个用于另一种情况)并使用 @Validated与合适的群体。

第一种方式如下:

public class ParentController{

    @Autowired
    Validator validator;
    ...

    @RequestMapping(value = "/test",method = RequestMethod.POST)
    public String doPost(ParentDto parentDto, BindingResult bindingResult){
        if(parentDto.isCreateChild()) {
            ValidationUtils.invokeValidator(validator, parentDto, bindingResult, Creation.class);
        } else {
            ValidationUtils.invokeValidator(validator, parentDto, bindingResult);
        }
        if(bindingResult.hasErrors()){
        ...
        }
    }
 }

ParentDto中:

// No GroupSequenceProvider here
public class ParentDto {

    @Valid
    private ChildDto childDto;

    ...
}

关于java - 如何将@ConvertGroup与@GroupSequenceProvider一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44629118/

相关文章:

Java 正则表达式验证特殊字符

java - Struts 2 中的格式编号 <s :property/> tag

java - Spring 测试模拟 findById 不工作

spring - 为存储库配置 beans 文件

java - PostgreSql 失败的 Spring Boot 数据源自动配置

spring-boot - Gradle无法同步Spring Boot项目

java - Tomcat URL 认证例如 : https://user:password@app. wibble.com

spring-boot - 如何将base64转换为java中的MultipartFile

spring-boot - Jprofiler不会在应用程序崩溃时分离

java - 这是 JAVA_OPT JVM 标志吗?