在Spring Boot中将实体与有效负载(dto)混合-最佳实践

时间:2018-12-06 12:18:09

标签: java spring-mvc spring-boot

将一个类同时作为实体(映射并存储在数据库中)和有效负载(对象序列化并从REST端点返回)是否是一种好习惯?

我听说某处实体永远都不应高于服务层,而应该映射到服务中的DTO对象,然后将这些DTO返回给控制器。

我个人认为这是不好的做法,因为在此类中,我们混合了用于序列化为JSON以及将对象映射到数据库的注释,这使得代码难以阅读。

但是也许还有其他一些争论。你觉得呢?

2 个答案:

答案 0 :(得分:1)

我个人认为,将各层分开是个好习惯。 我会激发以下动机。

假设您有一个客户,客户A。

客户A通过Restful端点集成到您的系统中,并需要帐户信息。您对Rest终结点进行版本控制,并返回已版本控制的Account实体。

@Entity
public class Account {
   private Long id;
   private String firstname;
   private String lastname;

   //Getters and setters are omitted for the sake of brevity
}

客户A对信息满意,并使用了6个月。

六个月后,您的数据库团队将开始清理/重构过程,并将姓氏更改为姓氏,将姓氏更改为name。 需要更改以下内容,因为它们都可能碰到对象:

  1. 数据库层
  2. 持久层
  3. 业务层
  4. 演示层

如您所见,小的更改会触发很多更改。 它还破坏了版本化的Restful端点的契约。

如果在业务层中将实体转换为DTO,则更改将包含在您的应用程序边界内,并且影响最小。合同也保持不变,并且客户方无需进行任何更改。

答案 1 :(得分:1)

每个案例都有自己的优点。但通常在实际情况下它们是不同的。

从概念上讲,除非您的服务确实是愚蠢的,否则您作为API公开的内容可能与您存储在数据库中的内容有所不同。

这三层是有原因分开的。

控制器用作接收特定格式请求的前端。它可以是来自RESTful请求的JSON有效负载,也可以是简单的普通旧表单提交。它对要传递给其他服务或组件的请求进行验证和预处理。

服务充当业务逻辑层。在请求中传递的内容不一定与该层处理的内容一一对应。它可能会调用其他服务,可能会将请求分解为较小的单独部分,甚至可能将请求排队以便稍后处理,这在CQRS类型的体系结构中通常会完成。它将接收到的请求转换为实体以传递到存储库。此外,该服务可能会从其他服务或多个控制器中使用。

存储库然后使用数据库实体及其关系来处理逻辑。它处理的实体将与数据库表更加对齐,并且在仍然是对象的同时,将具有更多的关系类型的设计。

您还需要记住的另一件事是内部实现和存储库的建模可能与API不同。创建一个抽象到正确级别的API,需要足够的技巧和精力,干净并且足够用户友好,并且大多数最佳实践建议实际上先进行“合同第一”,而又不要让API的实现影响您的DTO设计