java -DO、BO、DTO、VO和POJO实体类
·
DO、BO、DTO、VO和POJO
- DO(Data Object)是一个与数据库表结构对应的对象,也叫持久化对象。DO用来在DAO层和数据库进行交互,也可以在其他层使用,比如作为方法的参数或返回值。
- BO(Business Object)是一个封装业务逻辑的对象。BO用来在Service层处理业务规则,比如校验、计算、转换等。BO可以包含一个或多个DO对象的信息,也可以不包含DO对象的信息。
- DTO(Data Transfer Object)是一个用来传输数据的对象。DTO用来在不同层或不同系统之间传递数据,比如从Service层传递到Controller层或View层。DTO可以包含与视图相关的信息,也可以包含与业务相关的信息。
- VO(View Object)是一个用来展示数据的对象。VO用来在View层表示视图模型,比如JSP、HTML等。VO可以包含与视图相关的信息,比如页面展示的数据、页面需要的样式等
- POJO(Plain Ordinary Java Object)是一个普通的Java对象,它没有任何特殊的要求或约束,可以用来表示任何类型的数据。POJO通常是其他数据模型的基础,比如DO、DTO、BO、VO等。
在展示页/业务逻辑层/数据层 之间的关系图如下所示:
(来源:知乎 侵删)

┌─────────────────────────────────────────────────────────────┐
│ 前端 (Frontend) │
│ Vue/React/小程序 │
└───────────────────────────┬─────────────────────────────────┘
│ HTTP Request/Response
│ JSON 数据
┌───────────────────────────▼─────────────────────────────────┐
│ Controller 层 (表现层) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ @RestController / @Controller │ │
│ │ ├── ReqVO/ReqDTO ◄── 接收前端请求参数 │ │
│ │ └── RespVO/RespDTO ──► 返回给前端的数据 │ │
│ └─────────────────────────────────────────────────────┘ │
└───────────────────────────┬─────────────────────────────────┘
│ 调用 Service
│
┌───────────────────────────▼─────────────────────────────────┐
│ Service 层 (业务层) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ @Service │ │
│ │ ├── BO (Business Object) - 业务对象 │ │
│ │ ├── DTO - 服务间传输对象 │ │
│ │ │ │ │
│ │ │ 业务逻辑处理: │ │
│ │ │ • ReqVO → BO/DO 转换 │ │
│ │ │ • 调用 Mapper 进行数据库操作 │ │
│ │ │ • DO → VO 转换 │ │
│ └─────────────────────────────────────────────────────┘ │
└───────────────────────────┬─────────────────────────────────┘
│ 调用 Mapper/Repository
│
┌───────────────────────────▼─────────────────────────────────┐
│ Mapper/DAO 层 (数据访问层) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ @Mapper / @Repository │ │
│ │ └── DO/PO/Entity - 数据库实体对象 │ │
│ │ │ │
│ │ 操作: CRUD 方法 │ │
│ └─────────────────────────────────────────────────────┘ │
└───────────────────────────┬─────────────────────────────────┘
│ MyBatis/JPA/JDBC
│
┌───────────────────────────▼─────────────────────────────────┐
│ 数据库 (Database) │
│ MySQL/PostgreSQL/Oracle │
└─────────────────────────────────────────────────────────────┘
ReqVO (Request View Object)
@Data
public class UserLoginReqVO {
@NotBlank(message = "用户名不能为空")
private String username;
@NotBlank(message = "密码不能为空")
private String password;
}
- 作用: 接收前端请求参数
- 特点: 包含校验注解 (
@NotBlank,@Valid) - 命名:
XxxReqVO或XxxReqDTO
RespVO (Response View Object)
@Data
public class UserRespVO {
private Long id;
private String username;
private String nickname;
private String avatar;
// 不包含敏感信息如密码
}
- 作用: 返回给前端的数据
- 特点: 只包含前端需要的字段,脱敏处理
- 命名:
XxxRespVO或XxxVO
PageReqVO (分页请求)
@Data
public class UserPageReqVO extends PageParam {
private String username; // 查询条件
private Integer status; // 查询条件
}
DTO (Data Transfer Object)
@Data
public class UserDTO {
private Long id;
private String username;
private String email;
private List<RoleDTO> roles; // 可以包含关联对象
}
- 作用: 服务间传输数据(微服务架构)
- 特点: 可以组合多个 DO 的数据
- 使用场景: Service 调用 Service、RPC 调用
BO (Business Object)
@Data
public class OrderBO {
private OrderDO order; // 订单信息
private List<OrderItemDO> items; // 订单明细
private UserDO user; // 用户信息
// 业务方法
public BigDecimal calculateTotal() {
return items.stream()
.map(OrderItemDO::getAmount)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
- 作用: 封装复杂业务逻辑
- 特点: 包含业务方法,可组合多个 DO
- 使用场景: 复杂业务处理
DO (Data Object) / PO (Persistent Object)
@Data
@TableName("sys_user")
public class UserDO {
@TableId(type = IdType.AUTO)
private Long id;
private String username;
private String password;
private String email;
private Integer status;
private LocalDateTime createTime;
private LocalDateTime updateTime;
}
-
作用: 与数据库表一一对应
-
特点
:
- 字段与数据库列对应
- 包含 ORM 注解 (
@TableName,@TableId) - 不包含业务逻辑
-
命名:
XxxDO或XxxPO或XxxEntity
完整请求流程
// 1. Controller 层 - 接收请求
@RestController
@RequestMapping("/user")
public class UserController {
@PostMapping("/create")
public RespVO<Long> createUser(@Valid @RequestBody UserCreateReqVO reqVO) {
// ReqVO → Service
Long userId = userService.createUser(reqVO);
return RespVO.success(userId);
}
@GetMapping("/{id}")
public RespVO<UserRespVO> getUser(@PathVariable Long id) {
// Service → RespVO
UserRespVO user = userService.getUser(id);
return RespVO.success(user);
}
}
// 2. Service 层 - 业务处理
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public Long createUser(UserCreateReqVO reqVO) {
// ReqVO → DO 转换
UserDO userDO = BeanUtil.copyProperties(reqVO, UserDO.class);
userDO.setPassword(passwordEncoder.encode(reqVO.getPassword()));
// DO → Database
userMapper.insert(userDO);
return userDO.getId();
}
@Override
public UserRespVO getUser(Long id) {
// Database → DO
UserDO userDO = userMapper.selectById(id);
// DO → RespVO 转换
return BeanUtil.copyProperties(userDO, UserRespVO.class);
}
}
// 3. Mapper 层 - 数据访问
@Mapper
public interface UserMapper extends BaseMapper<UserDO> {
// 继承 BaseMapper,自动拥有 CRUD 方法
}
| 实体类 | 所在层 | 作用 | 特点 | 示例 |
|---|---|---|---|---|
| ReqVO/ReqDTO | Controller | 接收前端请求 | 包含校验注解 | UserLoginReqVO |
| RespVO/RespDTO | Controller | 返回给前端 | 只含必要字段 | UserRespVO |
| DTO | Service | 服务间传输 | 可组合数据 | UserDTO |
| BO | Service | 业务处理 | 含业务方法 | OrderBO |
| DO/PO/Entity | Mapper/DAO | 数据库映射 | 对应表结构 | UserDO |
Controller 层:
├── UserLoginReqVO (登录请求)
├── UserCreateReqVO (创建请求)
├── UserUpdateReqVO (更新请求)
├── UserPageReqVO (分页查询请求)
├── UserRespVO (响应)
└── UserSimpleRespVO (简化响应)
Service 层:
├── UserDTO (传输对象)
└── UserBO (业务对象)
Mapper 层:
└── UserDO (数据库对象)
💡 为什么要分这么多对象?
1. 职责分离
- 每层只关注自己的职责
- Controller 不直接操作 DO
2. 安全性
// ❌ 直接返回 DO,可能泄露密码
return userDO;
// ✅ 转换为 VO,过滤敏感字段
return convertToVO(userDO);
3. 灵活性
// 数据库字段变更不影响接口
// UserDO 改名,只需修改转换逻辑
4. 可维护性
- 各层独立,修改互不影响
- 便于单元测试
🔧 转换工具推荐
- 默认使用 {@link cn.hutool.core.bean.BeanUtil} 作为实现类,虽然不同 bean 工具的性能有差别,但是对绝大多数同学的项目,不用在意这点性能
- 针对复杂的对象转换,可以搜参考 AuthConvert 实现,通过 mapstruct + default 配合实现
1. MapStruct
@Mapper
public interface UserConverter {
UserConverter INSTANCE = Mappers.getMapper(UserConverter.class);
UserRespVO toVO(UserDO userDO);
UserDO toDO(UserCreateReqVO reqVO);
}
2. BeanUtils
UserRespVO vo = BeanUtil.copyProperties(userDO, UserRespVO.class);
📝 最佳实践总结
- ✅ Controller 只用 ReqVO/RespVO
- ✅ Service 用 DTO/BO 处理业务
- ✅ Mapper 只操作 DO
- ✅ 不同层的对象不要混用
- ✅ 使用工具类自动转换
- ✅ VO 中不要包含敏感信息
这样的分层设计让代码结构清晰、职责明确、易于维护!🎯
应用
假设我们有一个用户管理系统,其中包含以下实体类:
UserDO:表示数据库中用户表的数据对象。
UserBO:表示业务对象,用于在service层中封装用户相关的业务逻辑,可以包含多个DO对象。
UserDTO:表示数据传输对象,用于在service和controller层之间传输数据。
UserVO:表示视图对象,用于在controller层向前端页面展示数据。
User:表示POJO对象,用于在不同层之间转换数据。
首先定义一个DO类,用来映射数据库中的实体:
public class UserDO {
private Integer id;
private String username;
private String password;
private Integer age;
}
再定义一个BO类,用来封装业务逻辑:
public class UserBO {
private UserDO userDO; // 包含一个UserDO对象
private String role; // 包含一个业务逻辑相关的属性
// 包含一个业务逻辑相关的方法,比如判断用户是否是管理员
public boolean isAdmin() {
return "admin".equals(this.role);
}
}
接下来定义一个DTO类,用来传输数据:
public class UserDTO {
private String username; // 包含一个与视图相关的属性,比如用户名
private Integer age; // 包含一个与业务相关的属性,比如年龄
}
再定义一个VO类,用来展示数据:
public class UserVO {
private String username; // 包含一个与视图相关的属性,比如用户名
private String ageDesc; // 包含一个与视图相关的属性,比如年龄描述,比如“20岁以下
}
最后,定义一个POJO类:
public class User {
private Integer id;
private String username;
private String password;
private Integer age;
private String role;
//一些实体类转换方法,略
}
接下来演示如何在service、dao、controller层中使用.
DAO层
public interface UserDAO {
// 根据用户名查询用户信息,返回UserDO对象
UserDO findByUsername(String username);
// 根据用户id更新用户信息,接收UserDO对象作为参数
int updateById(UserDO userDO);
}
Service层
@Service
public class UserService {
@Autowired
private UserDao userDao;
public boolean validateUser(String username, String password) {
// 调用Dao层的方法,根据用户名查询用户信息,返回UserDO对象
UserDO userDO = userDao.findByUsername(username);
// 判断用户是否存在,以及密码是否正确
if (userDO != null && userDO.getPassword().equals(password)) {
return true;
} else {
return false;
}
}
public UserDTO getUserInfo(String username) {
// 调用Dao层的方法,根据用户名查询用户信息,返回UserDO对象
UserDO userDO = userDao.findByUsername(username);
// 判断用户是否存在
if (userDO != null) {
// 返回UserDTO对象
return User.toUserDTO(userDO);
} else {
// 返回null
return null;
}
}
@Override
public UserBO getUserInfo(Integer userId) {
UserDO userDO = userDao.findByUserId(userId);
// 判断用户是否存在
if (userDO != null) {
// 返回UserBO对象
return User.toUserBO(userDO);
} else {
// 返回null
return null;
}
}
}
Controller层:
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/info")
public UserVO info(String username) {
// 调用Service层的方法,根据用户名获取用户信息,返回UserDTO对象
UserDTO userDTO = userService.getUserInfo(username);
// 判断用户是否存在
if (userDTO != null) {
// 返回UserVO对象
return User.toUserVO(userDTO);
} else {
// 返回null
return null;
}
}
}
更多推荐


所有评论(0)