# meta-jpa **Repository Path**: 5iprogrammer/meta-jpa ## Basic Information - **Project Name**: meta-jpa - **Description**: 一个基于 JPA 和 Spring Boot 的元数据驱动、面向领域驱动设计(DDD)的 Java 框架,提供自动生成的动态 REST API、流式查询构建器和全面的实体元数据管理。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-08 - **Last Updated**: 2026-06-11 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Meta-JPA: 基于元数据的 JPA 领域驱动设计框架 [![Java](https://img.shields.io/badge/Java-17-orange.svg)](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) [![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.5.14-brightgreen.svg)](https://spring.io/projects/spring-boot) [![License](https://img.shields.io/badge/License-Proprietary-red.svg)]() > 一个基于 JPA 和 Spring Boot 的元数据驱动、面向领域驱动设计(DDD)的 Java 框架,提供自动生成的动态 REST API、流式查询构建器和全面的实体元数据管理。 --- ## 📋 目录 - [概述](#概述) - [架构设计](#架构设计) - [模块结构](#模块结构) - [核心概念](#核心概念) - [快速开始](#快速开始) - [注解参考](#注解参考) - [API 参考](#api-参考) - [高级用法](#高级用法) - [项目依赖](#项目依赖) --- ## 概述 **Meta-JPA** 是一个以元数据为中心的 Java 持久层框架,彻底改变了传统的 JPA 开发模式。开发者无需为每个实体编写重复的 DAO 层和 REST 控制器——只需为领域类添加注解,框架便会自动: - 🔍 **发现** 启动时扫描实体元数据 - 🗄️ **生成** 动态 CRUD 操作(无需编写 DAO 代码) - 🌐 **暴露** REST API 接口用于查询和持久化(`/api/d/{domainName}/...`) - 📊 **支持** 复杂查询、聚合统计、分组和分页 - 🔒 **集成** 基于角色的字段级和操作级权限控制(RBAC) - 🎨 **提供** UI 元数据,可自动生成管理后台界面 本框架专为采用**领域驱动设计(DDD)**模式的企业级应用而构建,在领域建模与基础设施之间搭建了桥梁。 --- ## 架构设计 ``` ┌──────────────────────────────────────────────────────────────┐ │ meta-controller-spring-boot-starter │ │ ┌─────────────────────┐ ┌──────────────────────────────┐ │ │ │ RestQueryController │ │ RestPersistenceController │ │ │ │ GET/POST /api/d/... │ │ POST/PUT/DELETE /api/d/... │ │ │ └──────────┬──────────┘ └──────────────┬───────────────┘ │ │ │ │ │ ├─────────────┼────────────────────────────┼────────────────────┤ │ ▼ ▼ │ │ meta-jpa-spring-boot-starter │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ DynamicService / DynamicDao │ │ │ │ ┌───────────────────┐ ┌──────────────────────────┐ │ │ │ │ │ DynamicServiceJpa │ │ DynamicDaoJpaImpl │ │ │ │ │ │ (事务管理) │ │ (JPA Criteria API) │ │ │ │ │ └─────────┬─────────┘ └────────────┬─────────────┘ │ │ │ │ │ │ │ │ │ │ ┌─────────▼─────────────────────────▼─────────────┐ │ │ │ │ │ MetaServiceImpl │ │ │ │ │ │ (实体元数据注册中心) │ │ │ │ │ └──────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ ├─────────────┼──────────────────────────────────────────────────┤ │ ▼ │ │ meta (核心 API) │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ 注解定义 │ 领域模型 │ 查询DSL │ 事件系统 │ 工具类 │ │ │ │ @Meta │ MetaDomain│QueryWrap│ Domain │ │ │ │ │ @Field │ MetaField │Condition│ Event │ │ │ │ │ @Relation│MetaRelation│ Page │ │ │ │ │ │ @VO │ │ Select │ │ │ │ │ └─────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────┘ ``` --- ## 模块结构 | 模块 | 构件标识 | 说明 | |--------|----------|-------------| | **meta** | `com.jr.basic:meta` | 核心 API — 注解、领域模型、查询 DSL、服务接口 | | **meta-jpa-spring-boot-starter** | `com.jr.basic:meta-jpa-spring-boot-starter` | JPA 实现 — Criteria API DAO、元数据扫描器、基础领域类 | | **meta-controller-spring-boot-starter** | `com.jr.basic:meta-controller-spring-boot-starter` | REST 控制器 — 自动生成的 `/api/d/{domainName}` 端点 | ### 依赖关系图 ``` meta-controller-spring-boot-starter └── meta meta-jpa-spring-boot-starter └── meta ``` --- ## 核心概念 ### 1. 领域对象(`Domain`) 每个持久化实体都继承抽象类 `Domain`,该类强制要求实现 `getId()` 方法: ```java public class User extends IdDomain { @Field(label = "用户名", isRequired = true, isQuery = true) private String username; @Field(label = "邮箱", isUnique = true) private String email; } ``` ### 2. 元数据注册中心(`MetaService`) 应用启动时,框架扫描所有 JPA 实体并构建内存中的元数据注册中心(`MetaDomain` 对象)。每个 `MetaDomain` 记录了: - 表/列映射关系 - 字段校验规则(必填、唯一、最小值/最大值) - CRUD 权限(每个字段的增删改查权限) - 查询能力(支持的运算符、可排序、范围查询) - UI 配置(组件类型、布局、排序) - 关联关系(一对一、一对多、多对一、多对多) - 聚合支持与分组能力 ### 3. 动态查询(`QueryWrapper`) 流式、类型安全的查询构建器,无需编写 Repository 方法: ```java QueryWrapper query = new QueryWrapper<>(User.class) .eq("status", 1) .like("username", "admin") .order("createdDate", OrderType.desc) .group("departmentId"); query.getPage() .setCurPage(1) .setMax(20) .setPageable(true); List users = dynamicService.findAll(User.class, query).orElse(List.of()); long total = dynamicService.count(User.class, query); ``` ### 4. 动态 REST API 配置完成后,每个带注解的领域对象自动暴露以下 REST 端点: | 方法 | 端点 | 说明 | |--------|----------|-------------| | `POST` | `/api/d/{domain}/allList` | 查询全部匹配记录(分页) | | `POST` | `/api/d/{domain}/list` | 查询匹配记录 | | `POST` | `/api/d/{domain}/select` | 查询下拉选择数据 | | `POST` | `/api/d/{domain}/count` | 统计匹配记录数 | | `GET` | `/api/d/{domain}/exists` | 判断记录是否存在 | | `POST` | `/api/d/{domain}/load` | 按条件加载单条记录 | | `GET` | `/api/d/{domain}/{id}` | 按 ID 获取记录 | | `GET` | `/api/d/{domain}/{id}/view` | 获取记录的显示文本 | | `POST` | `/api/d/{domain}` | 创建记录 | | `PUT` | `/api/d/{domain}/{id}` | 更新记录 | | `POST` | `/api/d/{domain}/batch` | 批量增删改 | | `PUT` | `/api/d/{domain}/batch` | 批量更新 | | `DELETE` | `/api/d/{domain}/{id}` | 删除记录 | ### 5. 事件系统 领域生命周期事件(`DomainEvent`)以 Spring `ApplicationEvent` 的形式发布,覆盖 `CREATE`、`UPDATE`、`DELETE`、`BATCHCREATE`、`BATCHUPDATE`、`BATCHREMOVE` 操作,支持解耦的副作用处理(审计、通知、缓存失效等)。 --- ## 快速开始 ### Maven 配置 将 Starter 依赖添加到你的 Spring Boot 项目中: ```xml com.jr.basic meta-jpa-spring-boot-starter 3.5.14 com.jr.basic meta-controller-spring-boot-starter 3.5.14 ``` ### 定义领域类 ```java import com.jr.basic.common.meta.annotation.*; import com.jr.basic.module.meta.jpa.domain.AuditableDomain; import jakarta.persistence.*; @Entity @Table(name = "sys_product") @Meta( name = "product", label = "产品", table = "sys_product", allowDynamic = true, defaultOrder = "createdDate", defaultOrderType = OrderType.desc ) public class Product extends AuditableDomain { @Field(label = "产品名称", isRequired = true, isQuery = true, isList = true, order = 1) private String name; @Field(label = "产品编码", isUnique = true, isQuery = true, order = 2) private String code; @Field(label = "价格", uiType = UIType.NUMBER, precision = 2, order = 3) private BigDecimal price; @Field(label = "分类", uiType = UIType.SELECT, isQuery = true, order = 4) @Enumerated(EnumType.STRING) private ProductCategory category; @Relation( type = MetaRelation.Type.MANY_TO_ONE, joinField = "supplierId", domain = Supplier.class, showField = "name" ) @Field(label = "供应商", uiType = UIType.DOMAINSELECT, order = 5) private Long supplierId; } ``` ### 使用 DynamicService ```java @RestController public class ProductController { @Autowired private DynamicService dynamicService; @GetMapping("/products/search") public List search(@RequestParam String keyword) { QueryWrapper query = new QueryWrapper<>(Product.class) .like("name", keyword) .order("createdDate", OrderType.desc); return dynamicService.findAll(Product.class, query).orElse(List.of()); } @PostMapping("/products") public Product create(@RequestBody Product product) { return dynamicService.create(product); } } ``` ### 访问自动生成的 REST API ```bash # 分页查询产品列表 curl -X POST http://localhost:8080/api/d/product/list \ -H "Content-Type: application/json" \ -d '{"page":{"curPage":1,"max":20,"pageable":true}}' # 创建产品 curl -X POST http://localhost:8080/api/d/product \ -H "Content-Type: application/json" \ -d '{"name":"小工具","code":"W-001","price":29.99}' # 按 ID 获取产品 curl http://localhost:8080/api/d/product/1 # 统计产品数量 curl -X POST http://localhost:8080/api/d/product/count \ -H "Content-Type: application/json" \ -d '{"conditions":[{"field":"price","type":"gt","value":10}]}' ``` --- ## 注解参考 ### `@Meta` — 领域元数据 配置领域对象的操作元数据。 | 属性 | 类型 | 默认值 | 说明 | |-----------|------|---------|-------------| | `name` | `String` | `""` | 领域对象名称 | | `label` | `String` | `""` | 中文显示名称 | | `alias` | `String` | `""` | URL 路径别名 | | `table` | `String` | `""` | 数据库表名 | | `module` | `String` | `""` | 所属模块 | | `allowDynamic` | `boolean` | `true` | 是否启用动态 API | | `allowCreate` | `boolean` | `true` | 是否允许创建 | | `allowUpdate` | `boolean` | `true` | 是否允许修改 | | `allowDelete` | `boolean` | `true` | 是否允许删除 | | `allowBatch` | `boolean` | `false` | 是否允许批量操作 | | `allowRegister` | `boolean` | `false` | 是否允许注册 | | `allowExistsCheck` | `boolean` | `false` | 是否允许存在性检查 | | `enable` | `boolean` | `true` | 启用/禁用该领域对象 | | `isCache` | `boolean` | `false` | 是否启用缓存 | | `isLogicDelete` | `boolean` | `false` | 是否逻辑删除(软删除) | | `isMock` | `boolean` | `true` | 是否支持 Mock 数据生成 | | `isSharding` | `boolean` | `false` | 是否分库分表 | | `owner` | `String` | `""` | 数据归属人字段(数据隔离) | | `showField` | `String` | `""` | 显示字段(如 name) | | `viewType` | `String` | `""` | 视图模板类型 | | `entityGraph` | `String` | `""` | JPA 实体图加载策略 | | `defaultOrder` | `String[]` | `{}` | 默认排序字段 | | `defaultOrderType` | `OrderType[]` | `{}` | 默认排序方向 | | `fieldGroups` | `String[]` | `{}` | 字段分组定义 | | `listRole` | `String[]` | `{}` | 列表查询所需角色 | | `createRole` | `String[]` | `{}` | 创建操作所需角色 | | `updateRole` | `String[]` | `{}` | 修改操作所需角色 | | `deleteRole` | `String[]` | `{}` | 删除操作所需角色 | | `remark` | `String` | `""` | 描述说明 | | `preStatisticsDomain` | `Class[]` | `{}` | 预统计关联领域对象 | ### `@Field` — 字段元数据 领域字段的丰富元数据注解。 | 属性 | 类型 | 默认值 | 说明 | |-----------|------|---------|-------------| | `name` | `String` | `""` | 字段名称 | | `label` | `String` | `""` | 中文显示名 | | `columnName` | `String` | `""` | 数据库列名 | | `isKey` | `boolean` | `false` | 是否主键 | | `isRequired` | `boolean` | `false` | 是否必填 | | `isUnique` | `boolean` | `false` | 是否唯一 | | `isVirtual` | `boolean` | `false` | 是否虚拟/计算字段 | | `isQuery` | `boolean` | `false` | 是否可查询 | | `isSort` | `boolean` | `false` | 是否可排序 | | `isRangeQuery` | `boolean` | `false` | 是否支持范围查询 | | `isList` | `boolean` | `true` | 是否在列表中显示 | | `isCreate` | `boolean` | `true` | 创建时是否可编辑 | | `isUpdate` | `boolean` | `true` | 修改时是否可编辑 | | `isView` | `boolean` | `true` | 详情中是否显示 | | `isDict` | `boolean` | `false` | 是否字典字段 | | `dictCode` | `String` | `""` | 字典编码 | | `isGroup` | `boolean` | `false` | 是否可分组的 | | `isJsonIgnore` | `boolean` | `false` | JSON 输出时忽略 | | `uiType` | `UIType[]` | `{}` | UI 组件类型 | | `uiParams` | `String` | `""` | UI 组件参数 | | `queryType` | `String` | `"eq"` | 默认查询操作符 | | `allowQueryType` | `String[]` | `{}` | 允许的查询操作符 | | `validateType` | `String[]` | `{}` | 校验规则 | | `defaultValue` | `String` | `""` | 默认值 | | `aggregates` | `Aggregate[]` | `{}` | 支持的聚合函数 | | `precision` | `int` | `0` | 小数精度 | | `colSpan` | `int` | `12` | UI 栅格列宽 | | `rowSpan` | `int` | `1` | UI 栅格行高 | | `order` | `int` | `5` | 显示排序 | | `importNum` | `int` | `-1` | 导入列序号 | | `exportNum` | `int` | `-1` | 导出列序号 | | `mockPattern` | `String` | `""` | Mock 数据表达式 | | `parentField` | `String[]` | `{}` | 上级级联字段 | | `fieldGroup` | `String` | `""` | 字段分组 | | `preStatistics` | `boolean` | `false` | 是否预统计 | | `remark` | `String` | `""` | 字段说明 | | `listRole` | `String[]` | `{}` | 列表查看所需角色 | | `createRole` | `String[]` | `{}` | 创建所需角色 | | `updateRole` | `String[]` | `{}` | 修改所需角色 | | `viewRole` | `String[]` | `{}` | 查看所需角色 | | `queryRole` | `String[]` | `{}` | 查询所需角色 | ### `@Relation` — 领域关联 定义领域对象之间的关联关系。 | 属性 | 类型 | 说明 | |-----------|------|-------------| | `type` | `MetaRelation.Type` | 关联类型:`ONE_TO_MANY`(一对多)、`MANY_TO_MANY`(多对多)、`ONE_TO_ONE`(一对一)、`MANY_TO_ONE`(多对一) | | `joinField` | `String` | 外键/关联字段 | | `domain` | `Class` | 关联的领域类 | | `showField` | `String` | 关联实体的显示字段 | | `searchField` | `String[]` | 可在关联中搜索的字段 | | `remark` | `String` | 描述说明 | ### `@VO` / `@VField` — 值对象 用于定义 DDD 值对象/视图对象: ```java @VO(label = "产品概要", domain = Product.class) public class ProductSummary { @VField(label = "产品名称", metaField = "name") private String productName; @VField(label = "价格", metaField = "price") private BigDecimal price; } ``` --- ## API 参考 ### DynamicService CRUD 操作的主要服务接口: ```java // 查询所有 Optional> findAll(Class clazz); Optional> findAll(Class clazz, QueryWrapper query); // 聚合查询 Optional>> findAggregate(Class clazz, QueryWrapper query); Integer countAggregate(Class clazz, QueryWrapper query); // 计数 long count(Class clazz, QueryWrapper query); // 单条查询 Optional get(Class clazz, Serializable id); Optional get(Class clazz, QueryWrapper query); // CRUD 操作 T create(T domain); List create(Iterable domains); T update(T domain); T patch(T domain); // 仅合并非空字段 void update(Iterable domains); void update(Class clazz, UpdateBatch updateBatch); // 删除 void delete(Class clazz, Serializable id); void delete(T domain); void deleteAll(Class clazz, QueryWrapper query); void deleteInBatch(Iterable domains); // 批量操作(混合增/删/改) void batch(Class domainClass, List batchParams); ``` ### QueryWrapper — 流式查询构建器 支持以下条件类型: `eq`(等于)、`ne`(不等于)、`gt`(大于)、`lt`(小于)、`ge`(大于等于)、`le`(小于等于)、`gth`(时间大于)、`lth`(时间小于)、`geth`(时间大于等于)、`leth`(时间小于等于)、`like`(模糊匹配)、`llike`(左匹配)、`rlike`(右匹配)、`in`(包含)、`noIn`(不包含)、`isNull`(为空)、`isNotNull`(非空) ```java QueryWrapper query = new QueryWrapper<>(Order.class) .eq("status", "PAID") // status = 'PAID' .geth("createdDate", startDate) // createdDate >= startDate .leth("createdDate", endDate) // createdDate <= endDate .like("customerName", "张") // customerName LIKE '%张%' .in("categoryId", List.of(1L, 2L, 3L)) // categoryId IN (1,2,3) .order("totalAmount", OrderType.desc) .group("categoryId"); // 分页配置 query.getPage().setCurPage(1).setMax(20).setPageable(true); ``` ### 聚合查询 ```java QueryWrapper query = new QueryWrapper<>(Order.class); query.getSelects().add( new Select("categoryId", "category", Select.Aggregate.COUNT) ); query.getSelects().add( new Select("totalAmount", "totalRevenue", Select.Aggregate.SUM) ); query.group("categoryId"); List> stats = dynamicService.findAggregate(Order.class, query).orElse(List.of()); ``` ### 条件批量更新 ```java UpdateBatch update = new UpdateBatch() .query(new QueryWrapper().eq("category", "OLD")) .value("category", "NEW") .value("updatedDate", LocalDateTime.now()); dynamicService.update(Product.class, update); ``` --- ## 高级用法 ### 领域继承体系 框架提供了四种基础类以适应不同场景: | 基础类 | 特性 | |-----------|----------| | `Domain` | 抽象基类,要求实现 `getId()` | | `IdDomain` | 自动生成 `Long` 类型 ID,使用 `@GeneratedValue(strategy = IDENTITY)` | | `VersionDomain` | 继承 `IdDomain`,增加 `@Version` 乐观锁支持 | | `AuditableDomain` | 继承 `VersionDomain`,增加 `createdBy`(创建人)、`createdDate`(创建时间)、`lastUpdatedBy`(最后修改人)、`lastUpdatedDate`(最后修改时间)审计字段 | ### 事件监听 ```java @Component public class ProductEventListener { @EventListener public void handleProductCreated(DomainEvent event) { if (event.getType() == DomainEvent.Type.CREATE) { Product product = event.getDomain(); log.info("产品已创建: {}", product.getId()); // 发送通知、刷新缓存等 } } } ``` ### 自定义命名策略 实现 `MetaNameStrategy` 接口以自定义表名/列名解析规则: ```java @Bean public MetaNameStrategy metaNameStrategy() { return new MetaNameStrategy() { @Override public String getTableName(Class entityClass) { return "t_" + entityClass.getSimpleName().toLowerCase(); } // ... }; } ``` ### 文件附件支持 通过设置 `application.attach.enabled=true` 启用文件附件功能: ```java // 自动暴露端点:/api/f/{domainName}/{id}/{field}.{suffix} // 文件由 AttachService 管理(默认实现:LocalFileAttachServiceImpl) ``` ### 权限控制 基于角色的权限控制直接在注解中配置: ```java @Meta( listRole = {"ADMIN", "MANAGER"}, // 允许查看列表的角色 createRole = {"ADMIN"}, // 允许创建的角色 deleteRole = {"ADMIN"} // 允许删除的角色 ) public class SensitiveData extends AuditableDomain { ... } @Field( label = "成本价", listRole = {"ADMIN", "FINANCE"}, // 仅这些角色在列表中可见 updateRole = {"ADMIN"} // 仅 ADMIN 可以修改 ) private BigDecimal costPrice; ``` ### 支持的 UI 组件类型 `@Field(uiType = UIType.XXX)` 支持以下 UI 组件类型: | 枚举值 | 说明 | 枚举值 | 说明 | |---------|------|---------|------| | `TEXT` | 文本框 | `PASSWORD` | 密码框 | | `TEXTAREA` | 文本域 | `EDITOR` | 富文本编辑器 | | `NUMBER` | 数字框 | `BOOL` | 布尔开关 | | `SELECT` | 下拉框 | `COMBOX` | 可输入下拉框 | | `DATE` | 日期选择 | `DATETIME` | 日期时间选择 | | `TIME` | 时间选择 | `YEAR` | 年份选择 | | `MONTH` | 月份选择 | `YEARMONTH` | 年度月份选择 | | `ENUM` | 枚举选择 | `DICT` | 字典选择 | | `FILE` | 文件上传 | `IMAGE` | 图片上传 | | `IMAGES` | 图片组 | `VIDEO` | 视频上传 | | `ICON` | 图标选择 | `HIDDEN` | 隐藏域 | | `POSITION` | 省市区三级联动 | `REGION` | 区域选择 | | `DOMAINSELECT` | 域对象下拉 | `DOMAINTREESELECT` | 域对象树形选择 | | `DOMAINTABLE` | 域对象列表选择 | `DOMAINCASCADE` | 域对象级联选择 | | `SUBDOMAINTABLE` | 子表创建 | | | --- ## 项目依赖 | 依赖 | 版本 | 用途 | |-----------|---------|---------| | Spring Boot | 3.5.14 | 应用框架 | | Spring Data JPA | (统一管理) | JPA/Hibernate ORM | | Hibernate Validator | 5.3.6.Final | Bean 校验 | | Guava | 33.2.0-jre | Google 核心工具库 | | Hutool | 5.8.22 | Java 工具集 | | Lombok | 1.18.28 | 减少样板代码 | | Commons IO | 2.16.1 | I/O 工具 | | Commons FileUpload | 1.5 | 文件上传支持 | | JJWT | 0.12.3 | JWT 令牌处理 | | Kaptcha | 2.3.2 | 验证码生成 | ---