前言
POJO(Plain Old Java Object)是 Java 编程中一个非常基础且重要的概念。简单来说,POJO 就是一个“普通、简单、纯粹”的 Java 对象。判断一个类是不是 POJO,通常遵循以下标准(严格定义,但是可以适当放宽):
- 不继承特定类
- 不实现特定接口
- 没有注解依赖
一个标准的 POJO 代码示例:
public class User {
private String name;
private Integer age;
public User() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
本文主要要介绍POJO类在项目开发中常见的几种业务概念实现。
1. DO / PO
DO (Data Object) / PO (Persistent Object)
- 中文名称:数据对象 / 持久化对象
- 对应层次:持久层(数据库)
- 定义:与数据库表结构一一对应的 Java 对象。
- 特点:
- 属性名通常与数据库字段名一致(或通过下划线/驼峰转换)。
- 只包含基础数据类型。
- 场景:当执行 SQL 查询后,数据库返回的数据封装成的对象。
- 示例:
// 对应数据库表 user (id, name, password, age)
public class UserDO {
private Long id;
private String name;
private String password; // 加密后的密码
private Integer age;
}
2. DTO
DTO (Data Transfer Object)
- 中文名称:数据传输对象
- 对应层次:在各层之间或网络之间传输
- 定义:用于在不同层之间传输数据的对象。
- 特点:
- 裁剪与聚合:它可以包含比 DO 更少或更多的字段。
- 隐藏敏感信息:比如 DO 里有
password,传给前端的 DTO 就不应该有。 - 组合数据:比如一个 DTO 可能包含
UserDO和OrderDO的部分字段组合。
- 场景:
- 接口返回(VO):传给前端的数据。
- 远程调用:微服务之间调用时传输的数据。
- 业务处理:一般业务方法内部处理时可以传递DTO。
- 示例:
// 用户查询接口返回给前端的数据
public class UserDTO {
private Long id;
private String name;
private Integer age;
// 注意:这里没有 password 字段,为了安全
}
3. BO
BO (Business Object)
- 中文名称:业务对象
- 对应层次:业务逻辑层
- 定义:封装了业务逻辑处理的对象。
- 特点:
- 它可能是多个 DO 的组合。
- 它可能包含复杂的计算逻辑或业务规则。
- 它是 Service 层内部流转的对象。
- 场景:
- 比如“创建订单”业务,需要操作“用户DO”、“商品DO”、“优惠DO”,Service 层会把它们组装成一个
OrderBO进行处理。
- 比如“创建订单”业务,需要操作“用户DO”、“商品DO”、“优惠DO”,Service 层会把它们组装成一个
- 示例:
// 提交订单时的业务对象
public class OrderBO {
private UserDO user; // 购买用户信息
private List<ProductDO> products; // 商品列表
private BigDecimal totalPrice; // 计算后的价格(业务逻辑算出来的)
private String couponCode; // 优惠券代码
}
4. VO
VO (View Object)
- 中文名称:视图对象 / 展示对象
- 对应层次:控制层 -> 前端(展示层)
- 定义:专门用于展示给前端(网页、App)的数据对象。
- 特点:
- 脱敏:通常会隐藏敏感字段(如手机号中间四位隐藏、不返回密码)。
- 格式化:将后端的数据格式化为前端易读的形式(如:
1.0->"VIP",Date->"2023-10-01")。 - 组装:可能聚合了多个 DO 或 BO 的数据,专门为了某个页面设计。
- 场景:
- 列表页展示的数据摘要。
- 详情页返回的完整信息。
- 前端下拉框需要的选项数据。
- 示例:
// 用户详情页返回给前端的数据
public class UserDetailVO {
private Long id;
private String username;
// 脱敏处理:手机号 138****1234
private String phoneNumber;
// 格式化处理:将 Date 类型的生日转为字符串 "1990-01-01"
private String birthdayStr;
// 组装处理:数据库里存的是 0/1,前端展示 "男/女"
private String genderDesc;
// 注意:这里绝对不包含 password 字段
}
5. CO
有两种用法:1. Config Object 2. Command Object
5.1 Config Object
- 中文名称:配置对象 / 属性对象
- 对应层次:基础设施层 / 配置层
- 定义:专门用于接收和绑定配置文件(如
.yml,.properties)中参数的 Java 对象。 - 特点:
- 通常配合
@ConfigurationProperties注解使用,指定配置文件的前缀。 - 支持松散绑定(如
userName可匹配user-name或user_name)。 - 同样支持 JSR-303 校验注解(如
@Min,@Email),确保启动时配置合法。
- 通常配合
- 场景:
- 数据库连接参数(URL、Username、Password)。
- 第三方接口的 AppKey 和超时时间。
- 业务自定义的开关或阈值。
- 示例:
@Component
@ConfigurationProperties(prefix = "app.sms")
@Validated // 开启配置参数校验
public class SmsConfigCO {
@NotBlank(message = "短信服务商Key不能为空")
private String accessKey;
@Min(value = 1, message = "重试次数最少为1次")
private Integer retryTimes = 3; // 默认值
private List<String> whiteList; // 支持列表类型绑定
// 标准 Getter and Setter
}
5.2 Command Object
- 中文名称:命令对象 / 请求对象
- 对应层次:控制层
- 定义:专门用于接收前端(或调用方)传入的参数的对象。
- 特点:
- 通常对应 Controller 的方法参数。
- 包含校验注解(如
@NotNull,@Email)。 - 有时也叫
VO(View Object) 或ReqDTO。
- 场景:
- 前端提交的注册表单、查询条件等。
- 示例:
// 用户注册请求
public class UserRegisterCO {
@NotBlank(message = "用户名不能为空")
private String username;
@NotBlank(message = "密码不能为空")
private String password;
}
6. QO
Query (Query Object)
- 中文名称:查询对象
- 对应层次:控制层 -> 业务层 -> 持久层
- 定义:专门用于封装查询条件、分页参数和排序规则的对象。
- 特点:
- 参数数量不固定,通常包含多个可选条件(如时间范围、模糊搜索)。
- 往往继承自一个基础的
BaseQuery(包含pageNum,pageSize等分页属性)。 - 字段通常是基本数据类型或简单对象,用于拼接 SQL 的
WHERE子句。
- 场景:
- 后台管理系统的列表筛选(按状态、按日期、按关键词搜索)。
- App 中的商品筛选(按价格区间、按品牌)。
- 示例:
// 用户列表查询条件
public class UserQuery {
private Integer pageNum = 1; // 当前页
private Integer pageSize = 10; // 每页条数
private String keyword; // 关键词(搜姓名或手机号)
private Integer status; // 状态(0-禁用,1-启用)
private LocalDate startDate; // 注册开始时间
private LocalDate endDate; // 注册结束时间
// Getter and Setter...
}