86 Commits
Author SHA1 Message Date
odboy aaf3d5fa1c !8 refactor(system): 重构系统模块中的菜单和角色关联关系
Merge pull request !8 from Odboy/dev
2026-01-15 13:54:00 +00:00
odboy 9e306aadc5 refactor(system): 重构系统模块中的菜单和角色关联关系 2026-01-15 21:52:56 +08:00
odboy 8918ce781b refactor(menu): 重构菜单服务提升性能和代码质量
- 将控制器返回类型从SystemMenuVo改为SystemMenuTb,避免不必要的对象转换
- 在Mapper层添加listAll默认方法提高数据查询效率
- 移除KitBeanUtil依赖减少代码耦合
- 引入懒加载代理解决循环依赖问题
- 优化菜单创建和编辑逻辑,使用exists方法提升数据库查询性能
- 重写菜单删除逻辑,采用批量操作和层级遍历提升删除效率
- 更新方法签名统一使用SystemMenuTb实体类
- 简化菜单父子关系查询逻辑,提升代码可读性
2026-01-15 19:18:40 +08:00
odboy a93a44c3d4 refactor(role): 优化角色服务中的权限查询和数据操作逻辑 2026-01-15 18:11:07 +08:00
odboy ff723a6044 chore(framework): 更新版权年份至2026年 2026-01-15 17:18:54 +08:00
odboy 0c57ef3d84 fix(quartz): 修复定时任务参数传递和文档注释问题
- 将 QuartzRunnable 中空字符串参数改为 null 值传递
- 为 SystemQuartzJobService 中的方法添加 TestPassed 标记注释
- 添加查询启用定时任务和根据ID查询定时任务的新方法
- 修复前端用户中心页面请求耗时显示的空值问题
- 在定时任务界面添加 Cron 表达式在线生成链接
- 统一后端服务层中查询方法的注释描述用词
2026-01-15 16:59:33 +08:00
odboy bb664df62f refactor(quartz): 重构定时任务相关服务和控制器 2026-01-15 16:17:23 +08:00
odboy 40f4657d6f refactor(storage): 重构本地存储服务的文件上传功能 2026-01-15 15:32:56 +08:00
odboy 6c79c5a0d0 refactor(job): 重构职位服务中的重复检查逻辑 2026-01-15 13:47:49 +08:00
odboy 4fc51fa0b5 refactor(system): 统一查询方法命名规范 2026-01-15 13:17:47 +08:00
odboy bba40ae048 feat(SystemUserJobService): 添加用户岗位绑定功能测试标记 2026-01-15 13:10:12 +08:00
odboy 252ae3765f docs(SystemUserRoleService): 更新用户角色服务类的Java文档注释
- 为批量绑定用户角色方法添加测试通过标记注释
- 为批量解绑用户角色方法添加测试通过标记注释
- 为根据用户ID查询方法添加测试通过标记注释
- 为权限检查方法添加测试通过标记注释
- 为根据用户id列举角色方法添加完整JavaDoc注释
- 为根据用户id列举角色级别方法添加完整JavaDoc注释
2026-01-15 11:17:28 +08:00
odboy 7425577126 refactor(system): 重构系统模块中的用户和角色相关功能 2026-01-15 11:11:30 +08:00
odboy 4d773797cd style(java): 优化代码格式和清理未使用导入 2026-01-15 09:35:18 +08:00
odboy 5178be95b3 Merge remote-tracking branch 'gitee/dev' into dev 2026-01-15 09:30:19 +08:00
odboy 4684b8ea5e refactor(framework): 优化 MyBatis Plus 查询工具类代码 2026-01-15 09:30:07 +08:00
odboy 5875ce0349 !5 refactor(system): 重构系统角色服务代码结构
Merge pull request !5 from Odboy/dev
2026-01-14 13:20:16 +00:00
odboy 31c4c3c0e1 refactor(system): 重构系统角色服务代码结构 2026-01-14 21:19:29 +08:00
odboy cf65b4f5ab feat(dict): 添加字典明细查询功能并重构系统服务代码结构 2026-01-14 20:20:11 +08:00
odboy c008daaaa1 style(operalog): 格式化操作日志切面代码并增强JSON序列化容错性 2026-01-14 20:14:12 +08:00
odboy 85e4557376 refactor(core): 替换 CollectionUtil 为 CollUtil 并优化代码结构 2026-01-14 18:53:52 +08:00
odboy c9db1e58f3 refactor(system): 重构系统模块的数据访问层和服务层
- 修改用户服务中的用户转换逻辑,区分是否包含密码的场景
- 优化部门层级查询性能,减少数据库查询次数
2026-01-14 18:42:13 +08:00
odboy 8e4e783871 !3 chore(config): 更新RSA私钥和Base64密钥配置
Merge pull request !3 from Odboy/dev
2026-01-14 04:47:22 +00:00
odboy 64a9dd2a4f chore(config): 更新RSA私钥和Base64密钥配置 2026-01-14 09:58:00 +08:00
odboy 7f72553ddd fix(starter配置): 追加缺少的配置项 2026-01-14 09:48:54 +08:00
odboy c11fd19351 refactor(constant): 将应用名称和标题常量统一管理 2026-01-13 14:19:30 +08:00
odboy 3b3bfff2c5 fix(util): 优化SQL工具类错误提示信息 2026-01-13 13:34:12 +08:00
odboy 0685e3ba28 refactor(system): 重构系统模块的分页参数处理和代码优化 2026-01-12 18:56:51 +08:00
odboy f41f436dd8 refactor(quartz): 重构定时任务日志查询接口参数处理 2026-01-12 18:54:31 +08:00
odboy 5aa5624350 style(framework): 优化代码风格和日志格式 2026-01-12 17:45:27 +08:00
odboy 8aa0830213 refactor(java): 优化Java代码实现细节 2026-01-12 17:30:23 +08:00
odboy b88254084d style(task) 2026-01-12 15:55:51 +08:00
odboy a55fbe0f06 refactor(task): 优化任务步骤执行逻辑 2026-01-12 15:49:58 +08:00
odboy ff22d3072c refactor(system): 重构系统模块的数据查询和分页功能 2026-01-12 15:12:40 +08:00
odboy 46bb831dea !2 docs(framework): 更新注释和导入包
Merge pull request !2 from Odboy/master
2026-01-09 04:38:43 +00:00
odboy e511ccdd6d docs(framework): 更新注释和导入包 2026-01-09 12:35:16 +08:00
odboy 4c7d250500 refactor(util): 重构工具类代码以改进资源管理和验证逻辑 2026-01-09 11:57:06 +08:00
odboy 42b9adc5bd refactor(framework): 优化代码结构和类型安全 2026-01-09 11:42:45 +08:00
odboy 2ece7de4de perf(security): 提升RSA加密密钥长度至4096位
- 将后端RSA密钥生成器初始化从1024位提升至4096位
- 更新前端RSA公钥配置为新的4096位密钥对
- 增强数据传输安全性并提高加密强度
2026-01-09 11:19:58 +08:00
odboy e5f11bb452 refactor(util): 重构工具类 2026-01-09 11:19:17 +08:00
odboy 00c3fddbf1 refactor(util): 重构工具类 2026-01-09 11:09:08 +08:00
odboy 01761ebf91 refactor(operalog): 优化操作日志切面的时间间隔处理 2026-01-08 19:34:35 +08:00
odboy a071953398 feat(util): 添加参数验证工具类并重构系统服务 2026-01-08 10:24:13 +08:00
odboy b8183844cd refactor(system): 重构系统服务模块的代码结构 2026-01-08 10:23:43 +08:00
odboy 20fb90b373 refactor(controller): 重构控制器代码结构和依赖管理 2026-01-08 09:44:51 +08:00
odboy 67d2170eda refactor(system): 重构系统模块的模型包结构 2026-01-08 09:34:08 +08:00
odboy 547421ad44 refactor(auth): 重构登录认证和验证码功能
- 创建 SystemAuthVo 类用于统一登录返回数据结构
- 创建 SystemCaptchaVo 类用于验证码信息封装
- 将验证码功能从 SystemAuthService 拆分为独立的 SystemCaptchaService
- 登录接口返回类型从 Map 改为 SystemAuthVo
- 验证码接口返回类型从 Map 改为 SystemCaptchaVo
- 登录时验证码校验改为调用 SystemCaptchaService
- 移除 SystemAuthService 中的验证码相关代码
- 统一数据返回格式,提高代码可读性
2026-01-08 09:25:31 +08:00
odboy da6fe40960 refactor(system): 重构系统模块的VO类和定时任务处理 2026-01-07 19:18:05 +08:00
odboy 394d1409e1 refactor(system): 优化角色服务的事务处理和集合操作 2026-01-07 18:40:22 +08:00
odboy 6364b0f577 refactor(system): 统一使用VO对象进行数据传输和处理 2026-01-07 18:37:59 +08:00
odboy e88d535153 refactor(util): 移除多余BeanUtil导入并添加参数验证工具类 2026-01-07 18:09:04 +08:00
odboy 54cae0855b refactor(auth): 优化用户认证信息获取逻辑 2026-01-07 16:26:33 +08:00
odboy b2cae22719 config(proxy): 添加验证码接口代理配置 2026-01-07 16:25:58 +08:00
odboy 1165eabb4b refactor(framework): 优化Bean拷贝工具类并更新相关实体类结构 2026-01-07 16:19:08 +08:00
odboy 595ab093b9 chore(version): 更新项目版本号从1.4.1到1.5.0 2025-12-31 15:58:20 +08:00
odboy 2182e4bd66 refactor(system): 重构系统服务依赖关系和服务调用方式 2025-12-31 15:54:50 +08:00
odboy 467b2a7d93 feat(user): 加入审计日志、用户中心操作日志 2025-12-31 15:19:40 +08:00
odboy bab3ea1a15 refactor(security): 修正静态资源配置 2025-12-31 15:18:18 +08:00
odboy cddb0cff08 refactor(api): 重构系统模块API函数命名规范 2025-12-31 14:36:34 +08:00
odboy 373a23159d refactor(api): 统一API接口命名规范 2025-12-31 14:24:38 +08:00
odboy 48e6e9298a refactor(api): 重构API端点和前端CRUD配置 2025-12-31 13:48:04 +08:00
odboy 5248d75a6e fix(upload): 修复本地文件上传路径生成问题
- 修复了在MAC系统下上传路径中用户名前缺少斜杠的问题
- 确保上传路径格式的一致性
2025-12-31 13:47:09 +08:00
odboy 4a4b3f1690 refactor(api): 重构系统API模块函数顺序和注释 2025-12-31 13:12:28 +08:00
odboy aa77eaf1b6 chore(deps): 更新 axios 依赖版本
- 将 axios 从 1.8.2 版本更新到 1.12.0 版本
- 修复潜在的安全漏洞和 bug
- 提升 HTTP 请求处理的稳定性
2025-12-31 13:12:02 +08:00
odboy 46ba8b966e refactor(system): 重构系统模块中的导出功能实现 2025-12-31 12:42:08 +08:00
odboy 6e778ff337 feat(util): 添加Excel导出工具类并重构导出功能
- 新增KitExcelExporter工具类,支持普通和分页模式导出
- 新增KitExcelPageWriteHelper分页写入工具,解决大数据量OOM问题
- 替换原有的KitXlsxExportUtil导出实现
- 重构部门、字典、岗位、菜单、角色等模块的导出功能
- 实现用户数据分页导出功能,支持大数据量场景
- 优化导出文件响应头设置和编码处理
2025-12-31 12:05:29 +08:00
odboy b15182afde feat(xlsx): 添加Excel导出工具类并重构导出功能
- 新增KitXlsxExportDataTransferRowHandler接口用于数据转换
- 新增KitXlsxExportUtil工具类提供统一的Excel导出功能
- 添加多个ExportRowVo类用于导出数据映射
- 重构部门、字典、岗位、菜单等模块的导出功能使用新工具类
- 添加SystemYesOrNoChConst和SystemZhConst常量接口
- 标记KitFileUtil.downloadExcel方法为废弃
- 优化文件名验证逻辑和字符串类型判断
2025-12-30 18:01:24 +08:00
odboy 88fbe36145 chore(deps): 更新 fastexcel 依赖版本
- 将 fastexcel 版本从 1.2.0 升级到 1.3.0
- 更新 cutejava-springboot3 模块中的 fastexcel 版本属性
2025-12-30 17:52:50 +08:00
odboy 83f75831f0 chore(build): 更新项目依赖版本并优化代码格式
- 升级 Spring Boot 父项目版本至 3.5.9
- 更新 MySQL 连接器版本至 9.4.0
- 更新 MyBatis-Plus 版本至 3.5.14
- 更新 Fastjson2 版本至 2.0.59
- 更新 Hutool 版本至 5.8.41
- 更新 JJWT 版本至 0.12.6
- 更新 Knife4j 版本至 4.5.0
- 更新 Undertow 版本至 2.3.20.Final
- 更新 Oshi 版本至 6.6.5
- 更新 Guava 版本至 33.5.0-jre
- 格式化注解文件中的代码缩进
- 移除多余的空行和注释格式调整
2025-12-30 12:53:51 +08:00
odboy 377b0989f8 refactor(system): 重构系统模块控制器代码结构
- 解决所有接口分页异常
- 剥离控制器校验逻辑
- 解决循环依赖问题
- 解决角色赋权后,权限回显不正确
2025-12-30 12:51:31 +08:00
odboy 79b847f9a4 fix(system): 修复重构导致用户认证失败问题 2025-12-30 10:29:12 +08:00
odboy 866e689ad3 feat(dict): 添加字典明细分页查询功能 2025-12-29 17:18:02 +08:00
odboy 4097e1801f style(java): 统一Springboot3版本代码格式化和优化依赖配置 2025-12-29 12:02:27 +08:00
odboy c1521dcb9a !1 refactor(system): 重构系统模块中的数据查询和删除方法命名
Merge pull request !1 from Odboy/feature_v202512
2025-12-29 03:54:20 +00:00
odboy 5a9dfcbe4d refactor(system): 重构系统模块中的数据查询和删除方法命名 2025-12-28 14:45:09 +08:00
odboy 830e122b79 refactor(service): 重构查询参数命名和方法调用 2025-12-28 13:15:57 +08:00
odboy 765b993101 refactor(system): 重构系统模块中的部门、字典、菜单等服务方法命名和实现
- 统一将修改方法名从 modify* 改为 update*
- 统一将删除方法名从 remove* 改为 delete*
- 统一将查询方法名从 query* 改为 search* 或 list*
- 重构部门服务中的树形结构构建逻辑
- 优化部门上级数据查询方法实现
- 调整数据权限查询方法命名
- 删除未使用的导入和方法
- 修复部门关联验证中的用户查询服务依赖
2025-12-28 10:54:19 +08:00
odboy 3a48388dec refactor(dal): 将数据访问层的查询方法从Mapper接口移至服务层 2025-12-27 16:50:01 +08:00
odboy 05914f1548 refactor(system): 重构系统模块的数据访问层和业务逻辑 2025-12-27 11:59:36 +08:00
odboy 79cb44c522 refactor(role): 重构角色服务的数据访问层实现 2025-12-27 11:55:19 +08:00
odboy fc951973a4 refactor(system): 重构用户模块数据查询逻辑 2025-12-27 11:43:11 +08:00
odboy 8113539fc6 refactor(system): 重构角色模块数据查询逻辑 2025-12-27 11:42:52 +08:00
odboy e31d9d7be8 fix(test): 修复测试类中实体对象类型错误
- 修复SystemApplicationTests中导入SystemUserVo类
- 修正测试数据创建时使用SystemUserVo替换SystemUserTb
- 更新Spring Boot父版本从3.3.13到3.5.9
2025-12-26 15:21:24 +08:00
odboy 137a35ee28 refactor: 解决springboot3版本功能异常问题 2025-12-26 14:43:40 +08:00
odboy 69800ef5c7 style(pom): 格式化pom.xml文件结构
- 统一XML元素的缩进格式
- 调整依赖项和模块的缩进层级
- 优化配置元素的布局结构

style(annotations): 优化注解类代码格式

- 调整AnonymousAccess注解的结构
- 重新格式化AnonymousDeleteMapping注解的属性布局
- 重新格式化AnonymousGetMapping注解的属性布局
- 重新格式化AnonymousPatchMapping注解的属性布局
- 重新格式化AnonymousPostMapping注解的属性布局
- 统一注解属性的缩进和换行格式
2025-12-26 13:56:15 +08:00
odboy 6ca6fdd567 refactor(system): 重构字典明细查询功能
- 创建 SystemDictDetailVo 视图对象用于数据传输
- 修改控制器返回类型为 SystemDictDetailVo
- 重构查询方法使用 LambdaQueryWrapper 替代 XML 配置
- 移除 SystemDictDetailTb 中的 dict 关联字段
- 添加字典名称查询的辅助方法
- 更新前端组件移除搜索功能并简化工具栏
2025-12-25 16:30:39 +08:00
683 changed files with 32043 additions and 27094 deletions
+43
View File
@@ -24,6 +24,7 @@
- ~~常用的辅助类的类名, 以`Cs`开头~~
- 常用的辅助类的类名, 以`Kit`开头。Kit有套件、装备等意思。
- 枚举类名,以`Enum`结尾
- 内部调用一律声明this
- 拒绝过度包装
- 命名规则(Mapper or Service)
- 简单查询:get + 名词
@@ -32,6 +33,7 @@
- 搜索(分页)功能:search + 名词
- 统计计数:count + By + 条件
- 存在检查:exists + By + 条件
- 增删改:save/delete/update
- 例子: 查询分页、查询列表的方法
- 分页:searchUser(args, page)
- 列表:listUser + (args)
@@ -44,6 +46,47 @@
- 单个:getUser + by + (args)
- 统计计数:count + By + (args)
#### 编码规范:举例说明
1. getUser - 简单查询
核心: 获取单个特定实体。
- 输入: 通常是一个唯一标识符(如ID 123)。
- 筛选: 非常精确,只匹配一个。
- 返回: 单个对象或文档,包含该用户的完整/详细信息。
- 示例: getUser(123) -> 返回 {id: 123, name: “Alice”, email: “...”}
2. listUsers - 列表查询
核心: 获取一个符合简单条件的实体集合,通常是有限的、预定义的。
- 输入: 可能没有参数,或只有非常简单的过滤条件(如 status=‘active’)。
- 筛选: 简单、常规。
- 返回: 一个数组/列表,包含多个用户的基本信息(通常是摘要字段,非完整详情)。
- 通常不分页,或隐式返回所有符合条件的(数据量预期不大)。
- 示例: listUsers() -> 返回 [{id: 1, name: “Alice”}, {id: 2, name: “Bob”}]
- 示例: listUsers({role: ‘admin’}) -> 返回所有管理员用户的列表。
3. queryUsersByCondition - 复杂查询
核心: 基于多个、可能较复杂的条件进行筛选。
- 输入: 一个组合条件对象,可能涉及多个字段的比较(如 age > 18 AND department = ‘Sales’ AND joinDate < ‘2023-01-01’)。
- 筛选: 复杂、灵活,类似数据库的WHERE子句。
- 返回: 一个匹配条件的数组/列表。
- 分页: 可能分页,也可能不分页。关键是它的侧重点在于复杂的“筛选”能力,而非分页机制。(这是标准,但是对于此项目来说,定为不分页的,复杂条件的,列表查询服务)
- 示例: queryUsersByCondition({minAge: 18, department: ‘Sales’, hasCertification: true})
4. searchUsers - 搜索(分页)功能
核心: 针对大量数据进行模糊匹配、全文检索,并强制包含分页机制以管理性能。
- 输入:
- 搜索关键词(可能对多个字段进行模糊匹配)。
- 分页参数(pageNumber, pageSize 或 limit, offset)。
- 可能附加的其他过滤条件。
- 筛选: 通常包含文本搜索(如 name LIKE ‘%Al%’),结果可能按相关性排序。
- 返回: 一个分页响应对象,而不仅仅是数组。
- 包含:data(当前页的数据列表)、total(总匹配数)、page(当前页)、pageSize(每页大小)等元数据。
- 示例: searchUsers({keyword: ‘Al’, page: 1, pageSize: 20}) -> 返回 {data: […], total: 45, page: 1, pageSize: 20}
#### 主要特性
- 使用最新技术栈,社区资源丰富。
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "cutejava-front",
"version": "1.4.1",
"version": "1.5.0",
"description": "CuteJava 前端源码",
"author": "Odboy",
"license": "Apache-2.0",
@@ -38,7 +38,7 @@
"@riophae/vue-treeselect": "^0.4.0",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^1.0.2",
"axios": "1.8.2",
"axios": "1.12.0",
"clipboard": "2.0.4",
"codemirror": "^5.49.2",
"core-js": "^2.6.12",
+2 -2
View File
@@ -15,14 +15,14 @@ export function login(username, password, code, uuid) {
export function getInfo() {
return request({
url: 'auth/info',
url: 'api/user/getCurrentUserInfo',
method: 'post'
})
}
export function getCodeImg() {
return request({
url: 'auth/captcha/getImage',
url: 'captcha/getCode',
method: 'post'
})
}
+6 -6
View File
@@ -1,27 +1,27 @@
import request from '@/utils/request'
export function sendResetEmailCaptcha(email) {
export function sendResetEmailCode(email) {
return request({
url: 'api/captcha/sendResetEmailCaptcha?email=' + email,
url: 'api/captcha/sendResetEmailCode?email=' + email,
method: 'post'
})
}
export function sendResetPasswordCaptcha(email) {
export function sendResetPasswordCode(email) {
return request({
url: 'api/captcha/sendResetPasswordCaptcha?email=' + email,
url: 'api/captcha/sendResetPasswordCode?email=' + email,
method: 'post'
})
}
export function checkEmailCaptcha(email, code, bizCode) {
export function verifyCode(email, code, bizCode) {
const params = {
email: email,
code: code,
bizCode: bizCode
}
return request({
url: 'api/captcha/checkEmailCaptcha',
url: 'api/captcha/verifyCode',
method: 'post',
data: params
})
+4 -4
View File
@@ -1,15 +1,15 @@
import request from '@/utils/request'
export function queryDeptSelectDataSource() {
export function listDeptSelectDataSource() {
return request({
url: 'api/component/queryDeptSelectDataSource',
url: 'api/component/listDeptSelectDataSource',
method: 'post'
})
}
export function queryDeptSelectProDataSource() {
export function listDeptSelectProDataSource() {
return request({
url: 'api/component/queryDeptSelectProDataSource',
url: 'api/component/listDeptSelectProDataSource',
method: 'post'
})
}
+24 -21
View File
@@ -1,23 +1,8 @@
import request from '@/utils/request'
export function queryDeptList(params) {
return request({
url: 'api/dept',
method: 'post',
data: params
})
}
export function queryDeptSuperiorTree(ids, exclude) {
exclude = exclude !== undefined ? exclude : false
const data = Array.isArray(ids) ? ids : [ids]
return request({
url: 'api/dept/queryDeptSuperiorTree?exclude=' + exclude,
method: 'post',
data: data
})
}
/**
* 默认入口:add、del、edit、get
*/
export function add(data) {
return request({
url: 'api/dept/saveDept',
@@ -28,7 +13,7 @@ export function add(data) {
export function del(ids) {
return request({
url: 'api/dept/removeDeptByIds',
url: 'api/dept/deleteDeptByIds',
method: 'post',
data: ids
})
@@ -36,10 +21,28 @@ export function del(ids) {
export function edit(data) {
return request({
url: 'api/dept/modifyDept',
url: 'api/dept/updateDeptById',
method: 'post',
data: data
})
}
export default { add, edit, del, queryDeptList, queryDeptSuperiorTree }
export function searchDept(params) {
return request({
url: 'api/dept/searchDept',
method: 'post',
data: params
})
}
export function searchDeptTree(ids, exclude) {
exclude = exclude !== undefined ? exclude : false
const data = Array.isArray(ids) ? ids : [ids]
return request({
url: 'api/dept/searchDeptTree?exclude=' + exclude,
method: 'post',
data: data
})
}
export default { add, edit, del, searchDept, searchDeptTree }
+8 -6
View File
@@ -1,5 +1,7 @@
import request from '@/utils/request'
/**
* 默认入口:add、del、edit、get
*/
export function add(data) {
return request({
url: 'api/dict/saveDict',
@@ -10,7 +12,7 @@ export function add(data) {
export function del(ids) {
return request({
url: 'api/dict/removeDictByIds',
url: 'api/dict/deleteDictByIds',
method: 'post',
data: ids
})
@@ -18,18 +20,18 @@ export function del(ids) {
export function edit(data) {
return request({
url: 'api/dict/modifyDictById',
url: 'api/dict/updateDictById',
method: 'post',
data: data
})
}
export function queryPageDict(data) {
export function searchDict(data) {
return request({
url: 'api/dict',
url: 'api/dict/searchDict',
method: 'post',
data: data
})
}
export default { add, edit, del, queryPageDict }
export default { add, edit, del, searchDict }
+6 -4
View File
@@ -1,5 +1,7 @@
import request from '@/utils/request'
/**
* 默认入口:add、del、edit、get
*/
export function get(dictName) {
const params = {
page: 1,
@@ -9,7 +11,7 @@ export function get(dictName) {
}
}
return request({
url: 'api/dictDetail/queryDictDetailByArgs',
url: 'api/dictDetail/searchDictDetail',
method: 'post',
data: params
})
@@ -25,7 +27,7 @@ export function add(data) {
export function del(id) {
return request({
url: 'api/dictDetail/removeDictDetailById',
url: 'api/dictDetail/deleteDictDetailById',
method: 'post',
data: { id: id }
})
@@ -33,7 +35,7 @@ export function del(id) {
export function edit(data) {
return request({
url: 'api/dictDetail/modifyDictDetailById',
url: 'api/dictDetail/updateDictDetailById',
method: 'post',
data: data
})
+4 -4
View File
@@ -7,17 +7,17 @@ export function getLastEmailConfig() {
})
}
export function modifyEmailConfig(data) {
export function updateEmailConfigById(data) {
return request({
url: 'api/email/modifyEmailConfig',
url: 'api/email/updateEmailConfigById',
method: 'post',
data: data
})
}
export function sendEmail(data) {
export function send(data) {
return request({
url: 'api/email/sendEmail',
url: 'api/email/send',
method: 'post',
data: data
})
+19 -18
View File
@@ -1,20 +1,7 @@
import request from '@/utils/request'
export function queryAllEnableJob() {
const params = {
page: 1,
size: 9999999,
args: {
enabled: true
}
}
return request({
url: 'api/job/queryAllEnableJob',
method: 'post',
data: params
})
}
/**
* 默认入口:add、del、edit、get
*/
export function add(data) {
return request({
url: 'api/job/saveJob',
@@ -25,7 +12,7 @@ export function add(data) {
export function del(ids) {
return request({
url: 'api/job/removeJobByIds',
url: 'api/job/deleteJobByIds',
method: 'post',
data: ids
})
@@ -33,10 +20,24 @@ export function del(ids) {
export function edit(data) {
return request({
url: 'api/job/modifyJobById',
url: 'api/job/updateJobById',
method: 'post',
data: data
})
}
export function searchJob() {
const params = {
page: 1,
size: 9999999,
args: {
enabled: true
}
}
return request({
url: 'api/job/searchJob',
method: 'post',
data: params
})
}
export default { add, edit, del }
@@ -1,5 +1,7 @@
import request from '@/utils/request'
/**
* 默认入口:add、del、edit、get
*/
export function add(data) {
return request({
url: 'api/localStorage/uploadFile',
@@ -10,7 +12,7 @@ export function add(data) {
export function del(ids) {
return request({
url: 'api/localStorage/removeFileByIds',
url: 'api/localStorage/deleteFileByIds',
method: 'post',
data: ids
})
@@ -18,7 +20,7 @@ export function del(ids) {
export function edit(data) {
return request({
url: 'api/localStorage/modifyLocalStorageById',
url: 'api/localStorage/updateLocalStorageById',
method: 'post',
data: data
})
+34 -31
View File
@@ -1,15 +1,42 @@
import request from '@/utils/request'
export function queryMenuListByPid(pid) {
/**
* 默认入口:add、del、edit、get
*/
export function add(data) {
return request({
url: 'api/menu/queryMenuListByPid?pid=' + pid,
url: 'api/menu/saveMenu',
method: 'post',
data: data
})
}
export function del(ids) {
return request({
url: 'api/menu/deleteMenuByIds',
method: 'post',
data: ids
})
}
export function edit(data) {
return request({
url: 'api/menu/updateMenuById',
method: 'post',
data: data
})
}
export function listMenuByPid(pid) {
return request({
url: 'api/menu/listMenuByPid?pid=' + pid,
method: 'post'
})
}
export function queryMenuByArgs(params) {
export function searchMenu(params) {
return request({
url: 'api/menu/queryMenuByArgs',
url: 'api/menu/searchMenu',
method: 'post',
data: params
})
@@ -24,9 +51,9 @@ export function queryMenuSuperior(ids) {
})
}
export function queryChildMenuSet(id) {
export function listChildMenuSetByMenuId(id) {
return request({
url: 'api/menu/queryChildMenuSet?id=' + id,
url: 'api/menu/listChildMenuSetByMenuId?id=' + id,
method: 'post'
})
}
@@ -38,28 +65,4 @@ export function buildMenus() {
})
}
export function add(data) {
return request({
url: 'api/menu/saveMenu',
method: 'post',
data: data
})
}
export function del(ids) {
return request({
url: 'api/menu/removeMenuByIds',
method: 'post',
data: ids
})
}
export function edit(data) {
return request({
url: 'api/menu/modifyMenuById',
method: 'post',
data: data
})
}
export default { add, edit, del, queryMenuListByPid, queryMenuSuperior, queryMenuByArgs, queryChildMenuSet }
export default { add, edit, del, listMenuByPid, queryMenuSuperior, searchMenu, listChildMenuSetByMenuId }
+4 -2
View File
@@ -1,5 +1,7 @@
import request from '@/utils/request'
/**
* 默认入口:add、del、edit、get
*/
export function add(data) {
return request({
url: 'api/ossStorage/uploadFile',
@@ -10,7 +12,7 @@ export function add(data) {
export function del(ids) {
return request({
url: 'api/ossStorage/removeFileByIds',
url: 'api/ossStorage/deleteFileByIds',
method: 'post',
data: ids
})
+6 -4
View File
@@ -1,5 +1,7 @@
import request from '@/utils/request'
/**
* 默认入口:add、del、edit、get
*/
export function add(data) {
return request({
url: 'api/quartzJob/createQuartzJob',
@@ -10,7 +12,7 @@ export function add(data) {
export function del(ids) {
return request({
url: 'api/quartzJob/removeJobByIds',
url: 'api/quartzJob/deleteJobByIds',
method: 'post',
data: ids
})
@@ -18,8 +20,8 @@ export function del(ids) {
export function edit(data) {
return request({
url: 'api/quartzJob',
method: 'put',
url: 'api/quartzJob/updateQuartzJobResumeCron',
method: 'post',
data: data
})
}
+23 -21
View File
@@ -1,13 +1,7 @@
import request from '@/utils/request'
// 获取所有的Role
export function queryRoleList() {
return request({
url: 'api/role/queryRoleList',
method: 'post'
})
}
/**
* 默认入口:add、del、edit、get
*/
export function add(data) {
return request({
url: 'api/role/saveRole',
@@ -18,22 +12,15 @@ export function add(data) {
export function get(id) {
return request({
url: 'api/role/queryRoleById',
url: 'api/role/getRoleById',
method: 'post',
data: { id: id }
})
}
export function getLevel() {
return request({
url: 'api/role/queryRoleLevel',
method: 'post'
})
}
export function del(ids) {
return request({
url: 'api/role/removeRoleByIds',
url: 'api/role/deleteRoleByIds',
method: 'post',
data: ids
})
@@ -41,18 +28,33 @@ export function del(ids) {
export function edit(data) {
return request({
url: 'api/role/modifyRoleById',
url: 'api/role/updateRoleById',
method: 'post',
data: data
})
}
// 获取所有的Role
export function listAllRole() {
return request({
url: 'api/role/listAllRole',
method: 'post'
})
}
export function getCurrentUserRoleLevel() {
return request({
url: 'api/role/getCurrentUserRoleLevel',
method: 'post'
})
}
export function editMenu(data) {
return request({
url: 'api/role/modifyBindMenuById',
url: 'api/role/updateBindMenuById',
method: 'post',
data
})
}
export default { add, edit, del, get, editMenu, getLevel }
export default { add, edit, del, get, editMenu, getCurrentUserRoleLevel }
+21 -18
View File
@@ -1,6 +1,9 @@
import request from '@/utils/request'
import { encrypt } from '@/utils/CsRsaUtil'
/**
* 默认入口:add、del、edit、get
*/
export function add(data) {
return request({
url: 'api/user/saveUser',
@@ -11,15 +14,7 @@ export function add(data) {
export function del(ids) {
return request({
url: 'api/user/removeUserByIds',
method: 'post',
data: ids
})
}
export function resetPwd(ids) {
return request({
url: 'api/user/resetUserPasswordByIds',
url: 'api/user/deleteUserByIds',
method: 'post',
data: ids
})
@@ -27,45 +22,53 @@ export function resetPwd(ids) {
export function edit(data) {
return request({
url: 'api/user/modifyUserById',
url: 'api/user/updateUserById',
method: 'post',
data: data
})
}
export function editUser(data) {
export function resetUserPasswordByIds(ids) {
return request({
url: 'api/user/modifyUserCenterInfoById',
url: 'api/user/resetUserPasswordByIds',
method: 'post',
data: ids
})
}
export function updateUserCenterInfoById(data) {
return request({
url: 'api/user/updateUserCenterInfoById',
method: 'post',
data: data
})
}
export function updatePass(user) {
export function updateUserPasswordByUsername(user) {
const data = {
oldPass: encrypt(user.oldPass),
newPass: encrypt(user.newPass)
}
return request({
url: 'api/user/modifyUserPasswordByUsername',
url: 'api/user/updateUserPasswordByUsername',
method: 'post',
data: data
})
}
export function updateEmail(form) {
export function updateUserEmailByUsername(form) {
const data = {
password: encrypt(form.pass),
email: form.email
}
return request({
url: 'api/user/modifyUserEmailByUsername/' + form.code,
url: 'api/user/updateUserEmailByUsername/' + form.code,
method: 'post',
data: data
})
}
export function queryUserMetaPage(query) {
export function queryUserMetadataOptions(query) {
const params = {
page: 1,
size: 50,
@@ -80,5 +83,5 @@ export function queryUserMetaPage(query) {
})
}
export default { add, edit, del, resetPwd, queryUserMetaPage }
export default { add, edit, del, resetUserPasswordByIds, queryUserMetadataOptions }
+4 -2
View File
@@ -17,8 +17,10 @@ function CRUD(options) {
idField: 'id',
// 标题
title: '',
// 请求数据的url
// 请求数据的url, @Controller注解的路径
url: '',
// 分页查询路由,@PostMapping注解的路径
searchRouter: '',
// 表格数据
data: [],
// 选择项
@@ -134,7 +136,7 @@ function CRUD(options) {
return new Promise((resolve, reject) => {
crud.loading = true
// 请求数据
initData(crud.url, crud.getQueryParams()).then(data => {
initData(crud.url + crud.searchRouter, crud.getQueryParams()).then(data => {
const table = crud.getTable()
if (table && table.lazy) { // 懒加载子节点数据,清掉已加载的数据
table.store.states.treeData = {}
+17 -5
View File
@@ -19,6 +19,8 @@ export default {
url: '',
// 查询数据的参数
params: {},
// 是否自定义参数
isCustomParams: false,
// 待查询的对象
query: {},
// 等待时间
@@ -76,11 +78,21 @@ export default {
Object.keys(this.params).length !== 0 && Object.keys(this.params).forEach(item => {
if (this.params[item] === null || this.params[item] === '') this.params[item] = undefined
})
return {
page: this.page,
size: this.size,
...this.query,
...this.params
if (this.isCustomParams) {
return {
page: this.page,
size: this.size,
args: {
...this.params
}
}
} else {
return {
page: this.page,
size: this.size,
...this.query,
...this.params
}
}
},
// 改变页码
+1 -1
View File
@@ -5,7 +5,7 @@ const api = {
// 图片上传
imagesUploadApi: baseUrl + '/api/localStorage/uploadPicture',
// 修改头像
updateAvatarApi: baseUrl + '/api/user/modifyUserAvatar',
updateAvatarApi: baseUrl + '/api/user/updateUserAvatar',
// Sql 监控
druidSqlApi: baseUrl + '/druid/index.html',
// websocket
+5 -2
View File
@@ -2,8 +2,11 @@ import JSEncrypt from 'jsencrypt/bin/jsencrypt.min'
// 密钥对生成 http://web.chacuo.net/netrsakeypair
const publicKey = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANL378k3RiZHWx5AfJqdH9xRNBmD9wGD\n' +
'2iRe41HdTNF8RUhNnHit5NpMNtGL0NPTSSpPjjI1kJfVorRvaQerUgkCAwEAAQ=='
const publicKey = 'MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAg975XAOL1zg5EOcSSGPIcxwx5DxcvPD2rBRQa0/o1HTF25cnsU9uSHfzP+qohkDG76kDk+1FA/cuQda4CDAmK2fWW' +
'q7KgglKd08hRkByjLuRsXu5WVApAAG15ItNM0CrXI7P47aOan+6YPU0Ni1+4WYQnwxfRYdUaKgY5G5gb3S+hx6VO1iN1KuRMBJ7y5FMh1WNJOM9bQb3X1pvaJ73drTpy1wJHAvfP80iG2+sSh0FfcOxCoRNEff' +
'CUsU2bYNH6dG6mXIDvo6XZStspwUfSitfgOER207uvBCCVyFlas+2Xs09yyAoJNjaWmeCPfA7uJvJrXUft/SMy8JNIXBY40vlwk4d4FE6OKOG9Wn0oRlofRKZ7NGvpUxEA5zOW6g2LsHKUUXpgOfu59M6ZHxviGM' +
't26WxJiq/ifVKJE3yVgx0MVIGEFTrG+spOCVsDYMSHnVsPEUdL6g5FV2YLyqNHljBqUqwyOEfUinp7hPRxrLJDMyX6GWy7y48Djg0wyh2hXro/ygVrZ6jcSd7MUAd2lYueUKK8Bey7OzIcOJ6GveHdLzGrspbbkn' +
'DuRsbcInR5bD6l7YA4vpnLsbiOH2wbKJWXNnxRwN5KuWSpwHDHhARB8f4wWrewUKIOxcFI/eJ6ke6D52JMOKhiGeZKn+2/giHwrPGkTREe47Ose6UvTMCAwEAAQ=='
// 加密
export function encrypt(txt) {
@@ -30,7 +30,7 @@
<script>
import { queryDeptList } from '@/api/system/dept'
import { searchDept } from '@/api/system/dept'
export default {
name: 'CuteDeptTree',
@@ -61,7 +61,7 @@ export default {
params['pid'] = node.data.id
}
setTimeout(() => {
queryDeptList({
searchDept({
page: 1,
size: 9999999,
args: params
@@ -25,7 +25,7 @@
<script>
import { queryDeptSelectDataSource } from '@/api/system/component'
import { listDeptSelectDataSource } from '@/api/system/component'
import CsMessage from '@/utils/elementui/CsMessage'
export default {
@@ -56,7 +56,7 @@ export default {
},
methods: {
fetchDeptData() {
queryDeptSelectDataSource().then(data => {
listDeptSelectDataSource().then(data => {
this.deptOptions = data
}).catch(error => {
console.error('获取部门数据失败:', error)
@@ -17,7 +17,7 @@
<script>
import { queryDeptSelectProDataSource } from '@/api/system/component'
import { listDeptSelectProDataSource } from '@/api/system/component'
import CsMessage from '@/utils/elementui/CsMessage'
export default {
@@ -62,7 +62,7 @@ export default {
})
},
fetchDeptData() {
queryDeptSelectProDataSource().then(data => {
listDeptSelectProDataSource().then(data => {
this.deptOptions = this.cleanEmptyChildren(data)
// console.error('deptOptions', this.deptOptions)
}).catch(error => {
@@ -57,15 +57,15 @@ export default {
this.loading = true
setTimeout(() => {
this.loading = false
this.queryUserMetaPage(query)
this.queryUserMetadataOptions(query)
}, 200)
} else {
this.options = []
}
},
queryUserMetaPage(query, options) {
queryUserMetadataOptions(query, options) {
const that = this
UserService.queryUserMetaPage(query).then(res => {
UserService.queryUserMetadataOptions(query).then(res => {
that.options = res
})
},
@@ -67,15 +67,15 @@ export default {
this.loading = true
setTimeout(() => {
this.loading = false
this.queryUserMetaPage(query)
this.queryUserMetadataOptions(query)
}, 200)
} else {
this.options = []
}
},
queryUserMetaPage(query, options) {
queryUserMetadataOptions(query, options) {
const that = this
UserService.queryUserMetaPage(query).then(res => {
UserService.queryUserMetadataOptions(query).then(res => {
that.options = res
})
},
@@ -78,7 +78,7 @@ export default {
}
},
fetch: async(queryParams) => {
return DictService.queryPageDict(queryParams)
return DictService.searchDict(queryParams)
},
pageProps: {
current: 1,
@@ -105,7 +105,7 @@ export default {
}
},
fetch: async(queryParams) => {
return DictService.queryPageDict(queryParams)
return DictService.searchDict(queryParams)
},
columns: [
{ prop: 'name', label: '名称' },
@@ -140,7 +140,7 @@ export default {
name: 'Dept',
components: { Treeselect, crudOperation, rrOperation, udOperation, DateRangePicker },
cruds() {
return CRUD({ title: '部门', url: 'api/dept', crudMethod: { ...crudDept }})
return CRUD({ title: '部门', url: 'api/dept', searchRouter: '/searchDept', crudMethod: { ...crudDept }})
},
mixins: [presenter(), header(), form(defaultForm), crud()],
// 设置数据字典
@@ -175,7 +175,7 @@ export default {
args: { pid: tree.id }
}
setTimeout(() => {
crudDept.queryDeptList(params).then(res => {
crudDept.searchDept(params).then(res => {
resolve(res.content)
})
}, 100)
@@ -195,7 +195,7 @@ export default {
}
},
getSupDepts(id) {
crudDept.queryDeptSuperiorTree(id, true).then(res => {
crudDept.searchDeptTree(id, true).then(res => {
const data = res.content
this.buildDepts(data)
this.depts = data
@@ -212,7 +212,7 @@ export default {
})
},
getDepts() {
crudDept.queryDeptList({
crudDept.searchDept({
page: 1,
size: 9999999,
args: { enabled: true }
@@ -228,7 +228,7 @@ export default {
// 获取弹窗内部门数据
loadDepts({ action, parentNode, callback }) {
if (action === LOAD_CHILDREN_OPTIONS) {
crudDept.queryDeptList({
crudDept.searchDept({
page: 1,
size: 9999999,
args: { enabled: true, pid: parentNode.id }
@@ -4,22 +4,6 @@
<div class="my-code">点击字典查看详情</div>
</div>
<div v-else>
<!--工具栏-->
<div class="head-container">
<div v-if="crud.props.searchToggle">
<!-- 搜索 -->
<el-input
v-model="query.label"
clearable
size="small"
placeholder="输入字典标签查询"
style="width: 200px;"
class="filter-item"
@keyup.enter.native="toQuery"
/>
<rrOperation />
</div>
</div>
<!--表单组件-->
<el-dialog
append-to-body
@@ -91,17 +75,16 @@
import crudDictDetail from '@/api/system/dictDetail'
import CRUD, { form, header, presenter } from '@crud/crud'
import pagination from '@crud/Pagination'
import rrOperation from '@crud/RR.operation'
import udOperation from '@crud/UD.operation'
const defaultForm = { id: null, label: null, value: null, dictSort: 999 }
export default {
components: { pagination, rrOperation, udOperation },
components: { pagination, udOperation },
cruds() {
return [
CRUD({
title: '字典详情', url: 'api/dictDetail', query: { dictName: '' },
title: '字典详情', url: 'api/dictDetail', searchRouter: '/searchDictDetail', query: { dictName: '' },
crudMethod: { ...crudDictDetail },
optShow: {
add: true,
@@ -114,7 +114,7 @@ export default {
components: { crudOperation, pagination, rrOperation, udOperation, dictDetail },
cruds() {
return [
CRUD({ title: '字典', url: 'api/dict', crudMethod: { ...crudDict }})
CRUD({ title: '字典', url: 'api/dict', searchRouter: '/searchDict', crudMethod: { ...crudDict }})
]
},
mixins: [presenter(), header(), form(defaultForm)],
@@ -27,7 +27,7 @@
</template>
<script>
import { getLastEmailConfig, modifyEmailConfig } from '@/api/system/email'
import { getLastEmailConfig, updateEmailConfigById } from '@/api/system/email'
export default {
name: 'Config',
@@ -67,7 +67,7 @@ export default {
this.$refs['form'].validate((valid) => {
if (valid) {
this.loading = true
modifyEmailConfig(this.form).then(res => {
updateEmailConfigById(this.form).then(res => {
this.$notify({
title: '修改成功',
type: 'success',
@@ -21,7 +21,7 @@
</template>
<script>
import { sendEmail } from '@/api/system/email'
import { send } from '@/api/system/email'
import { mapGetters } from 'vuex'
import E from 'wangeditor'
import { UploadFile } from '@/utils/CsDomUtil'
@@ -74,7 +74,7 @@ export default {
this.$refs['form'].validate((valid) => {
if (valid) {
this.loading = true
sendEmail(this.form).then(res => {
send(this.form).then(res => {
this.$notify({
title: '发送成功',
type: 'success',
@@ -70,6 +70,7 @@ export default {
return CRUD({
title: '岗位',
url: 'api/job',
searchRouter: '/searchJob',
crudMethod: { ...crudJob }
})
},
@@ -137,7 +137,7 @@
ref="table"
v-loading="crud.loading"
lazy
:load="queryMenuByArgs"
:load="searchMenu"
:data="crud.data"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
row-key="id"
@@ -239,7 +239,7 @@ export default {
name: 'Menu',
components: { Treeselect, IconSelect, crudOperation, rrOperation, udOperation, DateRangePicker },
cruds() {
return CRUD({ title: '菜单', url: 'api/menu', crudMethod: { ...crudMenu }})
return CRUD({ title: '菜单', url: 'api/menu', searchRouter: '/searchMenu', crudMethod: { ...crudMenu }})
},
mixins: [presenter(), header(), form(defaultForm), crud()],
data() {
@@ -273,14 +273,14 @@ export default {
this.menus.push({ id: 0, label: '顶级类目', children: null })
}
},
queryMenuByArgs(tree, treeNode, resolve) {
searchMenu(tree, treeNode, resolve) {
const params = {
page: 1,
size: 9999999,
args: { pid: tree.id }
}
setTimeout(() => {
crudMenu.queryMenuByArgs(params).then(res => {
crudMenu.searchMenu(params).then(res => {
resolve(res.content)
})
}, 100)
@@ -298,7 +298,7 @@ export default {
},
loadMenus({ action, parentNode, callback }) {
if (action === LOAD_CHILDREN_OPTIONS) {
crudMenu.queryMenuListByPid(parentNode.id).then(res => {
crudMenu.listMenuByPid(parentNode.id).then(res => {
parentNode.children = res.map(function(obj) {
if (!obj.leaf) {
obj.children = null
@@ -85,7 +85,7 @@ export default {
name: 'OnlineUser',
components: { pagination, crudOperation, rrOperation },
cruds() {
return CRUD({ url: 'api/user/online', title: '在线用户' })
return CRUD({ url: 'api/user/online', searchRouter: '/searchOnlineUser', title: '在线用户' })
},
mixins: [presenter(), header(), crud()],
data() {
@@ -28,6 +28,7 @@
>日志
</el-button>
</crudOperation>
<el-link type="primary" href="https://cron.ciding.cc/" target="_blank">Cron在线表达式生成</el-link>
<Log ref="log" />
</div>
<!--Form表单-->
@@ -192,7 +193,7 @@ export default {
name: 'QuartzJob',
components: { Log, pagination, crudOperation, rrOperation, DateRangePicker },
cruds() {
return CRUD({ title: '定时任务', url: 'api/quartzJob', crudMethod: { ...crudJob }})
return CRUD({ title: '定时任务', url: 'api/quartzJob', searchRouter: '/searchQuartzJob', crudMethod: { ...crudJob }})
},
mixins: [presenter(), header(), form(defaultForm), crud()],
data() {
@@ -73,7 +73,7 @@
<el-pagination
:total="total"
:current-page="page"
:page-size="6"
:page-size="size"
style="margin-top:8px;"
layout="total, prev, pager, next"
@size-change="sizeChange"
@@ -109,8 +109,14 @@ export default {
},
// 获取数据前设置好接口地址
beforeInit() {
this.url = 'api/quartzJob/logs'
this.size = 6
this.url = 'api/quartzJob/searchQuartzLog'
this.page = 1
this.isCustomParams = true
this.params = {
jobName: this.query.jobName,
createTime: this.query.createTime,
isSuccess: this.query.isSuccess
}
return true
},
// 异常详情
@@ -152,8 +152,8 @@
<script>
import crudRoles from '@/api/system/role'
import { queryDeptList, queryDeptSuperiorTree } from '@/api/system/dept'
import { queryChildMenuSet, queryMenuListByPid } from '@/api/system/menu'
import { searchDept, searchDeptTree } from '@/api/system/dept'
import { listChildMenuSetByMenuId, listMenuByPid } from '@/api/system/menu'
import CRUD, { crud, form, header, presenter } from '@crud/crud'
import rrOperation from '@crud/RR.operation'
import crudOperation from '@crud/CRUD.operation'
@@ -168,7 +168,7 @@ export default {
name: 'Role',
components: { Treeselect, pagination, crudOperation, rrOperation, udOperation, DateRangePicker },
cruds() {
return CRUD({ title: '角色', url: 'api/role', crudMethod: { ...crudRoles }})
return CRUD({ title: '角色', url: 'api/role', searchRouter: '/searchRole', crudMethod: { ...crudRoles }})
},
mixins: [presenter(), header(), form(defaultForm), crud()],
data() {
@@ -190,14 +190,14 @@ export default {
}
},
created() {
crudRoles.getLevel().then(data => {
crudRoles.getCurrentUserRoleLevel().then(data => {
this.level = data.level
})
},
methods: {
getMenuDatas(node, resolve) {
setTimeout(() => {
queryMenuListByPid(node.data.id ? node.data.id : 0).then(res => {
listMenuByPid(node.data.id ? node.data.id : 0).then(res => {
resolve(res)
})
}, 100)
@@ -261,7 +261,7 @@ export default {
},
menuChange(menu) {
// 获取该节点的所有子节点,id 包含自身
queryChildMenuSet(menu.id).then(childIds => {
listChildMenuSetByMenuId(menu.id).then(childIds => {
// 判断是否在 menuIds 中,如果存在则删除,否则添加
if (this.menuIds.indexOf(menu.id) !== -1) {
for (let i = 0; i < childIds.length; i++) {
@@ -313,7 +313,7 @@ export default {
},
// 获取部门数据
getDepts() {
queryDeptList({
searchDept({
page: 1,
size: 9999999,
args: { enabled: true }
@@ -331,7 +331,7 @@ export default {
depts.forEach(dept => {
ids.push(dept.id)
})
queryDeptSuperiorTree(ids).then(res => {
searchDeptTree(ids).then(res => {
const date = res.content
this.buildDepts(date)
this.depts = date
@@ -350,7 +350,7 @@ export default {
// 获取弹窗内部门数据
loadDepts({ action, parentNode, callback }) {
if (action === LOAD_CHILDREN_OPTIONS) {
queryDeptList({
searchDept({
page: 1,
size: 9999999,
args: { enabled: true, pid: parentNode.id }
@@ -154,7 +154,7 @@ export default {
return {
show: false,
monitor: null,
url: 'api/monitor/queryServerMonitorInfo',
url: 'api/monitor/getServerMonitorInfo',
data: {},
cpuInfo: {
tooltip: {
@@ -136,7 +136,7 @@ const defaultForm = { id: null, name: '' }
export default {
components: { pagination, crudOperation, rrOperation, DateRangePicker },
cruds() {
return CRUD({ title: '文件', url: 'api/localStorage', crudMethod: { ...crudFile }})
return CRUD({ title: '文件', url: 'api/localStorage', searchRouter: '/searchLocalStorage', crudMethod: { ...crudFile }})
},
mixins: [presenter(), header(), form(defaultForm), crud()],
data() {
@@ -107,7 +107,7 @@ const defaultForm = { id: null }
export default {
components: { pagination, crudOperation, rrOperation, DateRangePicker },
cruds() {
return CRUD({ title: '文件', url: 'api/ossStorage', crudMethod: { ...crudFile }})
return CRUD({ title: '文件', url: 'api/ossStorage', searchRouter: '/searchOssStorage', crudMethod: { ...crudFile }})
},
mixins: [presenter(), header(), form(defaultForm), crud()],
data() {
@@ -98,15 +98,15 @@
<!-- 操作日志 -->
<el-tab-pane label="操作日志" name="second">
<el-table v-loading="loading" :data="data" style="width: 100%;">
<el-table-column prop="description" label="行为" />
<el-table-column prop="bizName" label="业务名称" />
<el-table-column prop="requestIp" label="IP" />
<el-table-column :show-overflow-tooltip="true" prop="address" label="IP来源" />
<el-table-column prop="browser" label="浏览器" />
<el-table-column prop="time" label="请求耗时" align="center">
<el-table-column prop="browserInfo" label="浏览器" />
<el-table-column prop="executeTime" label="请求耗时" align="center">
<template slot-scope="scope">
<el-tag v-if="scope.row.time <= 300">{{ scope.row.time }}ms</el-tag>
<el-tag v-else-if="scope.row.time <= 1000" type="warning">{{ scope.row.time }}ms</el-tag>
<el-tag v-else type="danger">{{ scope.row.time }}ms</el-tag>
<el-tag v-if="scope.row.executeTime <= 300">{{ scope.row.time || 0 }}ms</el-tag>
<el-tag v-else-if="scope.row.executeTime <= 1000" type="warning">{{ scope.row.executeTime || 0 }}ms</el-tag>
<el-tag v-else type="danger">{{ scope.row.executeTime || 0 }}ms</el-tag>
</template>
</el-table-column>
<el-table-column
@@ -151,7 +151,7 @@ import { getToken } from '@/utils/auth'
import store from '@/store'
import { IsValidPhone } from '@/utils/CsValidateUtil'
import crud from '@/mixins/crud'
import { editUser } from '@/api/system/user'
import { updateUserCenterInfoById } from '@/api/system/user'
import Avatar from '@/assets/images/avatar.png'
export default {
@@ -211,7 +211,7 @@ export default {
}
},
beforeInit() {
this.url = 'api/logs/user'
this.url = 'api/logs/searchUserLog'
return true
},
cropUploadSuccess(jsonData, field) {
@@ -223,7 +223,7 @@ export default {
this.$refs['form'].validate((valid) => {
if (valid) {
this.saveLoading = true
editUser(this.form).then(() => {
updateUserCenterInfoById(this.form).then(() => {
this.editSuccessNotify()
store.dispatch('GetInfo').then(() => {
})
@@ -34,9 +34,9 @@
<script>
import store from '@/store'
import { validEmail } from '@/utils/CsValidateUtil'
import { updateEmail } from '@/api/system/user'
import { sendResetEmailCaptcha } from '@/api/system/code'
import { IsValidEmail } from '@/utils/CsValidateUtil'
import { updateUserEmailByUsername } from '@/api/system/user'
import { sendResetEmailCode } from '@/api/system/code'
export default {
props: {
@@ -51,7 +51,7 @@ export default {
callback(new Error('新邮箱不能为空'))
} else if (value === this.email) {
callback(new Error('新邮箱不能与旧邮箱相同'))
} else if (validEmail(value)) {
} else if (IsValidEmail(value)) {
callback()
} else {
callback(new Error('邮箱格式错误'))
@@ -83,7 +83,7 @@ export default {
this.codeLoading = true
this.buttonName = '验证码发送中'
const _this = this
sendResetEmailCaptcha(this.form.email).then(res => {
sendResetEmailCode(this.form.email).then(res => {
this.$message({
showClose: true,
message: '发送成功,验证码有效期5分钟',
@@ -113,7 +113,7 @@ export default {
this.$refs['form'].validate((valid) => {
if (valid) {
this.loading = true
updateEmail(this.form).then(res => {
updateUserEmailByUsername(this.form).then(res => {
this.loading = false
this.resetForm()
this.$notify({
@@ -30,7 +30,7 @@
<script>
import store from '@/store'
import { updatePass } from '@/api/system/user'
import { updateUserPasswordByUsername } from '@/api/system/user'
export default {
data() {
@@ -69,7 +69,7 @@ export default {
this.$refs['form'].validate((valid) => {
if (valid) {
this.loading = true
updatePass(this.form).then(res => {
updateUserPasswordByUsername(this.form).then(res => {
this.resetForm()
this.$notify({
title: '密码修改成功,请重新登录',
+11 -11
View File
@@ -196,9 +196,9 @@
<script>
import crudUser from '@/api/system/user'
import { IsValidPhone } from '@/utils/CsValidateUtil'
import { queryDeptList, queryDeptSuperiorTree } from '@/api/system/dept'
import { getLevel, queryRoleList } from '@/api/system/role'
import { queryAllEnableJob } from '@/api/system/job'
import { searchDept, searchDeptTree } from '@/api/system/dept'
import { getCurrentUserRoleLevel, listAllRole } from '@/api/system/role'
import { searchJob } from '@/api/system/job'
import CRUD, { crud, form, header, presenter } from '@crud/crud'
import rrOperation from '@crud/RR.operation'
import crudOperation from '@crud/CRUD.operation'
@@ -228,7 +228,7 @@ export default {
name: 'User',
components: { CuteDeptTree, Treeselect, crudOperation, rrOperation, udOperation, pagination, DateRangePicker },
cruds() {
return CRUD({ title: '用户', url: 'api/user', crudMethod: { ...crudUser }})
return CRUD({ title: '用户', url: 'api/user', searchRouter: '/aggregationSearchUser', crudMethod: { ...crudUser }})
},
mixins: [presenter(), header(), form(defaultForm), crud()],
// 数据字典
@@ -401,7 +401,7 @@ export default {
this.crud.toQuery()
},
getDepts() {
queryDeptList({
searchDept({
page: 1,
size: 9999999,
args: { enabled: true }
@@ -415,7 +415,7 @@ export default {
})
},
getSupDepts(deptId) {
queryDeptSuperiorTree(deptId).then(res => {
searchDeptTree(deptId).then(res => {
const date = res.content
this.buildDepts(date)
this.depts = date
@@ -434,7 +434,7 @@ export default {
// 获取弹窗内部门数据
loadDepts({ action, parentNode, callback }) {
if (action === LOAD_CHILDREN_OPTIONS) {
queryDeptList({
searchDept({
page: 1,
size: 9999999,
args: { enabled: true, pid: parentNode.id }
@@ -469,21 +469,21 @@ export default {
},
// 获取弹窗内角色数据
getRoles() {
queryRoleList().then(res => {
listAllRole().then(res => {
this.roles = res
}).catch(() => {
})
},
// 获取弹窗内岗位数据
getJobs() {
queryAllEnableJob().then(res => {
searchJob().then(res => {
this.jobs = res.content
}).catch(() => {
})
},
// 获取权限级别
getRoleLevel() {
getLevel().then(res => {
getCurrentUserRoleLevel().then(res => {
this.level = res.level
}).catch(() => {
})
@@ -502,7 +502,7 @@ export default {
ids.push(val.id)
})
console.log(ids)
crudUser.resetPwd(ids).then(() => {
crudUser.resetUserPasswordByIds(ids).then(() => {
this.crud.notify('重置成功, 用户新密码:123456', CRUD.NOTIFICATION_TYPE.SUCCESS)
}).catch(() => {
})
+7
View File
@@ -41,6 +41,13 @@ module.exports = {
pathRewrite: {
'^/auth': 'auth'
}
},
'/captcha': {
target: process.env.VUE_APP_BASE_API,
changeOrigin: true,
pathRewrite: {
'^/captcha': 'captcha'
}
}
}
},
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cutejava</artifactId>
<groupId>cn.odboy</groupId>
<version>1.4.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cutejava-framework</artifactId>
<name>公共模块</name>
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cutejava</artifactId>
<groupId>cn.odboy</groupId>
<version>1.5.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cutejava-framework</artifactId>
<name>公共模块</name>
</project>
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,7 +15,12 @@
*/
package cn.odboy.annotation;
import java.lang.annotation.*;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 用于标记匿名访问方法
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,15 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.lang.annotation.*;
/**
* Annotation for mapping HTTP {@code DELETE} requests onto specific handler methods. 支持匿名访问 DeleteMapping
*
@@ -38,38 +40,38 @@ import java.lang.annotation.*;
@RequestMapping(method = RequestMethod.DELETE)
public @interface AnonymousDeleteMapping {
/**
* Alias for {@link RequestMapping#name}.
*/
@AliasFor(annotation = RequestMapping.class) String name() default "";
/**
* Alias for {@link RequestMapping#name}.
*/
@AliasFor(annotation = RequestMapping.class) String name() default "";
/**
* Alias for {@link RequestMapping#value}.
*/
@AliasFor(annotation = RequestMapping.class) String[] value() default {};
/**
* Alias for {@link RequestMapping#value}.
*/
@AliasFor(annotation = RequestMapping.class) String[] value() default {};
/**
* Alias for {@link RequestMapping#path}.
*/
@AliasFor(annotation = RequestMapping.class) String[] path() default {};
/**
* Alias for {@link RequestMapping#path}.
*/
@AliasFor(annotation = RequestMapping.class) String[] path() default {};
/**
* Alias for {@link RequestMapping#params}.
*/
@AliasFor(annotation = RequestMapping.class) String[] params() default {};
/**
* Alias for {@link RequestMapping#params}.
*/
@AliasFor(annotation = RequestMapping.class) String[] params() default {};
/**
* Alias for {@link RequestMapping#headers}.
*/
@AliasFor(annotation = RequestMapping.class) String[] headers() default {};
/**
* Alias for {@link RequestMapping#headers}.
*/
@AliasFor(annotation = RequestMapping.class) String[] headers() default {};
/**
* Alias for {@link RequestMapping#consumes}.
*/
@AliasFor(annotation = RequestMapping.class) String[] consumes() default {};
/**
* Alias for {@link RequestMapping#consumes}.
*/
@AliasFor(annotation = RequestMapping.class) String[] consumes() default {};
/**
* Alias for {@link RequestMapping#produces}.
*/
@AliasFor(annotation = RequestMapping.class) String[] produces() default {};
/**
* Alias for {@link RequestMapping#produces}.
*/
@AliasFor(annotation = RequestMapping.class) String[] produces() default {};
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,15 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.lang.annotation.*;
/**
* Annotation for mapping HTTP {@code GET} requests onto specific handler methods.
* <p>
@@ -36,40 +38,40 @@ import java.lang.annotation.*;
@RequestMapping(method = RequestMethod.GET)
public @interface AnonymousGetMapping {
/**
* Alias for {@link RequestMapping#name}.
*/
@AliasFor(annotation = RequestMapping.class) String name() default "";
/**
* Alias for {@link RequestMapping#name}.
*/
@AliasFor(annotation = RequestMapping.class) String name() default "";
/**
* Alias for {@link RequestMapping#value}.
*/
@AliasFor(annotation = RequestMapping.class) String[] value() default {};
/**
* Alias for {@link RequestMapping#value}.
*/
@AliasFor(annotation = RequestMapping.class) String[] value() default {};
/**
* Alias for {@link RequestMapping#path}.
*/
@AliasFor(annotation = RequestMapping.class) String[] path() default {};
/**
* Alias for {@link RequestMapping#path}.
*/
@AliasFor(annotation = RequestMapping.class) String[] path() default {};
/**
* Alias for {@link RequestMapping#params}.
*/
@AliasFor(annotation = RequestMapping.class) String[] params() default {};
/**
* Alias for {@link RequestMapping#params}.
*/
@AliasFor(annotation = RequestMapping.class) String[] params() default {};
/**
* Alias for {@link RequestMapping#headers}.
*/
@AliasFor(annotation = RequestMapping.class) String[] headers() default {};
/**
* Alias for {@link RequestMapping#headers}.
*/
@AliasFor(annotation = RequestMapping.class) String[] headers() default {};
/**
* Alias for {@link RequestMapping#consumes}.
*
* @since 4.3.5
*/
@AliasFor(annotation = RequestMapping.class) String[] consumes() default {};
/**
* Alias for {@link RequestMapping#consumes}.
*
* @since 4.3.5
*/
@AliasFor(annotation = RequestMapping.class) String[] consumes() default {};
/**
* Alias for {@link RequestMapping#produces}.
*/
@AliasFor(annotation = RequestMapping.class) String[] produces() default {};
/**
* Alias for {@link RequestMapping#produces}.
*/
@AliasFor(annotation = RequestMapping.class) String[] produces() default {};
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,15 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.lang.annotation.*;
/**
* Annotation for mapping HTTP {@code PATCH} requests onto specific handler methods. 支持匿名访问 PatchMapping
*
@@ -38,38 +40,38 @@ import java.lang.annotation.*;
@RequestMapping(method = RequestMethod.PATCH)
public @interface AnonymousPatchMapping {
/**
* Alias for {@link RequestMapping#name}.
*/
@AliasFor(annotation = RequestMapping.class) String name() default "";
/**
* Alias for {@link RequestMapping#name}.
*/
@AliasFor(annotation = RequestMapping.class) String name() default "";
/**
* Alias for {@link RequestMapping#value}.
*/
@AliasFor(annotation = RequestMapping.class) String[] value() default {};
/**
* Alias for {@link RequestMapping#value}.
*/
@AliasFor(annotation = RequestMapping.class) String[] value() default {};
/**
* Alias for {@link RequestMapping#path}.
*/
@AliasFor(annotation = RequestMapping.class) String[] path() default {};
/**
* Alias for {@link RequestMapping#path}.
*/
@AliasFor(annotation = RequestMapping.class) String[] path() default {};
/**
* Alias for {@link RequestMapping#params}.
*/
@AliasFor(annotation = RequestMapping.class) String[] params() default {};
/**
* Alias for {@link RequestMapping#params}.
*/
@AliasFor(annotation = RequestMapping.class) String[] params() default {};
/**
* Alias for {@link RequestMapping#headers}.
*/
@AliasFor(annotation = RequestMapping.class) String[] headers() default {};
/**
* Alias for {@link RequestMapping#headers}.
*/
@AliasFor(annotation = RequestMapping.class) String[] headers() default {};
/**
* Alias for {@link RequestMapping#consumes}.
*/
@AliasFor(annotation = RequestMapping.class) String[] consumes() default {};
/**
* Alias for {@link RequestMapping#consumes}.
*/
@AliasFor(annotation = RequestMapping.class) String[] consumes() default {};
/**
* Alias for {@link RequestMapping#produces}.
*/
@AliasFor(annotation = RequestMapping.class) String[] produces() default {};
/**
* Alias for {@link RequestMapping#produces}.
*/
@AliasFor(annotation = RequestMapping.class) String[] produces() default {};
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,15 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.lang.annotation.*;
/**
* Annotation for mapping HTTP {@code POST} requests onto specific handler methods. 支持匿名访问 PostMapping
*
@@ -38,38 +40,38 @@ import java.lang.annotation.*;
@RequestMapping(method = RequestMethod.POST)
public @interface AnonymousPostMapping {
/**
* Alias for {@link RequestMapping#name}.
*/
@AliasFor(annotation = RequestMapping.class) String name() default "";
/**
* Alias for {@link RequestMapping#name}.
*/
@AliasFor(annotation = RequestMapping.class) String name() default "";
/**
* Alias for {@link RequestMapping#value}.
*/
@AliasFor(annotation = RequestMapping.class) String[] value() default {};
/**
* Alias for {@link RequestMapping#value}.
*/
@AliasFor(annotation = RequestMapping.class) String[] value() default {};
/**
* Alias for {@link RequestMapping#path}.
*/
@AliasFor(annotation = RequestMapping.class) String[] path() default {};
/**
* Alias for {@link RequestMapping#path}.
*/
@AliasFor(annotation = RequestMapping.class) String[] path() default {};
/**
* Alias for {@link RequestMapping#params}.
*/
@AliasFor(annotation = RequestMapping.class) String[] params() default {};
/**
* Alias for {@link RequestMapping#params}.
*/
@AliasFor(annotation = RequestMapping.class) String[] params() default {};
/**
* Alias for {@link RequestMapping#headers}.
*/
@AliasFor(annotation = RequestMapping.class) String[] headers() default {};
/**
* Alias for {@link RequestMapping#headers}.
*/
@AliasFor(annotation = RequestMapping.class) String[] headers() default {};
/**
* Alias for {@link RequestMapping#consumes}.
*/
@AliasFor(annotation = RequestMapping.class) String[] consumes() default {};
/**
* Alias for {@link RequestMapping#consumes}.
*/
@AliasFor(annotation = RequestMapping.class) String[] consumes() default {};
/**
* Alias for {@link RequestMapping#produces}.
*/
@AliasFor(annotation = RequestMapping.class) String[] produces() default {};
/**
* Alias for {@link RequestMapping#produces}.
*/
@AliasFor(annotation = RequestMapping.class) String[] produces() default {};
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,15 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.lang.annotation.*;
/**
* Annotation for mapping HTTP {@code PUT} requests onto specific handler methods. 支持匿名访问 PutMapping
*
@@ -38,38 +40,38 @@ import java.lang.annotation.*;
@RequestMapping(method = RequestMethod.PUT)
public @interface AnonymousPutMapping {
/**
* Alias for {@link RequestMapping#name}.
*/
@AliasFor(annotation = RequestMapping.class) String name() default "";
/**
* Alias for {@link RequestMapping#name}.
*/
@AliasFor(annotation = RequestMapping.class) String name() default "";
/**
* Alias for {@link RequestMapping#value}.
*/
@AliasFor(annotation = RequestMapping.class) String[] value() default {};
/**
* Alias for {@link RequestMapping#value}.
*/
@AliasFor(annotation = RequestMapping.class) String[] value() default {};
/**
* Alias for {@link RequestMapping#path}.
*/
@AliasFor(annotation = RequestMapping.class) String[] path() default {};
/**
* Alias for {@link RequestMapping#path}.
*/
@AliasFor(annotation = RequestMapping.class) String[] path() default {};
/**
* Alias for {@link RequestMapping#params}.
*/
@AliasFor(annotation = RequestMapping.class) String[] params() default {};
/**
* Alias for {@link RequestMapping#params}.
*/
@AliasFor(annotation = RequestMapping.class) String[] params() default {};
/**
* Alias for {@link RequestMapping#headers}.
*/
@AliasFor(annotation = RequestMapping.class) String[] headers() default {};
/**
* Alias for {@link RequestMapping#headers}.
*/
@AliasFor(annotation = RequestMapping.class) String[] headers() default {};
/**
* Alias for {@link RequestMapping#consumes}.
*/
@AliasFor(annotation = RequestMapping.class) String[] consumes() default {};
/**
* Alias for {@link RequestMapping#consumes}.
*/
@AliasFor(annotation = RequestMapping.class) String[] consumes() default {};
/**
* Alias for {@link RequestMapping#produces}.
*/
@AliasFor(annotation = RequestMapping.class) String[] produces() default {};
/**
* Alias for {@link RequestMapping#produces}.
*/
@AliasFor(annotation = RequestMapping.class) String[] produces() default {};
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.base;
import jakarta.validation.constraints.NotNull;
@@ -27,17 +26,20 @@ import lombok.Setter;
* @date 2025-07-23
*/
public class KitArgs {
@Getter
@Setter
public static class FindByLongId extends KitObject {
@NotNull(message = "id必填")
private Long id;
}
@Getter
@Setter
public static class DeleteById extends KitObject {
@NotNull(message = "id必填")
private Long id;
}
@Getter
@Setter
public static class FindByLongId extends KitObject {
@NotNull(message = "id必填")
private Long id;
}
@Getter
@Setter
public static class DeleteById extends KitObject {
@NotNull(message = "id必填")
private Long id;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,23 +13,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.base;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.annotations.ApiModelProperty;
import java.util.Date;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
@Getter
@Setter
@EqualsAndHashCode(callSuper = false)
public class KitBaseCreateTimeTb extends KitObject {
@Schema(name = "创建时间: yyyy-MM-dd HH:mm:ss", hidden = true)
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT)
@ApiModelProperty(value = "创建时间: yyyy-MM-dd HH:mm:ss", hidden = true)
private Date createTime;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,27 +13,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.base;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.annotations.ApiModelProperty;
import java.util.Date;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
@Getter
@Setter
@EqualsAndHashCode(callSuper = false)
public class KitBaseTimeTb extends KitObject {
@TableField(fill = FieldFill.INSERT)
@Schema(name = "创建时间: yyyy-MM-dd HH:mm:ss", hidden = true)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
@Schema(name = "更新时间: yyyy-MM-dd HH:mm:ss", hidden = true)
private Date updateTime;
@TableField(fill = FieldFill.INSERT)
@ApiModelProperty(value = "创建时间: yyyy-MM-dd HH:mm:ss", hidden = true)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
@ApiModelProperty(value = "更新时间: yyyy-MM-dd HH:mm:ss", hidden = true)
private Date updateTime;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,23 +13,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.base;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.annotations.ApiModelProperty;
import java.util.Date;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
@Getter
@Setter
@EqualsAndHashCode(callSuper = false)
public class KitBaseUpdateTimeTb extends KitObject {
@Schema(name = "更新时间: yyyy-MM-dd HH:mm:ss", hidden = true)
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
@ApiModelProperty(value = "更新时间: yyyy-MM-dd HH:mm:ss", hidden = true)
private Date updateTime;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,55 +13,55 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.base;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.annotations.ApiModelProperty;
import java.lang.reflect.Field;
import java.util.Date;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.data.annotation.CreatedBy;
import java.lang.reflect.Field;
import java.util.Date;
@Getter
@Setter
@EqualsAndHashCode(callSuper = false)
public class KitBaseUserCreateTimeTb extends KitObject {
@CreatedBy
@TableField(fill = FieldFill.INSERT)
@Schema(name = "创建人", hidden = true)
private String createBy;
@CreatedBy
@TableField(fill = FieldFill.INSERT)
@ApiModelProperty(value = "创建人", hidden = true)
private String
createBy;
@TableField(fill = FieldFill.INSERT)
@ApiModelProperty(value = "创建时间: yyyy-MM-dd HH:mm:ss", hidden = true)
private Date createTime;
@TableField(fill = FieldFill.INSERT)
@Schema(name = "创建时间: yyyy-MM-dd HH:mm:ss", hidden = true)
private Date createTime;
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
Field[] fields = this.getClass().getDeclaredFields();
try {
for (Field f : fields) {
f.setAccessible(true);
builder.append(f.getName(), f.get(this)).append("\n");
}
} catch (Exception e) {
builder.append("toString builder encounter an error");
}
return builder.toString();
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
Field[] fields = this.getClass().getDeclaredFields();
try {
for (Field f : fields) {
f.setAccessible(true);
builder.append(f.getName(), f.get(this)).append("\n");
}
} catch (Exception e) {
builder.append("toString builder encounter an error");
}
return builder.toString();
}
/* 分组校验 */
public @interface Create {
}
/* 分组校验 */
public @interface Create {
/* 分组校验 */
public @interface Update {
}
}
/* 分组校验 */
public @interface Update {
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,20 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.base;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.annotations.ApiModelProperty;
import java.util.Date;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.LastModifiedBy;
import java.util.Date;
/**
* 逻辑删除通用模型
*
@@ -36,22 +34,24 @@ import java.util.Date;
@Getter
@Setter
public class KitBaseUserTimeLogicTb extends KitObject {
@CreatedBy
@TableField(value = "create_by", fill = FieldFill.INSERT)
@Schema(name = "创建人", hidden = true)
private String createBy;
@LastModifiedBy
@TableField(value = "update_by", fill = FieldFill.INSERT_UPDATE)
@Schema(name = "更新人", hidden = true)
private String updateBy;
@TableField(value = "create_time", fill = FieldFill.INSERT)
@Schema(name = "创建时间", hidden = true)
private Date createTime;
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
@Schema(name = "更新时间", hidden = true)
private Date updateTime;
@Schema(name = "数据有效性", hidden = true)
@TableLogic
@TableField("available")
private Integer available;
@CreatedBy
@TableField(value = "create_by", fill = FieldFill.INSERT)
@ApiModelProperty(value = "创建人", hidden = true)
private String createBy;
@LastModifiedBy
@TableField(value = "update_by", fill = FieldFill.INSERT_UPDATE)
@ApiModelProperty(value = "更新人", hidden = true)
private String updateBy;
@TableField(value = "create_time", fill = FieldFill.INSERT)
@ApiModelProperty(value = "创建时间", hidden = true)
private Date createTime;
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
@ApiModelProperty(value = "更新时间", hidden = true)
private Date updateTime;
@ApiModelProperty(value = "数据有效性", hidden = true)
@TableLogic
@TableField("available")
private Integer
available;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,12 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.base;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.annotations.ApiModelProperty;
import java.lang.reflect.Field;
import java.util.Date;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
@@ -26,52 +27,49 @@ import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.LastModifiedBy;
import java.lang.reflect.Field;
import java.util.Date;
@Getter
@Setter
@EqualsAndHashCode(callSuper = false)
public class KitBaseUserTimeTb extends KitObject {
@CreatedBy
@TableField(fill = FieldFill.INSERT)
@Schema(name = "创建人", hidden = true)
private String createBy;
@CreatedBy
@TableField(fill = FieldFill.INSERT)
@ApiModelProperty(value = "创建人", hidden = true)
private String
createBy;
@LastModifiedBy
@TableField(fill = FieldFill.INSERT_UPDATE)
@ApiModelProperty(value = "更新人", hidden = true)
private String updateBy;
@TableField(fill = FieldFill.INSERT)
@ApiModelProperty(value = "创建时间: yyyy-MM-dd HH:mm:ss", hidden = true)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
@ApiModelProperty(value = "更新时间: yyyy-MM-dd HH:mm:ss", hidden = true)
private Date updateTime;
@LastModifiedBy
@TableField(fill = FieldFill.INSERT_UPDATE)
@Schema(name = "更新人", hidden = true)
private String updateBy;
@TableField(fill = FieldFill.INSERT)
@Schema(name = "创建时间: yyyy-MM-dd HH:mm:ss", hidden = true)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
@Schema(name = "更新时间: yyyy-MM-dd HH:mm:ss", hidden = true)
private Date updateTime;
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
Field[] fields = this.getClass().getDeclaredFields();
try {
for (Field f : fields) {
f.setAccessible(true);
builder.append(f.getName(), f.get(this)).append("\n");
}
} catch (Exception e) {
builder.append("toString builder encounter an error");
}
return builder.toString();
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
Field[] fields = this.getClass().getDeclaredFields();
try {
for (Field f : fields) {
f.setAccessible(true);
builder.append(f.getName(), f.get(this)).append("\n");
}
} catch (Exception e) {
builder.append("toString builder encounter an error");
}
return builder.toString();
}
/* 分组校验 */
public @interface Create {
}
/* 分组校验 */
public @interface Create {
/* 分组校验 */
public @interface Update {
}
}
/* 分组校验 */
public @interface Update {
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,10 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.base;
import java.io.Serial;
import java.io.Serializable;
/**
@@ -26,6 +24,6 @@ import java.io.Serializable;
* @date 2022-01-12
*/
public class KitObject implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private static final long serialVersionUID = 1L;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,18 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.base;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 数据分页参数
*
@@ -35,13 +33,14 @@ import java.io.Serializable;
@NoArgsConstructor
@AllArgsConstructor
public class KitPageArgs<T> implements Serializable {
@NotNull(message = "参数page不能为空")
@Min(value = 1, message = "参数page最小值为1")
@Schema(name = "页码", example = "1")
private Integer page;
@NotNull(message = "参数size不能为空")
@Min(value = 1, message = "参数size最小值为1")
@Schema(name = "每页数据量", example = "10")
private Integer size;
private T args;
@NotNull(message = "参数page不能为空")
@Min(value = 1, message = "参数page最小值为1")
@ApiModelProperty(value = "页码", example = "1")
private Integer page;
@NotNull(message = "参数size不能为空")
@Min(value = 1, message = "参数size最小值为1")
@ApiModelProperty(value = "每页数据量", example = "10")
private Integer size;
private T args;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,18 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.base;
import com.baomidou.mybatisplus.core.metadata.IPage;
import java.util.ArrayList;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
/**
* 结果封装类
*/
@@ -33,20 +31,21 @@ import java.util.List;
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class KitPageResult<T> extends KitObject {
private List<T> content;
private long totalElements;
public static <T> KitPageResult<T> emptyListData() {
KitPageResult<T> result = new KitPageResult<>();
result.setTotalElements(0);
result.setContent(new ArrayList<>());
return result;
}
private List<T> content;
private long totalElements;
public static <T> KitPageResult<T> listData(IPage<T> page) {
KitPageResult<T> result = new KitPageResult<>();
result.setTotalElements(page.getTotal());
result.setContent(page.getRecords());
return result;
}
public static <T> KitPageResult<T> emptyListData() {
KitPageResult<T> result = new KitPageResult<>();
result.setTotalElements(0);
result.setContent(new ArrayList<>());
return result;
}
public static <T> KitPageResult<T> listData(IPage<T> page) {
KitPageResult<T> result = new KitPageResult<>();
result.setTotalElements(page.getTotal());
result.setContent(page.getRecords());
return result;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,12 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.base;
import lombok.*;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
/**
* 元数据选项
@@ -32,7 +34,8 @@ import java.util.Map;
@NoArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class KitSelectOptionVo extends KitObject {
private String label;
private String value;
private Map<String, Object> ext;
private String label;
private String value;
private Map<String, Object> ext;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,31 +13,30 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.constant;
/**
* 验证码配置枚举
*/
public enum CaptchaCodeEnum {
/**
* 算数
*/
ARITHMETIC,
/**
* 中文
*/
CHINESE,
/**
* 中文闪图
*/
CHINESE_GIF,
/**
* 闪图
*/
GIF,
/**
* 静态
*/
SPEC
/**
* 算数
*/
ARITHMETIC,
/**
* 中文
*/
CHINESE,
/**
* 中文闪图
*/
CHINESE_GIF,
/**
* 闪图
*/
GIF,
/**
* 静态
*/
SPEC
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.constant;
import lombok.AllArgsConstructor;
@@ -22,9 +21,8 @@ import lombok.Getter;
@Getter
@AllArgsConstructor
public enum FileTypeEnum {
/* 文件类型 */
IMAGE("image", "图片"), DOC("doc", "文档"), VOICE("voice", "音频"), VIDEO("video", "视频"), OTHER("other", "其他");
private final String code;
private final String description;
/* 文件类型 */
IMAGE("image", "图片"), DOC("doc", "文档"), VOICE("voice", "音频"), VIDEO("video", "视频"), OTHER("other", "其他");
private final String code;
private final String description;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.constant;
import lombok.AllArgsConstructor;
@@ -22,48 +21,41 @@ import lombok.Getter;
@Getter
@AllArgsConstructor
public enum RequestMethodEnum {
/**
* 搜寻 @AnonymousGetMapping
*/
GET("GET"),
/**
* 搜寻 @AnonymousPostMapping
*/
POST("POST"),
/**
* 搜寻 @AnonymousPutMapping
*/
PUT("PUT"),
/**
* 搜寻 @AnonymousPatchMapping
*/
PATCH("PATCH"),
/**
* 搜寻 @AnonymousDeleteMapping
*/
DELETE("DELETE"),
/**
* 否则就是所有 Request 接口都放行
*/
ALL("All");
/**
* Request 类型
*/
private final String type;
/**
* 搜寻 @AnonymousGetMapping
*/
GET("GET"),
/**
* 搜寻 @AnonymousPostMapping
*/
POST("POST"),
/**
* 搜寻 @AnonymousPutMapping
*/
PUT("PUT"),
/**
* 搜寻 @AnonymousPatchMapping
*/
PATCH("PATCH"),
/**
* 搜寻 @AnonymousDeleteMapping
*/
DELETE("DELETE"),
/**
* 否则就是所有 Request 接口都放行
*/
ALL("All");
/**
* Request 类型
*/
private final String type;
public static RequestMethodEnum find(String type) {
for (RequestMethodEnum value : RequestMethodEnum.values()) {
if (value.getType().equals(type)) {
return value;
}
}
return ALL;
public static RequestMethodEnum find(String type) {
for (RequestMethodEnum value : RequestMethodEnum.values()) {
if (value.getType().equals(type)) {
return value;
}
}
return ALL;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,41 +13,39 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.constant;
/**
* 常用静态常量
*/
public interface SystemConst {
/**
* win 系统
*/
String WIN = "win";
/**
* mac 系统
*/
String MAC = "mac";
/**
* 请求头名称
*/
String HEADER_NAME = "Authorization";
/**
* Token前缀
*/
String TOKEN_PREFIX = "Bearer";
/**
* 小数点
*/
String SYMBOL_DOT = ".";
String SYMBOL_EQUAL = "=";
String SYMBOL_ADD = "+";
String SYMBOL_SUBTRACT = "-";
String SYMBOL_AT = "@";
String PROPERTY_OS_NAME = "os.name";
String OS_NAME_WINDOWS = "Windows";
/**
* win 系统
*/
String WIN = "win";
/**
* mac 系统
*/
String MAC = "mac";
/**
* 请求头名称
*/
String HEADER_NAME = "Authorization";
/**
* Token前缀
*/
String TOKEN_PREFIX = "Bearer";
/**
* 小数点
*/
String SYMBOL_DOT = ".";
String SYMBOL_EQUAL = "=";
String SYMBOL_ADD = "+";
String SYMBOL_SUBTRACT = "-";
String SYMBOL_AT = "@";
String PROPERTY_OS_NAME = "os.name";
String OS_NAME_WINDOWS = "Windows";
String CURRENT_APP_NAME = "cutejava";
String CURRENT_APP_TITLE = "CuteJava";
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,8 +30,9 @@ import org.springframework.stereotype.Component;
@Slf4j
@Component
public class BeanLoadFinishListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
log.info("所有的Bean都加载完毕了");
}
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
log.info("所有的Bean都加载完毕了");
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,14 +17,13 @@
package cn.odboy.framework.context;
import cn.hutool.core.util.StrUtil;
import java.net.InetAddress;
import java.net.UnknownHostException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* 主要目的是输出应用的服务地址
*
@@ -33,22 +32,24 @@ import java.net.UnknownHostException;
*/
@Slf4j
public class BootApplication {
protected static void inited(ConfigurableApplicationContext application) throws UnknownHostException {
Environment env = application.getEnvironment();
String ip = InetAddress.getLocalHost().getHostAddress();
String port = env.getProperty("server.port");
String path = StrUtil.isEmpty(env.getProperty("config.servlet.context-path")) ? "" : env.getProperty("config.servlet.context-path");
log.info("""
----------------------------------------------------------
\tApplication is running! Access URLs:
\tLocal: \t\thttp://localhost:{}{}
\tExternal: \thttp://{}:{}{}
\tSwagger文档: \thttp://{}:{}{}/doc.html
----------------------------------------------------------""", port, path, ip, port, path, ip, port, path);
}
@Bean
public KitSpringBeanHolder springBeanHolder() {
return new KitSpringBeanHolder();
}
}
protected static void inited(ConfigurableApplicationContext application) throws UnknownHostException {
Environment env = application.getEnvironment();
String ip = InetAddress.getLocalHost().getHostAddress();
String port = env.getProperty("server.port");
String path = StrUtil.isEmpty(env.getProperty("config.servlet.context-path")) ? ""
: env.getProperty("config.servlet.context-path");
log.info("""
----------------------------------------------------------
\tApplication is running! Access URLs:
\tLocal: \t\thttp://localhost:{}{}
\tExternal: \thttp://{}:{}{}
\tSwagger文档: \thttp://{}:{}{}/doc.html
----------------------------------------------------------""", port, path, ip, port, path, ip, port, path);
}
@Bean
public KitSpringBeanHolder springBeanHolder() {
return new KitSpringBeanHolder();
}
}
@@ -1,6 +1,6 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,17 +18,17 @@
package cn.odboy.framework.context;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Objects;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.util.Objects;
/**
* 获取 HttpServletRequest
*/
public class KitRequestHolder {
public static HttpServletRequest getHttpServletRequest() {
return ((ServletRequestAttributes)Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
}
public static HttpServletRequest getHttpServletRequest() {
return ((ServletRequestAttributes) Objects.requireNonNull(
RequestContextHolder.getRequestAttributes())).getRequest();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,13 +16,12 @@
package cn.odboy.framework.context;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* 脚本工具
*
@@ -32,32 +31,33 @@ import java.util.Map;
@Slf4j
@Component
public class KitScriptHelper {
public Object evalObj(String script, Map<String, Object> args) {
try (Context rhino = Context.enter()) {
Scriptable scope = rhino.initStandardObjects();
bindArgumentsToScope(scope, args);
Object result = rhino.evaluateString(scope, script, "JavaScript", 1, null);
log.info("执行结果: {}", Context.toString(result));
return result;
}
}
private void bindArgumentsToScope(Scriptable scope, Map<?, ?> args) {
if (args == null) {
return;
}
for (Map.Entry<?, ?> entry : args.entrySet()) {
Object jsValue = Context.javaToJS(entry.getValue(), scope);
scope.put(entry.getKey().toString(), scope, jsValue);
}
public Object evalObj(String script, Map<String, Object> args) {
try (Context rhino = Context.enter()) {
Scriptable scope = rhino.initStandardObjects();
bindArgumentsToScope(scope, args);
Object result = rhino.evaluateString(scope, script, "JavaScript", 1, null);
log.info("执行结果: {}", Context.toString(result));
return result;
}
}
private void bindArgumentsToScope(Scriptable scope, Object args) {
if (args == null) {
return;
}
// 单个对象参数
Object jsValue = Context.javaToJS(args, scope);
scope.put("args", scope, jsValue);
private void bindArgumentsToScope(Scriptable scope, Map<?, ?> args) {
if (args == null) {
return;
}
for (Map.Entry<?, ?> entry : args.entrySet()) {
Object jsValue = Context.javaToJS(entry.getValue(), scope);
scope.put(entry.getKey().toString(), scope, jsValue);
}
}
private void bindArgumentsToScope(Scriptable scope, Object args) {
if (args == null) {
return;
}
// 单个对象参数
Object jsValue = Context.javaToJS(args, scope);
scope.put("args", scope, jsValue);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,9 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.framework.context;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
@@ -24,147 +27,142 @@ import org.springframework.context.ApplicationContextAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Slf4j
@SuppressWarnings({"unchecked", "all"})
public class KitSpringBeanHolder implements ApplicationContextAware, DisposableBean {
private static final List<CallBack> CALL_BACKS = new ArrayList<>();
private static ApplicationContext applicationContext = null;
private static boolean addCallback = true;
private static final List<CallBack> CALL_BACKS = new ArrayList<>();
private static ApplicationContext applicationContext = null;
private static boolean addCallback = true;
/**
* 针对 某些初始化方法, 在SpringContextHolder 未初始化时 提交回调方法。 在SpringContextHolder 初始化后, 进行回调使用
*
* @param callBack 回调函数
*/
public synchronized static void addCallBacks(CallBack callBack) {
if (addCallback) {
KitSpringBeanHolder.CALL_BACKS.add(callBack);
} else {
log.warn("CallBack:{} 已无法添加!立即执行", callBack.getCallBackName());
callBack.executor();
}
/**
* 针对 某些初始化方法, 在SpringContextHolder 未初始化时 提交回调方法。 在SpringContextHolder 初始化后, 进行回调使用
*
* @param callBack 回调函数
*/
public synchronized static void addCallBacks(CallBack callBack) {
if (addCallback) {
CALL_BACKS.add(callBack);
} else {
log.warn("CallBack:{} 已无法添加!立即执行", callBack.getCallBackName());
callBack.executor();
}
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
public static <T> T getBean(String name) {
assertContextInjected();
return (T)applicationContext.getBean(name);
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
public static <T> T getBean(String name) {
assertContextInjected();
return (T) applicationContext.getBean(name);
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
public static <T> T getBean(Class<T> requiredType) {
assertContextInjected();
return applicationContext.getBean(requiredType);
}
/**
* 获取SpringBoot 配置信息
*
* @param property 属性key
* @param defaultValue 默认值
* @param requiredType 返回类型
* @return /
*/
public static <T> T getProperties(String property, T defaultValue, Class<T> requiredType) {
T result = defaultValue;
try {
result = getBean(Environment.class).getProperty(property, requiredType);
} catch (Exception ignored) {
}
return result;
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
public static <T> T getBean(Class<T> requiredType) {
assertContextInjected();
return applicationContext.getBean(requiredType);
/**
* 获取SpringBoot 配置信息
*
* @param property 属性key
* @return /
*/
public static String getProperties(String property) {
return getProperties(property, null, String.class);
}
/**
* 获取SpringBoot 配置信息
*
* @param property 属性key
* @param requiredType 返回类型
* @return /
*/
public static <T> T getProperties(String property, Class<T> requiredType) {
return getProperties(property, null, requiredType);
}
/**
* 检查ApplicationContext不为空.
*/
private static void assertContextInjected() {
if (applicationContext == null) {
throw new IllegalStateException("applicaitonContext属性未注入, 请在applicationContext" +
".xml中定义SpringContextHolder或在SpringBoot启动类中注册SpringContextHolder.");
}
}
/**
* 获取SpringBoot 配置信息
*
* @param property 属性key
* @param defaultValue 默认值
* @param requiredType 返回类型
* @return /
*/
public static <T> T getProperties(String property, T defaultValue, Class<T> requiredType) {
T result = defaultValue;
try {
result = getBean(Environment.class).getProperty(property, requiredType);
} catch (Exception ignored) {
}
return result;
/**
* 清除SpringContextHolder中的ApplicationContext为Null.
*/
private static void clearHolder() {
log.debug("清除SpringContextHolder中的ApplicationContext:{}", applicationContext);
applicationContext = null;
}
/**
* 获取 @Service 的所有 bean 名称
*
* @return /
*/
public static List<String> getAllServiceBeanName() {
return new ArrayList<>(Arrays.asList(applicationContext.getBeanNamesForAnnotation(Service.class)));
}
@Override
public void destroy() {
KitSpringBeanHolder.clearHolder();
}
@Override
public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
if (KitSpringBeanHolder.applicationContext != null) {
log.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:{}", KitSpringBeanHolder.applicationContext);
}
/**
* 获取SpringBoot 配置信息
*
* @param property 属性key
* @return /
*/
public static String getProperties(String property) {
return getProperties(property, null, String.class);
KitSpringBeanHolder.applicationContext = applicationContext;
if (addCallback) {
for (CallBack callBack : KitSpringBeanHolder.CALL_BACKS) {
callBack.executor();
}
CALL_BACKS.clear();
}
KitSpringBeanHolder.addCallback = false;
}
public interface CallBack {
/**
* 获取SpringBoot 配置信息
*
* @param property 属性key
* @param requiredType 返回类型
* @return /
* 回调执行方法
*/
public static <T> T getProperties(String property, Class<T> requiredType) {
return getProperties(property, null, requiredType);
}
void executor();
/**
* 检查ApplicationContext不为空.
*/
private static void assertContextInjected() {
if (applicationContext == null) {
throw new IllegalStateException(
"applicaitonContext属性未注入, 请在applicationContext" + ".xml中定义SpringContextHolder或在SpringBoot启动类中注册SpringContextHolder.");
}
}
/**
* 清除SpringContextHolder中的ApplicationContext为Null.
*/
private static void clearHolder() {
log.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
applicationContext = null;
}
/**
* 获取 @Service 的所有 bean 名称
* 本回调任务名称
*
* @return /
*/
public static List<String> getAllServiceBeanName() {
return new ArrayList<>(Arrays.asList(applicationContext.getBeanNamesForAnnotation(Service.class)));
}
@Override
public void destroy() {
KitSpringBeanHolder.clearHolder();
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (KitSpringBeanHolder.applicationContext != null) {
log.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + KitSpringBeanHolder.applicationContext);
}
KitSpringBeanHolder.applicationContext = applicationContext;
if (addCallback) {
for (CallBack callBack : KitSpringBeanHolder.CALL_BACKS) {
callBack.executor();
}
CALL_BACKS.clear();
}
KitSpringBeanHolder.addCallback = false;
}
interface CallBack {
/**
* 回调执行方法
*/
void executor();
/**
* 本回调任务名称
*
* @return /
*/
default String getCallBackName() {
return Thread.currentThread().getId() + ":" + this.getClass().getName();
}
default String getCallBackName() {
return Thread.currentThread().getId() + ":" + this.getClass().getName();
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,30 +16,30 @@
package cn.odboy.framework.exception;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
import lombok.Getter;
import org.springframework.http.HttpStatus;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
/**
* 统一异常处理
*/
@Getter
public class BadRequestException extends RuntimeException {
private Integer status = BAD_REQUEST.value();
private Integer status = BAD_REQUEST.value();
public BadRequestException(String msg) {
super(msg);
}
public BadRequestException(String msg) {
super(msg);
}
public BadRequestException(HttpStatus status, String msg) {
super(msg);
this.status = status.value();
}
public BadRequestException(HttpStatus status, String msg) {
super(msg);
this.status = status.value();
}
public BadRequestException(Throwable cause) {
super(cause.getMessage());
this.status = BAD_REQUEST.value();
}
public BadRequestException(Throwable cause) {
super(cause.getMessage());
this.status = BAD_REQUEST.value();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,27 +16,27 @@
package cn.odboy.framework.exception;
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
import lombok.Getter;
import org.springframework.http.HttpStatus;
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
@Getter
public class ServerException extends RuntimeException {
private Integer status = INTERNAL_SERVER_ERROR.value();
private Integer status = INTERNAL_SERVER_ERROR.value();
public ServerException(String msg) {
super(msg);
}
public ServerException(String msg) {
super(msg);
}
public ServerException(HttpStatus status, String msg) {
super(msg);
this.status = status.value();
}
public ServerException(HttpStatus status, String msg) {
super(msg);
this.status = status.value();
}
public ServerException(Throwable cause) {
super(cause.getMessage());
this.status = INTERNAL_SERVER_ERROR.value();
}
public ServerException(Throwable cause) {
super(cause.getMessage());
this.status = INTERNAL_SERVER_ERROR.value();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,26 +21,26 @@ import lombok.Data;
@Data
public final class ApiError {
private Integer status = 400;
private Long timestamp;
private String message;
private Integer status = 400;
private Long timestamp;
private String message;
private ApiError() {
timestamp = System.currentTimeMillis();
}
private ApiError() {
timestamp = System.currentTimeMillis();
}
public static ApiError error(final String message) {
ApiError apiError = new ApiError();
apiError.setMessage(message);
return apiError;
}
public static ApiError error(final String message) {
ApiError apiError = new ApiError();
apiError.setMessage(message);
return apiError;
}
public static ApiError error(final Integer status, final String message) {
ApiError apiError = new ApiError();
apiError.setStatus(status);
apiError.setMessage(message);
return apiError;
}
public static ApiError error(final Integer status, final String message) {
ApiError apiError = new ApiError();
apiError.setStatus(status);
apiError.setMessage(message);
return apiError;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,56 +37,56 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 处理所有不可知的异常
*/
@ExceptionHandler(Throwable.class)
public ResponseEntity<ApiError> handleException(Throwable e) {
// 打印堆栈信息
log.error(ExceptionUtil.stacktraceToString(e));
return buildResponseEntity(ApiError.error(e.getMessage()));
}
/**
* 处理所有不可知的异常
*/
@ExceptionHandler(Throwable.class)
public ResponseEntity<ApiError> handleException(Throwable e) {
// 打印堆栈信息
log.error(ExceptionUtil.stacktraceToString(e));
return buildResponseEntity(ApiError.error(e.getMessage()));
}
/**
* BadCredentialsException
*/
@ExceptionHandler(BadCredentialsException.class)
public ResponseEntity<ApiError> badCredentialsException(BadCredentialsException e) {
// 打印堆栈信息
String message = "坏的凭证".equals(e.getMessage()) ? "用户名或密码不正确" : e.getMessage();
log.error(message);
return buildResponseEntity(ApiError.error(message));
}
/**
* BadCredentialsException
*/
@ExceptionHandler(BadCredentialsException.class)
public ResponseEntity<ApiError> badCredentialsException(BadCredentialsException e) {
// 打印堆栈信息
String message = "坏的凭证".equals(e.getMessage()) ? "用户名或密码不正确" : e.getMessage();
log.error(message);
return buildResponseEntity(ApiError.error(message));
}
/**
* 处理自定义异常
*/
@ExceptionHandler(value = BadRequestException.class)
public ResponseEntity<ApiError> badRequestException(BadRequestException e) {
// 打印堆栈信息
log.error(ExceptionUtil.stacktraceToString(e));
return buildResponseEntity(ApiError.error(e.getStatus(), e.getMessage()));
}
/**
* 处理自定义异常
*/
@ExceptionHandler(value = BadRequestException.class)
public ResponseEntity<ApiError> badRequestException(BadRequestException e) {
// 打印堆栈信息
log.error(ExceptionUtil.stacktraceToString(e));
return buildResponseEntity(ApiError.error(e.getStatus(), e.getMessage()));
}
/**
* 处理所有接口数据验证异常
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ApiError> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
// 打印堆栈信息
log.error(ExceptionUtil.stacktraceToString(e));
ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
String message = objectError.getDefaultMessage();
if (objectError instanceof FieldError fieldError) {
message = fieldError.getField() + ": " + message;
}
return buildResponseEntity(ApiError.error(message));
/**
* 处理所有接口数据验证异常
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ApiError> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
// 打印堆栈信息
log.error(ExceptionUtil.stacktraceToString(e));
ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
String message = objectError.getDefaultMessage();
if (objectError instanceof FieldError fieldError) {
message = fieldError.getField() + ": " + message;
}
return buildResponseEntity(ApiError.error(message));
}
/**
* 统一返回
*/
private ResponseEntity<ApiError> buildResponseEntity(ApiError apiError) {
return new ResponseEntity<>(apiError, HttpStatus.valueOf(apiError.getStatus()));
}
/**
* 统一返回
*/
private ResponseEntity<ApiError> buildResponseEntity(ApiError apiError) {
return new ResponseEntity<>(apiError, HttpStatus.valueOf(apiError.getStatus()));
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,13 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.framework.logging;
import java.lang.annotation.*;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 统计执行时长
* 统计执行时长(仅对代理方法有效)
*
* @author odboy
*/
@@ -28,13 +32,14 @@ import java.lang.annotation.*;
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ExecutionTimeStatisticsFace {
/**
* 接口描述
*/
String description();
/**
* 是否展示异常日志
*/
boolean showErrLog() default true;
/**
* 接口描述
*/
String description();
/**
* 是否展示异常日志
*/
boolean showErrLog() default true;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,18 +33,22 @@ import org.springframework.stereotype.Component;
@Aspect
@Component
public class ExecutionTimeStatisticsFaceAspect {
@Around("@annotation(executionTimeStatisticsFace)")
public Object aroundFace(ProceedingJoinPoint joinPoint, ExecutionTimeStatisticsFace executionTimeStatisticsFace) throws Throwable {
TimeInterval timeInterval = new TimeInterval();
try {
Object proceed = joinPoint.proceed();
log.info("[{}] 接口执行成功,耗时: {} ms", executionTimeStatisticsFace.description(), timeInterval.intervalMs());
return proceed;
} catch (Exception e) {
if (executionTimeStatisticsFace.showErrLog()) {
log.error("[{}] 接口执行失败,耗时: {} ms", executionTimeStatisticsFace.description(), timeInterval.intervalMs(), e);
}
throw e;
}
@Around("@annotation(executionTimeStatisticsFace)")
public Object aroundFace(ProceedingJoinPoint joinPoint, ExecutionTimeStatisticsFace executionTimeStatisticsFace)
throws Throwable {
TimeInterval timeInterval = new TimeInterval();
try {
Object proceed = joinPoint.proceed();
log.info("[{}] 接口执行成功,耗时: {} ms", executionTimeStatisticsFace.description(),
timeInterval.intervalMs());
return proceed;
} catch (Exception e) {
if (executionTimeStatisticsFace.showErrLog()) {
log.error("[{}] 接口执行失败,耗时: {} ms", executionTimeStatisticsFace.description(),
timeInterval.intervalMs(), e);
}
throw e;
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,30 +31,31 @@ import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/healthCheck")
@Tag(name = "系统:健康检查接口")
public class HealthCheckController {
@Autowired
private KitHealthCheckPointService kitHealthCheckPointService;
/**
* 就绪检查
*/
@AnonymousGetMapping(value = "/readiness")
public ResponseEntity<?> doReadiness() {
return kitHealthCheckPointService.doReadiness();
}
@Autowired
private KitHealthCheckPointService kitHealthCheckPointService;
/**
* 存活检查
*/
@AnonymousGetMapping(value = "/liveness")
public ResponseEntity<?> doLiveness() {
return kitHealthCheckPointService.doLiveness();
}
/**
* 就绪检查
*/
@AnonymousGetMapping(value = "/readiness")
public ResponseEntity<?> doReadiness() {
return kitHealthCheckPointService.doReadiness();
}
// /**
// * 访问首页提示
// */
// @AnonymousGetMapping("/")
// public String index() {
// return "success";
// }
/**
* 存活检查
*/
@AnonymousGetMapping(value = "/liveness")
public ResponseEntity<?> doLiveness() {
return kitHealthCheckPointService.doLiveness();
}
// /**
// * 访问首页提示
// */
// @AnonymousGetMapping("/")
// public String index() {
// return "success";
// }
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,13 +19,14 @@ package cn.odboy.framework.monitor.service;
import org.springframework.http.ResponseEntity;
public interface KitHealthCheckPointService {
/**
* 就绪检查
*/
ResponseEntity<?> doReadiness();
/**
* 存活检查
*/
ResponseEntity<?> doLiveness();
/**
* 就绪检查
*/
ResponseEntity<?> doReadiness();
/**
* 存活检查
*/
ResponseEntity<?> doLiveness();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,140 +13,108 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.framework.mybatisplus.config;
import cn.odboy.framework.exception.BadRequestException;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
/**
* @author /
*/
@Getter
@Slf4j
@SuppressWarnings({"unchecked", "all"})
public enum DataTypeEnum {
/**
* mysql
*/
MYSQL("mysql", "mysql", "com.mysql.jdbc.Driver", "`", "`", "'", "'"),
/**
* oracle
*/
ORACLE("oracle", "oracle", "oracle.jdbc.driver.OracleDriver", "\"", "\"", "\"", "\""),
/**
* sql config
*/
SQLSERVER("sqlserver", "sqlserver", "com.microsoft.sqlserver.jdbc.SQLServerDriver", "\"", "\"", "\"", "\""),
/**
* h2
*/
H2("h2", "h2", "org.h2.Driver", "`", "`", "\"", "\""),
/**
* phoenix
*/
PHOENIX("phoenix", "hbase phoenix", "org.apache.phoenix.jdbc.PhoenixDriver", "", "", "\"", "\""),
/**
* mongo
*/
MONGODB("mongo", "mongodb", "mongodb.jdbc.MongoDriver", "`", "`", "\"", "\""),
/**
* sql4es
*/
ELASTICSEARCH("sql4es", "elasticsearch", "nl.anchormen.sql4es.jdbc.ESDriver", "", "", "'", "'"),
/**
* presto
*/
PRESTO("presto", "presto", "com.facebook.presto.jdbc.PrestoDriver", "", "", "\"", "\""),
/**
* moonbox
*/
MOONBOX("moonbox", "moonbox", "moonbox.jdbc.MbDriver", "`", "`", "`", "`"),
/**
* cassandra
*/
CASSANDRA("cassandra", "cassandra", "com.github.adejanovski.cassandra.jdbc.CassandraDriver", "", "", "'", "'"),
/**
* click house
*/
CLICKHOUSE("clickhouse", "clickhouse", "ru.yandex.clickhouse.ClickHouseDriver", "", "", "\"", "\""),
/**
* kylin
*/
KYLIN("kylin", "kylin", "org.apache.kylin.jdbc.Driver", "\"", "\"", "\"", "\""),
/**
* vertica
*/
VERTICA("vertica", "vertica", "com.vertica.jdbc.Driver", "", "", "'", "'"),
/**
* sap
*/
HANA("sap", "sap hana", "com.sap.db.jdbc.Driver", "", "", "'", "'"),
/**
* impala
*/
IMPALA("impala", "impala", "com.cloudera.impala.jdbc41.Driver", "", "", "'", "'");
private static final String JDBC_URL_PREFIX = "jdbc:";
private String feature;
private String desc;
private String driver;
private String keywordPrefix;
private String keywordSuffix;
private String aliasPrefix;
private String aliasSuffix;
/**
* mysql
*/
MYSQL("mysql", "mysql", "com.mysql.jdbc.Driver", "`", "`", "'", "'"),
/**
* oracle
*/
ORACLE("oracle", "oracle", "oracle.jdbc.driver.OracleDriver", "\"", "\"", "\"", "\""),
/**
* sql config
*/
SQLSERVER("sqlserver", "sqlserver", "com.microsoft.sqlserver.jdbc.SQLServerDriver", "\"", "\"", "\"", "\""),
/**
* h2
*/
H2("h2", "h2", "org.h2.Driver", "`", "`", "\"", "\""),
/**
* phoenix
*/
PHOENIX("phoenix", "hbase phoenix", "org.apache.phoenix.jdbc.PhoenixDriver", "", "", "\"", "\""),
/**
* mongo
*/
MONGODB("mongo", "mongodb", "mongodb.jdbc.MongoDriver", "`", "`", "\"", "\""),
/**
* sql4es
*/
ELASTICSEARCH("sql4es", "elasticsearch", "nl.anchormen.sql4es.jdbc.ESDriver", "", "", "'", "'"),
/**
* presto
*/
PRESTO("presto", "presto", "com.facebook.presto.jdbc.PrestoDriver", "", "", "\"", "\""),
/**
* moonbox
*/
MOONBOX("moonbox", "moonbox", "moonbox.jdbc.MbDriver", "`", "`", "`", "`"),
/**
* cassandra
*/
CASSANDRA("cassandra", "cassandra", "com.github.adejanovski.cassandra.jdbc.CassandraDriver", "", "", "'", "'"),
/**
* click house
*/
CLICKHOUSE("clickhouse", "clickhouse", "ru.yandex.clickhouse.ClickHouseDriver", "", "", "\"", "\""),
/**
* kylin
*/
KYLIN("kylin", "kylin", "org.apache.kylin.jdbc.Driver", "\"", "\"", "\"", "\""),
/**
* vertica
*/
VERTICA("vertica", "vertica", "com.vertica.jdbc.Driver", "", "", "'", "'"),
/**
* sap
*/
HANA("sap", "sap hana", "com.sap.db.jdbc.Driver", "", "", "'", "'"),
/**
* impala
*/
IMPALA("impala", "impala", "com.cloudera.impala.jdbc41.Driver", "", "", "'", "'");
private static final String JDBC_URL_PREFIX = "jdbc:";
private final String feature;
private final String desc;
private final String driver;
private final String keywordPrefix;
private final String keywordSuffix;
private final String aliasPrefix;
private final String aliasSuffix;
DataTypeEnum(String feature, String desc, String driver, String keywordPrefix, String keywordSuffix, String aliasPrefix, String aliasSuffix) {
this.feature = feature;
this.desc = desc;
this.driver = driver;
this.keywordPrefix = keywordPrefix;
this.keywordSuffix = keywordSuffix;
this.aliasPrefix = aliasPrefix;
this.aliasSuffix = aliasSuffix;
}
DataTypeEnum(String feature, String desc, String driver, String keywordPrefix, String keywordSuffix,
String aliasPrefix, String aliasSuffix) {
this.feature = feature;
this.desc = desc;
this.driver = driver;
this.keywordPrefix = keywordPrefix;
this.keywordSuffix = keywordSuffix;
this.aliasPrefix = aliasPrefix;
this.aliasSuffix = aliasSuffix;
}
public static DataTypeEnum urlOf(String jdbcUrl) {
String url = jdbcUrl.toLowerCase().trim();
for (DataTypeEnum dataTypeEnum : values()) {
if (url.startsWith(JDBC_URL_PREFIX + dataTypeEnum.feature)) {
try {
Class<?> aClass = Class.forName(dataTypeEnum.getDriver());
if (null == aClass) {
throw new BadRequestException("Unable to get driver instance for jdbcUrl: " + jdbcUrl);
}
} catch (ClassNotFoundException e) {
throw new BadRequestException("Unable to get driver instance: " + jdbcUrl);
}
return dataTypeEnum;
}
public static DataTypeEnum urlOf(String jdbcUrl) {
String url = jdbcUrl.toLowerCase().trim();
for (DataTypeEnum dataTypeEnum : values()) {
if (url.startsWith(JDBC_URL_PREFIX + dataTypeEnum.feature)) {
try {
Class.forName(dataTypeEnum.getDriver());
} catch (ClassNotFoundException e) {
throw new BadRequestException("Unable to get driver instance: " + jdbcUrl);
}
return null;
return dataTypeEnum;
}
}
return null;
}
public String getFeature() {
return feature;
}
public String getDesc() {
return desc;
}
public String getDriver() {
return driver;
}
public String getKeywordPrefix() {
return keywordPrefix;
}
public String getKeywordSuffix() {
return keywordSuffix;
}
public String getAliasPrefix() {
return aliasPrefix;
}
public String getAliasSuffix() {
return aliasSuffix;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,56 +20,56 @@ package cn.odboy.framework.mybatisplus.config;
* 动态查询 枚举
*/
public enum KitMpQTypeEnum {
/**
* 相等
*/
EQUAL
/**
* 大于等于
*/
, GREATER_THAN
/**
* 小于等于
*/
, LESS_THAN
/**
* 中模糊查询
*/
, INNER_LIKE
/**
* 左模糊查询
*/
, LEFT_LIKE
/**
* 右模糊查询
*/
, RIGHT_LIKE
/**
* 小于
*/
, LESS_THAN_NQ
/**
* 包含
*/
, IN
/**
* 不包含
*/
, NOT_IN
/**
* 不等于
*/
, NOT_EQUAL
/**
* between(注:被注解的属性一定得是数组或者集合, 长度大于等于2)
*/
, BETWEEN
/**
* 不为空
*/
, NOT_NULL
/**
* 为空
*/
, IS_NULL
/**
* 相等
*/
EQUAL
/**
* 大于等于
*/
, GREATER_THAN
/**
* 小于等于
*/
, LESS_THAN
/**
* 中模糊查询
*/
, INNER_LIKE
/**
* 左模糊查询
*/
, LEFT_LIKE
/**
* 右模糊查询
*/
, RIGHT_LIKE
/**
* 小于
*/
, LESS_THAN_NQ
/**
* 包含
*/
, IN
/**
* 不包含
*/
, NOT_IN
/**
* 不等于
*/
, NOT_EQUAL
/**
* between(注:被注解的属性一定得是数组或者集合, 长度大于等于2)
*/
, BETWEEN
/**
* 不为空
*/
, NOT_NULL
/**
* 为空
*/
, IS_NULL
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,18 +29,19 @@ import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface KitMpQuery {
/**
* 基本对象的属性名
*/
String propName() default "";
/**
* 查询方式
*/
KitMpQTypeEnum type() default KitMpQTypeEnum.EQUAL;
/**
* 基本对象的属性名
*/
String propName() default "";
/**
* 多字段模糊搜索, 仅支持String类型字段, 多个用逗号隔开, 如@MpQuery(blurry = "email,username")
*/
String blurry() default "";
/**
* 查询方式
*/
KitMpQTypeEnum type() default KitMpQTypeEnum.EQUAL;
/**
* 多字段模糊搜索, 仅支持String类型字段, 多个用逗号隔开, 如@MpQuery(blurry = "email,username")
*/
String blurry() default "";
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,43 +25,45 @@ import lombok.extern.slf4j.Slf4j;
*/
@Slf4j
public class MpCustomP6SpyLogger implements MessageFormattingStrategy {
/**
* 重置颜色
*/
private static final String RESET = "\u001B[0m";
/**
* 红色
*/
private static final String RED = "\u001B[31m";
/**
* 绿色
*/
private static final String GREEN = "\u001B[32m";
/**
* 蓝色
*/
private static final String BLUE = "\u001B[34m";
/**
* 格式化 sql
*
* @param connectionId 连接id
* @param now 当前时间
* @param elapsed 执行时长
* @param category sql分类
* @param prepared 预编译sql
* @param sql 执行sql
* @param url 数据库连接url
* @return 格式化后的sql
*/
@Override
public String formatMessage(int connectionId, String now, long elapsed, String category, String prepared, String sql, String url) {
// 去掉换行和多余空格
if (StrUtil.isNotBlank(sql)) {
sql = sql.replaceAll("\\s+", " ").trim();
}
// 格式化并加上颜色
return String.format("CuteJava - %s%s%s %s[%s] %sREVIEW_SQL [Interval: %dms]%s -> %s;", RED, now, RESET, GREEN, Thread.currentThread().getName(), BLUE,
elapsed, RESET, sql);
/**
* 重置颜色
*/
private static final String RESET = "\u001B[0m";
/**
* 红色
*/
private static final String RED = "\u001B[31m";
/**
* 绿色
*/
private static final String GREEN = "\u001B[32m";
/**
* 蓝色
*/
private static final String BLUE = "\u001B[34m";
/**
* 格式化 sql
*
* @param connectionId 连接id
* @param now 当前时间
* @param elapsed 执行时长
* @param category sql分类
* @param prepared 预编译sql
* @param sql 执行sql
* @param url 数据库连接url
* @return 格式化后的sql
*/
@Override
public String formatMessage(int connectionId, String now, long elapsed, String category, String prepared,
String sql, String url) {
// 去掉换行和多余空格
if (StrUtil.isNotBlank(sql)) {
sql = sql.replaceAll("\\s+", " ").trim();
}
}
// 格式化并加上颜色
return String.format("CuteJava - %s%s%s %s[%s] %sREVIEW_SQL [Interval: %dms]%s -> %s;", RED, now, RESET, GREEN,
Thread.currentThread().getName(), BLUE, elapsed, RESET, sql);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,9 +22,8 @@ import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.extension.injector.methods.AlwaysUpdateSomeColumnById;
import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn;
import org.apache.ibatis.session.Configuration;
import java.util.List;
import org.apache.ibatis.session.Configuration;
/**
* 批量插入SQL注入器
@@ -33,13 +32,14 @@ import java.util.List;
* @date 2025-01-11
*/
public class MpInsertBatchSqlInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Configuration configuration, Class<?> mapperClass, TableInfo tableInfo) {
List<AbstractMethod> methodList = super.getMethodList(configuration, mapperClass, tableInfo);
// 新增自定义方法, InsertBatchSomeColumn这个方法Mp没有开放出来
methodList.add(new InsertBatchSomeColumn(i -> i.getFieldFill() != FieldFill.UPDATE));
// 全量更新, 包括null字段
methodList.add(new AlwaysUpdateSomeColumnById(i -> i.getFieldFill() != FieldFill.INSERT));
return methodList;
}
}
@Override
public List<AbstractMethod> getMethodList(Configuration configuration, Class<?> mapperClass, TableInfo tableInfo) {
List<AbstractMethod> methodList = super.getMethodList(configuration, mapperClass, tableInfo);
// 新增自定义方法, InsertBatchSomeColumn这个方法Mp没有开放出来
methodList.add(new InsertBatchSomeColumn(i -> i.getFieldFill() != FieldFill.UPDATE));
// 全量更新, 包括null字段
methodList.add(new AlwaysUpdateSomeColumnById(i -> i.getFieldFill() != FieldFill.INSERT));
return methodList;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,28 +28,29 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableTransactionManagement
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor paginationInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// MySQL的分页拦截器
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
paginationInnerInterceptor.setMaxLimit(500L);
/// 这个配置会导致:当分页没数据时, 游标从0开始,会导致无论page为什么值,就算分页超出最大页数,依然能够查询到
/// paginationInnerInterceptor.setOverflow(true);
paginationInnerInterceptor.setOptimizeJoin(true);
interceptor.addInnerInterceptor(paginationInnerInterceptor);
// 乐观锁
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
// 防全表更新与删除
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
return interceptor;
}
/**
* Mapper支持批量插入
*/
@Bean
public MpInsertBatchSqlInjector insertBatchSqlInjector() {
return new MpInsertBatchSqlInjector();
}
@Bean
public MybatisPlusInterceptor paginationInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// MySQL的分页拦截器
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
paginationInnerInterceptor.setMaxLimit(500L);
/// 这个配置会导致:当分页没数据时, 游标从0开始,会导致无论page为什么值,就算分页超出最大页数,依然能够查询到
/// paginationInnerInterceptor.setOverflow(true);
paginationInnerInterceptor.setOptimizeJoin(true);
interceptor.addInnerInterceptor(paginationInnerInterceptor);
// 乐观锁
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
// 防全表更新与删除
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
return interceptor;
}
/**
* Mapper支持批量插入
*/
@Bean
public MpInsertBatchSqlInjector insertBatchSqlInjector() {
return new MpInsertBatchSqlInjector();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,9 +19,15 @@ package cn.odboy.framework.mybatisplus.config;
import com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceAutoConfigure;
import com.alibaba.druid.spring.boot3.autoconfigure.properties.DruidStatProperties;
import com.alibaba.druid.util.Utils;
import jakarta.servlet.*;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
@@ -29,63 +35,62 @@ import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
@Configuration
@SuppressWarnings({"unchecked", "all"})
@ConditionalOnWebApplication
@AutoConfigureAfter(DruidDataSourceAutoConfigure.class)
@ConditionalOnProperty(name = "spring.datasource.druid.stat-view-servlet.enabled", havingValue = "true", matchIfMissing = true)
@ConditionalOnProperty(name = "spring.datasource.druid.stat-view-servlet.enabled", havingValue = "true",
matchIfMissing = true)
public class RemoveDruidAdConfig {
/**
* 方法名: removeDruidAdFilterRegistrationBean 方法描述 除去页面底部的广告
*
* @param properties com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties
* @return org.springframework.boot.web.servlet.FilterRegistrationBean
*/
@Bean
public FilterRegistrationBean removeDruidAdFilterRegistrationBean(DruidStatProperties properties) {
/**
* 方法名: removeDruidAdFilterRegistrationBean 方法描述 除去页面底部的广告
*
* @param properties com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties
* @return org.springframework.boot.web.servlet.FilterRegistrationBean
*/
@Bean
public FilterRegistrationBean<Filter> removeDruidAdFilterRegistrationBean(DruidStatProperties properties) {
// 获取web监控页面的参数
DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
// 提取common.js的配置路径
String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*";
String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");
// 获取web监控页面的参数
DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
// 提取common.js的配置路径
String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*";
String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");
final String filePath = "support/http/resources/js/common.js";
final String filePath = "support/http/resources/js/common.js";
//创建filter进行过滤
Filter filter = new Filter() {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
//创建filter进行过滤
Filter filter = new Filter() {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest)request;
HttpServletResponse httpResponse = (HttpServletResponse)response;
if (httpRequest.getRequestURI().endsWith("js/common.js")) {
// 获取common.js
String text = Utils.readFromResource(filePath);
// 正则替换banner, 除去底部的广告信息
text = text.replaceAll("<a.*?druid_banner\"></a><br/>", "");
text = text.replaceAll("powered by.*?shrek.wang</a>", "");
httpResponse.setContentType("application/javascript");
httpResponse.setCharacterEncoding("UTF-8");
httpResponse.getWriter().write(text);
} else {
chain.doFilter(request, response);
}
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
if (httpRequest.getRequestURI().endsWith("js/common.js")) {
// 获取common.js
String text = Utils.readFromResource(filePath);
// 正则替换banner, 除去底部的广告信息
text = text.replaceAll("<a.*?druid_banner\"></a><br/>", "");
text = text.replaceAll("powered by.*?shrek.wang</a>", "");
httpResponse.setContentType("application/javascript");
httpResponse.setCharacterEncoding("UTF-8");
httpResponse.getWriter().write(text);
} else {
chain.doFilter(request, response);
}
}
@Override
public void destroy() {
}
};
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(filter);
registrationBean.addUrlPatterns(commonJsPattern);
return registrationBean;
}
@Override
public void destroy() {
}
};
FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(filter);
registrationBean.addUrlPatterns(commonJsPattern);
return registrationBean;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,14 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.framework.mybatisplus.core;
import cn.hutool.core.bean.BeanUtil;
import cn.odboy.util.KitBeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import java.util.ArrayList;
import java.util.List;
@@ -31,52 +29,54 @@ import java.util.List;
* @date 2025-05-15
*/
public class KitMpAnyQUtil {
public static <T> T selectOne(BaseMapper<T> baseMapper, Object queryParams) {
QueryWrapper<T> queryWrapper = KitMpQUtil.build(queryParams);
return baseMapper.selectOne(queryWrapper);
}
public static <T, M> M selectOne(BaseMapper<T> baseMapper, Object queryParams, Class<M> mapperClazz) {
QueryWrapper<T> queryWrapper = KitMpQUtil.build(queryParams);
T mapperTarget = baseMapper.selectOne(queryWrapper);
if (mapperTarget == null) {
return null;
}
return BeanUtil.copyProperties(mapperTarget, mapperClazz);
}
public static <T> T selectOne(BaseMapper<T> baseMapper, Object queryParams) {
QueryWrapper<T> queryWrapper = KitMpQUtil.build(queryParams);
return baseMapper.selectOne(queryWrapper);
}
public static <T> List<T> selectList(BaseMapper<T> baseMapper, Object queryParams) {
QueryWrapper<T> queryWrapper = KitMpQUtil.build(queryParams);
return baseMapper.selectList(queryWrapper);
public static <T, M> M selectOne(BaseMapper<T> baseMapper, Object queryParams, Class<M> mapperClazz) {
QueryWrapper<T> queryWrapper = KitMpQUtil.build(queryParams);
T mapperTarget = baseMapper.selectOne(queryWrapper);
if (mapperTarget == null) {
return null;
}
return KitBeanUtil.copyToClass(mapperTarget, mapperClazz);
}
public static <T, M> List<M> selectList(BaseMapper<T> baseMapper, Object queryParams, Class<M> mapperClazz) {
QueryWrapper<T> queryWrapper = KitMpQUtil.build(queryParams);
List<T> mapperTarget = baseMapper.selectList(queryWrapper);
if (mapperTarget == null) {
return new ArrayList<>();
}
return BeanUtil.copyToList(mapperTarget, mapperClazz);
}
public static <T> List<T> selectList(BaseMapper<T> baseMapper, Object queryParams) {
QueryWrapper<T> queryWrapper = KitMpQUtil.build(queryParams);
return baseMapper.selectList(queryWrapper);
}
public static <T> Long selectCount(BaseMapper<T> baseMapper, Object queryParams) {
QueryWrapper<T> queryWrapper = KitMpQUtil.build(queryParams);
return baseMapper.selectCount(queryWrapper);
public static <T, M> List<M> selectList(BaseMapper<T> baseMapper, Object queryParams, Class<M> mapperClazz) {
QueryWrapper<T> queryWrapper = KitMpQUtil.build(queryParams);
List<T> mapperTarget = baseMapper.selectList(queryWrapper);
if (mapperTarget == null) {
return new ArrayList<>();
}
return KitBeanUtil.copyToList(mapperTarget, mapperClazz);
}
public static <T> Page<T> selectPage(BaseMapper<T> baseMapper, Page<T> page, Object queryParams) {
QueryWrapper<T> queryWrapper = KitMpQUtil.build(queryParams);
return baseMapper.selectPage(page, queryWrapper);
}
public static <T> Long selectCount(BaseMapper<T> baseMapper, Object queryParams) {
QueryWrapper<T> queryWrapper = KitMpQUtil.build(queryParams);
return baseMapper.selectCount(queryWrapper);
}
public static <T, M> Page<M> selectPage(BaseMapper<T> baseMapper, Page<T> page, Object queryParams, Class<M> mapperClazz) {
QueryWrapper<T> queryWrapper = KitMpQUtil.build(queryParams);
Page<T> tPage = baseMapper.selectPage(page, queryWrapper);
Page<M> mapperTarget = new Page<>();
mapperTarget.setRecords(BeanUtil.copyToList(tPage.getRecords(), mapperClazz));
mapperTarget.setTotal(tPage.getTotal());
mapperTarget.setSize(tPage.getSize());
mapperTarget.setCurrent(tPage.getCurrent());
return mapperTarget;
}
public static <T> Page<T> selectPage(BaseMapper<T> baseMapper, Page<T> page, Object queryParams) {
QueryWrapper<T> queryWrapper = KitMpQUtil.build(queryParams);
return baseMapper.selectPage(page, queryWrapper);
}
public static <T, M> Page<M> selectPage(BaseMapper<T> baseMapper, Page<T> page, Object queryParams,
Class<M> mapperClazz) {
QueryWrapper<T> queryWrapper = KitMpQUtil.build(queryParams);
Page<T> tPage = baseMapper.selectPage(page, queryWrapper);
Page<M> mapperTarget = new Page<>();
mapperTarget.setRecords(KitBeanUtil.copyToList(tPage.getRecords(), mapperClazz));
mapperTarget.setTotal(tPage.getTotal());
mapperTarget.setSize(tPage.getSize());
mapperTarget.setCurrent(tPage.getCurrent());
return mapperTarget;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.framework.mybatisplus.core;
import cn.hutool.core.util.StrUtil;
@@ -21,7 +20,12 @@ import cn.odboy.base.KitBaseUserTimeTb;
import cn.odboy.framework.exception.BadRequestException;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.IDbQuery;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.querys.MySqlQuery;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
@@ -29,13 +33,12 @@ import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.keywords.MySqlKeyWordsHandler;
import lombok.Data;
import org.apache.ibatis.annotations.Mapper;
import java.sql.Types;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import lombok.Data;
import org.apache.ibatis.annotations.Mapper;
/**
* 代码生成器入口
@@ -45,157 +48,166 @@ import java.util.function.Consumer;
*/
@Data
public class KitMpCmdGenUtil {
// 项目根路径。生成结果 C:\Users\Administrator\Documents\GitHub\cutejava\cutejava
private static final String projectRootPath = System.getProperty("user.dir") + "/";
/**
* 数据库类型 MySQL
*/
private static final IDbQuery DB_QUERY = new MySqlQuery();
/**
* 类型转换
*/
private static final String TYPE_TINY_INT = "tinyint";
private static final String TYPE_DATETIME = "datetime";
private static final String TYPE_DATE = "date";
private String databaseUrl;
private String databaseUsername;
private String databasePassword;
private String driverClassName;
private String parentPackageName = "cn.odboy";
private String parentModuleName;
private static Consumer<StrategyConfig.Builder> getEntityConfigConsumer() {
return strategyConfigBuilder -> strategyConfigBuilder.entityBuilder().enableLombok()
// 如果不需要生成注解, 去掉.enableTableFieldAnnotation()
.enableTableFieldAnnotation().enableFileOverride().naming(NamingStrategy.underline_to_camel).columnNaming(NamingStrategy.underline_to_camel)
.idType(IdType.AUTO);
}
// 项目根路径。生成结果 C:\Users\Administrator\Documents\GitHub\cutejava\cutejava
private static final String projectRootPath = System.getProperty("user.dir") + "/";
/**
* 数据库类型 MySQL
*/
private static final IDbQuery DB_QUERY = new MySqlQuery();
/**
* 类型转换
*/
private static final String TYPE_TINY_INT = "tinyint";
private static final String TYPE_DATETIME = "datetime";
private static final String TYPE_DATE = "date";
private String databaseUrl;
private String databaseUsername;
private String databasePassword;
private String driverClassName;
private String parentPackageName = "cn.odboy";
private String parentModuleName;
private static Consumer<StrategyConfig.Builder> getStrategyConfigConsumer(List<String> tableNames) {
return strategyConfigBuilder -> strategyConfigBuilder.enableCapitalMode().enableSkipView().disableSqlFilter().addInclude(tableNames)
// 实体类生成策略
.entityBuilder().superClass(KitBaseUserTimeTb.class).addIgnoreColumns("create_time", "update_time", "create_by", "update_by")
// 开启生成实体时生成字段注解。
// 会在实体类的属性前,添加[@TableField("nickname")]
.enableTableFieldAnnotation().disableSerialVersionUID()
// 阶段2:Mapper策略配置
.mapperBuilder()
// 开启 @Mapper 注解。
// 会在mapper接口上添加注解[@Mapper]
// .enableMapperAnnotation()
// 启用 BaseResultMap 生成。
// 会在mapper.xml文件生成[通用查询映射结果]配置。
// .enableBaseResultMap()
// 启用 BaseColumnList。
// 会在mapper.xml文件生成[通用查询结果列 ]配置
// .enableBaseColumnList()
// 阶段4:Controller策略配置
.controllerBuilder()
// 会在控制类中加[@RestController]注解。
.enableRestStyle()
// 开启驼峰转连字符
.enableHyphenStyle().build();
}
private static Consumer<StrategyConfig.Builder> getEntityConfigConsumer() {
return strategyConfigBuilder -> strategyConfigBuilder.entityBuilder().enableLombok()
// 如果不需要生成注解, 去掉.enableTableFieldAnnotation()
.enableTableFieldAnnotation().enableFileOverride().naming(NamingStrategy.underline_to_camel)
.columnNaming(NamingStrategy.underline_to_camel).idType(IdType.AUTO);
}
private static Consumer<GlobalConfig.Builder> getGlobalConfigConsumer() {
String outputDir = projectRootPath + "CodeGen";
return globalConfigBuilder -> globalConfigBuilder.enableSwagger().outputDir(outputDir).author("codegen").commentDate("yyyy-MM-dd")
.dateType(DateType.TIME_PACK);
}
private static Consumer<StrategyConfig.Builder> getStrategyConfigConsumer(List<String> tableNames) {
return strategyConfigBuilder -> strategyConfigBuilder.enableCapitalMode().enableSkipView().disableSqlFilter()
.addInclude(tableNames)
// 实体类生成策略
.entityBuilder().superClass(KitBaseUserTimeTb.class)
.addIgnoreColumns("create_time", "update_time", "create_by", "update_by")
// 开启生成实体时生成字段注解。
// 会在实体类的属性前,添加[@TableField("nickname")]
.enableTableFieldAnnotation().disableSerialVersionUID()
// 阶段2:Mapper策略配置
.mapperBuilder()
// 开启 @Mapper 注解。
// 会在mapper接口上添加注解[@Mapper]
// .enableMapperAnnotation()
// 启用 BaseResultMap 生成。
// 会在mapper.xml文件生成[通用查询映射结果]配置。
// .enableBaseResultMap()
// 启用 BaseColumnList。
// 会在mapper.xml文件生成[通用查询结果列 ]配置
// .enableBaseColumnList()
// 阶段4:Controller策略配置
.controllerBuilder()
// 会在控制类中加[@RestController]注解。
.enableRestStyle()
// 开启驼峰转连字符
.enableHyphenStyle().build();
}
private static Consumer<StrategyConfig.Builder> getStrategyConfigConsumer() {
return strategyConfigBuilder -> strategyConfigBuilder.mapperBuilder().mapperAnnotation(Mapper.class).formatMapperFileName("%sMapper")
.formatXmlFileName("%sMapper").entityBuilder().formatFileName("%sTb");
}
private static Consumer<GlobalConfig.Builder> getGlobalConfigConsumer() {
String outputDir = projectRootPath + "CodeGen";
return globalConfigBuilder -> globalConfigBuilder.enableSwagger().outputDir(outputDir).author("codegen")
.commentDate("yyyy-MM-dd").dateType(DateType.TIME_PACK);
}
private static Consumer<DataSourceConfig.Builder> getDataSourceConfigConsumer() {
return builder -> builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {
int typeCode = metaInfo.getJdbcType().TYPE_CODE;
if (typeCode == Types.SMALLINT) {
return DbColumnType.INTEGER;
}
if (typeCode == Types.DATE) {
return DbColumnType.DATE;
}
if (typeCode == Types.TIME) {
return DbColumnType.DATE;
}
if (typeCode == Types.TIMESTAMP) {
return DbColumnType.DATE;
}
return typeRegistry.getColumnType(metaInfo);
});
}
private static Consumer<StrategyConfig.Builder> getStrategyConfigConsumer() {
return strategyConfigBuilder -> strategyConfigBuilder.mapperBuilder().mapperAnnotation(Mapper.class)
.formatMapperFileName("%sMapper").formatXmlFileName("%sMapper").entityBuilder().formatFileName("%sTb");
}
/**
* 代码生成函数
*
* @param moduleName 模块名称
* @param tablePrefix 表前缀(可空)
* @param tableNames 表名称, 多个用逗号分隔
*/
public void gen(String moduleName, String tablePrefix, List<String> tableNames) {
this.parentModuleName = moduleName;
// 1.数据库配置
DataSourceConfig.Builder dataSourceConfigBuilder =
new DataSourceConfig.Builder(this.databaseUrl, this.databaseUsername, this.databasePassword).driverClassName(this.driverClassName);
dataSourceConfigBuilder.dbQuery(DB_QUERY);
dataSourceConfigBuilder.keyWordsHandler(new MySqlKeyWordsHandler());
// 1.1.快速生成器
FastAutoGenerator fastAutoGenerator = FastAutoGenerator.create(dataSourceConfigBuilder);
// 2.全局配置
// 自定义类型转换
fastAutoGenerator.dataSourceConfig(getDataSourceConfigConsumer());
// 覆盖已生成文件
// 添加swagger注解
// 设置注释的作者
// 设置注释的日期格式
// 使用java8新的时间类型
fastAutoGenerator.globalConfig(getGlobalConfigConsumer());
// 3.包配置
// 设置父包名
// 设置父包模块名
// 设置MVC下各个模块的包名
// 设置XML资源文件的目录
fastAutoGenerator.packageConfig(getPackageConfigConsumer());
// 4.模板配置
// 使用Freemarker引擎模板, 默认的是Velocity引擎模板
AbstractTemplateEngine templateEngine = new FreemarkerTemplateEngine();
fastAutoGenerator.templateEngine(templateEngine);
// 5.策略配置
// 设置需要生成的表名
// 设置过滤表前缀
fastAutoGenerator.strategyConfig(getStrategyConfigConsumer(tableNames));
if (tablePrefix != null) {
// 表前缀, 可多个
fastAutoGenerator.strategyConfig(strategyConfigBuilder -> strategyConfigBuilder.addTablePrefix(tablePrefix));
}
// 5.1.Entity策略配置
// 生成实体时生成字段的注解, 包括@TableId注解等
// 数据库表和字段映射到实体的命名策略, 为下划线转驼峰
// 全局主键类型为None
// 实体名称格式化为XXXEntity
fastAutoGenerator.strategyConfig(getEntityConfigConsumer());
// 5.2.Controller策略配置
// 开启生成@RestController控制器
fastAutoGenerator.strategyConfig(strategyConfigBuilder -> strategyConfigBuilder.controllerBuilder().enableRestStyle());
// 如果不需要生成Controller, fastAutoGenerator.templateConfig(templateConfig -> templateConfig.controller(""))。5.3.Service策略配置:格式化service接口和实现类的文件名称, 去掉默认的ServiceName前面的I
fastAutoGenerator.strategyConfig(
strategyConfigBuilder -> strategyConfigBuilder.serviceBuilder().formatServiceFileName("%sService").formatServiceImplFileName("%sServiceImpl"));
// 5.4.Mapper策略配置
// 格式化 mapper文件名,格式化xml实现类文件名称
fastAutoGenerator.strategyConfig(getStrategyConfigConsumer());
// 6.生成代码
fastAutoGenerator.execute();
}
private static Consumer<DataSourceConfig.Builder> getDataSourceConfigConsumer() {
return builder -> builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {
int typeCode = metaInfo.getJdbcType().TYPE_CODE;
if (typeCode == Types.SMALLINT) {
return DbColumnType.INTEGER;
}
if (typeCode == Types.DATE) {
return DbColumnType.DATE;
}
if (typeCode == Types.TIME) {
return DbColumnType.DATE;
}
if (typeCode == Types.TIMESTAMP) {
return DbColumnType.DATE;
}
return typeRegistry.getColumnType(metaInfo);
});
}
private Consumer<PackageConfig.Builder> getPackageConfigConsumer() {
String mapperPath = projectRootPath + "CodeGen/resources/mapper";
if (StrUtil.isBlank(this.parentModuleName)) {
throw new BadRequestException("模块名称必填");
}
return packageConfigBuilder -> packageConfigBuilder.parent(this.parentPackageName).moduleName(this.parentModuleName).entity("dal.dataobject")
.mapper("dal.mysql").service("service").serviceImpl("service.impl").controller("controller")
.pathInfo(Collections.singletonMap(OutputFile.xml, mapperPath));
/**
* 代码生成函数
*
* @param moduleName 模块名称
* @param tablePrefix 表前缀(可空)
* @param tableNames 表名称, 多个用逗号分隔
*/
public void gen(String moduleName, String tablePrefix, List<String> tableNames) {
this.parentModuleName = moduleName;
// 1.数据库配置
DataSourceConfig.Builder dataSourceConfigBuilder =
new DataSourceConfig.Builder(this.databaseUrl, this.databaseUsername,
this.databasePassword).driverClassName(this.driverClassName);
dataSourceConfigBuilder.dbQuery(DB_QUERY);
dataSourceConfigBuilder.keyWordsHandler(new MySqlKeyWordsHandler());
// 1.1.快速生成器
FastAutoGenerator fastAutoGenerator = FastAutoGenerator.create(dataSourceConfigBuilder);
// 2.全局配置
// 自定义类型转换
fastAutoGenerator.dataSourceConfig(getDataSourceConfigConsumer());
// 覆盖已生成文件
// 添加swagger注解
// 设置注释的作者
// 设置注释的日期格式
// 使用java8新的时间类型
fastAutoGenerator.globalConfig(getGlobalConfigConsumer());
// 3.包配置
// 设置父包名
// 设置父包模块名
// 设置MVC下各个模块的包名
// 设置XML资源文件的目录
fastAutoGenerator.packageConfig(getPackageConfigConsumer());
// 4.模板配置
// 使用Freemarker引擎模板, 默认的是Velocity引擎模板
AbstractTemplateEngine templateEngine = new FreemarkerTemplateEngine();
fastAutoGenerator.templateEngine(templateEngine);
// 5.策略配置
// 设置需要生成的表名
// 设置过滤表前缀
fastAutoGenerator.strategyConfig(getStrategyConfigConsumer(tableNames));
if (tablePrefix != null) {
// 表前缀, 可多个
fastAutoGenerator.strategyConfig(
strategyConfigBuilder -> strategyConfigBuilder.addTablePrefix(tablePrefix));
}
}
// 5.1.Entity策略配置
// 生成实体时生成字段的注解, 包括@TableId注解等
// 数据库表和字段映射到实体的命名策略, 为下划线转驼峰
// 全局主键类型为None
// 实体名称格式化为XXXEntity
fastAutoGenerator.strategyConfig(getEntityConfigConsumer());
// 5.2.Controller策略配置
// 开启生成@RestController控制器
fastAutoGenerator.strategyConfig(
strategyConfigBuilder -> strategyConfigBuilder.controllerBuilder().enableRestStyle());
// 如果不需要生成Controller, fastAutoGenerator.templateConfig(templateConfig -> templateConfig.controller(""))。5.3
// .Service策略配置:格式化service接口和实现类的文件名称, 去掉默认的ServiceName前面的I
fastAutoGenerator.strategyConfig(
strategyConfigBuilder -> strategyConfigBuilder.serviceBuilder().formatServiceFileName("%sService")
.formatServiceImplFileName("%sServiceImpl"));
// 5.4.Mapper策略配置
// 格式化 mapper文件名,格式化xml实现类文件名称
fastAutoGenerator.strategyConfig(getStrategyConfigConsumer());
// 6.生成代码
fastAutoGenerator.execute();
}
private Consumer<PackageConfig.Builder> getPackageConfigConsumer() {
String mapperPath = projectRootPath + "CodeGen/resources/mapper";
if (StrUtil.isBlank(this.parentModuleName)) {
throw new BadRequestException("模块名称必填");
}
return packageConfigBuilder -> packageConfigBuilder.parent(this.parentPackageName)
.moduleName(this.parentModuleName).entity("dal.dataobject").mapper("dal.mysql").service("service")
.serviceImpl("service.impl").controller("controller")
.pathInfo(Collections.singletonMap(OutputFile.xml, mapperPath));
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,10 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.framework.mybatisplus.core;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.odboy.base.KitBaseUserTimeTb;
@@ -29,167 +28,205 @@ import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Field;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
/**
* 查询条件创建工具
*/
@Slf4j
public class KitMpQUtil {
public static <R, Q> QueryWrapper<R> build(Q query) {
QueryWrapper<R> queryWrapper = new QueryWrapper<>();
if (query == null) {
return queryWrapper;
}
Class<?> clazz = query.getClass();
try {
List<Field> fields = getAllFields(clazz, new ArrayList<>());
for (Field field : fields) {
if (!field.canAccess(query)) {
field.setAccessible(true);
KitMpQuery q = field.getAnnotation(KitMpQuery.class);
if (q != null) {
String attributeName = getAttributeName(q, field);
Object fieldVal = field.get(query);
if (ObjectUtil.isNull(fieldVal) || "".equals(fieldVal)) {
continue;
}
if (StrUtil.isNotBlank(q.blurry())) {
handleBlurryQuery(queryWrapper, q.blurry(), fieldVal);
continue;
}
handleWrapper(q, queryWrapper, attributeName, fieldVal);
}
field.setAccessible(false);
}
}
} catch (Exception e) {
log.error("Failed to build query wrapper for class: {}", clazz.getName(), e);
}
return queryWrapper;
}
private static String getAttributeName(KitMpQuery q, Field field) {
String attributeName = StrUtil.isBlank(q.propName()) ? field.getName() : q.propName();
return StrUtil.toUnderlineCase(attributeName);
public static <R, Q> QueryWrapper<R> build(Q query) {
QueryWrapper<R> queryWrapper = new QueryWrapper<>();
if (query == null) {
return queryWrapper;
}
private static <R> void handleWrapper(KitMpQuery q, QueryWrapper<R> queryWrapper, String attributeName, Object fieldVal) {
switch (q.type()) {
case EQUAL -> queryWrapper.eq(attributeName, fieldVal);
case GREATER_THAN -> queryWrapper.ge(attributeName, fieldVal);
case LESS_THAN -> queryWrapper.le(attributeName, fieldVal);
case LESS_THAN_NQ -> queryWrapper.lt(attributeName, fieldVal);
case INNER_LIKE -> queryWrapper.like(attributeName, fieldVal);
case LEFT_LIKE -> queryWrapper.likeLeft(attributeName, fieldVal);
case RIGHT_LIKE -> queryWrapper.likeRight(attributeName, fieldVal);
case IN -> handleInOrNotQuery(true, queryWrapper, attributeName, fieldVal);
case NOT_IN -> handleInOrNotQuery(false, queryWrapper, attributeName, fieldVal);
case NOT_EQUAL -> queryWrapper.ne(attributeName, fieldVal);
case NOT_NULL -> queryWrapper.isNotNull(attributeName);
case IS_NULL -> queryWrapper.isNull(attributeName);
case BETWEEN -> handleBetweenQuery(queryWrapper, fieldVal, attributeName);
default -> {
Class<?> clazz = query.getClass();
try {
List<Field> fields = getAllFields(clazz, new ArrayList<>());
for (Field field : fields) {
if (!field.canAccess(query)) {
field.setAccessible(true);
KitMpQuery q = field.getAnnotation(KitMpQuery.class);
if (q != null) {
String attributeName = getAttributeName(q, field);
Object fieldVal = field.get(query);
if (ObjectUtil.isNull(fieldVal) || "".equals(fieldVal)) {
continue;
}
if (StrUtil.isNotBlank(q.blurry())) {
handleBlurryQuery(queryWrapper, q.blurry(), fieldVal);
continue;
}
handleWrapper(q, queryWrapper, attributeName, fieldVal);
}
field.setAccessible(false);
}
}
} catch (Exception e) {
log.error("Failed to build query wrapper for class: {}", clazz.getName(), e);
}
return queryWrapper;
}
private static <R> void handleInOrNotQuery(boolean b, QueryWrapper<R> queryWrapper, String attributeName, Object fieldVal) {
Collection<?> wrapNotInVal = (Collection<?>)fieldVal;
if (CollectionUtil.isNotEmpty(wrapNotInVal)) {
Optional<?> anyValOptional = wrapNotInVal.stream().findAny();
if (anyValOptional.isPresent()) {
Object o = anyValOptional.get();
if (o instanceof Long) {
if (b) {
queryWrapper.in(attributeName, fieldVal);
} else {
queryWrapper.notIn(attributeName, fieldVal);
}
} else if (o instanceof Integer) {
if (b) {
queryWrapper.in(attributeName, fieldVal);
} else {
queryWrapper.notIn(attributeName, fieldVal);
}
} else {
throw new BadRequestException("InOrNotIn查询参数类型的对象属性值必须是Long/Integer类型集合");
}
}
}
private static String getAttributeName(KitMpQuery q, Field field) {
String attributeName = StrUtil.isBlank(q.propName()) ? field.getName() : q.propName();
return StrUtil.toUnderlineCase(attributeName);
}
private static <R> void handleWrapper(KitMpQuery q, QueryWrapper<R> queryWrapper, String attributeName,
Object fieldVal) {
switch (q.type()) {
case EQUAL:
queryWrapper.eq(attributeName, fieldVal);
break;
case GREATER_THAN:
queryWrapper.ge(attributeName, fieldVal);
break;
case LESS_THAN:
queryWrapper.le(attributeName, fieldVal);
break;
case LESS_THAN_NQ:
queryWrapper.lt(attributeName, fieldVal);
break;
case INNER_LIKE:
queryWrapper.like(attributeName, fieldVal);
break;
case LEFT_LIKE:
queryWrapper.likeLeft(attributeName, fieldVal);
break;
case RIGHT_LIKE:
queryWrapper.likeRight(attributeName, fieldVal);
break;
case IN:
handleInOrNotQuery(true, queryWrapper, attributeName, fieldVal);
break;
case NOT_IN:
handleInOrNotQuery(false, queryWrapper, attributeName, fieldVal);
break;
case NOT_EQUAL:
queryWrapper.ne(attributeName, fieldVal);
break;
case NOT_NULL:
queryWrapper.isNotNull(attributeName);
break;
case IS_NULL:
queryWrapper.isNull(attributeName);
break;
case BETWEEN:
handleBetweenQuery(queryWrapper, fieldVal, attributeName);
break;
default:
break;
}
}
private static <R> void handleBetweenQuery(QueryWrapper<R> queryWrapper, Object fieldVal, String finalAttributeName) {
if (fieldVal instanceof List) {
List<Object> between = new ArrayList<>((List<?>)fieldVal);
int minLength = 2;
if (CollectionUtil.isNotEmpty(between) && between.size() >= minLength) {
queryWrapper.between(finalAttributeName, between.get(0), between.get(1));
} else {
throw new BadRequestException("BETWEEN类型的对象列表长度必须 >= 2");
}
private static <R> void handleInOrNotQuery(boolean b, QueryWrapper<R> queryWrapper, String attributeName,
Object fieldVal) {
Collection<?> wrapNotInVal = (Collection<?>) fieldVal;
if (CollUtil.isNotEmpty(wrapNotInVal)) {
Optional<?> anyValOptional = wrapNotInVal.stream().findAny();
if (anyValOptional.isPresent()) {
Object o = anyValOptional.get();
if (o instanceof Long) {
if (b) {
queryWrapper.in(attributeName, fieldVal);
} else {
queryWrapper.notIn(attributeName, fieldVal);
}
} else if (o instanceof Integer) {
if (b) {
queryWrapper.in(attributeName, fieldVal);
} else {
queryWrapper.notIn(attributeName, fieldVal);
}
} else {
throw new BadRequestException("BETWEEN类型的对象必须是一个List子集合");
throw new BadRequestException("InOrNotIn查询参数类型的对象属性值必须是Long/Integer类型集合");
}
}
}
}
/**
* 模糊多字段
*
* @param queryWrapper /
* @param blurry /
* @param fieldVal /
* @param <R> /
*/
private static <R> void handleBlurryQuery(QueryWrapper<R> queryWrapper, String blurry, Object fieldVal) {
List<String> blurryList = Arrays.stream(blurry.split(",")).filter(StrUtil::isNotBlank).distinct().toList();
queryWrapper.and(wrapper -> {
for (String blurryItem : blurryList) {
String column = StrUtil.toUnderlineCase(blurryItem);
wrapper.or();
wrapper.like(column, fieldVal.toString());
}
});
private static <R> void handleBetweenQuery(QueryWrapper<R> queryWrapper, Object fieldVal,
String finalAttributeName) {
if (fieldVal instanceof List) {
List<Object> between = new ArrayList<>((List<?>) fieldVal);
int minLength = 2;
if (CollUtil.isNotEmpty(between) && between.size() >= minLength) {
queryWrapper.between(finalAttributeName, between.get(0), between.get(1));
} else {
throw new BadRequestException("BETWEEN类型的对象列表长度必须 >= 2");
}
} else {
throw new BadRequestException("BETWEEN类型的对象必须是一个List子集合");
}
}
public static List<Field> getAllFields(Class<?> clazz, List<Field> fields) {
if (clazz != null) {
fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
getAllFields(clazz.getSuperclass(), fields);
}
return fields;
}
/**
* 模糊多字段
*
* @param queryWrapper /
* @param blurry /
* @param fieldVal /
* @param <R> /
*/
private static <R> void handleBlurryQuery(QueryWrapper<R> queryWrapper, String blurry, Object fieldVal) {
List<String> blurryList =
Arrays.stream(blurry.split(",")).filter(StrUtil::isNotBlank).distinct().collect(Collectors.toList());
queryWrapper.and(wrapper -> {
for (String blurryItem : blurryList) {
String column = StrUtil.toUnderlineCase(blurryItem);
wrapper.or();
wrapper.like(column, fieldVal.toString());
}
});
}
public static void main(String[] args) {
QueryWrapper<TestDomain> query = new QueryWrapper<>();
query.or(wrapper -> wrapper.eq("username", 1).or().eq("nickname", 2));
query.eq("id", 1);
query.orderByDesc("id");
System.err.println("getSqlSelect=================================");
System.err.println(query.getSqlSelect());
System.err.println("getSqlSegment=================================");
System.err.println(query.getSqlSegment());
System.err.println("getSqlComment=================================");
System.err.println(query.getSqlComment());
System.err.println("getSqlSet=================================");
System.err.println(query.getSqlSet());
System.err.println("getTargetSql=================================");
System.err.println(query.getTargetSql());
public static List<Field> getAllFields(Class<?> clazz, List<Field> fields) {
if (clazz != null) {
fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
getAllFields(clazz.getSuperclass(), fields);
}
return fields;
}
@TableName("test_domain")
private static class TestDomain {
@NotNull(groups = KitBaseUserTimeTb.Update.class)
@TableId(value = "user_id", type = IdType.AUTO)
private Long id;
@TableField(value = "dept_id")
private Long deptId;
@NotBlank
private String username;
@NotBlank
private String nickName;
}
public static void main(String[] args) {
QueryWrapper<TestDomain> query = new QueryWrapper<>();
query.or(wrapper -> wrapper.eq("username", 1).or().eq("nickname", 2));
query.eq("id", 1);
query.orderByDesc("id");
System.err.println("getSqlSelect=================================");
System.err.println(query.getSqlSelect());
System.err.println("getSqlSegment=================================");
System.err.println(query.getSqlSegment());
System.err.println("getSqlComment=================================");
System.err.println(query.getSqlComment());
System.err.println("getSqlSet=================================");
System.err.println(query.getSqlSet());
System.err.println("getTargetSql=================================");
System.err.println(query.getTargetSql());
}
@Data
@TableName("test_domain")
private static class TestDomain {
@NotNull(groups = KitBaseUserTimeTb.Update.class)
@TableId(value = "user_id", type = IdType.AUTO)
private Long id;
@TableField(value = "dept_id")
private Long deptId;
@NotBlank
private String username;
@NotBlank
private String nickName;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,28 +13,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.framework.mybatisplus.core.interfaces;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.odboy.base.KitPageResult;
import cn.odboy.util.KitBeanUtil;
import cn.odboy.util.KitPageUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;
import org.springframework.data.domain.Pageable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.ibatis.annotations.Param;
import org.springframework.data.domain.Pageable;
/**
* 公共抽象Mapper接口类
@@ -43,144 +41,147 @@ import java.util.concurrent.ConcurrentHashMap;
* @date 2022-04-03
*/
public interface KitMpMapper<E> extends BaseMapper<E> {
/**
* 批量插入
*
* @param entityList List<E>
* @return 影响的行数
*/
int insertBatchSomeColumn(List<E> entityList);
/**
* 根据id全量更新
*
* @param entity E
* @return 影响的行数
*/
int alwaysUpdateSomeColumnById(@Param("et") E entity);
/**
* 批量插入
*
* @param entityList List<E>
* @return 影响的行数
*/
int insertBatchSomeColumn(List<E> entityList);
/**
* 获取字典
*
* @param wrapper LambdaQueryWrapper<E>
* @param keyName 键对应的列名称
* @param valueName 值对应的列名称
* @return Map<String, Object>
*/
default Map<String, Object> getMapWithKv(LambdaQueryWrapper<E> wrapper, String keyName, String valueName) {
Map<String, Object> result = new ConcurrentHashMap<>(1);
List<E> list = this.selectList(wrapper);
if (CollUtil.isEmpty(list)) {
return new HashMap<>(3);
}
E tempObj = list.stream().findFirst().orElse(null);
if (tempObj == null) {
return new HashMap<>(3);
}
Field[] fields = ReflectUtil.getFields(tempObj.getClass());
for (E e : list) {
Field keyField = null;
Field valueField = null;
for (Field field : fields) {
String fieldName = field.getName();
if (fieldName.equals(keyName)) {
keyField = field;
} else if (fieldName.equals(valueName)) {
valueField = field;
break;
}
}
String fieldKey = String.valueOf(ReflectUtil.getFieldValue(e, keyField));
Object fieldValue = ReflectUtil.getFieldValue(e, valueField);
if (fieldKey != null) {
result.put(fieldKey, fieldValue);
}
}
return result;
/**
* 根据id全量更新
*
* @param entity E
* @return 影响的行数
*/
int alwaysUpdateSomeColumnById(@Param("et") E entity);
/**
* 获取字典
*
* @param wrapper LambdaQueryWrapper<E>
* @param keyName 键对应的列名称
* @param valueName 值对应的列名称
* @return Map<String, Object>
*/
default Map<String, Object> getMapWithKv(LambdaQueryWrapper<E> wrapper, String keyName, String valueName) {
Map<String, Object> result = new ConcurrentHashMap<>(1);
List<E> list = this.selectList(wrapper);
if (CollUtil.isEmpty(list)) {
return new HashMap<>(3);
}
/**
* 条件查询列表, 并返回期望的对象
*
* @param wrapper LambdaQueryWrapper<E>
* @param clazz 期望的对象类型
* @return List<T>
*/
default <T> List<T> queryFeatureClazzList(LambdaQueryWrapper<E> wrapper, Class<T> clazz) {
List<E> list = this.selectList(wrapper);
if (CollUtil.isEmpty(list)) {
return new ArrayList<>();
}
return BeanUtil.copyToList(list, clazz);
E tempObj = list.stream().findFirst().orElse(null);
if (tempObj == null) {
return new HashMap<>(3);
}
/**
* 条件查询列表, 并返回期望的对象
*
* @param wrapper LambdaQueryWrapper<E>
* @param clazz 期望的对象类型
* @return List<T>
*/
default <T> List<T> queryFeatureClazzList(LambdaQueryChainWrapper<E> wrapper, Class<T> clazz) {
List<E> list = wrapper.list();
if (CollUtil.isEmpty(list)) {
return new ArrayList<>();
Field[] fields = ReflectUtil.getFields(tempObj.getClass());
for (E e : list) {
Field keyField = null;
Field valueField = null;
for (Field field : fields) {
String fieldName = field.getName();
if (fieldName.equals(keyName)) {
keyField = field;
} else if (fieldName.equals(valueName)) {
valueField = field;
break;
}
return BeanUtil.copyToList(list, clazz);
}
String fieldKey = String.valueOf(ReflectUtil.getFieldValue(e, keyField));
Object fieldValue = ReflectUtil.getFieldValue(e, valueField);
if (fieldKey != null) {
result.put(fieldKey, fieldValue);
}
}
return result;
}
/**
* 条件查询分页列表, 并返回期望的对象
*
* @param pageable 分页参数
* @param wrapper LambdaQueryWrapper<E> wrapper
* @param clazz 期望的对象类型
* @return IPage<T>
*/
default <T> KitPageResult<T> queryFeatureClazzPage(Pageable pageable, LambdaQueryWrapper<E> wrapper, Class<T> clazz) {
int pageNumber = pageable.getPageNumber();
int pageSize = pageable.getPageSize();
pageNumber = pageNumber <= 0 ? 1 : pageNumber;
pageSize = pageSize <= 0 ? 10 : pageSize;
IPage<E> pageInfo = this.selectPage(new Page<>(pageNumber, pageSize), wrapper);
if (CollUtil.isEmpty(pageInfo.getRecords())) {
return new KitPageResult<>(new ArrayList<>(), pageInfo.getTotal());
}
return new KitPageResult<>(BeanUtil.copyToList(pageInfo.getRecords(), clazz), pageInfo.getTotal());
/**
* 条件查询列表, 并返回期望的对象
*
* @param wrapper LambdaQueryWrapper<E>
* @param clazz 期望的对象类型
* @return List<T>
*/
default <T> List<T> queryFeatureClazzList(LambdaQueryWrapper<E> wrapper, Class<T> clazz) {
List<E> list = this.selectList(wrapper);
if (CollUtil.isEmpty(list)) {
return new ArrayList<>();
}
return KitBeanUtil.copyToList(list, clazz);
}
/**
* 条件查询分页列表, 并返回期望的对象
*
* @param pageable 分页参数
* @param wrapper LambdaQueryWrapper<E> wrapper
* @param clazz 期望的对象类型
* @return IPage<T>
*/
default <T> KitPageResult<T> queryFeatureClazzPage(Pageable pageable, LambdaQueryChainWrapper<E> wrapper, Class<T> clazz) {
int pageNumber = pageable.getPageNumber();
int pageSize = pageable.getPageSize();
pageNumber = pageNumber <= 0 ? 1 : pageNumber;
pageSize = pageSize <= 0 ? 10 : pageSize;
IPage<E> pageInfo = wrapper.page(new Page<>(pageNumber, pageSize));
if (CollUtil.isEmpty(pageInfo.getRecords())) {
return KitPageUtil.emptyListData();
}
return new KitPageResult<>(BeanUtil.copyToList(pageInfo.getRecords(), clazz), pageInfo.getTotal());
/**
* 条件查询列表, 并返回期望的对象
*
* @param wrapper LambdaQueryWrapper<E>
* @param clazz 期望的对象类型
* @return List<T>
*/
default <T> List<T> queryFeatureClazzList(LambdaQueryChainWrapper<E> wrapper, Class<T> clazz) {
List<E> list = wrapper.list();
if (CollUtil.isEmpty(list)) {
return new ArrayList<>();
}
return KitBeanUtil.copyToList(list, clazz);
}
/**
* 获取目标类
*
* @param wrapper LambdaQueryChainWrapper<E> wrapper
* @param clazz 期望的对象类型
* @return T
*/
default <T> T getFeatureClazz(LambdaQueryChainWrapper<E> wrapper, Class<T> clazz) {
E e = this.selectOne(wrapper);
if (e == null) {
return null;
}
return BeanUtil.copyProperties(e, clazz);
/**
* 条件查询分页列表, 并返回期望的对象
*
* @param pageable 分页参数
* @param wrapper LambdaQueryWrapper<E> wrapper
* @param clazz 期望的对象类型
* @return IPage<T>
*/
default <T> KitPageResult<T> queryFeatureClazzPage(Pageable pageable, LambdaQueryWrapper<E> wrapper,
Class<T> clazz) {
int pageNumber = pageable.getPageNumber();
int pageSize = pageable.getPageSize();
pageNumber = pageNumber <= 0 ? 1 : pageNumber;
pageSize = pageSize <= 0 ? 10 : pageSize;
IPage<E> pageInfo = this.selectPage(new Page<>(pageNumber, pageSize), wrapper);
if (CollUtil.isEmpty(pageInfo.getRecords())) {
return new KitPageResult<>(new ArrayList<>(), pageInfo.getTotal());
}
return new KitPageResult<>(KitBeanUtil.copyToList(pageInfo.getRecords(), clazz), pageInfo.getTotal());
}
/**
* 条件查询分页列表, 并返回期望的对象
*
* @param pageable 分页参数
* @param wrapper LambdaQueryWrapper<E> wrapper
* @param clazz 期望的对象类型
* @return IPage<T>
*/
default <T> KitPageResult<T> queryFeatureClazzPage(Pageable pageable, LambdaQueryChainWrapper<E> wrapper,
Class<T> clazz) {
int pageNumber = pageable.getPageNumber();
int pageSize = pageable.getPageSize();
pageNumber = pageNumber <= 0 ? 1 : pageNumber;
pageSize = pageSize <= 0 ? 10 : pageSize;
IPage<E> pageInfo = wrapper.page(new Page<>(pageNumber, pageSize));
if (CollUtil.isEmpty(pageInfo.getRecords())) {
return KitPageUtil.emptyData();
}
return new KitPageResult<>(KitBeanUtil.copyToList(pageInfo.getRecords(), clazz), pageInfo.getTotal());
}
/**
* 获取目标类
*
* @param wrapper LambdaQueryChainWrapper<E> wrapper
* @param clazz 期望的对象类型
* @return T
*/
default <T> T getFeatureClazz(LambdaQueryChainWrapper<E> wrapper, Class<T> clazz) {
E e = this.selectOne(wrapper);
if (e == null) {
return null;
}
return KitBeanUtil.copyToClass(e, clazz);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.framework.mybatisplus.core.interfaces;
import cn.odboy.base.KitPageResult;
@@ -21,7 +20,6 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.service.IService;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
@@ -33,39 +31,41 @@ import java.util.List;
* @date 2022-04-03
*/
public interface KitMpService<T> extends IService<T> {
<G> int saveFeatureClazz(G resources);
<G> int saveFeatureClazzList(List<G> resources);
<G> int saveFeatureClazz(G resources);
<G> int modifyFeatureClazzById(G resources);
<G> int saveFeatureClazzList(List<G> resources);
<G> boolean modifyFeatureClazzListById(Collection<G> resources, int batchSize);
<G> int modifyFeatureClazzById(G resources);
<G> G queryFeatureClazzById(Serializable id, Class<G> targetClazz);
<G> boolean modifyFeatureClazzListById(Collection<G> resources, int batchSize);
T queryClazzByArgs(LambdaQueryWrapper<T> wrapper, SFunction<T, ?> orderColumn);
<G> G queryFeatureClazzById(Serializable id, Class<G> targetClazz);
<G> G queryFeatureClazzByArgs(LambdaQueryWrapper<T> wrapper, SFunction<T, ?> orderColumn, Class<G> clazz);
T queryClazzByArgs(LambdaQueryWrapper<T> wrapper, SFunction<T, ?> orderColumn);
<G> List<G> queryFeatureClazzListByIds(List<Serializable> ids, Class<G> targetClazz);
<G> G queryFeatureClazzByArgs(LambdaQueryWrapper<T> wrapper, SFunction<T, ?> orderColumn, Class<G> clazz);
<Q> List<T> queryClazzListByArgs(Q criteria);
<G> List<G> queryFeatureClazzListByIds(List<Serializable> ids, Class<G> targetClazz);
List<T> queryClazzListByArgs(LambdaQueryWrapper<T> wrapper);
<Q> List<T> queryClazzListByArgs(Q args);
<G, Q> List<G> queryFeatureClazzListByArgs(Q criteria, Class<G> targetClazz);
List<T> queryClazzListByArgs(LambdaQueryWrapper<T> wrapper);
<G> List<G> queryFeatureClazzListByArgs(LambdaQueryWrapper<T> wrapper, Class<G> targetClazz);
<G, Q> List<G> queryFeatureClazzListByArgs(Q args, Class<G> targetClazz);
KitPageResult<T> queryClazzPageByArgs(LambdaQueryWrapper<T> wrapper, IPage<T> pageable);
<G> List<G> queryFeatureClazzListByArgs(LambdaQueryWrapper<T> wrapper, Class<G> targetClazz);
<G> KitPageResult<G> queryFeatureClazzPageByArgs(LambdaQueryWrapper<T> wrapper, IPage<T> pageable, Class<G> targetClazz);
KitPageResult<T> queryClazzPageByArgs(LambdaQueryWrapper<T> wrapper, IPage<T> pageable);
<G, Q> KitPageResult<G> queryFeatureClazzPageByArgs(Q criteria, IPage<T> pageable, Class<G> targetClazz);
<G> KitPageResult<G> queryFeatureClazzPageByArgs(LambdaQueryWrapper<T> wrapper, IPage<T> pageable,
Class<G> targetClazz);
<Q> KitPageResult<T> queryClazzPageByArgs(Q criteria, IPage<T> pageable);
<G, Q> KitPageResult<G> queryFeatureClazzPageByArgs(Q args, IPage<T> pageable, Class<G> targetClazz);
int modifyClazzByArgs(LambdaQueryWrapper<T> wrapper, T entity);
<Q> KitPageResult<T> queryClazzPageByArgs(Q args, IPage<T> pageable);
int removeClazzByArgs(LambdaQueryWrapper<T> wrapper);
int modifyClazzByArgs(LambdaQueryWrapper<T> wrapper, T entity);
int removeClazzByArgs(LambdaQueryWrapper<T> wrapper);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,25 +13,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.framework.mybatisplus.core.interfaces;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.odboy.base.KitPageResult;
import cn.odboy.framework.exception.BadRequestException;
import cn.odboy.framework.mybatisplus.core.KitMpQUtil;
import cn.odboy.util.KitBeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.ibatis.binding.MapperMethod;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import org.apache.ibatis.binding.MapperMethod;
/**
* 公共抽象Mapper接口类
@@ -40,217 +38,221 @@ import java.util.List;
* @date 2022-04-03
*/
public class KitMpServiceImpl<M extends KitMpMapper<T>, T> extends ServiceImpl<M, T> {
/**
* 快速插入
*
* @param resources /
*/
public <G> int saveFeatureClazz(G resources) {
return getBaseMapper().insert(BeanUtil.copyProperties(resources, this.getEntityClass()));
}
/**
* 快速批量插入
*
* @param resources /
*/
public <G> int saveFeatureClazzList(List<G> resources) {
return getBaseMapper().insertBatchSomeColumn(BeanUtil.copyToList(resources, this.getEntityClass()));
}
/**
* 快速插入
*
* @param resources /
*/
public <G> int saveFeatureClazz(G resources) {
return getBaseMapper().insert(KitBeanUtil.copyToClass(resources, this.getEntityClass()));
}
/**
* 快速更新
*
* @param resources /
*/
public <G> int modifyFeatureClazzById(G resources) {
return getBaseMapper().updateById(BeanUtil.copyProperties(resources, this.getEntityClass()));
}
/**
* 快速批量插入
*
* @param resources /
*/
public <G> int saveFeatureClazzList(List<G> resources) {
return getBaseMapper().insertBatchSomeColumn(KitBeanUtil.copyToList(resources, this.getEntityClass()));
}
/**
* 快速批量更新
*
* @param resources /
* @param batchSize 每批数量
*/
public <G> boolean modifyFeatureClazzListById(Collection<G> resources, int batchSize) {
String sqlStatement = this.getSqlStatement(SqlMethod.UPDATE_BY_ID);
return this.executeBatch(resources, batchSize, (sqlSession, entity) -> {
MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
param.put("et", BeanUtil.copyProperties(entity, this.getEntityClass()));
sqlSession.update(sqlStatement, param);
});
}
/**
* 快速更新
*
* @param resources /
*/
public <G> int modifyFeatureClazzById(G resources) {
return getBaseMapper().updateById(KitBeanUtil.copyToClass(resources, this.getEntityClass()));
}
/**
* 通过id查询
*
* @param id /
* @param targetClazz 目标类型
*/
public <G> G queryFeatureClazzById(Serializable id, Class<G> targetClazz) {
T entity = this.getById(id);
return entity == null ? null : BeanUtil.copyProperties(entity, targetClazz);
}
/**
* 快速批量更新
*
* @param resources /
* @param batchSize 每批数量
*/
public <G> boolean modifyFeatureClazzListById(Collection<G> resources, int batchSize) {
String sqlStatement = this.getSqlStatement(SqlMethod.UPDATE_BY_ID);
return this.executeBatch(resources, batchSize, (sqlSession, entity) -> {
MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
param.put("et", KitBeanUtil.copyToClass(entity, this.getEntityClass()));
sqlSession.update(sqlStatement, param);
});
}
/**
* 查一条数据
*
* @param wrapper 制造条件
*/
public T queryClazzByArgs(LambdaQueryWrapper<T> wrapper, SFunction<T, ?> orderColumn) {
if (orderColumn == null) {
throw new BadRequestException("参数orderColumn(排序的列)必填");
}
if (wrapper == null) {
wrapper = new LambdaQueryWrapper<>();
}
wrapper.last("limit 1");
wrapper.orderByDesc(orderColumn);
List<T> ts = baseMapper.selectList(wrapper);
if (ts.isEmpty()) {
return null;
}
return ts.stream().findFirst().get();
}
/**
* 通过id查询
*
* @param id /
* @param targetClazz 目标类型
*/
public <G> G queryFeatureClazzById(Serializable id, Class<G> targetClazz) {
T entity = this.getById(id);
return entity == null ? null : KitBeanUtil.copyToClass(entity, targetClazz);
}
public <G> G queryFeatureClazzByArgs(LambdaQueryWrapper<T> wrapper, SFunction<T, ?> orderColumn, Class<G> clazz) {
if (orderColumn == null) {
throw new BadRequestException("参数orderColumn(排序的列)必填");
}
if (wrapper == null) {
wrapper = new LambdaQueryWrapper<>();
}
wrapper.last("limit 1");
wrapper.orderByDesc(orderColumn);
List<T> ts = baseMapper.selectList(wrapper);
if (ts.isEmpty()) {
return null;
}
return BeanUtil.copyProperties(ts.stream().findFirst().get(), clazz);
/**
* 查一条数据
*
* @param wrapper 制造条件
*/
public T queryClazzByArgs(LambdaQueryWrapper<T> wrapper, SFunction<T, ?> orderColumn) {
if (orderColumn == null) {
throw new BadRequestException("参数orderColumn(排序的列)必填");
}
if (wrapper == null) {
wrapper = new LambdaQueryWrapper<>();
}
wrapper.last("limit 1");
wrapper.orderByDesc(orderColumn);
List<T> ts = baseMapper.selectList(wrapper);
if (ts.isEmpty()) {
return null;
}
return ts.stream().findFirst().get();
}
/**
* 通过id集合查询
*
* @param ids /
* @param targetClazz 目标类型
*/
public <G> List<G> queryFeatureClazzListByIds(List<Serializable> ids, Class<G> targetClazz) {
List<T> entitys = this.listByIds(ids);
return entitys == null || entitys.isEmpty() ? CollUtil.newArrayList() : BeanUtil.copyToList(entitys, targetClazz);
public <G> G queryFeatureClazzByArgs(LambdaQueryWrapper<T> wrapper, SFunction<T, ?> orderColumn, Class<G> clazz) {
if (orderColumn == null) {
throw new BadRequestException("参数orderColumn(排序的列)必填");
}
if (wrapper == null) {
wrapper = new LambdaQueryWrapper<>();
}
wrapper.last("limit 1");
wrapper.orderByDesc(orderColumn);
List<T> ts = baseMapper.selectList(wrapper);
if (ts.isEmpty()) {
return null;
}
return KitBeanUtil.copyToClass(ts.stream().findFirst().get(), clazz);
}
/**
* 查有关的数据
*
* @param criteria 动态条件
*/
public <Q> List<T> queryClazzListByArgs(Q criteria) {
QueryWrapper<T> predicate = KitMpQUtil.build(criteria);
return baseMapper.selectList(predicate);
}
/**
* 通过id集合查询
*
* @param ids /
* @param targetClazz 目标类型
*/
public <G> List<G> queryFeatureClazzListByIds(List<Serializable> ids, Class<G> targetClazz) {
List<T> entitys = this.listByIds(ids);
return entitys == null || entitys.isEmpty() ? CollUtil.newArrayList() : KitBeanUtil.copyToList(entitys, targetClazz);
}
/**
* 查有关的数据
*
* @param wrapper 制造条件
*/
public List<T> queryClazzListByArgs(LambdaQueryWrapper<T> wrapper) {
if (wrapper == null) {
wrapper = new LambdaQueryWrapper<>();
}
return baseMapper.selectList(wrapper);
}
/**
* 查有关的数据
*
* @param args 动态条件
*/
public <Q> List<T> queryClazzListByArgs(Q args) {
QueryWrapper<T> predicate = KitMpQUtil.build(args);
return baseMapper.selectList(predicate);
}
/**
* 查有关的数据并转成目标类型的数据
*
* @param criteria 动态条件
* @param targetClazz 目标类型
*/
public <G, Q> List<G> queryFeatureClazzListByArgs(Q criteria, Class<G> targetClazz) {
QueryWrapper<T> predicate = KitMpQUtil.build(criteria);
List<T> data = baseMapper.selectList(predicate);
return BeanUtil.copyToList(data, targetClazz);
/**
* 查有关的数据
*
* @param wrapper 制造条件
*/
public List<T> queryClazzListByArgs(LambdaQueryWrapper<T> wrapper) {
if (wrapper == null) {
wrapper = new LambdaQueryWrapper<>();
}
return baseMapper.selectList(wrapper);
}
/**
* 查有关的数据并转换为目标类型
*
* @param wrapper 制造条件
* @param targetClazz 目标类型
*/
public <G> List<G> queryFeatureClazzListByArgs(LambdaQueryWrapper<T> wrapper, Class<G> targetClazz) {
if (wrapper == null) {
wrapper = new LambdaQueryWrapper<>();
}
return BeanUtil.copyToList(baseMapper.selectList(wrapper), targetClazz);
}
/**
* 查有关的数据并转成目标类型的数据
*
* @param args 动态条件
* @param targetClazz 目标类型
*/
public <G, Q> List<G> queryFeatureClazzListByArgs(Q args, Class<G> targetClazz) {
QueryWrapper<T> predicate = KitMpQUtil.build(args);
List<T> data = baseMapper.selectList(predicate);
return KitBeanUtil.copyToList(data, targetClazz);
}
/**
* 查有关的分页数据
*
* @param wrapper 制造条件
* @param pageable 分页参数
*/
public KitPageResult<T> queryClazzPageByArgs(LambdaQueryWrapper<T> wrapper, IPage<T> pageable) {
if (wrapper == null) {
wrapper = new LambdaQueryWrapper<>();
}
IPage<T> originPageData = baseMapper.selectPage(pageable, wrapper);
return new KitPageResult<>(originPageData.getRecords(), originPageData.getTotal());
/**
* 查有关的数据并转换为目标类型
*
* @param wrapper 制造条件
* @param targetClazz 目标类型
*/
public <G> List<G> queryFeatureClazzListByArgs(LambdaQueryWrapper<T> wrapper, Class<G> targetClazz) {
if (wrapper == null) {
wrapper = new LambdaQueryWrapper<>();
}
return KitBeanUtil.copyToList(baseMapper.selectList(wrapper), targetClazz);
}
/**
* 查有关的分页数据
*
* @param wrapper 制造条件
* @param pageable 分页参数
* @param targetClazz 目标类型
*/
public <G> KitPageResult<G> queryFeatureClazzPageByArgs(LambdaQueryWrapper<T> wrapper, IPage<T> pageable, Class<G> targetClazz) {
if (wrapper == null) {
wrapper = new LambdaQueryWrapper<>();
}
IPage<T> originPageData = baseMapper.selectPage(pageable, wrapper);
return new KitPageResult<>(BeanUtil.copyToList(originPageData.getRecords(), targetClazz), originPageData.getTotal());
/**
* 查有关的分页数据
*
* @param wrapper 制造条件
* @param pageable 分页参数
*/
public KitPageResult<T> queryClazzPageByArgs(LambdaQueryWrapper<T> wrapper, IPage<T> pageable) {
if (wrapper == null) {
wrapper = new LambdaQueryWrapper<>();
}
IPage<T> originPageData = baseMapper.selectPage(pageable, wrapper);
return new KitPageResult<>(originPageData.getRecords(), originPageData.getTotal());
}
public <G, Q> KitPageResult<G> queryFeatureClazzPageByArgs(Q criteria, IPage<T> pageable, Class<G> targetClazz) {
QueryWrapper<T> wrapper = KitMpQUtil.build(criteria);
IPage<T> originPageData = baseMapper.selectPage(pageable, wrapper);
return new KitPageResult<>(BeanUtil.copyToList(originPageData.getRecords(), targetClazz), originPageData.getTotal());
/**
* 查有关的分页数据
*
* @param wrapper 制造条件
* @param pageable 分页参数
* @param targetClazz 目标类型
*/
public <G> KitPageResult<G> queryFeatureClazzPageByArgs(LambdaQueryWrapper<T> wrapper, IPage<T> pageable,
Class<G> targetClazz) {
if (wrapper == null) {
wrapper = new LambdaQueryWrapper<>();
}
IPage<T> originPageData = baseMapper.selectPage(pageable, wrapper);
return new KitPageResult<>(KitBeanUtil.copyToList(originPageData.getRecords(), targetClazz),
originPageData.getTotal());
}
public <Q> KitPageResult<T> queryClazzPageByArgs(Q criteria, IPage<T> pageable) {
QueryWrapper<T> wrapper = KitMpQUtil.build(criteria);
IPage<T> originPageData = baseMapper.selectPage(pageable, wrapper);
return new KitPageResult<>(originPageData.getRecords(), originPageData.getTotal());
}
public <G, Q> KitPageResult<G> queryFeatureClazzPageByArgs(Q args, IPage<T> pageable, Class<G> targetClazz) {
QueryWrapper<T> wrapper = KitMpQUtil.build(args);
IPage<T> originPageData = baseMapper.selectPage(pageable, wrapper);
return new KitPageResult<>(KitBeanUtil.copyToList(originPageData.getRecords(), targetClazz),
originPageData.getTotal());
}
/**
* 条件更新
*
* @param wrapper 制造条件
* @param entity 更新内容
*/
public int modifyClazzByArgs(LambdaQueryWrapper<T> wrapper, T entity) {
if (wrapper == null) {
throw new BadRequestException("参数wrapper必填");
}
return baseMapper.update(entity, wrapper);
}
public <Q> KitPageResult<T> queryClazzPageByArgs(Q args, IPage<T> pageable) {
QueryWrapper<T> wrapper = KitMpQUtil.build(args);
IPage<T> originPageData = baseMapper.selectPage(pageable, wrapper);
return new KitPageResult<>(originPageData.getRecords(), originPageData.getTotal());
}
/**
* 条件删除
*
* @param wrapper 制造条件
*/
public int removeClazzByArgs(LambdaQueryWrapper<T> wrapper) {
if (wrapper == null) {
throw new BadRequestException("参数wrapper必填");
}
return baseMapper.delete(wrapper);
/**
* 条件更新
*
* @param wrapper 制造条件
* @param entity 更新内容
*/
public int modifyClazzByArgs(LambdaQueryWrapper<T> wrapper, T entity) {
if (wrapper == null) {
throw new BadRequestException("参数wrapper必填");
}
return baseMapper.update(entity, wrapper);
}
/**
* 条件删除
*
* @param wrapper 制造条件
*/
public int removeClazzByArgs(LambdaQueryWrapper<T> wrapper) {
if (wrapper == null) {
throw new BadRequestException("参数wrapper必填");
}
return baseMapper.delete(wrapper);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,12 @@
package cn.odboy.framework.properties;
import cn.odboy.framework.properties.model.*;
import cn.odboy.framework.properties.model.CaptchaModel;
import cn.odboy.framework.properties.model.ContentRsaEncodeSettingModel;
import cn.odboy.framework.properties.model.JwtAuthSettingModel;
import cn.odboy.framework.properties.model.StorageOSSModel;
import cn.odboy.framework.properties.model.ThreadPoolSettingModel;
import cn.odboy.framework.properties.model.UserLoginSettingModel;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@@ -31,12 +36,13 @@ import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "app")
public class AppProperties {
private ContentRsaEncodeSettingModel rsa;
private JwtAuthSettingModel jwt;
private UserLoginSettingModel login;
private ThreadPoolSettingModel asyncTaskPool;
private CaptchaModel captcha;
private StorageOSSModel oss;
private ContentRsaEncodeSettingModel rsa;
private JwtAuthSettingModel jwt;
private UserLoginSettingModel login;
private ThreadPoolSettingModel asyncTaskPool;
private CaptchaModel captcha;
private StorageOSSModel oss;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,8 +23,9 @@ import lombok.Setter;
@Getter
@Setter
public class CaptchaModel extends KitObject {
/**
* 验证码有效时间, 单位: 秒
*/
private Long expireTime;
/**
* 验证码有效时间, 单位: 秒
*/
private Long expireTime;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,5 +26,6 @@ import lombok.Setter;
@Getter
@Setter
public class ContentRsaEncodeSettingModel extends KitObject {
private String privateKey;
private String privateKey;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,23 +26,24 @@ import lombok.Setter;
@Getter
@Setter
public class JwtAuthSettingModel extends KitObject {
/**
* 必须使用最少88位的Base64对该令牌进行编码
*/
private String base64Secret;
/**
* 令牌过期时间 此处单位/毫秒
*/
private Long tokenValidityInSeconds;
/**
* 必须使用最少88位的Base64对该令牌进行编码
*/
private String base64Secret;
/**
* token 续期检查
*/
private Long detect;
/**
* 令牌过期时间 此处单位/毫秒
*/
private Long tokenValidityInSeconds;
/**
* 续期时间
*/
private Long renew;
/**
* token 续期检查
*/
private Long detect;
/**
* 续期时间
*/
private Long renew;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,20 +23,21 @@ import lombok.Setter;
@Getter
@Setter
public class OSSConfigModel extends KitObject {
/**
* 服务地址
*/
private String endpoint;
/**
* 存储桶名称
*/
private String bucketName;
/**
* Access Key
*/
private String accessKey;
/**
* Secret Key
*/
private String secretKey;
/**
* 服务地址
*/
private String endpoint;
/**
* 存储桶名称
*/
private String bucketName;
/**
* Access Key
*/
private String accessKey;
/**
* Secret Key
*/
private String secretKey;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 Odboy
* Copyright 2021-2026 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,9 +22,10 @@ import lombok.Setter;
@Getter
@Setter
public class StorageOSSModel {
/**
* 上传大小, 单位: M
*/
private Long maxSize;
private OSSConfigModel minio;
/**
* 上传大小, 单位: M
*/
private Long maxSize;
private OSSConfigModel minio;
}

Some files were not shown because too many files have changed in this diff Show More