DTO = Data Transfer Object,数据传输对象 一句话:用来在程序各个层之间、服务之间传递数据的载体。
- Entity(PO):和数据库表一一对应,从数据库拿数据
- DTO:服务内部/接口入参、微服务之间传数据
- VO:返回给前端展示
DTO 分两种最常见场景
1)接收前端传过来的参数(入参DTO)
前端POST提交表单、查询条件,用DTO接住请求参数。
Controller接收前端JSON → DTO
java
// 用户新增入参 DTO
public class UserAddDTO {
private String username;
private String password;
private String phone;
}
✅ 好处:可以做参数校验(@NotBlank、@Size);不用直接拿Entity接收前端参数,防止前端传一些不该改的字段(比如id、createTime)。
2)跨层/微服务之间传输数据
Controller ↔ Service,或者A服务调用B服务,互相传数据用DTO。
Service层内部、RPC调用,用DTO。
为什么不能直接用 Entity 代替 DTO?
- 防止脏数据 Entity里面有数据库字段(如创建时间、删除标记),如果直接用Entity接收前端参数,黑客可以恶意传入
id=999、isDelete=true,直接篡改数据库。 - 按需组合字段 一次业务可能只需要Entity里部分字段,或者需要多个表的数据拼在一起,单独组装DTO,不用改动数据库实体。
- 职责分离,解耦 数据库表改了,不一定影响上层业务;业务逻辑变更,也不用动数据库映射。
简单流转示例
前端JSON → DTO(入参) → Controller → Service → Entity → DB DB → Entity → Service组装 → VO → 返回前端JSON
也有很多项目,微服务互相调用返回的数据也叫DTO,这时候和VO容易混。 简单判断原则:
✅ 给前端看的 = VO
✅ 程序内部流转、接收前端提交参数、服务之间调用 = DTO
举个对比(一眼看懂)
- Entity:数据库表,包含所有列,有MyBatis/JPA注解
@TableName - DTO:接收前端提交,或者服务之间传参,没有数据库注解 ,常加校验注解
@NotBlank - VO:返回给前端,剔除敏感字段(密码、身份证)
常见坑
- 不要在DTO里写数据库相关注解;
- DTO不要放太多业务逻辑,只用来存数据(POJO);
- 不要不分层,项目简单就图省事全用Entity(上线容易出现安全漏洞,就是live site issue隐患)。