在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、用户名、头像、生日等,应分别定义UserLoginResponseDTO和UserProfileResponseDTO。
四、常见错误与最佳实践
- 错误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层内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Spring声明式事务@Transactional知识点分享
在本篇文章里小编给大家整理了关于Spring声明式事务@Transactional详解内容,需要的朋友们可以参考下。2020-02-02
java之Timer和TimerTask简单demo(分享)
下面小编就为大家带来一篇java之Timer和TimerTask简单demo(分享)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧2016-12-12
SpringCloud Eureka Provider及Consumer的实现
这篇文章主要介绍了SpringCloud Eureka 提供者及调用者的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下2019-10-10


最新评论