Java中对象命名(POJO、PO、BO、VO、DTO、DAO)说明
我们来聊聊很多人搞混的那几个名词——PO、VO、DAO、BO、DTO、POJO。这些概念其实在 Java 开发里天天见,但很多人只是“模糊知道”,真要让你说清楚它们之间的关系,还真有点卡壳。
从数据库到页面,这几位是怎么“传球”的
我们先把场景放到一个熟悉的地方,比如一个电商项目。
你下单买个鼠标,从数据库查到商品信息到最后页面展示,大概会经过这么一条路线:
DAO → PO → BO → DTO → VO
看起来有点像传球,DAO 是开球的那位,VO 是最后射门的前锋。
PO(Persistent Object)
PO 叫持久化对象,最靠近数据库。你可以理解为它就是数据库那张表在 Java 里的影子。
比如数据库里有个商品表 t_product:
CREATE TABLE t_product ( id BIGINT PRIMARY KEY, name VARCHAR(100), price DECIMAL(10,2), stock INT );
对应的 PO 类就是这样:
public class ProductPO { private Long id; private String name; private BigDecimal price; private Integer stock; // getter、setter略 }
PO 不负责业务逻辑,只是映射数据库字段。ORM 框架(比如 MyBatis、JPA)会帮你把 SQL 查询结果填进去。
DAO(Data Access Object)
DAO 是负责跟数据库打交道的对象。它就像仓库管理员,别人要查、要存、要删,全得找它。
比如:
@Mapper public interface ProductDAO { @Select("SELECT * FROM t_product WHERE id = #{id}") ProductPO findById(Long id); @Insert("INSERT INTO t_product(name, price, stock) VALUES(#{name}, #{price}, #{stock})") int insert(ProductPO product); }
DAO 层只干“数据操作”,它不关心你业务逻辑。简单说:它帮你“拿数据”,但不帮你“算逻辑”。
BO(Business Object)
BO 就是业务对象。它不是数据库表映射,而是“业务里的核心模型”。
比如商品打折、库存检查、上下架逻辑,这些都属于业务范畴。那我们就可以封装到 BO 里:
public class ProductBO { private Long id; private String name; private BigDecimal price; private Integer stock; public boolean canSell() { return stock > 0; } public BigDecimal getDiscountPrice(BigDecimal rate) { return price.multiply(rate); } }
BO 的重点是——它有业务逻辑。也就是说,BO 是面向业务规则的,而 PO 是面向数据库结构的。
DTO(Data Transfer Object)
DTO 是数据传输对象。你可以把它理解为“中间传输快递包”。
在分布式系统或微服务架构下,一个模块调用另一个模块时,不可能直接传 BO 或 PO(会泄露内部结构),于是用 DTO 作为“中立格式”。
比如下单服务要从商品服务那边拿数据:
public class ProductDTO { private Long id; private String name; private BigDecimal price; }
DTO 通常是通过转换工具(比如 MapStruct 或 BeanUtils)从 BO 转过来的:
ProductDTO dto = BeanUtils.copyProperties(productBO, ProductDTO.class);
DTO 不带业务逻辑,只负责“跨模块传输”。
VO(View Object)
VO 是视图对象,跟页面展示打交道。
比如前端要显示商品信息,就用 VO:
public class ProductVO { private String name; private String priceText; }
业务层拿到 BO 后再转成 VO:
public class ProductVO convertToVO(ProductBO bo) { ProductVO vo = new ProductVO(); vo.setName(bo.getName()); vo.setPriceText("¥" + bo.getPrice().toString()); return vo; }
VO 一般不直接出现业务逻辑,它只关心“展示层的数据长啥样”。
POJO(Plain Old Java Object)
POJO 是个更广义的概念,意思是“普通的 Java 对象”,不依赖任何框架、不实现任何接口。
换句话说,上面提到的 PO、BO、DTO、VO,其实都属于 POJO 的一种,只是各自有不同的职责。
简单总结一下
| 名称 | 全称 | 主要用途 | 是否包含业务逻辑 | 常见位置 |
|---|---|---|---|---|
| PO | Persistent Object | 映射数据库表 | 否 | DAO 层 |
| DAO | Data Access Object | 访问数据库 | 否 | Repository 层 |
| BO | Business Object | 封装业务逻辑 | 是 | Service 层 |
| DTO | Data Transfer Object | 系统间传输数据 | 否 | API 层 |
| VO | View Object | 页面展示数据 | 否 | Controller 层 |
| POJO | Plain Old Java Object | 纯 Java 对象 | 可有可无 | 任意 |
举个完整例子
假设我们写一个商品查询接口:
@RestController @RequestMapping("/product") public class ProductController { @Autowired private ProductService productService; @GetMapping("/{id}") public ProductVO getProduct(@PathVariable Long id) { ProductBO bo = productService.findProductById(id); return convertToVO(bo); } private ProductVO convertToVO(ProductBO bo) { ProductVO vo = new ProductVO(); vo.setName(bo.getName()); vo.setPriceText("¥" + bo.getPrice()); return vo; } }
Service 层:
@Service public class ProductService { @Autowired private ProductDAO productDAO; public ProductBO findProductById(Long id) { ProductPO po = productDAO.findById(id); ProductBO bo = new ProductBO(); BeanUtils.copyProperties(po, bo); return bo; } }
DAO 层:
@Mapper public interface ProductDAO { @Select("SELECT * FROM t_product WHERE id = #{id}") ProductPO findById(Long id); }
整个流程就串起来了,从数据库到前端一条龙。
PO 存数据库,DAO 取数据,BO 搞逻辑,DTO 传数据,VO 给前端看,POJO 是老祖宗。
理解它们的区别,其实就是理解你代码“在哪一层”做“哪一件事”。
如果你现在还在 Controller 里直接 new 一个 PO 返回给前端……那说明你还没真正理解分层架构 😄

浙公网安备 33010602011771号