服务层是否应该接受来自控制器的 DTO 或自定义请求对象?

2024-02-11

正如标题所示,设计服务层时的最佳实践是什么?。我确实理解服务层应该始终返回 DTO,以便域(实体)对象保留在服务层中。但是控制器向服务层的输入应该是什么?

下面我提出三点我自己的建议:

方法一: 在此方法中,域对象 (Item) 保留在服务层内。

class Controller
{
    @Autowired
    private ItemService service;

    public ItemDTO createItem(IntemDTO dto)
    {
        // service layer returns a DTO object and accepts a DTO object
        return service.createItem(dto);
    }
}

方法二: 这是服务层接收自定义请求对象的地方。我在 AWS Java SDK 和 Google Cloud Java API 中广泛看到了这种模式

class Controller
{
    @Autowired
    private ItemService service;

    public ItemDTO createItem(CreateItemRequest request)
    {
        // service layer returns a DTO object and accepts a custom request object
        return service.createItem(request);
    }
}

方法三: 服务层接受 DTO 并返回域对象。我不喜欢这种方法。但它在我的工作场所被广泛使用。

class Controller
{
    @Autowired
    private ItemService service;

    public ItemDTO createItem(CreateItemRequest request)
    {
        // service layer returns a DTO object and accepts a DTO object
        Item item = service.createItem(request);
        return ItemDTO.fromEntity(item);
    }
}

如果上述所有 3 种方法都不正确或不是最佳方法,请就最佳实践向我提出建议。


从概念上讲,您希望能够跨表示层并通过不同的访问端口重用服务/应用程序层(例如控制台应用程序通过 Web 套接字与您的应用程序通信)。此外,您不希望每个域更改都冒泡到应用程序层之上的层中。

控制器在概念上属于表示层。因此,您不希望应用程序层耦合到控制器定义在同一概念层中定义的契约上。您也不希望控制器依赖于域,否则当域时它可能必须更改变化。

您需要一个解决方案,其中应用程序层方法契约(参数和返回类型)以任何 Java 本机类型或服务层边界中定义的类型表示。

如果我们采取IDDD 样本 https://github.com/VaughnVernon/IDDD_Samples/blob/master/iddd_collaboration/src/main/java/com/saasovation/collaboration/application/calendar/CalendarEntryApplicationService.java从Vaughn Vernon,我们可以看到他的应用程序服务方法契约是用Java原生类型定义的。鉴于他使用了 CQRS,他的应用程序服务命令方法也不会产生任何结果,但我们可以看到查询方式 https://github.com/VaughnVernon/IDDD_Samples/blob/master/iddd_collaboration/src/main/java/com/saasovation/collaboration/application/calendar/CalendarEntryQueryService.java返回应用程序/服务层包中定义的 DTO。

上面列出的 3 种方法哪些是正确的/错误的?

#1 和 #2 都非常相似,从依赖性的角度来看可能是正确的,只要ItemDto and CreateItemRequest在应用程序层包中定义,但我更喜欢#2,因为输入数据类型是根据用例命名的,而不是简单地根据它处理的实体类型命名:实体命名焦点更适合 CRUD,因此您可能会发现很难为在同一类型实体上运行的其他用例方法的输入数据类型找到好的名称。 #2 也通过 CQRS(命令通常发送到命令总线)而得到普及,但并非 CQRS 所独有。沃恩·弗农 (Vaughn Vernon) 在IDDD样本 https://github.com/VaughnVernon/IDDD_Samples/blob/master/iddd_identityaccess/src/main/java/com/saasovation/identityaccess/application/AccessApplicationService.java。请注意你所说的request通常被称为command.

然而,#3 并不理想,因为它将控制器(表示层)与域耦合在一起。

例如,某些方法接收 4 或 5 个参数。根据埃里克·埃文斯(Eric Evans)在《清洁代码》中的说法,必须避免这种方法。

这是一个很好的遵循准则,我并不是说这些示例无法改进,但请记住,在 DDD 中,重点是根据通用语言 (UL) 命名事物并尽可能严格地遵循它。因此,仅仅为了将论点组合在一起而将新概念强加到设计中可能是有害的。具有讽刺意味的是,尝试这样做的过程仍然可能提供一些好的见解,并允许发现可以丰富 UL 的被忽视和有用的领域概念。

PS:《Clean Code》的作者是 Robert C. Martin,而不是因蓝皮书而闻名的 Eric Evans。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

服务层是否应该接受来自控制器的 DTO 或自定义请求对象? 的相关文章

  • Outlook Rest 调用表单 angularjs

    使用 Outlook 我正在尝试创建事件 当我使用 POSTMAN 发送请求时 它工作正常 但 Angularjs 中的相同代码却不起作用 代码有什么问题 请帮忙 scope createEvents function var url ht
  • 使用 PayPal REST API,如何取消付款?

    使用 PayPal REST API 在客户点击 取消订单并返回网站 链接后 我似乎无法弄清楚如何取消付款 也许在生产模式下 PayPal 会自动取消这些付款 但在沙盒模式下它们似乎仍处于 已创建 状态 这一观察结果使我相信 我需要在返回网
  • 使用 Ruby Curb 传递 GET 参数

    我正在尝试使用 Curb curb rubyforge org 调用需要在 get 请求中提供参数的 RESTful API 我想获取一个像这样的URLhttp foo com bar xml bla blablabla 我希望能够做类似的
  • 如何使用 Hibernate 解决错误“由于启用了‘集合获取分页失败’而失败”?

    我正在尝试使用 Spring Data 查询数据库中表 Product 的前 5 个元素 然后是接下来的 5 个元素等 Pageable 但是我的表 产品 包含与另一个名为 公司 的表的关系 所以我需要做一个join fetch也可以获取公
  • REST 中子资源和路径变量冲突?

    设计路径解析可能含糊不清的 REST API 是否被认为是不好的做法 例如 GET animals id Returns the animal with the given ID GET animals dogs Returns all a
  • 使用 authlogic_api 进行 Rails REST API 访问

    我正在为 Steam 游戏编写 Rails 后端 API 该游戏只能通过 REST 调用访问 因此不需要特定于用户的身份验证 我正在努力实施authlogic api 插件 http github com phurni authlogic
  • Linq to SQL DTO 和复合对象

    我使用与其他人类似的方法将 LINQ 对象保留在 LINQ 数据提供程序中并返回 IQueryable 以允许过滤等 这对于按 ID 或其他属性过滤简单对象来说效果很好 但我遇到了问题由其他子对象组成的连接表对象 CoreDBDataCon
  • Laravel 中的 PATCH Ajax 请求

    是否可以向 Laravel 发出 Ajax PATCH 请求 或者我是否仅限于 POST Laravel 在输入隐藏字段中使用 PATCH 但是 我没有使用表单元素 只是在单击时 通过 Ajax 请求 应该部分更新记录的按钮 这条路线会是什
  • 在应用程序中注册API

    通过 django rest framework 我正在使用DefaultRouter 我想为多个应用程序提供 API 所以我的问题是我能否以 django 方式执行此操作 并将我的路由器注册放入每个应用程序 URLconf 中 并让它们显
  • 如何在没有可用行选择器的情况下为 APEX 21.1 REST 数据源设置数据配置文件

    我正在使用 APEX 21 1 并为 Web 服务创建了一个 REST 数据源 该服务以以下格式返回响应 1499040000000 A time stamp 0 01634790 A value etc 1499040000100 A t
  • 如何进行 REST 式更新?

    如果我有一个对象 请说Employee 我想提供两种不同的更新方式 更新绩效评级或更新联系信息 构建 API 的 REST 式方式是什么 我认为正确的方法是 POST 我担心的是 对于用户来说 首先获取对象的两个部分 绩效评级和联系信息 仅
  • 来自复杂对象的 spring RestTemplate POST 参数

    我正在尝试使用 postForObject 方法使用restTemplate 来测试我们的REST 服务 单元测试 Test public void testPostOrder String url BASE URL orders Orde
  • 如何触发应用程序通过 REST 服务获取数据?

    我正在寻找一种方法来触发应用程序从远程 REST 服务获取数据 该方法不需要轮询 iOS 推送通知似乎不是一个选项 因为它可以被用户停用 然而 我可能是错的 是否有最佳实践来完成此任务 实际上 推送通知是可行的方法 在 ios8 及更高版本
  • REST - 获取随机数 GET 还是 POST?

    应该如何在 REST 中正确实现随机数生成器 GET RANDOM or POST RANDOM 服务器每次返回不同的随机数 我可以看到这两种方式的论点 我想说这与返回的包含当前时间的页面相同 其中许多都是使用 GET 完成的 抽象地说 获
  • 使用 JWT 创建 PostMan GET 请求

    我是 PostMan 的新手 通常我使用curl 这是获得 JTW 的一个 curl X POST H X Requested With XMLHttpRequest H Content Type application json H Ca
  • 当会话令牌无效时,我应该使用什么状态代码?

    创建 Web 服务 RESTful 时 当会话令牌无效时我应该使用什么状态代码 目前我公司的人给我发了一个404 未找到 但我认为这是不正确的 因为资源存在 也许我应该使用 401 Unauthorized 你怎么认为 您建议我在这种情况下
  • 获取/发布到 RESTful Web 服务

    我需要从 VB6 对 RESTful Web 服务进行一些 GET 和 POST 操作 最好和最简单的方法是什么 您需要添加对 MSXML 库的引用 Dim sUrl As String Dim response As String Dim
  • 如何获取数组作为 GraphQL 解析器的输入

    我想得到一个字符串数组ids查询变量中的参数并在我的解析器中使用它 下面是我的代码 People resolver ts import Resolver Query Mutation Args from nestjs graphql imp
  • 在 Postman 中连接 ECONNREFUSED

    我试图通过邮递员测试我的 REST API 但收到以下错误 这是我编写的第一个 REST API 我对邮差很陌生 所以不确定我做错了什么 下面是我尝试使用此 URL 在邮递员中调用的代码 我在 URL 中传递两个日期参数 https loc
  • 如何在控制器、服务和存储库模式中使用 DTO

    我正在遵循控制器 服务和存储库模式 我只是想知道 DTO 在哪里出现 控制器应该只接收 DTO 吗 我的理解是您不希望外界了解底层域模型 从领域模型到 DTO 的转换应该发生在控制器层还是服务层 在今天使用 Spring MVC 和交互式

随机推荐

  • 在 Javascript 中,给定值,从对象字面量中查找名称

    我是 JavaScript 新手 试图找到一种更简单的方法来查找给定对象文字值的名称 e g var cars Toyata Camry Prius Highlander Honda Accord Civic Pilot Nissan Al
  • 从用户硬盘浏览并选择文件在 IE 中给出未定义

    当我使用输入按钮浏览用户计算机上的文件时 它适用于 FF IE9 和 Chrome 但是当我将文件传递给 IE9 中的 JS 函数时 我得到了未定义的结果 而它在 FF 和 Chrome 中工作得很好
  • 枚举的详尽 switch 语句的静态分析[重复]

    这个问题在这里已经有答案了 考虑以下代码 enum MyEnum A B C int foo MyEnum e switch e case A return 1 case B return 2 case C return 3 error m
  • MPAndoid 图表具有以下样式

    我在我的项目中使用 MPAndroid Chart 我想将 LineChart 的样式设置如下 基本上我想要所有 4 个象限和其他样式 如渐变颜色等 首先通过这样做来填充线条后面的颜色 dataset setDrawFilled true
  • 如何从 STL 容器中获取仅移动类型?

    让我们考虑一个std unordered set of std unique ptr
  • 保存文件后自动启动单元测试

    借助 Ruby on Rails 当我保存代码文件时 我可以使用自动测试来自动运行所有测试 此外 该框架仅启动受更改影响的测试 并通知我测试结果 我使用Eclipse进行java开发有类似的情况吗 我不想要为我生成测试的东西 它只是应该在正
  • 使用 PHP 检索文本区域的值

    有人可能知道如何使用 PHP 获取 HTML 文档中特定元素的值吗 我现在正在做的是使用file get contents从另一个网站提取 HTML 代码 该网站上有一个文本区域
  • 关闭模态并滚动到 div

    contact form click function html body animate scrollTop contact section offset top 2000 div class modal fade div class m
  • 在 ImageButton 中动态更改图像

    XML
  • 使用 Swift 推断类方法中的泛型类型

    泛型方法是否可以根据执行它的类来推断其类型 我使用 CoreData NSManagedObject 模型来存储和检索本地数据 并设法以一种易于阅读和可用的方式使所有内容通用 除了在一个地方 如果用户希望查询本地数据库以获取对象列表 他将编
  • 在c#中添加或删除新记录后刷新gridview

    我的页面上有一个网格 我需要刷新 gridview 添加和删除新记录 但它不是 这是代码 将行添加到 GridView private void AddClientToGrid int clientID int Parse ddlClien
  • <导航> 或 <菜单> (HTML5)

    W3Schools com 并且我很确定我记得看到过 W3C org 声明 menu 应用于工具栏菜单和列表表单控制命令 那么 我的主菜单应该使用哪一个呢 Nav or Menu 有关系吗 nav用于内部链接组 a元素 一般来说 这意味着链
  • PDFBox - 获取单词位置(而不仅仅是字符)

    是否可以使用 PDFBox 获取单词的位置 类似于 processTextPosition 似乎 processTextPosition 仅在单个字符上调用 将它们合并为单词的代码是 PDFTextStripper 在 规范化 中 方法的一
  • PHP SQL:如果变量为空则跳过查询部分的方法

    我正在编写一个查询 该查询使用搜索表单中的输入 其中品牌 类型和价格是可选输入字段 SELECT FROM database WHERE brand LIKE brand AND type LIKE type AND price LIKE
  • 配置选项错误:\377\376h

    我正在将我的系统设置为代码提交 但出现以下错误 我点击了以下链接 https docs aws amazon com codecommit latest userguide setting up ssh windows html https
  • 当服务器发送 HTML 而不是图像数据时,是否可以捕获失败的 IMG 加载?

    我有一个网站链接到其他网站上的不同图像 有时这些图像已被删除或域不再存在等 为了不显示这些图像并删除它们 我使用 jQuery 来执行此操作 catch image load errors img error function read o
  • Swift 1.2 中的 @noescape 属性

    Swift 1 2 中有一个新属性 在函数中带有闭包参数 正如文档所述 这表明 参数仅被调用 或作为 noescape 调用中的参数 这意味着它不能 比调用的生命周期更长 据我了解 在此之前 我们可以使用 weak self 不要让闭包有强
  • 如何从 TFS 控制下的项目中删除空文件夹?

    假设我有一个项目 MyLib 在该项目下 我创建了一个文件夹 例如Folder1 该文件夹下没有文件 该项目已连接到 TFS 然后我想删除这个文件夹Folder1 我从上下文菜单中删除了它 并将项目签入 TFS 然后我使用 Team Exp
  • 传递给函数的原始变量名? [复制]

    这个问题在这里已经有答案了 可能的重复 PHP 获取作为参数传递的变量的名称 https stackoverflow com questions 2379166 php get name of variable passed as argu
  • 服务层是否应该接受来自控制器的 DTO 或自定义请求对象?

    正如标题所示 设计服务层时的最佳实践是什么 我确实理解服务层应该始终返回 DTO 以便域 实体 对象保留在服务层中 但是控制器向服务层的输入应该是什么 下面我提出三点我自己的建议 方法一 在此方法中 域对象 Item 保留在服务层内 cla