diff --git a/README.md b/README.md index c7a1976..a417e32 100644 --- a/README.md +++ b/README.md @@ -1,106 +1,126 @@ # tape-mybatis-generator-plugin -> MyBatis 代码生成插件 +> MyBatis 代码生成插件(基于 MyBatis Generator **1.4.1** 开发,Maven 插件建议使用 **1.4.0+**) ## 功能特性 本插件为 MyBatis Generator 提供了以下增强功能: -1. **TapeMybatisGeneratorPlugin** - 扩展 MyBatis Mapper,添加 `selectPrimaryKeyByExample`, `batchInsert` 方法,拓展查询分页支持 -2. **TapeTableRepositoryGeneratorPlugin** - 为非视图表自动生成 Repository 接口和实现类,提供完整的 CRUD 和软删除功能 -3. **TapeViewRepositoryGeneratorPlugin** - 为视图表自动生成 ViewRepository 接口和实现类,提供查询功能 +1. **TapeMybatisGeneratorPlugin** — 扩展 Mapper(`selectPrimaryKeyByExample`、`batchInsert`)与 Example(分页、回收站筛选等) +2. **TapeTableRepositoryGeneratorPlugin** — 为非视图表生成 Repository 接口与实现,提供 CRUD、软删除与回收站 +3. **TapeViewRepositoryGeneratorPlugin** — 为视图表生成 View Repository 接口与实现,提供只读查询 + +**视图表识别**:通过 JDBC 元数据 `tableType == "VIEW"` 判断;非视图表与视图表由不同插件分别生成代码。 + +**运行时依赖**:生成的 Repository 使用 Spring `@Repository`、`@Resource` 及 SLF4J,使用方项目需引入对应依赖。 ## 插件说明 ### TapeMybatisGeneratorPlugin -扩展 MyBatis Mapper,添加以下功能: +扩展 MyBatis Mapper 与 Example 类: -- 在 Mapper 接口中添加 `selectPrimaryKeyByExample` 方法 -- 在 Mapper XML 中生成对应的 SQL 查询语句 +**Mapper 接口 / XML** + +- `selectPrimaryKeyByExample(Example)` — 按条件查询主键列表(支持 Example 分页 `limit`) +- `batchInsert(List)` — 批量插入,返回影响行数 + +**Mapper XML 动态 SQL** + +- 为 `selectByExample`、`selectByExampleWithBLOBs`、`selectAll` 等查询追加 `limit` 片段(`rows` / `offset`) ### TapeTableRepositoryGeneratorPlugin -为非视图表生成 Repository 层代码: +为非视图表生成 Repository(类名后缀由 `domainRepositoryType` 控制,默认 `Repository`): -- **接口位置**: `{facadeRepositoryPackage}.I{TableName}Repository` -- **实现类位置**: `{domainRepositoryPackage}.{TableName}RepositoryImpl` +- **接口**:`{facadeRepositoryPackage}.I{TableName}{domainRepositoryType}` +- **实现**:`{domainRepositoryPackage}.{TableName}{domainRepositoryType}Impl` -**生成的方法**: +示例(默认后缀):`IYourTableNameRepository`、`YourTableNameRepositoryImpl` -- `trashById(long id)` - 移动到回收站(单个) -- `trashAll({Example} example)` - 移动到回收站(批量) -- `deleteById(long id, boolean release)` - 删除(单个,支持物理删除) -- `deleteAll({Example} example, boolean release)` - 删除(批量,支持物理删除) -- `recoverById(long id)` - 从回收站恢复(单个) -- `recoverAll({Example} example)` - 从回收站恢复(批量) -- `findById(long id)` - 根据主键查询数据 -- `findOne({Example} example)` - 查找单条数据 -- `getList({Example} example)` - 获取多条数据 -- `count({Example} example)` - 统计记录数 -- `countByWithPage({Example} example)` - 统计分页记录数 -- `insert({Model} record)` - 插入记录(自动生成 GUID、设置默认值) -- `batchInsert(List<{Model}> records)` - 批量插入记录(自动生成 GUID、设置默认值) -- `updateByExampleSelective({Model} record, {Example} example)` - 按条件更新记录 -- `update({Model} record)` - 更新记录(支持乐观锁) +**生成的方法**(均声明 `throws Throwable`): + +| 方法 | 说明 | +|------|------| +| `trashById(long id)` → `int` | 移入回收站(`is_hidden=1`) | +| `trashAll(Example)` → `int` | 批量移入回收站;自动限定 `is_delete=0` 且 `is_hidden=0` | +| `deleteById(long id, boolean release)` → `int` | `release=false` 软删;`release=true` 物理删除 | +| `deleteAll(Example, boolean release)` → `int` | `release=false` 仅软删回收站中记录(`is_hidden=1`);`release=true` 直接 `deleteByExample` | +| `recoverById(long id)` → `int` | 从回收站恢复 | +| `recoverAll(Example)` → `int` | 批量恢复;自动限定 `is_delete=0` 且 `is_hidden=1` | +| `findAnyById(long id)` → `Model` | 未删除(`is_delete=0`),不区分是否在回收站 | +| `findValidById(long id)` → `Model` | 有效数据(`is_hidden=0` 且 `is_delete=0`) | +| `findTrashById(long id)` → `Model` | 回收站数据(`is_hidden=1` 且 `is_delete=0`) | +| `findOne(Example)` → `Model` | 单条(内部 `usePage(1,1)`) | +| `getList(Example)` → `List` | 列表;按 `resultType` 过滤;含 BLOB 且分页时先查主键再查详情 | +| `count(Example)` → `long` | 计数(含 `resultType` 过滤) | +| `countWithPage(Example)` → `long` | 仅当 `offset`、`rows` 均已设置时调用 `count`,否则返回 `0` | +| `insert(Model)` → `Model` | 插入并返回带 GUID 的记录 | +| `batchInsert(List)` → `List` | 批量插入并返回记录列表 | +| `update(Model)` → `int` | 按主键更新(支持乐观锁) | +| `updateByExampleSelective(Model, Example)` → `int` | 按条件选择性更新 | ### TapeViewRepositoryGeneratorPlugin -为视图表生成 RepoView 层代码: +为视图表生成 View Repository(类名后缀由 `domainViewRepositoryType` 控制,默认 `Repository`): -- **接口位置**: `{facadeViewRepositoryPackage}.I{TableName}Repo` -- **实现类位置**: `{domainViewRepositoryPackage}.{TableName}RepoImpl` +- **接口**:`{facadeViewRepositoryPackage}.I{TableName}{domainViewRepositoryType}` +- **实现**:`{domainViewRepositoryPackage}.{TableName}{domainViewRepositoryType}Impl` -**生成的方法**: +示例(默认后缀):`IYourTableNameRepository`、`YourTableNameRepositoryImpl` -- `findOne({Example} example)` - 查找单条记录 -- `getList({Example} example)` - 获取记录列表(支持分页) -- `count({Example} example)` - 统计记录数 +**生成的方法**(均声明 `throws Throwable`): -### 其他功能 +| 方法 | 说明 | +|------|------| +| `findOne(Example)` → `Model` | 单条 | +| `getList(Example)` → `List` | 列表(支持 Example 分页;含 BLOB 时按 `withBLOBs` 选择查询方法) | +| `count(Example)` → `long` | 计数 | +| `countWithPage(Example)` → `long` | 行为同表 Repository | -通过 `TapeMybatisGeneratorPlugin` 为所有 Example 类添加支持: +### Example 类增强(TapeMybatisGeneratorPlugin) -**添加的字段**: +**所有表/视图共有的字段与方法**: -- `offset` - 偏移量 -- `rows` - 每页数量 -- `startPageNum` - 最小页码(默认 1) -- `ignorePageSize` - 忽略分页数量(默认 10000)每页数量大于10000时,忽略分页 -- `maxPageSize` - 最大每页数量(默认 100) -- `withBLOBs` - 是否返回BLOBs列的数据 -- `resultType` - 返回数据格式:any, trash, valid(默认) +| 字段 / 方法 | 说明 | +|------------|------| +| `offset`、`rows` | 分页偏移与条数 | +| `startPageNum` | 起始页码(默认 `1`,表级可覆盖) | +| `ignorePageSize` | `usePage` 时若 `pageSize >=` 该值则取消分页(默认 `10000`) | +| `maxPageSize` | `usePage` 时每页上限(默认 `100`) | +| `limit(rows)` / `limit(offset, rows)` | 设置分页 | +| `limitOffset(offset, rows)` | 设置 offset,`rows` 置为极大值(仅偏移) | +| `usePage(pageNum, pageSize)` | 按页码计算 offset/rows | +| `getPageNum()` / `getPageSize()` / `getOffset()` / `getRows()` | 读取分页状态;未设 `rows` 时 `getPageSize()` 返回 `ignorePageSize` | +| `getLimitString()` / `getWhereString()` | 调试用 limit/where 字符串 | +| `cloneExample()` | 克隆条件与分页状态 | +| `get/setMaxPageSize`、`get/setIgnorePageSize`、`get/setStartPageNum` | 分页参数读写 | -**添加的方法**: +**仅非视图表额外支持**: -- `limit(int rows)` - 设置每页数量 -- `limit(int offset, int rows)` - 设置偏移量和每页数量 -- `usePage(int pageNum, int pageSize)` - 使用页码和每页数量(自动计算 offset) -- `setWithBLOBs(boolean withBLOBs)` - 设置是否返回BLOBs列的数据 -- `isWithBLOBs()` - 是否返回BLOBs列的数据 -- `setResultType(String type)` - 设置返回值的类型 -- `resultAny()` - 不区分 -- `isResultAny()` - 查询不区分 -- `resultTrash()` - 回收站 -- `isResultTrash()` - 查询回收站 -- `resultValid()` - 有效数据 -- `isResultValid()` - 查询有效数据 -- `getPageNum()` - 获取当前页码 -- `getPageSize()` - 获取当前每页数量 -- `getOffset()` - 获取当前分页limit的offset -- `getRows()` - 获取当前分页limit的rows +| 字段 / 方法 | 说明 | +|------------|------| +| `resultType` | `null`(默认,等同有效数据)、`any`、`trash`、`valid` | +| `setResultType` / `resultAny` / `resultTrash` / `resultValid` | 设置筛选类型 | +| `isResultAny` / `isResultTrash` / `isResultValid` | `isResultValid` 在既非 any 也非 trash 时为 true(含 `resultType==null`) | + +**仅含 BLOB 列的表/视图**: + +| 字段 / 方法 | 说明 | +|------------|------| +| `withBLOBs` | 默认 `true` | +| `setWithBLOBs` / `isWithBLOBs` | 是否查询 BLOB 列 | + +`getList` / `count` 在表 Repository 中会根据 `resultType` 自动附加 `is_hidden`、`is_delete` 条件。 ## 使用方法 ### 1. 在 `pom.xml` 中配置插件 ```xml - application - - org.mybatis.generator mybatis-generator-maven-plugin @@ -142,9 +162,7 @@ ### 2. 在 `mybatis.generator.xml` 中配置插件 ```xml - - @@ -166,12 +184,10 @@ - - @@ -182,47 +198,47 @@ ### 3. 全局配置参数说明 -| 参数名 | 说明 | 默认值 | 必需 | -|--------------------------------|-------------------------------|---------------------------------------------------------|----| -| `targetProject` | 生成代码的目标项目路径 | `src/main/java` | 否 | -| `mapperPackage` | Mapper 接口的包路径 | `com.iqudoo.platform.application.database.mapper` | 是 | -| `modelPackage` | Model 类的包路径 | `com.iqudoo.platform.application.database.model` | 是 | -| `facadeRepositoryPackage` | Repository 接口的包路径 | `com.iqudoo.platform.application.facade.repository` | 否 | -| `domainRepositoryPackage` | Repository 实现类的包路径 | `com.iqudoo.platform.application.domain.repository` | 否 | -| `domainRepositoryType` | RepoView 名称后缀 | `Repository` | 否 | -| `facadeViewRepositoryPackage` | RepoView 接口的包路径 | `com.iqudoo.platform.application.facade.repoview` | 否 | -| `domainViewRepositoryPackage` | RepoView 实现类的包路径 | `com.iqudoo.platform.application.domain.repoview` | 否 | -| `domainViewRepositoryType` | RepoView 名称后缀 | `Repository` | 否 | -| `guidGeneratorClass` | GUID生成工具类 | `com.iqudoo.framework.tape.modules.utils.SnowflakeUtil` | 否 | -| `guidGeneratorCode` | GUID生成方法 | `SnowflakeUtil.nextId()` | 否 | -| `changeLogContextClassPackage` | 变更日志上下文包路径 | `com.iqudoo.platform.application.domain.changeLog` | 否 | -| `changeLogContextClassName` | 变更日志上下文类 | `ChangeLogContext` | 否 | -| `changeLogEnable` | 变更日志监听开关 | `false` | 否 | -| `slowQueryLoggerTime` | 慢查询日志时间阈值 | `300` | 否 | -| `slowQueryLoggerLevel` | 慢查询日志类型:error,warn,debug,info | `error` | 否 | -| `optimisticLockEnable` | 乐观锁开关 | `true` | 否 | -| `ignorePageSize` | 忽略分页阈值 | `10000` | 否 | -| `startPageNum` | 分页开始页码 | `1` | 否 | -| `maxPageSize` | 最大每页数量 | `100` | 否 | +| 参数名 | 说明 | 默认值 | 必需 | +|--------|------|--------|------| +| `targetProject` | 生成代码的目标项目路径 | `src/main/java` | 否 | +| `mapperPackage` | Mapper 接口包路径 | `com.iqudoo.platform.application.database.mapper` | 是 | +| `modelPackage` | Model 类包路径 | `com.iqudoo.platform.application.database.model` | 是 | +| `facadeRepositoryPackage` | 表 Repository 接口包路径 | `com.iqudoo.platform.application.facade.repository` | 否 | +| `domainRepositoryPackage` | 表 Repository 实现类包路径 | `com.iqudoo.platform.application.domain.repository` | 否 | +| `domainRepositoryType` | 表 Repository 类名后缀 | `Repository` | 否 | +| `facadeViewRepositoryPackage` | 视图 Repository 接口包路径 | `com.iqudoo.platform.application.facade.repoview` | 否 | +| `domainViewRepositoryPackage` | 视图 Repository 实现类包路径 | `com.iqudoo.platform.application.domain.repoview` | 否 | +| `domainViewRepositoryType` | 视图 Repository 类名后缀 | `Repository` | 否 | +| `guidGeneratorClass` | GUID 生成工具类(需 import) | `com.iqudoo.framework.tape.modules.utils.SnowflakeUtil` | 否 | +| `guidGeneratorCode` | GUID 生成表达式(写入生成代码) | `SnowflakeUtil.nextId()` | 否 | +| `changeLogContextClassPackage` | 变更日志上下文包路径 | `com.iqudoo.platform.application.domain.changeLog` | 否 | +| `changeLogContextClassName` | 变更日志上下文类名 | `ChangeLogContext` | 否 | +| `changeLogEnable` | 变更日志开关 | `false` | 否 | +| `slowQueryLoggerTime` | 慢查询阈值(毫秒) | `300` | 否 | +| `slowQueryLoggerLevel` | 慢查询日志级别:error / warn / debug / info | `error` | 否 | +| `optimisticLockEnable` | 乐观锁开关 | `true` | 否 | +| `ignorePageSize` | `usePage` 取消分页的 pageSize 阈值 | `10000` | 否 | +| `startPageNum` | 分页起始页码 | `1` | 否 | +| `maxPageSize` | 单页最大条数 | `100` | 否 | -### 3. TABLE级配置 -> 当存在table配置时,以table配置优先,未配置时使用全局配置,目前支持的table属性如下 +### 4. TABLE 级配置 -| 参数名 | -|------------------------| -| `changeLogEnable` | -| `slowQueryLoggerTime` | -| `slowQueryLoggerLevel` | -| `optimisticLockEnable` | -| `ignorePageSize` | -| `startPageNum` | -| `maxPageSize` | +表级 `` 优先于全局 ``,未配置时回退到全局值。 + +| 参数名 | 说明 | +|--------|------| +| `changeLogEnable` | 变更日志开关 | +| `slowQueryLoggerTime` | 慢查询阈值(毫秒) | +| `slowQueryLoggerLevel` | 慢查询日志级别 | +| `optimisticLockEnable` | 乐观锁开关 | +| `ignorePageSize` | 取消分页阈值 | +| `startPageNum` | 起始页码 | +| `maxPageSize` | 单页最大条数 | 示例: ```xml - - fieldChanges) { - // your thing code + public static void addLog(String tableName, String eventType, Long dataGuid, + Map fieldChanges) { + // 自行实现 } - } ``` +**eventType 取值**: + +| eventType | 触发操作 | +|-----------|----------| +| `insert` | `insert` | +| `batchInsert` | `batchInsert` | +| `update` | `update` | +| `updateByExampleSelective` | `updateByExampleSelective` | +| `deleteById` | `deleteById`(软删) | +| `deleteAll` | `deleteAll`(软删) | +| `trashById` | `trashById` | +| `trashAll` | `trashAll` | +| `recoverById` | `recoverById` | +| `recoverAll` | `recoverAll` | + +`fieldChanges` 中 `Object[]` 为 `[旧值, 新值]`;插入/删除类事件通常为空 `Map`。 + ## 数据库表结构要求 ### 标准表结构模板 -为了使用完整的 Repository 功能(软删除、回收站等),表结构需要包含以下标准字段: +使用完整 Repository 功能(软删除、回收站、乐观锁)时,表需包含以下标准字段: ```mysql DROP TABLE IF EXISTS `your_table_name`; CREATE TABLE `your_table_name` ( `guid` bigint(0) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'GUID', - -- ---------------------------- - -- add your table other table field - -- ---------------------------- + -- 业务字段 `is_hidden` int(0) NOT NULL DEFAULT 0 COMMENT '隐藏标志', `is_delete` int(0) NOT NULL DEFAULT 0 COMMENT '删除标志', `delete_token` varchar(32) NULL DEFAULT '' COMMENT '删除令牌', @@ -287,11 +315,11 @@ CREATE TABLE `your_table_name` ( ### 索引优化指南 -唯一键索引: +唯一键索引(含 `delete_token` 以支持回收站后重建): ```sql UNIQUE KEY `idx_your_unique_key` ( - `you unique key`, + `your_unique_key`, `delete_token` ) USING BTREE ``` @@ -299,33 +327,31 @@ UNIQUE KEY `idx_your_unique_key` ( 查询索引: ```sql -KEY `idx_your_query_case` ( - /* 等值查询字段 */ - `is_hidden`,`is_delete`, - /* 其他参与排序字段 */ +KEY `idx_your_query_case` ( + `is_hidden`, `is_delete`, `create_time` desc, `guid` ) USING BTREE ``` -**必需字段说明**: +**标准字段说明**: -- `guid` - 主键,类型为 `bigint UNSIGNED` -- `is_hidden` - 隐藏标志,用于回收站功能 -- `is_delete` - 删除标志,用于软删除功能 -- `delete_token` - 删除令牌,用于标识删除状态 -- `data_version` - 数据版本,用于乐观锁 -- `create_time` - 创建时间,自动设置 -- `update_time` - 更新时间,自动更新 +| 字段 | 说明 | +|------|------| +| `guid` | 主键,`bigint UNSIGNED` | +| `is_hidden` | 回收站标志(`1` = 在回收站) | +| `is_delete` | 软删除标志 | +| `delete_token` | 删除令牌(有效数据为 `VALID`,进回收站后变更) | +| `data_version` | 乐观锁版本号 | +| `create_time` / `update_time` | 插入时自动设置 | -### 视图表结构 +### 视图表 -视图表不需要上述标准字段,只需要包含业务字段即可。 +视图表无需上述标准字段,仅需业务列;由 `TapeViewRepositoryGeneratorPlugin` 生成只读 Repository。 ### 在 `mybatis.generator.xml` 中配置表 ```xml -
= ignorePageSize` 时不加分页。 +4. **乐观锁**:`update` 使用 `data_version`;`optimisticLockEnable=false` 时不校验版本。 +5. **软删除**:`deleteById` / `deleteAll` 默认软删(`is_delete=1`);`release=true` 为物理删除。 +6. **回收站**:`trash*` 设置 `is_hidden=1`;`recover*` 恢复为 `is_hidden=0`、`delete_token=VALID`。 +7. **批量删除**:`deleteAll(release=false)` 仅作用于已在回收站的记录。 +8. **自动字段**:`insert` / `batchInsert` 自动设置 `guid`(`guidGeneratorCode`)、`is_delete=0`、`is_hidden=0`、`delete_token=VALID`、`data_version=1`、时间戳等。 +9. **BLOB**:含 BLOB 列时,`getList` 分页查询先 `selectPrimaryKeyByExample` 再按 GUID 拉取详情;可通过 `withBLOBs` 控制是否查询 BLOB 列。