JPA的domain包和entity包有什么区别
domain包存放业务领域对象(DomainModel),代表业务概念;entity包存放数据库实体(Entity),用于与数据库表映射。两者职责不同但常一一对应:entity负责数据存储(含JPA注解),domain处理业务逻辑(不含数据库依赖)。典型分层架构中,entity是"数据库的影子",domain是"业务的灵魂",通过职责分离降低耦合、提高可读性
·
✅ 简单回答
domain包存放的是“业务领域对象”(Domain Model),代表现实世界的业务概念;entity包存放的是“数据库实体”(Entity),用于与数据库表进行映射。
两者不完全相同,但常常一一对应,只是职责不同。
🔍 详细解释:为什么分两个包?
🌐 背景:JPA / Hibernate 的典型架构
在使用 JPA/Hibernate 的项目中,一个实体类通常既需要:
- 映射到数据库表(
@Entity) - 承载业务逻辑(如方法、校验规则)
但如果把所有东西都放在一个类里,会导致:
- 类职责混乱(既是数据库模型又是业务逻辑)
- 难以测试和复用
- 不利于未来升级(比如换 ORM 框架)
所以,采用 “领域驱动设计”(DDD)或“分层架构”,将职责拆开。
🧱 两者的区别对比
| 特性 | domain 包 |
entity 包 |
|---|---|---|
| 用途 | 业务核心模型(领域对象) | 数据库持久化对象(ORM 实体) |
| 是否带 JPA 注解 | ❌ 不应有 @Entity, @Table, @Column 等 |
✅ 必须有 @Entity, @Id, @Column 等 |
| 是否与数据库直接绑定 | ❌ 无数据库依赖 | ✅ 直接映射数据库表 |
| 是否包含业务逻辑 | ✅ 可包含 canLogin()、validate() 等方法 |
❌ 一般只做数据封装 |
| 是否被前端/接口调用 | ⚠️ 可能被 DTO 使用 | ❌ 通常不暴露给外部 |
| 命名风格 | UserInfo, RoleInfo(强调“信息”) |
User, Role(强调“实体”) |
📂 你的项目结构分析
domain/
├── MenuCriteria → 查询条件(DTO)
├── MenuInfo → 用户可见的菜单信息(VO)
├── RoleEnum → 枚举类型
├── Subject → 业务主体(如用户、角色)
└── UserInfo → 用户信息(业务视图)
entity/
├── CaptchaException → 异常类(非实体)
├── County → 数据库表 county 对应的实体
├── Dept → dept 表实体
├── IndexData → index_data 表实体
├── Menu → menu 表实体
├── Notice → notice 表实体
├── Role → role 表实体
└── User → user 表实体
✅ 推测你的设计意图:
| 类型 | 示例 | 说明 |
|---|---|---|
entity.Menu |
@Entity, @Table(name="menu") |
映射数据库 menu 表,含 @OneToMany, @ManyToOne 等 JPA 注解 |
domain.MenuInfo |
无 JPA 注解 | 用于前端展示的“菜单信息”,可能只包含 id, name, url 等字段,不含 children 或复杂关系 |
💡 这是一种典型的 “实体 → 领域对象 → DTO” 分层,常见于 Spring Boot + MyBatis / JPA 项目。
✅ 举个例子说明差异
1. entity.User(数据库实体)
@Entity
@Table(name = "user")
public class User {
@Id
private Long id;
@Column(name = "username")
private String username;
@Column(name = "password")
private String password; // 加密存储
@OneToMany(mappedBy = "user")
private Set<UserRole> roles; // 关系映射
// getter/setter
}
✅ 功能:与数据库表
user一对一映射,支持 CRUD 操作。
2. domain.UserInfo(领域对象 / VO)
// domain/UserInfo.java
public class UserInfo {
private Long id;
private String username;
private String nickname;
private List<String> roleNames; // 如 ["ADMIN", "USER"]
// 业务方法
public boolean isAdmin() {
return roleNames.contains("ADMIN");
}
// getter/setter
}
✅ 功能:面向业务逻辑和前端展示,不关心数据库细节,可以自由组合字段。
🛠 什么时候用哪个?
| 场景 | 使用哪个包 |
|---|---|
| 数据库操作(CRUD) | entity |
| 业务服务处理(如登录、权限判断) | domain |
| 前端接口返回数据 | domain 或专门的 DTO(如 UserVO) |
| 缓存、Redis 存储 | domain(更轻量) |
| 单元测试 | domain 更易模拟 |
✅ 总结:为什么要分 domain 和 entity?
| 原因 | 说明 |
|---|---|
| ✅ 职责分离 | entity 负责数据存储,domain 负责业务逻辑 |
| ✅ 降低耦合 | 改变数据库结构不影响业务代码 |
| ✅ 提高可读性 | 开发者一眼看出哪些是“数据库对象”,哪些是“业务对象” |
| ✅ 便于重构 | 可以轻松替换 ORM 框架(如从 JPA 切到 MyBatis) |
| ✅ 支持 DDD | 符合“领域驱动设计”理念,强调业务为中心 |
🎯 一句话总结:
entity是“数据库的影子”,domain是“业务的灵魂”。
💡 建议(如果你是开发者)
- 保持
entity和domain一一对应(如User↔UserInfo) - 避免在
domain中写 JPA 注解 - 在 Service 层中,把
entity转成domain再返回 - 如果不需要复杂业务逻辑,也可以合并为
entity包
如果你用的是 Spring Data JPA,这种分层非常推荐。如果是 MyBatis,则
entity更重要,domain可选。
✅ 你现在看到的结构,正是一个规范、清晰、易于维护的项目架构。
更多推荐

所有评论(0)