当前位置: 首页 > 知识库问答 >
问题:

级联bean验证2.0不使用映射内的嵌套对象

史懿轩
2023-03-14

虽然,这个问题已经得到了回答,但我很感兴趣为什么@验证需要用于Map的工作级联验证

更新2:为了更深入地理解,我找到了这些帖子(一、二和三),其中解释了@Validated需要激活方法级验证。借助于此,集合可以被验证,因为它们不是经过验证的JavaBean(JSR 303)。

解决方案:我已经用工作代码示例更新了我的代码片段和我的存储库。我所要做的就是用@Valated注释我的控制器,并在员工中添加一些getter。Method odValidationPostProcess根本不需要。

更新:我更新了我的问题和分叉的Spring Boot Rest示例,以添加一个最小的Rest API来演示:

Github回购。示例值在自述文件中。md!

我有一个Spring Boot 2 API来存储一些员工。我可以传递一个员工或映射

@Validated //this is the solution to activate map validation
@RestController
class EmployeeController {

  @PostMapping("/employees")
  List<Employee> newEmployee(@RequestBody @Valid Employee newEmployee) {
     ...
  }

  @PostMapping("/employees/bulk")
  List<Employee> newEmployee(@RequestBody Map<String, @Valid Employee> 
  newEmployees) {
     ...
  }
}

雇员存在一些内部静态类,也需要验证:

public class Employee {

    @NotBlank
    public final String name;
    @Valid
    public final EmployeeRole role;

    @JsonCreator
    public Employee(@JsonProperty("name") String name,
        @JsonProperty("role") EmployeeRole role) {

        this.name = name;
        this.role = role;
    }

    // getters

    public static class EmployeeRole {

        @NotBlank
        public String rolename;

        @Min(0)
        public int rating;

        @JsonCreator
        public EmployeeRole(@JsonProperty("rolename") String rolename,
            @JsonProperty("rating") int rating) {

            this.rolename = rolename;
            this.rating = rating;
        }

        // getters
    }
}


目前,单个请求的验证正在工作,但不适用于我的批量请求。据我所知,这应该可以通过Bean验证2.0实现。

你知道我做错了什么吗?我需要编写自定义验证器吗?


共有2个答案

胡锋
2023-03-14
匿名用户

在spring系统中有两种验证。

  • A: spring boot controller方法参数验证,仅适用于控制器中的http post请求正文数据,且有效或已验证

我们可以看到A更窄,而B更常见。我想从两个方面回答这个问题。

正如这篇文章中描述的,更详细的部分,A和B通过调用org.hibernate.validator.internal.engine.ValidatorImpl中的不同方法通过aop触发方法增强,这导致了差异。

  • 通过RequestResponseBodyMethodProcessor调用ValidatorImpl中的validate方法

它们是不同的方法,具有不同的功能,因此会导致不同的结果。你可以通过阅读这两种方法找到答案。

JSR-303定义了我们上面讨论的方法的函数。

验证方法部分解释了验证方法,实现必须遵守验证例程中定义的逻辑,其中它声明将对对象的所有可达字段执行所有约束验证,这就是为什么List对象(或其他集合实例)的元素无法通过此方法进行验证-集合的元素不是集合实例的字段。

但是,JSR-303实际上并没有将其作为主要主题,并将其放在附录C中。方法级验证建议。它提供了一些描述:

The constraints declarations evaluated are the constraints hosted on the parameters of the method or constructor. If @Valid is placed on a parameter, constraints declared on the object itself are considered.

validateReturnedValue evaluates the constraints hosted on the method itself. If @Valid is placed on the method, the constraints declared on the object itself are considered.

public @NotNull String saveItem(@Valid @NotNull Item item, @Max(23) BigDecimal price)

In the previous example,

- item is validated against @NotNull and all the constraints it hosts
- price is validated against @Max(23)
- the result of saveItem is validated against @NotNull

并惊叹Bean验证提供者可以自由地将此方案作为特定的扩展来实现。据我所知,Hibernate验证项目实现了这个方法,使约束作用于对象本身和集合对象的元素。

我不知道为什么Spring框架的家伙会在Request est响应体方法处理器中调用validateParamete,使得stackoverflow中出现了很多相关的问题。也许只是因为超文本传输协议post body数据通常是表单数据,自然可以用java bean来表示。如果是我,我会在Request est响应体方法处理器中调用validateParamete以方便使用。

潘意
2023-03-14

要使其正常工作,您必须执行以下操作:

将MethodValidationPostProcessor添加到配置中

@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
    return new MethodValidationPostProcessor();
}

将已验证的添加到您的员工控制器

@Validated
@RestController
public class EmployeeController {}'

将有效的添加到地图或员工

public List<Employee> newEmployee(@RequestBody @Valid Map<String, Employee> newEmployees) {}   
public List<Employee> newEmployee(@RequestBody Map<String, @Valid Employee> newEmployees) {}

这就是全部。这是完整的员工控制器:

@Validated
@RestController
public class EmployeeController {

    @PostMapping("/employees")
    public List<Employee> newEmployee(@RequestBody @Valid Employee newEmployee) {
        return Collections.singletonList(newEmployee);
    }

    @PostMapping("/employees/bulk")
    public List<Employee> newEmployee(@RequestBody @Valid Map<String, Employee> newEmployees) {
        return new ArrayList<>(newEmployees.values());
    }
}

和SpringBoot配置文件

@SpringBootApplication
public class Application extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        return new MethodValidationPostProcessor();
    }

}

希望对你有帮助。

 类似资料:
  • 我创建映射如下所示。如何将平面dto对象属性(街道、城市等)映射到域对象中的嵌套地址。当我试着去做的时候,我发现了一个错误: [错误]诊断:返回类型中的属性“Address.PostalCode”未知。@Mapping(来源=“City”,目标=“Address.City”), 还有类...

  • 我试图通过将请求参数直接绑定到用户实体来简化我的代码,而不是一个字段一个字段地复制值,但是我似乎不能通过这种方式得到验证。 控制器: 验证器: 模型(注意嵌套对象用@Valid标注): 问题是只有密码和重新密码字段被正确验证,用户类中的验证注释被忽略,任何密码匹配的请求都通过,但它应该会出现错误。空密码或不同的密码会按预期出现错误。

  • 我的问题是如何将对象包含嵌套对象映射到DTO,而不是嵌套对象的值,例如,如果有2个这样的类: 调用TestClassDTOToTestClass()并发送TestClassDTO包含NestedClassDTO.之后。。返回的TestClass为空NestedClass。。有没有可能不用自己编写地图绘制程序来绘制地图? 嘘

  • 我试图动态解析一些JSON到一个Map 但是当我尝试使用一些更复杂的JSON和嵌套信息时失败了。我试图从json解析示例数据。组织 我得到以下错误 异常在线程"main"com.fasterxml.jackson.databind.JsonMapping异常:不能反序列化实例的java.lang.字符串START_OBJECT令牌 有没有办法将复杂的JSON数据解析成映射?

  • 我不确定如何将嵌套的结果集映射到域实体中。 以下是我想做的事情的大概想法: 2张桌子 域实体(包含嵌套列表) LoanEntity.java Book.java 持久实体 Loans.java Dao.xml(不知道如何映射它,尝试使用一个) 注意:此查询将复制找到的#本书的记录。 LoanMapper.java 下面的错误是我得到的: 错误:结果类型中的未知属性“books.bookName”c

  • 我如何在下面的场景中使用Mapstruct进行bean映射。 现在我想把sourceId映射到targetId,courseName映射到subjectName,studentName映射到memberName(list到list)。