”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 如果跳过 DTO 会发生什么

如果跳过 DTO 会发生什么

发布于2024-08-02
浏览:752

What can happen if you skip the DTOs

像SpringBoot这样的框架可以为你做很多事情,这真是太好了。

您只需要一个 JPA 实体类加上一个简单的存储库接口,SpringData 将为您提供典型 CRUD 数据库操作所需的一切。

您编写了一个简单的 REST 控制器类,并且运行了一个 REST API,对吧?

嘿,但是你忘记写 DTO 了!但是,当您的应用程序无需它也可以运行时,为什么您实际上需要它?

当然有一些一般原因:

  • 分层结构(例如六边形架构或端口和适配器):为了可维护性,最好将外部通信代码与核心(业务逻辑)解耦
  • 安全性和性能:如果您按原样在 API 中公开数据库结构,您很快就会达到公开超出需要的程度;可能被恶意行为者滥用或浪费资源(CPU、内存和网络带宽)
  • DTO 与 JPA 实体不同,可以是不可变的(您可以使用 Java 记录),这有利于数据驱动(函数式)编程风格、良好的单元测试、更安全的并发性等。

但是其他奇怪的事情也可能发生。我将根据我的经验向您展示一个奇怪的例子。

此 GitHub 存储库包含一个无需 DTO 即可运行的简单应用程序。有一个User实体,每个User可以有多个Transaction。我们甚至在存储库和 RestController 之间有一个 Service bean,用于捕获可能的数据库访问异常。

由于我们想要制作一个可用于生产的应用程序,因此我们不希望 Hibernate 生成 DDL。相反,我们有一个 schema.sql 来创建表(稍后我们可能会切换到 Flyway 或 Liquibase)。对于我们的简单示例,我们还有一个 data.sql,以便我们的表不为空。

当我们运行应用程序并调用 http://localhost:8080/users 处的 API 端点时,我们会得到包含用户及其交易的预期 JSON。

现在我们关注Transaction类中的两行代码,标记为//!!

@JsonIgnore //!!

第一个味道是,在 Transaction 类中,我们必须将 @JsonIgnore 注释添加到 User 引用中。如果没有该注释,JSON 序列化会因无限递归而崩溃。

现在让我们想象一下,有人在向 Transaction 实体添加另一个字段(描述)时犯了一个错误,但忘记调整 SQL 语句(或者在尚未应用架构更改的环境中运行应用程序)。

私有字符串描述;//!!

当然,现在API调用失败了。但看看错误处理! UserService 内的 catch 子句未按预期工作。相反,我们可以在日志中看到奇怪的堆栈跟踪:
GlobalExceptionHandler:意外错误org.springframework.http.converter.HttpMessageNotWritableException:无法写入JSON:

我曾经见过这种情况(显然,应用程序比这个示例大得多),我花了很长时间才理解为什么 SQL 异常逃逸了服务以及为什么我收到 HttpMessageNotWritableException。你能看见它吗?

发生的情况是,UserService 类(通过 UserRepository)仅查询 USERS 数据库表。由于默认的 Hibernate 延迟加载,事务实体不是结果的一部分。仅当 Jackson 反序列化器尝试从 User 实例创建 JSON 时,它才会调用其 getTransactions 方法,使 Hibernate 获取 Transaction 实体。

这就是为什么我们得到一个奇怪的堆栈跟踪,结合了 JSON 和 SQL 的内容。该异常被 GlobalExceptionHandler 捕获,但不知道如何处理它,这就是日志消息为“意外错误”的原因。

我希望这个小练习能让您更深入地了解允许应用程序的不同层混合是多么危险。在应用程序还很小的时候只看到应用程序的“晴天”场景可能会导致一些开发人员继续做错误的事情,直到为时已晚。

您不必编写在 DTO 和应用程序的其他层之间映射字段的样板代码。 MapStruct 可以为您做到。

版本声明 本文转载于:https://dev.to/marianvarga/what-can-happen-if-you-skip-the-dtos-aaj?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 弃用 `ereg_replace` 后,如何将多个空格替换为单个空格?
    弃用 `ereg_replace` 后,如何将多个空格替换为单个空格?
    用单个空格替换多个空格:弃用 ereg_replace虽然使用 ereg_replace 用单个空格替换多个空格可能看起来很简单,但它已被弃用。因此,您在尝试使用它时可能会遇到错误。本文提出了一种替代解决方案。迁移到 preg_replace()要替换 ereg_replace,请切换到 preg_...
    编程 发布于2024-11-06
  • 如何开始自由职业?
    如何开始自由职业?
    您是否正在努力通过 Upwork 赚钱?别担心!我曾经去过那里,我来这里是为了分享我将这些挣扎转化为成功的旅程。凭借奉献精神和正确的方法,您可以开始在 Upwork 上赚钱,并打开通往一系列机会的大门。让我们深入探讨最大化您的收入潜力的关键步骤。 掌握技巧游戏 在 Upwork 上取...
    编程 发布于2024-11-06
  • 如何将 8 个字符作为打包单精度浮点数加载到 __m256 变量中?
    如何将 8 个字符作为打包单精度浮点数加载到 __m256 变量中?
    将 8 个字符从内存加载到 __m256 变量中作为打包单精度浮点数为了优化高斯模糊算法,您寻求用 __m256 内在变量替换浮点缓冲区的使用。本问题旨在确定此任务的最佳指令。AVX2 架构说明:利用 PMOVZX 将字符零扩展为 32 位256b 寄存器中的整数。使用 VCVTDQ2PS 就地转换...
    编程 发布于2024-11-06
  • 如何在Python中查找字符串中子字符串的第n次出现?
    如何在Python中查找字符串中子字符串的第n次出现?
    查找字符串中某个子字符串第 n 次出现识别某个子字符串第 n 次出现对应的索引为各种编程场景中经常出现的任务。在Python中,没有专门为此目的而设计的内置函数。但是,可以采用多种方法来实现此结果。一种简单的方法是使用循环来迭代字符串并计算子字符串的出现次数。起始索引被初始化为第一次出现的结果,循环...
    编程 发布于2024-11-06
  • 编程语言解释
    编程语言解释
    ? 注意:缩略图是使用生成的 ComfyUI 帮助下的 Flux Schnell 模型; 本文是在 NI - 自然智能 的帮助下撰写的 ? 没有时间阅读? - 观看我们创建的视频: 集会 ? 最初所有程序都是用二进制编写的 - 所谓的汇编 编程语言。你从字面上指示CPU在内做什么 ...
    编程 发布于2024-11-06
  • Go Context — TODO() 与 Background() 不再令人困惑!
    Go Context — TODO() 与 Background() 不再令人困惑!
    在 Go 中,上下文包有助于管理请求范围的值、取消信号和截止日期。 启动上下文的两种常见方法是 context.TODO() 和 context.Background()。 尽管它们的行为相似,但它们的目的不同。 上下文.背景() 当您不需要任何特殊处理(例如取消或截止日期)...
    编程 发布于2024-11-06
  • 如何检测 CMake 中的 C++11 编译器支持?
    如何检测 CMake 中的 C++11 编译器支持?
    CMake 中 C 11 编译器支持的检测概述在本指南中,我们探索自动检测编译器是否支持 C 11 的方法CMake,提供对最新和以前 CMake 版本的全面分析。CMake 3.1.0 及更高版本CMake 3.1.0 版本引入了一个强大的功能:检测编译器。这是通过 cmake_minimum_r...
    编程 发布于2024-11-06
  • 基于属性的测试:深入探讨现代测试方法
    基于属性的测试:深入探讨现代测试方法
    基于属性的测试是一种强大的测试方法,它侧重于软件的属性或特征,而不是特定的输入输出情况。与手动定义特定测试用例的传统测试不同,基于属性的测试会自动生成各种输入来验证某些属性是否始终成立。这种方法可以更广泛地探索潜在场景,使其成为发现隐藏错误并确保稳健的软件行为的有效方法。 测试方法的演变 从传统的...
    编程 发布于2024-11-06
  • 为开发人员和安全团队提供主动的 AppSec 持续漏洞管理
    为开发人员和安全团队提供主动的 AppSec 持续漏洞管理
    现代软件开发环境中哪些日益增长的网络安全风险让 CISO 忙碌? 开发人员和安全团队面临着越来越多的威胁,从复杂的开源和供应商控制的供应链攻击到 AI 生成的代码引入的漏洞,例如提示注入和 GitHub Copilot 的代码安全性差。现代应用程序通常严重依赖开源组件(例如在 npm、PyPI 或 ...
    编程 发布于2024-11-06
  • 如何使用 React 对 MeteorJS 中的 Bootstrap Spacing 实用程序类进行故障排除?
    如何使用 React 对 MeteorJS 中的 Bootstrap Spacing 实用程序类进行故障排除?
    在 Bootstrap 中使用间距实用程序类在 Bootstrap 中,间距实用程序类允许您轻松控制元素周围的间距。但是,如果您在使用它们时遇到问题,这里有一个指南可以帮助您解决。更新的间距语法(Bootstrap 4 和 5)Bootstrap 4 引入了间距实用程序类的简化语法:边距:m{sid...
    编程 发布于2024-11-06
  • 如何在Python中设置子进程的工作目录?
    如何在Python中设置子进程的工作目录?
    如何在Python中设置子进程的工作目录在Python中,subprocess.Popen()函数允许您在Py​​thon中执行命令子进程。一个常见的要求是指定子进程的工作目录。问题:如何使用 subprocess.Popen() 设置子进程的工作目录? 答案:要指定工作目录,请使用 subproc...
    编程 发布于2024-11-06
  • Pandas 什么时候创建视图而不是副本?
    Pandas 什么时候创建视图而不是副本?
    Pandas 视图与副本生成规则Pandas 在决定 DataFrame 上的切片操作是否产生视图或结果时采用特定规则复制。通过了解这些规则,您可以优化数据操作并避免意外行为。从始终生成副本的操作开始:所有操作,除了那些专门设计用于修改的操作就地 DataFrame,创建副本。只有某些操作支持 in...
    编程 发布于2024-11-06
  • 使用代理服务器解锁地理限制网站
    使用代理服务器解锁地理限制网站
    利用代理服务器绕过区域封锁是一种常用且有效的方法。代理服务器作为中介,可以隐藏用户的真实IP地址,使用户的请求看起来像是来自代理服务器的地理位置,从而绕过区域封锁。 使用代理服务器绕过区域封锁的关键步骤:‌‌ 选择合适的代理服务器‌:根据目标区域的网络环境和遮挡情况,选择覆盖该区域的...
    编程 发布于2024-11-06
  • 如何为三角形中的线性渐变锯齿线创建平滑边缘?
    如何为三角形中的线性渐变锯齿线创建平滑边缘?
    为线性渐变锯齿线创建平滑边缘为了设计具有由两个三角形形成的尖底的响应式图像,开发人员在三角形线上遇到了意外的锯齿状边缘。为了解决这个问题,我们探索了产生更平滑渐变过渡的策略。虽然硬停止线性渐变图像中的颜色通常会导致锯齿状边缘,但调整停止点和起始点可以缓解此问题。不要突然从一种颜色变为另一种颜色,而是...
    编程 发布于2024-11-06
  • Java 中“static”的魔力:一为所有,一切为一!
    Java 中“static”的魔力:一为所有,一切为一!
    老实说,当我们第一次遇到 static 关键字时,我们都会想:“这是什么魔法?” ?但别担心,我会用一种简单、深入、甚至有点有趣的方式来分解它! 想象一下你正在参加一个聚会?你和你所有的朋友都戴着帽子。但每个人都必须分享一顶帽子。这基本上就是 Java 中 static 关键字的作用!您不必为每个朋...
    编程 发布于2024-11-06

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3