首页 > 解决方案 > Spring 应用程序中的应用程序层

问题描述

我正在参与实现 REST API 应用程序,我们坚持将 Spring Boot 作为一个框架。

我们刚刚开始实施该系统,但即使在项目的这个阶段,它也开始觉得应用程序设计有问题。

我们的应用程序中有 3 层:

  1. 控制器层 - 在这一层我们(其中一些是由 spring 自动完成的):
    • 接收客户的请求
    • 将其转换为 dto 对象并验证此 dto
    • 将 dto 和登录的用户信息转换为某个对象或数据库实体 (!) 以调用服务层。
    • 将结果作为从某个对象或数据库实体(!)转换而来的 dto 对象返回给客户端
  2. 服务级别 - 在这一层,我们:
    • 执行所有业务逻辑,例如外部服务调用
    • 通过存储库层调用更改/创建/删除实体
    • 将业务逻辑的结果作为某个对象或 DB 实体对象(!)
  3. 存储库级别 - 在此级别,我们指定将数据库实体返回到服务级别的逻辑。
    • 对我们的数据库进行查询以获取实体并将其按原样返回给服务层

我对上述应用程序设计的担忧:

  1. 所有应用层都知道数据库实体
  2. 在实体具有延迟获取代理的情况下,至少控制会话、事务和所有东西应该是相当困难的。
  3. 不确定,如果我们需要,但我们可以引入某种类型的 ServiceDto,因此合同如下:
    • 控制器将经过验证的客户端 dto 转换为 ServiceDto,并将其作为输入调用服务层
    • Service 使用 ServiceDto 执行业务逻辑,并将业务操作和 ServiceDto 的结果转换为 DB 实体,并以此作为输入调用 Repository 层
    • 存储库接受数据库实体并像以前一样返回数据库实体
    • 这里唯一可能非常苛刻的是所有这些 DTO 之间的映射

查看某些类型的指南、最佳实践或项目将非常有帮助,这些指南、最佳实践或项目展示了如何在此类应用程序中组织应用程序层之间的通信。

非常感谢!

下面的补充

一些代码片段:

class OrderController {
    @Autowired
    private OrderService orderService;
    @Autowired
    private UserService userService;
    public OrderResultDto createOrder(OrderRequestDto dto) {
        return orderService.makeOrderRequest(userService.getAuthenticatedUser(), dto)
    }
}

class OrderService {
    @Autowired
    private OrderRepository orderRepo;

    public makeOrderRequest(User user, OrderRequestDto dto) {
        // do some complex business logic
    }
}

将我们发送到前端的 dto 作为 JSON 分配给 Service 合同似乎不太好……此外,如果我们需要从另一个方法调用此服务,该方法也将绑定到此 dto,这不好。

标签: javaspringspring-bootarchitectureapplication-design

解决方案


控制器层是面向 Web 的层。它的工作是接受输入,一般来说,将其转换为服务层使用的格式并调用服务。正如您所说,Spring 开箱即用地进行了这种转换,EG 根据控制器方法参数的类型将 JSON 建模为 DTO。

将 dto 和登录的用户信息转换为某个对象或数据库实体 (!) 以调用服务层。将结果作为从某个对象或数据库实体转换的 dto 对象返回给客户端(!)

这是抽象的差分离。例如,您将如何管理交易?将“实时”JPA 实体暴露给 Web 层也是危险的。此外,Web 只是您可能希望与服务交互的一种方式。如果您想使用 EG Quartz 作为计划作业运行您的服务会发生什么?从 JPA 实体到 DTO 的转换应该在服务层中完成,事务管理也应该如此。

将业务逻辑的结果作为某个对象或数据库实体对象(!)返回。同样,服务应该将实体映射到 DTO。不应该有对象从存储库泄漏到服务之外。

控制器可以与 DTO 进行自动对话,这可以是服务的输入/输出。EG 控制器接受 PersonDTO,Spring 使用 jsr-303 bean 验证执行到 DTO 的映射,使用 PersonDTO 调用服务,将 DTO 映射到实体,调用存储库层,将返回的实体映射到 DTO,然后返回DTO。

从你的问题来看,听起来你的想法是正确的。我唯一要问的是是否需要控制器 DTO 和服务 DTO。为此使用相同的类很好。


推荐阅读