如何将@ConvertGroup 与@GroupSequenceProvider 一起使用
How to use @ConvertGroup with @GroupSequenceProvider
我正在尝试使用 @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 注释应该在子级验证中通过 The 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})
添加到此 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;
}
}
如果创建布尔值为真,此序列提供程序将添加 creatChild 组。
我确实通过将字符串 属性 添加到带有 @NotEmpty(groups = CreateChild.class)
的 parentDto 来测试 groupSequenceProvider。这引发了验证错误,因此我知道已提供该组。
控制器方法:
@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 为真时,childDto 中的名称 属性 未被验证。
我错过了什么?
下面的 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
class 而不是 ChildDto
。因此 ChildDto
只能看到默认组。所以组转换规则必须是:
@Valid
@ConvertGroup(from= Default.class , to = Creation.class)
private ChildDto childDto;
这解决了当前场景的问题,但产生了另一个问题:在另一个场景中,当您使用 Default
组验证 ParentDto
时(当 createChild
为 false 时),它仍然得到ChildDto
转换为 Creation
组。结果只有用 groups = Creation.class
注释的验证得到验证,我认为这不是你打算做的(在那种情况下)。
一般来说,我不推荐您目前尝试验证 classes 的方式。要么使用 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;
...
}
我正在尝试使用 @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 注释应该在子级验证中通过 The 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})
添加到此 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;
}
}
如果创建布尔值为真,此序列提供程序将添加 creatChild 组。
我确实通过将字符串 属性 添加到带有 @NotEmpty(groups = CreateChild.class)
的 parentDto 来测试 groupSequenceProvider。这引发了验证错误,因此我知道已提供该组。
控制器方法:
@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 为真时,childDto 中的名称 属性 未被验证。
我错过了什么?
下面的 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
class 而不是 ChildDto
。因此 ChildDto
只能看到默认组。所以组转换规则必须是:
@Valid
@ConvertGroup(from= Default.class , to = Creation.class)
private ChildDto childDto;
这解决了当前场景的问题,但产生了另一个问题:在另一个场景中,当您使用 Default
组验证 ParentDto
时(当 createChild
为 false 时),它仍然得到ChildDto
转换为 Creation
组。结果只有用 groups = Creation.class
注释的验证得到验证,我认为这不是你打算做的(在那种情况下)。
一般来说,我不推荐您目前尝试验证 classes 的方式。要么使用 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;
...
}