我在控制器中有一个端点处理程序方法:
@PutMapping("/users/{userId}")
public UserDto updateUser(@PathVariable UUID userId, @RequestBody UserRequestDto updateRequest) {
...
}
在UserRequestDto
对象中,我有一个email
字段。
我想验证email
值是否尚未使用。
创建不是问题,因为我只需要检查电子邮件是否不在数据库中。我创建了一个简单的ConstraintValidator,一切正常。
但是对于更新,我需要检查其他人是否未使用更新的电子邮件地址,并忽略当前更新的用户。因此,我需要同时在userId
和updateRequest
上进行操作。创建自定义ConstraintValidator来处理这种情况是否可行?
答案 0 :(得分:1)
自从您发布@RestController
中的代码以来,我假设我们正在谈论控制器级别的验证。我可以分享一些看法:
1)请注意,您正在尝试将与业务逻辑相关的验证放入ConstraintValidator
中。在您的情况下,它正在验证包含请求属性的数据传输对象(即UserRequestDto
)中的字段。在控制器级别,我们应该只验证请求本身(即“是否提供了所有必要的信息,这样我才能真正开始执行操作?”)。
2)因为对“有效”的理解很可能因业务用例而异,所以与业务逻辑相关的验证应放入@Service
bean中,在其中可以执行用例特定的验证(例如“是否还有其他具有相同用户名或电子邮件的用户?”)。大多数情况下,这是通过手动检查不同的条件来完成的,例如执行数据库查询或咨询其他应用程序。在这个级别上,ConstraintValidator
适得其反。
3)ConstraintValidator
大部分时间用于执行语法验证(即“所有必要的值都以预期的格式存在吗?”),但对于语义验证而言就不是那么多了(即“信息是根据我的业务逻辑(可能涉及数据库查询和咨询其他应用程序)正确吗?”。
因此,在您的情况下,如果需要检查客户端是否已以特定格式传递了所有必需的属性,则使用自定义UserRequestDto
来验证ConstraintValidator
对象是绝对可以的。但是,应该由逻辑层以用例特定的方式(在ConstraintValidator
之外)检查用户名/电子邮件是否已被另一个用户使用。
答案 1 :(得分:0)
我能想到的两种方法:
方法1:
在数据库架构中对电子邮件ID设置唯一约束。如果你 尝试保存/更新已使用的电子邮件ID,但违反了约束 将会引发异常。
方法2:
在研究上述主题时,我遇到了link。您 可以参考一次,看看您的需求是否足够。
答案 2 :(得分:0)
也许您可以使用类级约束:
访问更多详细信息最后但并非最不重要的一点,也可以在类级别上放置约束。在这种情况下,验证的对象不是单个属性,而是完整的对象。如果验证依赖于对象的多个属性之间的相关性,则类级约束很有用。
答案 3 :(得分:0)
您可以使用Spring的@Validated
注释您的控制器(类级别),然后@NotBlank @PathVariable String something
也可以使用。
Spring将围绕您的所有方法创建一个AOP代理,并在每个参数上查找JSR 303批注,但它不会触及@RequestBody
,因此对于正文,您仍然必须添加@Valid
,它将用标准方法检查。
另外,请参见此问题https://github.com/spring-projects/spring-framework/issues/26219