首页 文章

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

提问于
浏览
0

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

我为这个问题创建了一个精简的项目 .

你可以在这里查看: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;
    }
}

如果创建布尔值为true,则此序列提供程序将添加creatChild组 .

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

控制器mehtod:

@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>

1 回答

  • 2

    Documentation bean验证 @GroupSequence 状态:

    默认组序列覆盖是在其定义的类的本地,并且不会传播到关联的对象 . 对于该示例,这意味着将DriverChecks添加到RentalCar的默认组序列将不会产生任何影响 . 只有组Default才会传播到驱动程序关联 . 请注意,您可以通过声明组转换规则来控制传播的组

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

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

    这解决了当前场景的问题,但又产生了另一个问题:在另一个场景中,当您使用 Default group验证 ParentDto 时(当 createChild 为false时),它仍然会转换为 CreationCreation 组 . 因此,只有使用 groups = Creation.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;
    
        ...
    }
    

相关问题