-
属性与表字段完全对应
-
无业务逻辑方法(仅有getter/setter)
publicclassUserPO{
private Long id; // 对应表主键
private String name; // 对应name字段
}
publicinterfaceUserDao{
// 根据ID查询PO
UserPO findById(Long id);
// 分页查询
List<UserPO> findPage(@Param("offset")int offset, @Param("limit")int limit);
}
publicclassOrderVO{
private String orderNo;
private String createTime; // 格式化后的日期 private String userName; // 关联用户表字段
//状态码转文字描述
public String getStatusText(){
return OrderStatus.of(this.status).getDesc();
}
}
-
接口方法对应SQL操作 -
返回PO或PO集合
-
包含业务状态机、校验规则 -
可持有多个PO引用
publicclassOrderBO{
// 主订单数据
private OrderPO orderPO;
// 子订单项
private List<OrderItemPO> items;
// 业务方法:执行退款
public RefundResult refund(String reason){
if (!"PAID".equals(orderPO.getStatus())) {
thrownew IllegalStateException("未支付订单不可退款");
} // 计算退款金额、调用支付网关等 }
}
-
属性集是PO的子集(如排除 password字段) -
支持序列化(实现 Serializable)
publicclassUserDTOimplementsSerializable{
private Long id;
private String name;
}
-
属性可包含格式化数据(如日期转 yyyy-MM-dd) -
聚合多表数据(如订单VO包含用户名字)
-
只有属性+getter/setter -
无框架依赖(如不继承Spring类)
// 自动生成getter/setter
@Data
publicclassUserPOJO{
private Long id;
private String name;
}
// Service层
public UserDTO getUserById(Long id){
UserPO userPO = userDao.findById(id); // 从DAO获取PO
UserDTO dto = new UserDTO();
dto.setId(userPO.getId());
dto.setName(userPO.getName()); // 过滤敏感字段
return dto; // 返回DTO
}
// Controller层
public UserVO getUser(Long id){
UserDTO dto = userService.getUserById(id);
UserVO vo = new UserVO();
vo.setUserId(dto.getId());
vo.setUserName(dto.getName());
vo.setRegisterTime(formatDate(dto.getCreateTime())); // 格式化日期
return vo;
}
// Domain层:订单领域对象
publicclassOrderDO{
private OrderPO orderPO;
private PaymentPO paymentPO;
// 业务方法:支付校验
publicvoidvalidatePayment(){
if (paymentPO.getAmount() < orderPO.getTotalAmount()) {
thrownew PaymentException("支付金额不足");
}
}
}
// App层:协调领域对象
public OrderPaymentDTO pay(OrderPayCmd cmd){
OrderDO order = orderRepo.findById(cmd.getOrderId());
order.validatePayment(); // 调用领域方法 return OrderConverter.toDTO(order); // 转DTO
}
优点:业务高内聚,适合复杂规则系统
@Mapper
publicinterfaceUserConverter{
UserConverter INSTANCE = Mappers.getMapper(UserConverter.class);
@Mapping(source = "createTime", target = "registerDate")
UserDTO poToDto(UserPO po);
}
// 编译后生成UserConverterImpl.java
publicclassUserConverterImpl{
public UserDTO poToDto(UserPO po){
UserDTO dto = new UserDTO();
dto.setRegisterDate(po.getCreateTime()); // 自动赋值!
return dto;
}
}
-
Lombok:自动生成getter/setter
-
Dozer:XML/注解配置字段映射
// Lombok注解
@Data
publicclassUserVO{
private String userId;
private String userName;
}
// 转换配置
<field>
<a>userId</a>
<b>id</b>
</field>
publicclassOrderVOBuilder{
public OrderVO build(OrderDTO dto){
return OrderVO.builder()
.orderNo(dto.getOrderNo())
.amount(dto.getAmount() + "元") // 动态拼接
.statusText(convertStatus(dto.getStatus()))
.build();
}
}
// 致命错误:暴露数据库敏感字段!
public UserPO getUser(Long id){
// 返回的PO包含password
return userDao.findById(id);
}
-
使用DTO过滤字段 -
注解屏蔽: @JsonIgnore
publicclassOrderDTO{
// 错误!DTO不应有业务方法
publicvoidvalidate(){
if (amount < 0)
thrownew Exception();
}
}
// OrderVO中嵌套List<ProductVO>
publicclassOrderVO{
// 嵌套对象
private List<ProductVO> products;
}
// 转换时触发N+1查询
orderVO.setProducts(order.getProducts()
.stream()
.map(p -> convertToVO(p)) // 循环查询数据库
.collect(toList()));
-
单一职责: PO只存数据,BO只管业务,VO只负责展示——绝不越界!
-
安全隔离:
-
PO永不出DAO层(防数据库泄露)
-
VO永不出Controller(防前端逻辑污染服务)
-
性能优先:
-
大对象转换用MapStruct(编译期生成代码)
-
嵌套集合用批量查询(杜绝N+1)
-
适度设计:
-
10张表以内的系统:可用POJO一撸到底
-
百张表以上核心系统:必须严格分层
往期推荐
SpringBoot 实现数据加密脱敏
Spring 在多线程环境下如何确保事务一致性
蚂蚁又开源了一个顶级 Java 项目!
网易二面:阿里为何建议MVC+Manager层混合架构?
从一个程序员的角度告诉你:“12306”有多牛逼!
Arthas全面使用指南:离线安装+Docker/K8s集成+集中管理

