java—SpringBoot中实体与有效负载(dto)的混合—最佳实践

ar7v8xwq  于 2021-06-30  发布在  Java
关注(0)|答案(2)|浏览(394)

一个类同时是实体(Map并存储在数据库中)和负载(对象序列化并从rest端点返回)是一种好的做法吗?
我在某个地方听说,实体永远不应该高于服务层,而应该Map到服务中的dto对象,然后这些dto应该返回给控制器。
我个人认为这是一种不好的做法,因为在这样的类中,我们混合了用于序列化为json的注解和用于将对象Map到数据库的注解,这使得代码很难阅读。
但也许还有其他的论点。你怎么认为?

kd3sttzy

kd3sttzy1#

每个案子都有它的优点。但通常在现实情况下,它们是不同的。
从概念上讲,作为api公开的内容可能与存储在数据库中的内容不同,除非您的服务是一个非常愚蠢的服务。
这三层被分开是有原因的。
控制器充当接收特定格式请求的前端。它可以是restful请求的json负载,也可以是简单的普通旧表单提交。它对要传递给其他服务或组件的请求执行验证和预处理。
服务充当业务逻辑层。请求中传递的内容不一定是一对一Map到该层中处理的内容。它可能会调用其他服务,它可能会将请求分解为更小的独立部分,甚至可能会将请求排队等待以后的处理,这在cqrs类型的体系结构中是典型的。它可能会将接收到的请求转换为实体以传递给存储库。此外,该服务可能从其他服务或多个控制器使用。
然后,存储库处理数据库实体及其关系的逻辑。它处理的实体将与数据库表更加一致,并且在仍然是对象的情况下,将具有更多的关系型设计。
您必须记住的另一件事是,内部实现和存储库的建模方式可能与api不同。创建一个抽象到适当级别、足够干净和用户友好的api需要大量的技巧和注意,大多数最佳实践都建议,在不让api的实现影响dto设计的情况下,实际执行这个“契约优先”。

z9smfwbn

z9smfwbn2#

我个人认为把这些层分开是一个很好的做法。我会用以下几点来激励你。
假设你有一个客户,客户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个月。
6个月后,您的数据库团队开始清理/重构过程,并将lastname更改为姓氏,firstname更改为name。以下内容需要更改,因为它们都可能接触到对象:
数据库层
持久层
业务层
表示层
正如你所看到的,微小的变化会引发很多变化。它还破坏了版本化restful端点的契约。
如果实体被转换为dto,比如说在业务层,那么更改将包含在应用程序边界内,并且影响最小。合同也保持原样,客户方无需更改。

相关问题