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 返回给前端……那说明你还没真正理解分层架构 😄

 

https://mp.weixin.qq.com/s/3b-8lQiUvAjCgpIfqm5gTA

posted @ 2019-12-07 09:37  wq9  阅读(2980)  评论(0)    收藏  举报