在Spring项目中DTO层的作用和最佳实践

 更新时间:2026年02月27日 09:53:27   作者:知我Deja_Vu  
本文介绍了DTO(Data Transfer Object)在Spring项目中的作用和最佳实践,通过本文,读者可以更好地理解DTO在Spring项目中的重要性和如何合理设计DTO以满足业务需求,感兴趣的朋友跟随小编一起看看吧

DTO(Data Transfer Object)中需要传递的数据并非固定,而是根据业务场景接口需求来判断的。核心原则是:只传递必要的数据,避免冗余或敏感信息。以下从具体场景和判断方法两方面详细说明:

一、DTO传递数据的核心原则

  • 按需传递:只包含接口所需的字段,不多不少。
    • 例如:创建用户接口只需传递用户名、密码、邮箱,无需传递用户ID(数据库自增)或创建时间(系统自动生成)。
  • 隔离数据:避免直接暴露数据库表结构(POJO/Entity)。
    • 例如:用户表可能有password字段,但查询用户列表的响应DTO不应包含该字段(敏感信息)。
  • 适配接口:同一实体在不同接口中可能需要不同的DTO。
    • 例如:用户实体的创建接口需要password,但查询接口不需要;详情接口可能包含更多字段(如注册时间),而列表接口只需要ID和用户名

二、不同类型DTO的传参判断(结合场景)

DTO通常分为请求DTO(RequestDTO)响应DTO(ResponseDTO),两者的设计逻辑不同:

1. 请求DTO(接收客户端参数)

作用:定义客户端需要传递给后端的参数,用于接口输入。
判断依据:后端接口处理业务时,必须依赖哪些参数?

  • 必填字段:业务逻辑必须的参数(如创建订单时的商品ID、数量)。
  • 可选字段:非必须但能优化功能的参数(如分页查询时的页码、每页条数,默认有值则可选)。
  • 禁止传递
    • 系统自动生成的字段(如ID、createTime)。
    • 后端可推导的字段(如当前登录用户ID,应从令牌中获取,而非客户端传递,避免篡改)。
    • 敏感字段(如用户角色ID,若客户端无需指定,则不允许传递)。

示例
创建运营商的BillerCreateRequestDTO需要传递:

// 必须传递:业务需要的核心信息
private String billerCode; // 运营商编码(业务唯一标识)
private String name;       // 运营商名称
private String contact;    // 联系人(非必须,但业务可能需要)
private String phone;      // 联系电话(非必须)
// 禁止传递:系统自动处理的字段
// private Long id;          // 数据库自增,无需客户端传
// private Integer status;   // 默认为"待审批",后端固定赋值

2. 响应DTO(返回给客户端的数据)

作用:定义后端需要返回给客户端的结果,用于接口输出。
判断依据:客户端展示或后续处理需要哪些数据?

  • 必须返回:客户端必须展示的核心信息(如订单详情中的订单号、金额、状态)。
  • 按需返回:根据接口粒度决定(详情接口返回全量,列表接口返回精简)。
  • 禁止返回
    • 敏感信息(如用户密码、加密密钥)。
    • 客户端无需关心的内部字段(如数据库版本号、中间表关联ID)。
    • 过大或无用的字段(如长文本日志,客户端用不到则不返回)。

示例
运营商详情的BillerResultDTO需要返回:

// 必须返回:客户端展示的核心信息
private String billerCode; // 编码
private String name;       // 名称
private String contact;    // 联系人
private String phone;      // 电话
private String statusDesc; // 状态描述(如"正常",而非数据库存储的1)
// 按需返回:辅助信息
private LocalDateTime createTime; // 创建时间(客户端可能需要展示)
// 禁止返回:
// private String auditRemark; // 内部审批备注,客户端无需知道
// private Integer status;     // 数据库存储的状态码(应转换为描述文字)

三、如何精准判断DTO需要哪些字段?

  • 从业务流程出发
    • 思考接口的目的:这个接口是用来做什么的?(创建/查询/更新/删除)
    • 例如:更新运营商接口(BillerUpdateRequestDTO)需要billerCode(定位要更新的对象)和需要修改的字段(如name、phone),无需传递未修改的字段。
  • 参考前端需求
    • 和前端开发者确认:他们需要哪些参数来调用接口?需要哪些返回值来展示页面?
    • 例如:前端列表页只展示运营商的编码、名称、状态,则列表接口的响应DTO只需这三个字段,无需返回详细地址等信息。
  • 考虑数据安全性
    • 敏感字段(密码、身份证号)即使前端需要,也应脱敏处理(如138****5678)。
    • 权限相关字段(如用户角色)若客户端无需展示,则不返回。
  • 避免"一刀切"
    • 不要为了省事用一个DTO适配所有接口(如用POJO直接当DTO)。
    • 例如:用户实体有10个字段,登录接口只需返回ID、用户名,而个人中心接口需要返回ID、用户名、头像、生日等,应分别定义UserLoginResponseDTOUserProfileResponseDTO

四、常见错误与最佳实践

  • 错误1:DTO包含POJO的所有字段,包括id、createTime等系统字段。
    • → 改进:只保留接口所需字段,删除冗余。
  • 错误2:响应DTO返回数据库原始字段(如状态用1/2/3,而非"正常/禁用/待审批")。
    • → 改进:在Service层转换为客户端易理解的枚举或描述文字。
  • 错误3:请求DTO允许传递本应后端控制的字段(如status状态字段,客户端可能恶意篡改)。
    • → 改进:状态由后端根据业务逻辑(如审批通过后自动更新),而非客户端传递。
  • 最佳实践
    • @NotBlank@NotNull等注解标记请求DTO的必填字段,配合@Valid做参数校验。
    • 响应DTO中对日期字段格式化(如@JsonFormat(pattern = "yyyy-MM-dd")),方便前端处理。
    • 复杂场景下,使用工具(如MapStruct)自动完成POJO与DTO的转换,减少手动代码。

总结

DTO传递的数据=业务必需+前端需要+安全合规的交集。判断时需结合具体接口的用途、前后端协作需求和数据安全性,避免冗余和暴露敏感信息。核心思想是:DTO是为接口服务的,而非为数据库表服务

到此这篇关于在Spring项目中,DTO层的作用详解的文章就介绍到这了,更多相关spring项目dto层内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • JDK14的新特性:instanceof模式匹配的使用

    JDK14的新特性:instanceof模式匹配的使用

    这篇文章主要介绍了JDK 14的新特性:instanceof模式匹配的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05
  • Spring声明式事务@Transactional知识点分享

    Spring声明式事务@Transactional知识点分享

    在本篇文章里小编给大家整理了关于Spring声明式事务@Transactional详解内容,需要的朋友们可以参考下。
    2020-02-02
  • RocketMQTemplate 注入失败的解决

    RocketMQTemplate 注入失败的解决

    这篇文章主要介绍了RocketMQTemplate 注入失败的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • Milvus快速入门及用Java操作Milvus的全过程

    Milvus快速入门及用Java操作Milvus的全过程

    Milvus是面向向量的数据库,通过相似性搜索处理非结构化数据特征,本文给大家介绍Milvus快速入门以及用Java操作Milvus的方法,感兴趣的朋友一起看看吧
    2025-09-09
  • java之Timer和TimerTask简单demo(分享)

    java之Timer和TimerTask简单demo(分享)

    下面小编就为大家带来一篇java之Timer和TimerTask简单demo(分享)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-12-12
  • Java中操作Redis的详细方法

    Java中操作Redis的详细方法

    基于Jedis实现对redis中字符串的操作,文中通过实例代码给大家介绍的非常详细,包括连接池JedisPool应用的实例代码,对Java操作Redis的相关知识感兴趣的朋友一起看看吧
    2021-11-11
  • Java集合Map的clear与new Map区别详解

    Java集合Map的clear与new Map区别详解

    这篇文章主要介绍了Java集合Map的clear与new Map区别详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • SpringCloud Eureka Provider及Consumer的实现

    SpringCloud Eureka Provider及Consumer的实现

    这篇文章主要介绍了SpringCloud Eureka 提供者及调用者的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-10-10
  • 通过实例解析spring环绕通知原理及用法

    通过实例解析spring环绕通知原理及用法

    这篇文章主要介绍了通过实例解析spring环绕通知原理及用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-10-10
  • 基于mybatis逆向工程的使用步骤详解

    基于mybatis逆向工程的使用步骤详解

    下面小编就为大家带来一篇基于mybatis逆向工程的使用步骤详解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-11-11

最新评论