如何通过VODTOEntity转换优化项目开发中的数据传输规范?
- 内容介绍
- 相关推荐
本文共计834个文字,预计阅读时间需要4分钟。
项目中对对象传递,字段混乱、命名混淆、敏感信息裸露——根本原因不是写法不对,而是没搞清+VO、DTO、Entity等各自在哪一层、干啥事。
DTO 是接口的“守门人”
它只出现在 Controller 层接收请求的地方,专为入参设计。前端提交什么,DTO 就定义什么,但不包含任何业务逻辑或数据库细节。
- 字段名尽量贴近前端习惯,比如 user_name → username,避免让前端猜映射
- 必须加校验注解(@NotBlank、@Email、@Min),校验逻辑前置到 DTO 层
- 密码、token、盐值等字段,只在 DTO 中出现一次,进系统后立刻加密或丢弃,绝不透传到 Entity
- 不要在 DTO 里写方法、继承、复杂嵌套;它就是个干净的“数据容器”
Entity 是数据库的“镜像”
它和表结构强绑定,字段、类型、注解(@Column、@Table)都得对得上。它只在 Service 和 Mapper/Repository 层内部流转,不出现在 Controller 或返回体中。
- 哪怕只是加个 @Transient 字段,也要想清楚:这个字段真要存进数据库?还是临时用?别污染 Entity
- 敏感字段(如 password、idCard)必须加密存储,Entity 里存的是密文,不是明文
- 字段增删改 → 只动 Entity + 数据库迁移脚本,其他层不受影响
- 别在 Entity 上写业务方法(比如 getUserLevel()),那是 Service 的事
VO 是前端的“定制包装盒”
它只服务于页面展示,字段完全按前端需求来,可以拼接、格式化、补缺、翻译状态码,甚至聚合多个 Entity 的数据。
- 日期字段统一转成 "yyyy-MM-dd HH:mm" 字符串,别让前端自己 parse
- 状态字段(如 status=1)→ 转成 statusText="已启用",前端直接渲染
- 头像地址可拼接 CDN 域名:avatarUrl = "https://cdn.xxx.com/" + avatarPath
- VO 不需要 Lombok 的 @Data 全包,用 @Getter + 手动 setter 更可控(有些字段只读不设)
转换不是“拷贝”,是“有意识的映射”
别依赖工具自动全字段 copy。BeanUtils.copyProperties 看似省事,但容易漏掉语义转换、字段重命名、空值处理等关键逻辑。
- DTO → Entity:补默认值(createTime=now())、加密(passwordEncoder.encode())、权限初始化
- Entity → VO:格式化时间、枚举转文案、null 转默认值(nickName ?: "游客")、脱敏(mobile="138****1234")
- 建议用静态工具类封装转换逻辑,比如 UserConvert.toVO(userEntity),比零散 copy 更易维护、可测、可追溯
- 集合转换别用 stream.map(x -> toVO(x)) 反复 new,批量构造更高效(尤其分页查 20 条以上时)
本文共计834个文字,预计阅读时间需要4分钟。
项目中对对象传递,字段混乱、命名混淆、敏感信息裸露——根本原因不是写法不对,而是没搞清+VO、DTO、Entity等各自在哪一层、干啥事。
DTO 是接口的“守门人”
它只出现在 Controller 层接收请求的地方,专为入参设计。前端提交什么,DTO 就定义什么,但不包含任何业务逻辑或数据库细节。
- 字段名尽量贴近前端习惯,比如 user_name → username,避免让前端猜映射
- 必须加校验注解(@NotBlank、@Email、@Min),校验逻辑前置到 DTO 层
- 密码、token、盐值等字段,只在 DTO 中出现一次,进系统后立刻加密或丢弃,绝不透传到 Entity
- 不要在 DTO 里写方法、继承、复杂嵌套;它就是个干净的“数据容器”
Entity 是数据库的“镜像”
它和表结构强绑定,字段、类型、注解(@Column、@Table)都得对得上。它只在 Service 和 Mapper/Repository 层内部流转,不出现在 Controller 或返回体中。
- 哪怕只是加个 @Transient 字段,也要想清楚:这个字段真要存进数据库?还是临时用?别污染 Entity
- 敏感字段(如 password、idCard)必须加密存储,Entity 里存的是密文,不是明文
- 字段增删改 → 只动 Entity + 数据库迁移脚本,其他层不受影响
- 别在 Entity 上写业务方法(比如 getUserLevel()),那是 Service 的事
VO 是前端的“定制包装盒”
它只服务于页面展示,字段完全按前端需求来,可以拼接、格式化、补缺、翻译状态码,甚至聚合多个 Entity 的数据。
- 日期字段统一转成 "yyyy-MM-dd HH:mm" 字符串,别让前端自己 parse
- 状态字段(如 status=1)→ 转成 statusText="已启用",前端直接渲染
- 头像地址可拼接 CDN 域名:avatarUrl = "https://cdn.xxx.com/" + avatarPath
- VO 不需要 Lombok 的 @Data 全包,用 @Getter + 手动 setter 更可控(有些字段只读不设)
转换不是“拷贝”,是“有意识的映射”
别依赖工具自动全字段 copy。BeanUtils.copyProperties 看似省事,但容易漏掉语义转换、字段重命名、空值处理等关键逻辑。
- DTO → Entity:补默认值(createTime=now())、加密(passwordEncoder.encode())、权限初始化
- Entity → VO:格式化时间、枚举转文案、null 转默认值(nickName ?: "游客")、脱敏(mobile="138****1234")
- 建议用静态工具类封装转换逻辑,比如 UserConvert.toVO(userEntity),比零散 copy 更易维护、可测、可追溯
- 集合转换别用 stream.map(x -> toVO(x)) 反复 new,批量构造更高效(尤其分页查 20 条以上时)

