如何在春季的一个ConstraintValidator中同时验证@PathVariable和@RequestBody?

时间:2019-11-15 05:58:57

标签: java spring validation bean-validation

我在控制器中有一个端点处理程序方法:

@PutMapping("/users/{userId}")
public UserDto updateUser(@PathVariable UUID userId, @RequestBody UserRequestDto updateRequest) {
  ...
}

UserRequestDto对象中,我有一个email字段。

我想验证email值是否尚未使用。

创建不是问题,因为我只需要检查电子邮件是否不在数据库中。我创建了一个简单的ConstraintValidator,一切正常。

但是对于更新,我需要检查其他人是否未使用更新的电子邮件地址,并忽略当前更新的用户。因此,我需要同时在userIdupdateRequest上进行操作。创建自定义ConstraintValidator来处理这种情况是否可行?

4 个答案:

答案 0 :(得分:1)

自从您发布@RestController中的代码以来,我假设我们正在谈论控制器级别的验证。我可以分享一些看法:

1)请注意,您正在尝试将与业务逻辑相关的验证放入ConstraintValidator中。在您的情况下,它正在验证包含请求属性的数据传输对象(即UserRequestDto)中的字段。在控制器级别,我们应该只验证请求本身(即“是否提供了所有必要的信息,这样我才能真正开始执行操作?”)。

2)因为对“有效”的理解很可能因业务用例而异,所以与业务逻辑相关的验证应放入@Service bean中,在其中可以执行用例特定的验证(例如“是否还有其他具有相同用户名或电子邮件的用户?”)。大多数情况下,这是通过手动检查不同的条件来完成的,例如执行数据库查询或咨询其他应用程序。在这个级别上,ConstraintValidator适得其反。

3)ConstraintValidator大部分时间用于执行语法验证(即“所有必要的值都以预期的格式存在吗?”),但对于语义验证而言就不是那么多了(即“信息是根据我的业务逻辑(可能涉及数据库查询和咨询其他应用程序)正确吗?”。

因此,在您的情况下,如果需要检查客户端是否已以特定格式传递了所有必需的属性,则使用自定义UserRequestDto来验证ConstraintValidator对象是绝对可以的。但是,应该由逻辑层以用例特定的方式(在ConstraintValidator之外)检查用户名/电子邮件是否已被另一个用户使用。

答案 1 :(得分:0)

我能想到的两种方法:

方法1:

  

在数据库架构中对电子邮件ID设置唯一约束。如果你   尝试保存/更新已使用的电子邮件ID,但违反了约束   将会引发异常。

方法2:

  

在研究上述主题时,我遇到了link。您   可以参考一次,看看您的需求是否足够。

答案 2 :(得分:0)

也许您可以使用类级约束:

  

最后但并非最不重要的一点,也可以在类级别上放置约束。在这种情况下,验证的对象不是单个属性,而是完整的对象。如果验证依赖于对象的多个属性之间的相关性,则类级约束很有用。

您可以从https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/?v=6.1#validator-usingvalidator-classlevel

访问更多详细信息

答案 3 :(得分:0)

您可以使用Spring的@Validated注释您的控制器(类级别),然后@NotBlank @PathVariable String something也可以使用。

Spring将围绕您的所有方法创建一个AOP代理,并在每个参数上查找JSR 303批注,但它不会触及@RequestBody,因此对于正文,您仍然必须添加@Valid,它将用标准方法检查。

另外,请参见此问题https://github.com/spring-projects/spring-framework/issues/26219