我们得到了这个设计: 休息控制器 - >呼叫服务 - >调用JPA DAO
让我们说救员工。我们有要求验证员工姓名。
IEmployeeService.saveEmployee(Employee emp) EmployeeController.saveEmployee(Employee emp)
选项1:我可以在Employee上注入JSR303注释,让Rest Rest Controller将其作为自动验证的一部分进行验证。
选项2:我在服务方法中验证并引发异常,让控制器返回该异常的正确JSON。
似乎服务应该进行验证...但是在JSR303注释控制器存在的情况下,控制器正在做所有事情,因此如果服务也进行了这些检查,那么似乎存在重复逻辑。
你怎么接近?欢迎大家的评论,我们将不胜感激。
由于 巴巴尔
答案 0 :(得分:0)
恕我直言,标准方法是使用选项1和选项2。
但是,你必须定义每层中要验证的内容。
这是我最喜欢的方法:
一方面注意:实体永远不应该暴露在外面。我们应该有某种转换器逻辑将实体转换为输出JSON / model
答案 1 :(得分:0)
理想情况下,面向Web的部分应该实现验证逻辑。服务层应该纯粹用于项目的业务部分。在达到您的服务层代码之前,它也是安全性最佳实践。如今人们会混淆层,想要在同一层做所有事情。 jsr-303
注释是bean级别验证。所以通常它应用于模型进入画面的地方。
所以你可以在
那样做javax.validation.Validator
在服务层进行任何特定验证。答案 2 :(得分:0)
我会做两件事。
在您的示例中,您似乎有两个方法都引用Employee
,这在非常简单的场景中可能是可能的,但在实际情况下,这不是。
您更有可能拥有一个{J}属性映射到Java对象字段的EmployeeDTO
。您甚至可能具有针对特定员工操作的更具体的DTO(例如更改密码),具体取决于您的UI所公开的形式。这将由您的控制器接收,并且JSR303可以帮助执行语法验证,例如检查字符串不为空,名称不包含数字等。
DTO不应该渗透到服务中,但是它的数据应该转换为服务期望的任何内容,这应该与控制器的输入分离。
您的服务将收到Employee
。如果它是有意义的,则可以是JPA实体,或者与正在执行的操作相关的一些其他中间域对象。理想情况下,Employee
的创建应该已经强制执行一些简单的检查(例如非空检查),以确保在构造之后对象是一致的。然后,服务本身应该验证它接收的内容,而不管控制器验证的内容。该服务可以由其他控制器使用,或者将来由其他服务调用,因此您应该始终以防御性方式进行编程。该服务还可以进行更多逻辑检查(例如,是否存在具有相同ID但存在不同详细信息的另一名员工?等等)这将进行业务逻辑验证,从而强制执行更强大的功能。
如果您在DTO和实体或中间对象之间看到很多公共代码,那么还有mapper实用程序库可以帮助您避免重复,例如MapStruct。