区分PO、DTO、VO、BO
简介
Controller层:入参是DTO
DTO的角色:DTO(Data Transfer Object)是数据传输对象,专为外部输入设计。它把前端传来的零散参数封装成一个对象,便于校验(比如用@Valid
注解)和扩展。如果不用DTO,多个参数散落在方法签名里,代码可读性下降。
Service层:入参DTO,加工成BO
BO的角色:BO(Business Object)是业务对象,承载业务逻辑加工后的数据。这里从UserPO(数据库映射对象)转成UserBO,并在BO中添加了registerDays字段。BO不一定是“领域对象”(Domain Object,领域驱动设计DDD中的概念),而是Service层内部对业务数据的封装。
DAO层:入参是PO
PO的角色:PO(Persistent Object)是持久化对象,与数据库表结构一一对应,由MyBatis自动映射查询结果。Mapper的返回值是UserPO。
返回前端:VO出场
VO的角色:VO(Value Object)是视图对象,专为前端定制。如果直接返回UserBO,可能暴露多余字段(比如id),用VO可以精确控制输出。
自动转换策略
1.BeanUtils(Spring自带) Spring提供的BeanUtils.copyProperties
可以快速复制属性
优点:简单,字段名一致时直接用。
缺点:不支持复杂转换(比如字段名不同、类型不一致),需要额外处理。
2.MapStruct(推荐) MapStruct是一个编译时生成转换代码的库,性能高且类型安全。
1️⃣引入依赖后:
1 | <dependency> |
2️⃣定义转换接口:
1 | @Mapper(componentModel = "spring") |
3️⃣在Service中使用:
1 | public UserVO getUserInfo(UserQueryDTO queryDTO) { |
优点:自动生成转换代码,支持复杂映射(字段名不同、类型转换),运行时零开销。
缺点:需要学习配置,初期有一定上手成本。
总结
- DTO:传输层,解耦外部输入。
- BO:业务层,承载逻辑加工(非必须,视复杂度而定)。
- PO:持久层,绑定数据库。
- VO:视图层,适配输出。