241 Commits

Author SHA1 Message Date
cuijiawang
92b772373b fix: port 2025-09-30 14:54:05 +08:00
cuijiawang
8f433a2594 fix: 启动类 2025-09-30 14:48:56 +08:00
cuijiawang
e0db7a251c Merge branch 'dev-pwd' into dev-codegen 2025-09-30 10:20:40 +08:00
cuijiawang
84bb7410cf fix: 登录校验密码 2025-09-30 10:19:52 +08:00
cuijiawang
2d75478bb7 fix: 代码生成器 系统模板 2025-09-29 16:55:30 +08:00
cuijiawang
5e47425ab5 fix: 代码生成器 未完成的解析器 2025-09-29 14:44:18 +08:00
cuijiawang
a4d6306259 fix: 性能优化 2025-09-28 10:41:05 +08:00
cuijiawang
852eb05cbf fix: 代码生成器 模板内容预览 系统内容 2025-09-28 09:31:09 +08:00
cuijiawang
90f98d66cc feat: 代码生成器 模板内容预览 2025-09-27 19:38:07 +08:00
cuijiawang
bf6e0dd952 feat: 代码生成器 自定义模板 使用次数 2025-09-27 19:01:07 +08:00
cuijiawang
04da9f9c02 feat: 代码生成器 自定义模板 显隐控制 2025-09-27 18:33:33 +08:00
cuijiawang
b4525cd1a6 fix: 代码生成器 自定义模板 逻辑删除问题 2025-09-27 17:50:32 +08:00
cuijiawang
b51f113053 fix: 代码生成器 自定义模板 复制 2025-09-27 17:23:19 +08:00
cuijiawang
685cc3d92c fix: 代码生成器 自定义模板 新增删除 2025-09-27 17:15:32 +08:00
cuijiawang
e512fc29e0 fix: 代码生成器 自定义模板 编辑 2025-09-27 16:38:17 +08:00
cuijiawang
5d19f5589a 代码生成器 模板仓库 模板预览 2025-09-27 16:03:47 +08:00
cuijiawang
d6be017f37 代码生成器 模板仓库 模板描述 2025-09-27 15:22:50 +08:00
cuijiawang
db5bda1bba 代码生成器 模板仓库fix 2025-09-27 14:19:02 +08:00
cuijiawang
c9929c84d2 代码生成器 模板仓库 2025-09-26 17:55:35 +08:00
cuijiawang
f91ecee6cc 代码生成功能 2025-09-25 14:52:14 +08:00
cuijiawang
142c24ca90 ftl 2025-09-25 14:14:03 +08:00
cuijiawang
a59dd25156 Merge branch 'dev' into dev-codegen 2025-09-24 17:26:59 +08:00
cuijiawang
d23500d656 del 2025-09-24 16:49:29 +08:00
cuijiawang
fe8d987527 del 2025-09-24 16:41:06 +08:00
cuijiawang
a3ec97fec1 codegen 2025-09-24 16:38:11 +08:00
cuijiawang
ea37855991 fix user 2025-09-24 11:51:27 +08:00
cuijiawang
c54a0db6ab fix 2025-09-23 17:05:42 +08:00
cuijiawang
f0633dfcea Merge branch 'dev-hzm' into dev
# Conflicts:
#	agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/user/service/ISysUserService.java
#	agileboot-system/agileboot-system-base/src/main/java/com/agileboot/system/user/service/impl/SysUserServiceImpl.java
2025-09-23 16:58:14 +08:00
cuijiawang
ccfdd18516 岗位与通知增删改查 2025-09-23 16:55:39 +08:00
cuijiawang
f4ce15986c Merge branch 'dev-role' into dev 2025-09-23 11:50:06 +08:00
cuijiawang
46da855dd4 新增时不填充修改字段 2025-09-23 09:53:22 +08:00
Hzm
b06d2503a4 修复--修改角色菜单不生效 2025-09-22 19:21:44 +08:00
cuijiawang
b2c882f70f 角色增删改查 未完成 2025-09-22 18:09:08 +08:00
cuijiawang
c8899a20a4 fix 2025-09-22 17:56:29 +08:00
cuijiawang
59e5777e28 增加物理删除 2025-09-22 17:54:33 +08:00
Hzm
c724387a16 satoken配置类测试还原 2025-09-22 15:09:56 +08:00
Hzm
ced025e292 通知公告的crud+分页查询 2025-09-22 15:08:53 +08:00
Hzm
37e264491f 岗位管理的crud+分页查询 2025-09-22 12:05:11 +08:00
cuijiawang
d379f79869 部门增删改查 2025-09-22 11:28:12 +08:00
Hzm
be4adbe00b 优化了LogAspect的代码 2025-09-21 19:57:31 +08:00
wol
33fc749363 uuid cost 2025-09-21 19:46:30 +08:00
Hzm
eb5978eb9d 定义了controller下的请求日志 2025-09-21 19:27:50 +08:00
cuijiawang
db7dbcc97e 菜单增删改查 2025-09-20 18:14:51 +08:00
cuijiawang
cba659010a fix 2025-09-19 17:57:19 +08:00
wol
0a8c05e1df addExclude /auth/register 2025-09-18 19:51:26 +08:00
cuijiawang
7a961d63a6 增加clientId 2025-09-18 18:00:32 +08:00
cuijiawang
16779413a6 登录 2025-09-18 11:42:29 +08:00
cuijiawang
c0c2e492b8 fix 2025-09-18 10:27:31 +08:00
cuijiawang
023d35fecd fix 2025-09-18 09:51:47 +08:00
wol
895ae7383a init 2025-09-14 00:54:48 +08:00
cuijiawang
0d12345ed4 yaml 配置数据库和redis链接 2025-08-28 14:37:34 +08:00
wol
e6c1041202 role part 2025-08-26 23:27:08 +08:00
wol
d7b36d9f59 user part 2025-08-26 00:05:22 +08:00
wol
fb81670776 menu 2025-08-25 00:09:18 +08:00
wol
f22189bc00 fix 2025-08-20 23:39:52 +08:00
cuijiawang
74d030a97e 1 2025-08-20 17:40:27 +08:00
cuijiawang
609bef8a87 gateway依赖 2025-08-20 09:37:52 +08:00
wol
0fa91a472d api 2025-08-19 22:47:54 +08:00
cuijiawang
bdd3f251a2 1 2025-08-19 18:02:47 +08:00
wol
4a0b1499c7 auth 2025-08-17 22:20:34 +08:00
wol
74064a4dc4 fix 2025-08-15 23:34:59 +08:00
wol
4c4f1acf32 1 2025-08-15 00:24:30 +08:00
cuijiawang
92246a6767 1 2025-08-14 18:02:58 +08:00
cuijiawang
6419f88c63 fix 2025-08-14 14:31:10 +08:00
cuijiawang
eee546fcc4 fix 2025-08-14 10:05:51 +08:00
wol
714b759050 config 2025-08-14 00:39:03 +08:00
cuijiawang
2d3024b3e7 1 2025-08-13 18:06:33 +08:00
cuijiawang
8b79ae515d mybatis yml 2025-08-13 11:40:21 +08:00
cuijiawang
8ccfe35b49 rename 2025-08-13 10:17:02 +08:00
cuijiawang
b12f104161 del 2025-08-13 10:03:56 +08:00
cuijiawang
a9bb36dacc 添加后台系统模块 2025-08-13 09:59:58 +08:00
wol
8a73e9bec4 Merge branch 'dev-cloud-v3.5.4' into dev-boot-v3.5.4
# Conflicts:
#	pom.xml
2025-08-12 23:33:57 +08:00
wol
0002cf457d 1 2025-08-12 23:30:14 +08:00
wol
01748fe738 Merge branch 'refs/heads/dev-boot-v3.5.4-module-ai' into dev-boot-v3.5.4 2025-08-12 23:12:24 +08:00
wol
bf2956c51c Merge branch 'refs/heads/dev-boot-v3.5.4-auth' into dev-boot-v3.5.4 2025-08-12 23:11:32 +08:00
wol
1e9baade51 Merge branch 'dev-boot-v3.5.4-redis' into dev-boot-v3.5.4 2025-08-12 22:56:01 +08:00
wol
0babec14cf add RedisConfiguration 2025-08-12 22:55:45 +08:00
wol
4806918ef9 auth 2025-08-12 22:50:03 +08:00
wol
0c87b1d63e 1 2025-08-12 22:42:10 +08:00
wol
cbaa3e7c42 module-ai 2025-08-12 22:10:00 +08:00
wol
30f8584d33 run 2025-08-12 22:09:14 +08:00
cuijiawang
29e43f6e36 boot-start 2025-08-12 18:12:47 +08:00
cuijiawang
985b82c604 modules 2025-08-12 17:46:36 +08:00
cuijiawang
54cc4c4ba5 server-cloud 2025-08-12 17:40:09 +08:00
cuijiawang
302e085a18 common-json 2025-08-12 17:21:44 +08:00
cuijiawang
ff174056a0 common-web 2025-08-12 16:50:21 +08:00
cuijiawang
c2a9f58926 del 2025-08-12 16:40:37 +08:00
wol
c80d8909dd common-redis 2025-08-11 23:49:28 +08:00
wol
e04a663fdb common-mybatis 2025-08-11 23:01:07 +08:00
wol
b92f6a6f53 common-doc 2025-08-10 22:28:58 +08:00
wol
99e64a9295 aop 2025-08-10 21:53:29 +08:00
wol
c13efa788c common-core 2025-08-10 21:48:49 +08:00
wol
ea916df3ce fix 2025-08-10 19:52:35 +08:00
wol
3b7501458a fix 2025-08-10 19:49:54 +08:00
wol
f301ea5840 javax -> jakarta 2025-08-10 19:24:38 +08:00
wol
084dad491e del test 2025-08-10 17:22:49 +08:00
cuijiawang
0bb060b273 refactor(admin): 重构开发环境配置并添加 Docker 支持
- 修改应用端口为 18080
- 更新数据库配置,使用加密凭据
- 调整 Redis 配置
- 添加 Jasypt 加密器配置
- 新增 Dockerfile 用于构建 Docker 镜像
- 更新 Maven 依赖,添加 Jasypt 支持
2025-07-31 16:06:55 +08:00
valarchie
4e9ab30d68 Merge pull request #81 from BruceBlink/dev
更新junit单元测试的相关依赖
2025-06-04 20:26:41 +08:00
valarchie
454bdd44bc Merge pull request #80 from BruceBlink/main
增加Github Actions的CI/CD配置
2025-06-04 20:24:11 +08:00
likanug
2fa20aaaf3 更新junit的相关依赖及版本,修复admin模块中maven test批量跑单元测试时报错的问题 2025-06-04 20:09:26 +08:00
likanug
d017e2bb64 更新AgileBootConfigTest单元测试 2025-06-04 19:08:03 +08:00
likanug
e2f398b794 Revert "添加发布release的GitHub Actions配置"
This reverts commit 9fbc14c171.
2025-06-04 18:30:50 +08:00
likanug
664d845ea4 Revert "增加GitHub打包配置"
This reverts commit 5b3809abd9.
2025-06-04 18:30:18 +08:00
likanug
5b3809abd9 增加GitHub打包配置 2025-06-04 17:55:54 +08:00
likanug
9fbc14c171 添加发布release的GitHub Actions配置 2025-06-04 17:45:56 +08:00
likanug
bc1b97f720 删除更新依赖图的配置 2025-06-04 17:31:27 +08:00
likanug
f5c6125d74 修复Java 17更新依赖图时报错的问题 2025-06-04 17:18:47 +08:00
likanug
4ed71fdf5d 删除构建完成后的slack通知配置 2025-06-04 17:08:28 +08:00
likanug
ab3bcda857 修复发送构建通知失败的问题 2025-06-04 17:03:24 +08:00
likanug
68575d141c 修复Missing download info for actions/cache@v2的问题 2025-06-04 16:56:46 +08:00
likanug
dd535bfa50 增加Java 8的构建配置 2025-06-04 16:53:25 +08:00
likanug
47394d92ae 修复更新“依赖图”错误的问题 2025-06-04 16:52:18 +08:00
likanug
2644ed4368 更新actions/upload-artifact为v4 2025-06-04 16:41:30 +08:00
likanug
c09c7e4ca8 增加GitHub Actions的CI/CD配置 2025-06-04 16:38:06 +08:00
valarchie
ce83324c44 Merge pull request #79 from BruceBlink/main
更新Lombok版本,修复在JDK21下,代码编译报错的问题
更新h2的sql脚本以及增加h2的MySQL语法兼容设置,修复test模式下项目启动报错的问题
2025-05-07 16:15:16 +08:00
likanug
9ad9895510 Revert "删除无用的pom依赖"
This reverts commit f489ef45fd.
2025-05-07 15:49:06 +08:00
likanug
f489ef45fd 删除无用的pom依赖 2025-05-07 12:10:18 +08:00
likanug
f1b3ca650d 更新h2的sql脚本以及增加h2的MySQL语法兼容设置,修复test模式下项目启动报错的问题 2025-05-07 12:07:33 +08:00
likanug
42bf932d86 更新Lombok版本,修复在JDK21下,代码编译报错的问题 2025-05-07 11:13:04 +08:00
valarchie
1ccbfa2881 Merge pull request #77 from gongxuanzhang/main
Util classes should have private constructors
2024-12-31 14:26:28 +08:00
Xuan-Zhang Gong
6e4155a146 Util classes should have private constructors 2024-11-18 14:11:20 +08:00
valarchie
0bc4148a34 Merge pull request #75 from 1065700104/develop
fix(DeptModel): 修复父级部门为null时NPE的bug
2024-09-12 16:06:49 +08:00
李嘉伟
6a4245f541 feat(DeptModel): 修复父级部门为null时NPE的bug 2024-09-04 17:05:42 +08:00
valarchie
660dfa6a1e Update README.md 2024-05-29 08:29:38 +08:00
valarchie
62f81adc74 Merge pull request #71 from deepbreath/main
update:更新 pgsql 表
2024-04-09 17:14:24 +08:00
Yuchen
21ed5ef781 update:更新 pgsql 表 2024-04-09 17:09:06 +08:00
valarchie
073cda31e8 Merge pull request #70 from habyss/main
fix: xxxQuery放到对应目录
2024-04-03 17:06:20 +08:00
hankun
a845cf66ce fix: xxxQuery放到对应目录 2024-04-03 13:35:17 +08:00
valarchie
d2eb733ab3 Merge pull request #61 from aniyayee/main
fix: 删除角色时将操作类型更正为DELETE
2023-11-13 16:07:28 +08:00
yayee
f09c1fa47f fix: 删除角色时将操作类型更正为DELETE 2023-11-13 15:57:41 +08:00
valarchie
4716b3c977 Merge pull request #60 from burningimlam/main
fix: 分页查询时可能出现的NPE
2023-11-08 19:32:42 +08:00
imlam
aa2de6a6f2 fix: 分页查询时可能出现的NPE 2023-11-08 19:02:57 +08:00
valarchie
e9df8f01a1 Merge remote-tracking branch 'origin/main' 2023-10-12 16:09:24 +08:00
valarchie
9793f97613 fix: 修复缓存问题 2023-10-12 16:09:10 +08:00
valarchie
ea6117cf4e Merge pull request #56 from qcxy/main
修改引入包注释
2023-10-12 09:49:49 +08:00
gzy
a8afdce2fa 修改引入包注释 2023-10-12 09:36:21 +08:00
valarchie
7b78527e6d Merge pull request #55 from qcxy/main
去掉多余的两个引入的包
2023-10-12 09:35:37 +08:00
gzy
5a20edaff8 去掉多余的两个引入的包
结构变为common->infrastructure->domain->admin
2023-10-12 09:30:40 +08:00
valarchie
c054f3e3e8 Merge pull request #54 from gyzhang/fix_by_kevin_20231004
fix: 修改“岗位管理”-查询功能中的1-默认排序为数据库中的post_sort,2-设置漏掉的前端查询条件“创建时间”对应的字段cre…
2023-10-06 22:11:58 +08:00
Kevin Zhang
1ba6a55e93 fix: 代码异动位置:“岗位管理”-查询功能中的1-默认排序为数据库中的post_sort,2-设置漏掉的前端查询条件“创建时间”对应的字段 2023-10-06 15:30:29 +08:00
Kevin Zhang
72cde4c5cf fix: 修改“岗位管理”-查询功能中的1-默认排序为数据库中的post_sort,2-设置漏掉的前端查询条件“创建时间”对应的字段create_time 2023-10-04 23:40:14 +08:00
valarchie
050905fbc0 Merge pull request #53 from gyzhang/fix_by_kevin_20231003
fix: 修改“岗位管理”-删除-按钮功能错误:前端传递参数和后端不匹配,参照操作日志的删除功能做了修改。
2023-10-03 18:14:28 +08:00
Kevin Zhang
135a135d0f fix: 修改“岗位管理”-删除-按钮功能错误:前端传递参数和后端不匹配,参照操作日志的删除功能做了修改。 2023-10-03 16:39:30 +08:00
valarchie
0c4f58fd23 Merge pull request #52 from gyzhang/fix_by_kevin_20231002
fix: 修改“岗位管理”-全部导出-按钮功能错误:请求类型修改为get,请求路径修改为/excel,重新提供方法返回不分页的查询结果。
2023-10-02 18:38:22 +08:00
Kevin Zhang
a6344a2662 fix: 修改“岗位管理”-全部导出-按钮功能错误:请求类型修改为get,请求路径修改为/excel,重新提供方法返回不分页的查询结果。 2023-10-02 16:53:18 +08:00
Kevin Zhang
9527c95734 fix: 修改“岗位管理”-全部导出-按钮功能错误:请求类型修改为get,请求路径修改为/excel,重新提供方法返回不分页的查询结果。 2023-10-02 16:44:54 +08:00
valarchie
fcf41c68da Merge pull request #51 from penbox/main
fix: AddRoleCommand 中的 roleSort 约束为 @NotBlank,导致新增角色报错
2023-09-22 16:50:18 +08:00
penbox
c7436ec289 Merge branch 'main' into main 2023-09-22 16:45:36 +08:00
penbox86@126.com
90f80a7d27 fix: AddRoleCommand 中的 roleSort 约束为 @NotBlank,导致新增角色报错 2023-09-22 16:39:16 +08:00
valarchie
4aeafb8ab1 Merge pull request #47 from wunaidouzi/fixed-20230914
fixed: roleSort使用NotBlank导致无法update
2023-09-14 19:20:13 +08:00
LiuZhiYun
d8093fffe9 fixed: roleSort使用NotBlank导致无法update 2023-09-14 18:35:18 +08:00
valarchie
33ce250371 Merge pull request #45 from penbox/main
fix:移除 selectMenuListByUserId 中无效的排序字段
2023-09-07 10:36:19 +08:00
penbox86@126.com
88841b7ed0 fix:移除 selectMenuListByUserId 中无效的排序字段 2023-09-07 10:13:08 +08:00
valarchie
1a93fe4d95 refactor: 更新readMe 2023-08-16 18:52:54 +08:00
valarchie
251db3a146 refactor: 更新readMe 2023-08-15 11:01:19 +08:00
valarchie
18cba6b975 refactor: 更新gitignore 2023-08-15 09:53:44 +08:00
valarchie
a6792705ba refactor: 去除NonNull注解 2023-08-15 09:42:58 +08:00
valarchie
02fb771994 refactor: 修改Readme 2023-08-15 08:50:53 +08:00
valarchie
6ebea15fb3 refactor: 添加初始化sql文件 2023-08-15 08:40:08 +08:00
valarchie
76f1ddc9fe refactor: 修改ReadMe 2023-08-15 08:38:54 +08:00
valarchie
198b0856af refactor: 修改ReadMe 2023-08-15 08:32:07 +08:00
valarchie
0ab467dc6c Merge branch 'For-Pure'
# Conflicts:
#	agileboot-common/src/main/java/com/agileboot/common/enums/BasicEnumUtil.java
#	agileboot-common/src/test/java/com/agileboot/common/enums/BasicEnumUtilTest.java
2023-08-15 08:22:36 +08:00
valarchie
b920a748ed refactor: 使用final修饰符取代 @NonNull注解 进行bean注入 2023-08-14 23:22:11 +08:00
valarchie
4e0c6b80b7 refactor: 规范全局事务管理器 2023-08-14 22:47:41 +08:00
valarchie
16a06edb89 refactor: 移除orm模块 以及xml内容 2023-08-14 22:28:09 +08:00
valarchie
53e63c8b8e refactor: 修改数据类服务切面 2023-08-14 22:14:41 +08:00
valarchie
00f65d91ab refactor: 将orm包中数据相关类 挪到domain包中 2023-08-14 22:10:24 +08:00
valarchie
f3aaa771f6 refactor: 修复addTimeCondition方法 2023-08-14 20:45:27 +08:00
valarchie
5f31b9c27e refactor: 将orm包中的common类挪到common模块 2023-08-14 20:44:09 +08:00
valarchie
01afc4505f refactor: 将enum接口挪到common包 2023-08-14 17:16:23 +08:00
valarchie
b340bff225 refactor: 将RoleInfo与orm包解耦 2023-08-14 17:11:04 +08:00
valarchie
74c71156f0 refactor: 把MapCache挪到domain包 2023-08-14 17:03:42 +08:00
valarchie
90c231221f refactor: 把GuavaCacheService挪到domain包 2023-08-14 16:56:51 +08:00
valarchie
58b0d14340 refactor: 把RedisCacheService挪到domain包 2023-08-14 16:46:57 +08:00
valarchie
d72be1a446 refactor: 清理RoleInfo缓存 2023-08-14 16:21:26 +08:00
valarchie
157afb3673 refactor: 将异步工厂类挪到admin模块 2023-08-14 16:10:16 +08:00
valarchie
0ae219e942 refactor: 将操作日志AOP挪到 2023-08-14 16:00:46 +08:00
valarchie
377afbb8fc Merge remote-tracking branch 'origin/For-Pure' into For-Pure 2023-08-14 15:13:33 +08:00
valarchie
64e2fc9912 refactor: 新增dev 配置文件 2023-08-14 14:55:56 +08:00
valarchie
3e25d18463 refactor: 将集成测试模块挪到领域逻辑domain模块中 2023-08-14 14:35:52 +08:00
valarchie
37e052ef62 refactor: 上传dev配置文件 2023-08-08 19:19:37 +08:00
valarchie
aa0e1f91c5 refactor: 调整包结构以便二次开发 2023-08-05 14:33:08 +08:00
valarchie
242f536986 feature: 新增filter填入requestId方便跟踪日志 2023-08-01 20:25:43 +08:00
valarchie
df7f6950d1 refactor: 新增API的请求拦截 2023-08-01 14:02:27 +08:00
valarchie
3f384fbe79 refactor: 去掉返回类中的requestId API模块使用undertow服务器 2023-08-01 13:44:43 +08:00
valarchie
7c9b86a304 refactor: 把配置文件挪到admin和api模块 2023-07-30 16:07:08 +08:00
valarchie
917050e543 refactor: 把登录用户 拆分为系统用户和App用户 2023-07-30 13:44:43 +08:00
valarchie
6f96216248 refactor: 把登录逻辑移到admin 因为不同项目的登录 可能是不一样的 2023-07-30 13:32:25 +08:00
valarchie
fcb88e5a94 refactor: 把登录逻辑移到admin 因为不同项目的登录 可能是不一样的 2023-07-30 12:55:54 +08:00
valarchie
37f2b63038 refactor: 调整基础设施模块 2023-07-30 12:03:23 +08:00
valarchie
b59ed7d7d6 refactor: 将请求重复提交和请求限流重构区分为App和Web 2023-07-30 11:49:05 +08:00
valarchie
3a9fbb563e refactor: 将请求重复提交和请求限流重构区分为App和Web 2023-07-30 11:35:05 +08:00
valarchie
ec8dda127a fix: 调整common包 2023-07-30 00:45:09 +08:00
valarchie
59f6693005 refactor: 重构错误码的设计以及错误处理 2023-07-26 22:12:23 +08:00
valarchie
7a570300b5 refactor: 重构个人中心功能 2023-07-25 19:50:43 +08:00
valarchie
4174c15934 refactor: 新增用户页面 2023-07-24 21:46:55 +08:00
Lyp
891f908522 fix: 修改新增角色参数的序号类型 2023-07-23 20:52:16 +08:00
valarchie
d52a5bcbe5 refactor: 重构路由菜单功能 2023-07-22 17:22:10 +08:00
valarchie
7da7481887 refactor: 重构路由菜单功能 2023-07-22 17:15:43 +08:00
valarchie
71c9a7589d refactor: 重构部门页面 2023-07-20 22:53:47 +08:00
valarchie
3b091cbd4a Merge pull request #43 from daniyyer/exportExcel
Update CustomExcelUtil.java
2023-07-20 16:34:36 +08:00
daniyyer
df4996096c Update CustomExcelUtil.java
ExcelUtil.getWriter()默认创建xls格式的Excel,因此写出到客户端也需要自定义文件名为XXX.xls,现在配套的前端代码中设置的文件扩展名为xlsx,导出后打开会出现文件损坏的提示。改为ExcelUtil.getWriter(true)后,可生成xlsx格式的文件。
2023-07-20 16:06:38 +08:00
valarchie
f148232f0a refactor: 重构配置页面 2023-07-20 15:07:26 +08:00
valarchie
2318ce903d refactor: 重构缓存监控页面 2023-07-19 23:02:12 +08:00
valarchie
83df81583c refactor: 重构在线用户页面 2023-07-19 10:35:07 +08:00
valarchie
aa3b050b3f fix: 修复DB层异常捕获失败 2023-07-18 22:21:05 +08:00
valarchie
4605289348 feat: 更新数据库 2023-07-18 21:35:43 +08:00
valarchie
fc0a41a4e6 feat: 重构接口文档页面 2023-07-18 15:15:34 +08:00
valarchie
1382d2a32d refactor: 适配pure-admin登录日志页面 2023-07-16 21:39:07 +08:00
valarchie
97fc6d0367 refactor: 修改操作日志的后台导出excel 2023-07-16 14:04:22 +08:00
valarchie
52890e6e6e feat: 重构操作日志 2023-07-15 17:51:28 +08:00
valarchie
259e948325 Merge remote-tracking branch 'origin/For-Pure' into For-Pure 2023-07-15 08:18:01 +08:00
valarchie
9859bb1360 fix: 重构日志模块 2023-07-15 08:16:45 +08:00
valarchie
f03f441cb4 Merge pull request #42 from burningimlam/For-Pure
补充缺少的javadoc&消除部分代码检查警告
2023-07-14 22:05:29 +08:00
imlam
92782b9407 消除部分Sonar代码检查警告 2023-07-14 20:17:40 +08:00
imlam
0573b66ddc 补充缺少的javadoc&消除部分代码检查警告 2023-07-14 17:08:39 +08:00
valarchie
fb40f307b9 Update README.md 2023-07-14 16:03:29 +08:00
valarchie
2e435497b9 Update README.md 2023-07-14 16:02:46 +08:00
valarchie
32e95e858e Merge pull request #41 from burningimlam/For-Pure
fix: 补充缺少的javadoc注释
2023-07-14 15:50:59 +08:00
imlam
92b698a313 补充缺少的javadoc注释 2023-07-14 14:20:20 +08:00
valarchie
bcc9d7c757 Merge pull request #39 from TheLastSunset/mvnw
feat: add maven wrapper
2023-07-13 16:07:08 +08:00
valarchie
8d214bc4d1 Merge pull request #40 from TheLastSunset/optimize
refactor: optimize BasicEnumUtil
2023-07-13 15:41:29 +08:00
TheLastSunset
7bb6d625e4 refactor: optimize BasicEnumUtil 2023-07-13 14:11:40 +08:00
valarchie
2401ec2c62 refactor: 通知公告模块重构为更严格的restful风格 2023-07-13 12:13:08 +08:00
valarchie
7fdd8ef871 refactor: 规范字典类的名称 2023-07-12 21:03:32 +08:00
valarchie
4f7ada223a factor: 适配新的前端pure admin. 重构query基础类 2023-07-12 16:53:22 +08:00
TheLastSunset
88e22c270d feat: add mvnw execute permission 2023-07-12 08:40:48 +00:00
valarchie
19f4eb29bb factor: 适配新的前端pure admin. 重构query基础类 2023-07-12 16:01:18 +08:00
TheLastSunset
37e297626b feat: add maven wrapper 2023-07-12 10:58:12 +08:00
valarchie
0b0edfa7a5 docs: 添加关于securityConfig的注释 2023-07-07 18:20:50 +08:00
valarchie
c56dd18064 feat: 实现登录登出的逻辑,拆分配置接口 2023-07-04 21:55:41 +08:00
valarchie
d6bb477219 refactor: 拆分一个getConfig接口用于返回系统的配置参数,重构错误码类,使其可以跳转到i18n文件 2023-07-02 20:55:30 +08:00
valarchie
aea62eb6e2 feat: 新增pure项目对应的sql文件 2023-07-01 16:45:51 +08:00
valarchie
76d5cccf95 refactor: 新增路由代码 2023-06-29 23:01:20 +08:00
valarchie
d27352ecbc Merge branch 'main' into For-Pure 2023-06-29 19:29:20 +08:00
valarchie
c46dbc512b refactor: 使用固定的版本号, revision会导致子module install不成功 2023-06-27 21:23:12 +08:00
valarchie
aeb3576be6 Merge branch 'main' into For-Pure 2023-06-27 15:22:02 +08:00
valarchie
afddd03fda feat: 新增密码加密登录操作,重构登录代码 2023-06-25 21:44:02 +08:00
valarchie
a37997583a doc: 添加内置redis关于macos启动失败的说明 2023-06-20 22:32:38 +08:00
valarchie
8976a867e3 refactor: 把前端端口从80改成3000,避免有些用户启用不了80端口 2023-06-20 22:30:14 +08:00
valarchie
fdef3ed7ad refactor: 修改mysql启动步骤 2023-06-17 21:54:02 +08:00
633 changed files with 19020 additions and 17568 deletions

View File

@@ -1,36 +0,0 @@
---
name: Bug 报告
about: 创建BUG报告以改进项目
title: ''
labels: ''
assignees: ''
---
**BUG描述**
关于BUG清晰简洁的描述。
**复现步骤**
详细的复现步骤。
**正确的行为**
你认为这个修复这个BUG后正确的行为应该是什么。
**详细截图**
如果可以的话请添加截图以帮助调查BUG.
**桌面端:**
- 操作系统: [例如. iOS]
- 浏览器及版本 [例如. chrome 11]
- 项目版本 [例如. 1.6.0]
**手机端:**
- 设备: [例如. iPhone6]
- 操作系统: [例如. iOS8.1]
- 浏览器及版本 [例如.safari 8]
- 项目版本 [例如. 1.6.0]
**Additional context**
任何其他你认为有助于排查错误的信息,或者你的猜测。

View File

@@ -1,20 +0,0 @@
---
name: 功能建议
about: 关于该项目的建议
title: ''
labels: ''
assignees: ''
---
**您的功能请求是否与问题相关? 请描述。**
清楚简明地描述问题所在。
**描述您想要的解决方案**
对您所设想的问题的清晰简洁的描述。
**描述您考虑过的替代方案**
对您考虑过的任何替代解决方案或功能的清晰简洁的描述。
**附加上下文**
在此处添加有关功能请求的任何其他上下文或屏幕截图。

6
.gitignore vendored
View File

@@ -45,6 +45,6 @@ nbdist/
!*/build/*.java
!*/build/*.html
!*/build/*.xml
/agileboot-admin/src/main/resources/application-dev.yml
/agileboot-infrastructure/src/main/resources/application-prod.yml
/agileboot-infrastructure/src/main/resources/logback-prod.xml
/agileboot-admin/src/main/resources/application-prod.yml

8
Dockerfile Normal file
View File

@@ -0,0 +1,8 @@
FROM amazoncorretto:17
ADD agileboot-admin/target/agileboot-admin-1.0.0.jar /agileboot-admin.jar
EXPOSE 18080
#ENV CONTEXT_PATH /
# ENV NACOS_ENABLED true
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
ENTRYPOINT ["java", "-jar", "/agileboot-admin.jar"]

21
LICENSE
View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2022 valarchie
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -15,8 +15,7 @@
<img alt="logo" height="200" src="https://oscimg.oschina.net/oscnet/up-eda2a402cc061f1f5f40d9ac4c084f4c98c.png">
</p>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">AgileBoot v1.8.0</h1>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">AgileBoot v2.0.0 </h1>
<h4 align="center">基于SpringBoot+Vue3前后端分离的Java快速开发脚手架</h4>
<p align="center">
</p>
@@ -27,7 +26,8 @@ AgileBoot是一套开源的全栈精简快速开发平台毫无保留给个
适合个人开发者的小型项目或者公司内部项目使用。也可作为供初学者学习使用的案例。
* 前端采用Vue3、Element Plus。对应前端仓库 [AgileBoot-Front-End](https://github.com/valarchie/AgileBoot-Front-End) ,保持同步更新
* 前端是基于优秀的开源项目[Pure-Admin](https://github.com/pure-admin/vue-pure-admin)开发而成。在此感谢Pure-Admin作者
* 前端采用Vue3、Element Plus、TypeScript、Pinia。对应前端仓库 [AgileBoot-Front-End](https://github.com/valarchie/AgileBoot-Front-End) ,保持同步更新。
* 后端采用Spring Boot、Spring Security & Jwt、Redis & MySql、Mybatis Plus、Hutool工具包。
* 权限认证使用Jwt支持多终端认证系统。
* 支持注解式主从数据库切换,注解式请求限流,注解式重复请求拦截。
@@ -35,6 +35,9 @@ AgileBoot是一套开源的全栈精简快速开发平台毫无保留给个
* 支持加载动态权限菜单,实时权限控制。
* ***有大量的单元测试,集成测试覆盖确保业务逻辑正确***。
***V1.0.0版本使用JS开发V2.0.0版本使用TS开发***。
***V1.0.0地址:[后端(AgileBoot-Back-End-Basic)](https://github.com/valarchie/AgileBoot-Back-End-Basic) - [前端(AgileBoot-Front-End-Basic)](https://github.com/valarchie/AgileBoot-Front-End-Basic)***
> 有任何问题或者建议,可以在 _Issues_ 中提给作者。
>
> 您的Issue比Star更重要
@@ -148,9 +151,9 @@ git clone https://github.com/valarchie/AgileBoot-Front-End
#### 后端启动
```
1. 生成所需的数据库表
找到后端项目根目录下的sql目录中的agileboot_xxxxx.sql脚本文件。 导入到你新建的数据库中。
找到后端项目根目录下的sql目录中的agileboot_xxxxx.sql脚本文件(取最新的sql文件)。 导入到你新建的数据库中。
2. 在infrastructure模块底下找到resource目录下的application-dev.yml文件
2. 在admin模块底下找到resource目录下的application-dev.yml文件
配置数据库以及Redis的 地址、端口、账号密码
3. 在根目录执行mvn install
@@ -168,10 +171,12 @@ git clone https://github.com/valarchie/AgileBoot-Front-End
```
#### 前端启动
```
1. npm install
详细步骤请查看对应前端部分
2. npm run dev
```
1. pnpm install
2. pnpm run dev
3. 当出现以下字样时即为启动成功
@@ -202,6 +207,8 @@ agileboot.embedded.redis: false
agileboot.embedded.mysql: true
agileboot.embedded.redis: true
请注意:高版本的MacOS系统无法启动内置的Redis
3. 找到agileboot-admin模块中的AgileBootAdminApplication启动类直接启动即可
```
@@ -230,8 +237,6 @@ agileboot.embedded.redis: true
| | 连接池监视 | 监视当前系统数据库连接池状态可进行分析SQL找出系统性能瓶颈 |
目前版本是V1.8.0将在2.0版本后陆续新增新功能。
## 🐯 工程结构 🐯
```
@@ -242,25 +247,20 @@ agileboot
├── agileboot-common -- 精简基础工具模块
├── agileboot-infrastructure -- 基础设施模块(主要是配置和集成)
├── agileboot-infrastructure -- 基础设施模块(主要是配置和集成,不包含业务逻辑
├── agileboot-domain -- 业务模块
├ ├── user -- 用户模块(举例)
├ ├── command -- 命令参数接收模型(命令)
├ ├── dto -- 返回数据类
├ ├── db -- DB操作类
├ ├── entity -- 实体类
├ ├── service -- DB Service
├ ├── mapper -- DB Dao
├ ├── model -- 领域模型类
├ ├── query -- 查询参数模型(查询)
│ ├────── UserApplicationService -- 应用服务(事务层,操作领域模型类完成业务逻辑)
├── agileboot-integration-test -- 集成测试模块
├── agileboot-orm -- 数据映射模块(仅包含数据相关逻辑)
├ ├── entiy -- 实体类
├ ├── enums -- 数据相关枚举
├ ├── mapper -- DAO
├ ├── query -- 封装查询对象
├ ├── result -- 封装多表查询对象
└── └── service -- 服务层
```
### 代码流转
@@ -284,11 +284,16 @@ agileboot
│ ├── member -- 会员模块
├── agileboot-domain --
├ ├── member -- 会员模块
── agileboot-orm --
├── member -- 会员模块
├ ├── member -- 会员模块(举例)
├ ├── command -- 命令参数接收模型(命令)
├── dto -- 返回数据类
├── db -- DB操作类
├ ├── entity -- 实体类
├ ├── service -- DB Service
├ ├── mapper -- DB Dao
├ ├── model -- 领域模型类
├ ├── query -- 查询参数模型(查询)
│ ├────── MemberApplicationService -- 应用服务(事务层,操作领域模型类完成业务逻辑)
└─
```
@@ -313,11 +318,12 @@ agileboot
- 请导入统一的代码格式化模板Google: Settings > Editor > Code Style > Java > 设置按钮 > import schema > 选择项目根目录下的GoogleStyle.xml文件
- 如需要生成新的表请使用CodeGenerator类进行生成。
- 填入数据库地址,账号密码,库名。然后填入所需的表名执行代码即可。(大概看一下代码就知道怎么填啦)
- 生成的类在orm模块下的target/classes目录下
- 生成的类在infrastructure模块下的target/classes目录下
- 不同的数据库keywordsHandler方法请填入对应不同数据库handler。搜索keywordsHandler关键字
- 项目基础环境搭建请参考docker目录下的指南搭建。保姆级启动说明
- [AgileBoot - 手把手一步一步带你Run起全栈项目(SpringBoot+Vue3)](https://juejin.cn/post/7153812187834744845)
- 注意管理后台的后端启动类是AgileBoot**Admin**Application
- Swagger的API地址为 http://localhost:8080/v3/api-docs
## 🎬 AgileBoot全栈交流群 🎬

View File

@@ -1,32 +0,0 @@
package com.agileboot.admin;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
/**
* 启动程序
* 定制banner.txt的网站
* http://patorjk.com/software/taag
* http://www.network-science.de/ascii/
* http://www.degraeve.com/img2txt.php
* http://life.chacuo.net/convertfont2char
* @author valarchie
*/
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@ComponentScan(basePackages = "com.agileboot.*")
public class AgileBootAdminApplication {
public static void main(String[] args) {
SpringApplication.run(AgileBootAdminApplication.class, args);
String successMsg = " ____ _ _ __ _ _ \n"
+ " / ___| | |_ __ _ _ __ | |_ _ _ _ __ ___ _ _ ___ ___ ___ ___ ___ / _| _ _ | || |\n"
+ " \\___ \\ | __|/ _` || '__|| __| | | | || '_ \\ / __|| | | | / __|/ __|/ _ \\/ __|/ __|| |_ | | | || || |\n"
+ " ___) || |_| (_| || | | |_ | |_| || |_) | \\__ \\| |_| || (__| (__| __/\\__ \\\\__ \\| _|| |_| || ||_|\n"
+ " |____/ \\__|\\__,_||_| \\__| \\__,_|| .__/ |___/ \\__,_| \\___|\\___|\\___||___/|___/|_| \\__,_||_|(_)\n"
+ " |_| ";
System.out.println(successMsg);
}
}

View File

@@ -1,129 +0,0 @@
package com.agileboot.admin.controller.common;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileNameUtil;
import com.agileboot.common.constant.Constants.UploadSubDir;
import com.agileboot.common.core.dto.ResponseDTO;
import com.agileboot.common.exception.ApiException;
import com.agileboot.common.exception.error.ErrorCode;
import com.agileboot.common.exception.error.ErrorCode.Business;
import com.agileboot.common.utils.ServletHolderUtil;
import com.agileboot.common.utils.file.FileUploadUtils;
import com.agileboot.common.utils.jackson.JacksonUtil;
import com.agileboot.domain.common.dto.UploadDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
/**
* 通用请求处理
*
* @author valarchie
*/
@Tag(name = "上传API", description = "上传相关接口")
@RestController
@RequestMapping("/file")
@Slf4j
public class FileController {
/**
* 通用下载请求
* download接口 其实不是很有必要
* @param fileName 文件名称
*/
@Operation(summary = "下载文件")
@GetMapping("/download")
public ResponseEntity<byte[]> fileDownload(String fileName, HttpServletResponse response) {
try {
if (!FileUploadUtils.isAllowDownload(fileName)) {
// 返回类型是ResponseEntity 不能捕获异常, 需要手动将错误填到 ResponseEntity
ResponseDTO<Object> fail = ResponseDTO.fail(
new ApiException(Business.FILE_NOT_ALLOWED_TO_DOWNLOAD, fileName));
return new ResponseEntity<>(JacksonUtil.to(fail).getBytes(), null, HttpStatus.OK);
}
String filePath = FileUploadUtils.getFileAbsolutePath(UploadSubDir.DOWNLOAD_PATH, fileName);
HttpHeaders downloadHeader = FileUploadUtils.getDownloadHeader(fileName);
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
return new ResponseEntity<>(FileUtil.readBytes(filePath), downloadHeader, HttpStatus.OK);
} catch (Exception e) {
log.error("下载文件失败", e);
return null;
}
}
/**
* 通用上传请求(单个)
*/
@Operation(summary = "单个上传文件")
@PostMapping("/upload")
public ResponseDTO<UploadDTO> uploadFile(MultipartFile file) {
if (file == null) {
throw new ApiException(ErrorCode.Business.UPLOAD_FILE_IS_EMPTY);
}
// 上传并返回新文件名称
String fileName = FileUploadUtils.upload(UploadSubDir.UPLOAD_PATH, file);
String url = ServletHolderUtil.getContextUrl() + fileName;
UploadDTO uploadDTO = UploadDTO.builder()
// 全路径
.url(url)
// 相对路径
.fileName(fileName)
// 新生成的文件名
.newFileName(FileNameUtil.getName(fileName))
// 原始的文件名
.originalFilename(file.getOriginalFilename()).build();
return ResponseDTO.ok(uploadDTO);
}
/**
* 通用上传请求(多个)
*/
@Operation(summary = "多个上传文件")
@PostMapping("/uploads")
public ResponseDTO<List<UploadDTO>> uploadFiles(List<MultipartFile> files) {
if (CollUtil.isEmpty(files)) {
throw new ApiException(ErrorCode.Business.UPLOAD_FILE_IS_EMPTY);
}
List<UploadDTO> uploads = new ArrayList<>();
for (MultipartFile file : files) {
if (file != null) {
// 上传并返回新文件名称
String fileName = FileUploadUtils.upload(UploadSubDir.UPLOAD_PATH, file);
String url = ServletHolderUtil.getContextUrl() + fileName;
UploadDTO uploadDTO = UploadDTO.builder()
.url(url)
.fileName(fileName)
.newFileName(FileNameUtil.getName(fileName))
.originalFilename(file.getOriginalFilename()).build();
uploads.add(uploadDTO);
}
}
return ResponseDTO.ok(uploads);
}
}

View File

@@ -1,132 +0,0 @@
package com.agileboot.admin.controller.common;
import cn.hutool.core.util.StrUtil;
import com.agileboot.common.config.AgileBootConfig;
import com.agileboot.common.core.dto.ResponseDTO;
import com.agileboot.common.exception.error.ErrorCode.Business;
import com.agileboot.domain.common.cache.CacheCenter;
import com.agileboot.domain.common.dto.UserPermissionDTO;
import com.agileboot.domain.system.menu.MenuApplicationService;
import com.agileboot.domain.system.menu.dto.RouterDTO;
import com.agileboot.domain.system.user.command.AddUserCommand;
import com.agileboot.domain.system.user.dto.UserDTO;
import com.agileboot.infrastructure.annotations.RateLimit;
import com.agileboot.infrastructure.annotations.RateLimit.CacheType;
import com.agileboot.infrastructure.annotations.RateLimit.LimitType;
import com.agileboot.infrastructure.cache.map.MapCache;
import com.agileboot.infrastructure.security.AuthenticationUtils;
import com.agileboot.infrastructure.web.domain.login.CaptchaDTO;
import com.agileboot.infrastructure.web.domain.login.LoginDTO;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.infrastructure.web.domain.login.TokenDTO;
import com.agileboot.infrastructure.web.domain.ratelimit.RateLimitKey;
import com.agileboot.infrastructure.web.service.LoginService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
/**
* 首页
*
* @author valarchie
*/
@Tag(name = "登录API", description = "登录相关接口")
@RestController
@RequiredArgsConstructor
public class LoginController {
@NonNull
private LoginService loginService;
@NonNull
private MenuApplicationService menuApplicationService;
@NonNull
private AgileBootConfig agileBootConfig;
/**
* 访问首页,提示语
*/
@Operation(summary = "首页")
@GetMapping("/")
@RateLimit(key = RateLimitKey.TEST_KEY, time = 10, maxCount = 5, cacheType = CacheType.Map,
limitType = LimitType.GLOBAL)
public String index() {
return StrUtil.format("欢迎使用{}后台管理框架当前版本v{},请通过前端地址访问。",
agileBootConfig.getName(), agileBootConfig.getVersion());
}
/**
* 生成验证码
*/
@Operation(summary = "验证码")
@RateLimit(key = RateLimitKey.LOGIN_CAPTCHA_KEY, time = 10, maxCount = 10, cacheType = CacheType.REDIS,
limitType = LimitType.IP)
@GetMapping("/captchaImage")
public ResponseDTO<CaptchaDTO> getCaptchaImg() {
CaptchaDTO captchaImg = loginService.generateCaptchaImg();
return ResponseDTO.ok(captchaImg);
}
/**
* 登录方法
*
* @param loginDTO 登录信息
* @return 结果
*/
@Operation(summary = "登录")
@PostMapping("/login")
public ResponseDTO<TokenDTO> login(@RequestBody LoginDTO loginDTO) {
// 生成令牌
String token = loginService.login(loginDTO);
return ResponseDTO.ok(new TokenDTO(token));
}
/**
* 获取用户信息
*
* @return 用户信息
*/
@Operation(summary = "获取当前登录用户信息")
@GetMapping("/getLoginUserInfo")
public ResponseDTO<UserPermissionDTO> getLoginUserInfo() {
LoginUser loginUser = AuthenticationUtils.getLoginUser();
UserPermissionDTO permissionDTO = new UserPermissionDTO();
permissionDTO.setUser(new UserDTO(CacheCenter.userCache.getObjectById(loginUser.getUserId())));
permissionDTO.setRoleKey(loginUser.getRoleInfo().getRoleKey());
permissionDTO.setPermissions(loginUser.getRoleInfo().getMenuPermissions());
permissionDTO.setDictTypes(MapCache.dictionaryCache());
return ResponseDTO.ok(permissionDTO);
}
/**
* 获取路由信息
*
* @return 路由信息
*/
@Operation(summary = "获取用户对应的菜单路由", description = "用于动态生成路由")
@GetMapping("/getRouters")
public ResponseDTO<List<RouterDTO>> getRouters() {
LoginUser loginUser = AuthenticationUtils.getLoginUser();
List<RouterDTO> routerTree = menuApplicationService.getRouterTree(loginUser);
return ResponseDTO.ok(routerTree);
}
@Operation(summary = "注册接口", description = "暂未实现")
@PostMapping("/register")
public ResponseDTO<Void> register(@RequestBody AddUserCommand command) {
return ResponseDTO.fail(Business.UNSUPPORTED_OPERATION);
}
}

View File

@@ -1,83 +0,0 @@
package com.agileboot.admin.controller.monitor;
import com.agileboot.common.core.base.BaseController;
import com.agileboot.common.core.dto.ResponseDTO;
import com.agileboot.common.core.page.PageDTO;
import com.agileboot.domain.common.cache.CacheCenter;
import com.agileboot.domain.system.monitor.MonitorApplicationService;
import com.agileboot.domain.system.monitor.dto.OnlineUserInfo;
import com.agileboot.domain.system.monitor.dto.RedisCacheInfoDTO;
import com.agileboot.domain.system.monitor.dto.ServerInfo;
import com.agileboot.infrastructure.annotations.AccessLog;
import com.agileboot.orm.common.enums.BusinessTypeEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 缓存监控
*
* @author valarchie
*/
@Tag(name = "监控API", description = "监控相关信息")
@RestController
@RequestMapping("/monitor")
@RequiredArgsConstructor
public class MonitorController extends BaseController {
@NonNull
private MonitorApplicationService monitorApplicationService;
@Operation(summary = "Redis信息")
@PreAuthorize("@permission.has('monitor:cache:list')")
@GetMapping("/cacheInfo")
public ResponseDTO<RedisCacheInfoDTO> getRedisCacheInfo() {
RedisCacheInfoDTO redisCacheInfo = monitorApplicationService.getRedisCacheInfo();
return ResponseDTO.ok(redisCacheInfo);
}
@Operation(summary = "服务器信息")
@PreAuthorize("@permission.has('monitor:server:list')")
@GetMapping("/serverInfo")
public ResponseDTO<ServerInfo> getServerInfo() {
ServerInfo serverInfo = monitorApplicationService.getServerInfo();
return ResponseDTO.ok(serverInfo);
}
/**
* 获取在线用户列表
* @param ipaddr
* @param userName
* @return
*/
@Operation(summary = "在线用户列表")
@PreAuthorize("@permission.has('monitor:online:list')")
@GetMapping("/onlineUser/list")
public ResponseDTO<PageDTO<OnlineUserInfo>> list(String ipaddr, String userName) {
List<OnlineUserInfo> onlineUserList = monitorApplicationService.getOnlineUserList(userName, ipaddr);
return ResponseDTO.ok(new PageDTO<>(onlineUserList));
}
/**
* 强退用户
*/
@Operation(summary = "强退用户")
@PreAuthorize("@permission.has('monitor:online:forceLogout')")
@AccessLog(title = "在线用户", businessType = BusinessTypeEnum.FORCE_LOGOUT)
@DeleteMapping("/onlineUser/{tokenId}")
public ResponseDTO<Void> forceLogout(@PathVariable String tokenId) {
CacheCenter.loginUserCache.delete(tokenId);
return ResponseDTO.ok();
}
}

View File

@@ -1,106 +0,0 @@
package com.agileboot.admin.controller.system;
import com.agileboot.common.core.base.BaseController;
import com.agileboot.common.core.dto.ResponseDTO;
import com.agileboot.common.core.page.PageDTO;
import com.agileboot.domain.common.cache.CacheCenter;
import com.agileboot.domain.system.config.ConfigApplicationService;
import com.agileboot.domain.system.config.command.ConfigUpdateCommand;
import com.agileboot.domain.system.config.dto.ConfigDTO;
import com.agileboot.domain.system.config.query.ConfigQuery;
import com.agileboot.infrastructure.annotations.AccessLog;
import com.agileboot.infrastructure.cache.map.MapCache;
import com.agileboot.orm.common.enums.BusinessTypeEnum;
import com.agileboot.orm.common.result.DictionaryData;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Positive;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 参数配置 信息操作处理
* @author valarchie
*/
@RestController
@RequestMapping("/system/config")
@Validated
@RequiredArgsConstructor
@Tag(name = "配置API", description = "配置相关的增删查改")
public class SysConfigController extends BaseController {
@NonNull
private ConfigApplicationService configApplicationService;
/**
* 获取参数配置列表
*/
@Operation(summary = "参数列表", description = "分页获取配置参数列表")
@PreAuthorize("@permission.has('system:config:list')")
@GetMapping("/list")
public ResponseDTO<PageDTO<ConfigDTO>> list(ConfigQuery query) {
PageDTO<ConfigDTO> page = configApplicationService.getConfigList(query);
return ResponseDTO.ok(page);
}
/**
* 根据字典类型查询字典数据信息
* 换成用Enum
*/
@GetMapping(value = "/dict/{dictType}")
@Operation(summary = "字典数据", description = "获取字典列表")
@Parameter(name = "dictType", description = "字典对应类别")
public ResponseDTO<List<DictionaryData>> dictType(@PathVariable String dictType) {
List<DictionaryData> dictionaryData = MapCache.dictionaryCache().get(dictType);
return ResponseDTO.ok(dictionaryData);
}
/**
* 根据参数编号获取详细信息
*/
@PreAuthorize("@permission.has('system:config:query')")
@GetMapping(value = "/{configId}")
@Operation(summary = "配置信息", description = "配置的详细信息")
public ResponseDTO<ConfigDTO> getInfo(@NotNull @Positive @PathVariable Long configId) {
ConfigDTO config = configApplicationService.getConfigInfo(configId);
return ResponseDTO.ok(config);
}
/**
* 修改参数配置
*/
@PreAuthorize("@permission.has('system:config:edit')")
@AccessLog(title = "参数管理", businessType = BusinessTypeEnum.MODIFY)
@Operation(summary = "配置修改", description = "配置修改")
@PutMapping
public ResponseDTO<Void> edit(@RequestBody ConfigUpdateCommand config) {
configApplicationService.updateConfig(config);
return ResponseDTO.ok();
}
/**
* 刷新参数缓存
*/
@Operation(summary = "刷新配置缓存")
@PreAuthorize("@permission.has('system:config:remove')")
@AccessLog(title = "参数管理", businessType = BusinessTypeEnum.CLEAN)
@DeleteMapping("/refreshCache")
public ResponseDTO<Void> refreshCache() {
CacheCenter.configCache.invalidateAll();
return ResponseDTO.ok();
}
}

View File

@@ -1,112 +0,0 @@
package com.agileboot.admin.controller.system;
import cn.hutool.core.lang.tree.Tree;
import com.agileboot.common.core.base.BaseController;
import com.agileboot.common.core.dto.ResponseDTO;
import com.agileboot.domain.system.dept.DeptApplicationService;
import com.agileboot.domain.system.dept.command.AddDeptCommand;
import com.agileboot.domain.system.dept.command.UpdateDeptCommand;
import com.agileboot.domain.system.dept.dto.DeptDTO;
import com.agileboot.domain.system.dept.query.DeptQuery;
import com.agileboot.infrastructure.annotations.AccessLog;
import com.agileboot.orm.common.enums.BusinessTypeEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import javax.validation.constraints.NotNull;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 部门信息
*
* @author valarchie
*/
@RestController
@RequestMapping("/system/dept")
@Validated
@RequiredArgsConstructor
@Tag(name = "部门API", description = "部门相关的增删查改")
public class SysDeptController extends BaseController {
@NonNull
private DeptApplicationService deptApplicationService;
/**
* 获取部门列表
*/
@Operation(summary = "部门列表")
@PreAuthorize("@permission.has('system:dept:list')")
@GetMapping("/list")
public ResponseDTO<List<DeptDTO>> list(DeptQuery query) {
List<DeptDTO> deptList = deptApplicationService.getDeptList(query);
return ResponseDTO.ok(deptList);
}
/**
* 根据部门编号获取详细信息
*/
@Operation(summary = "部门详情")
@PreAuthorize("@permission.has('system:dept:query')")
@GetMapping(value = "/{deptId}")
public ResponseDTO<DeptDTO> getInfo(@PathVariable Long deptId) {
DeptDTO dept = deptApplicationService.getDeptInfo(deptId);
return ResponseDTO.ok(dept);
}
/**
* 获取部门下拉树列表
*/
@Operation(summary = "获取部门树级结构")
@GetMapping("/dropdownList")
public ResponseDTO<List<Tree<Long>>> dropdownList() {
List<Tree<Long>> deptTree = deptApplicationService.getDeptTree();
return ResponseDTO.ok(deptTree);
}
/**
* 新增部门
*/
@Operation(summary = "新增部门")
@PreAuthorize("@permission.has('system:dept:add')")
@AccessLog(title = "部门管理", businessType = BusinessTypeEnum.ADD)
@PostMapping
public ResponseDTO<Void> add(@RequestBody AddDeptCommand addCommand) {
deptApplicationService.addDept(addCommand);
return ResponseDTO.ok();
}
/**
* 修改部门
*/
@Operation(summary = "修改部门")
@PreAuthorize("@permission.has('system:dept:edit') AND @dataScope.checkDeptId(#updateCommand.deptId)")
@AccessLog(title = "部门管理", businessType = BusinessTypeEnum.MODIFY)
@PutMapping
public ResponseDTO<Void> edit(@RequestBody UpdateDeptCommand updateCommand) {
deptApplicationService.updateDept(updateCommand);
return ResponseDTO.ok();
}
/**
* 删除部门
*/
@Operation(summary = "删除部门")
@PreAuthorize("@permission.has('system:dept:remove') AND @dataScope.checkDeptId(#deptId)")
@AccessLog(title = "部门管理", businessType = BusinessTypeEnum.DELETE)
@DeleteMapping("/{deptId}")
public ResponseDTO<Void> remove(@PathVariable @NotNull Long deptId) {
deptApplicationService.removeDept(deptId);
return ResponseDTO.ok();
}
}

View File

@@ -1,80 +0,0 @@
package com.agileboot.admin.controller.system;
import com.agileboot.common.core.base.BaseController;
import com.agileboot.common.core.dto.ResponseDTO;
import com.agileboot.common.core.page.PageDTO;
import com.agileboot.common.exception.error.ErrorCode;
import com.agileboot.common.utils.poi.CustomExcelUtil;
import com.agileboot.domain.common.command.BulkOperationCommand;
import com.agileboot.domain.system.logininfo.LoginInfoApplicationService;
import com.agileboot.domain.system.logininfo.dto.LoginInfoDTO;
import com.agileboot.domain.system.logininfo.query.LoginInfoQuery;
import com.agileboot.infrastructure.annotations.AccessLog;
import com.agileboot.orm.common.enums.BusinessTypeEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 系统访问记录
*
* @author valarchie
*/
@Tag(name = "登录日志API", description = "登录日志相关API")
@RestController
@RequestMapping("/loginInfo")
@Validated
@RequiredArgsConstructor
public class SysLoginInfoController extends BaseController {
@NonNull
private LoginInfoApplicationService loginInfoApplicationService;
@Operation(summary = "日志列表")
@PreAuthorize("@permission.has('monitor:logininfor:list')")
@GetMapping("/list")
public ResponseDTO<PageDTO<LoginInfoDTO>> list(LoginInfoQuery query) {
PageDTO<LoginInfoDTO> pageDTO = loginInfoApplicationService.getLoginInfoList(query);
return ResponseDTO.ok(pageDTO);
}
@Operation(summary = "日志列表导出", description = "将登录日志导出到excel")
@AccessLog(title = "登录日志", businessType = BusinessTypeEnum.EXPORT)
@PreAuthorize("@permission.has('monitor:logininfor:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, LoginInfoQuery query) {
PageDTO<LoginInfoDTO> pageDTO = loginInfoApplicationService.getLoginInfoList(query);
CustomExcelUtil.writeToResponse(pageDTO.getRows(), LoginInfoDTO.class, response);
}
@Operation(summary = "删除登录日志")
@PreAuthorize("@permission.has('monitor:logininfor:remove')")
@AccessLog(title = "登录日志", businessType = BusinessTypeEnum.DELETE)
@DeleteMapping("/{infoIds}")
public ResponseDTO<Void> remove(@PathVariable @NotNull @NotEmpty List<Long> infoIds) {
loginInfoApplicationService.deleteLoginInfo(new BulkOperationCommand<>(infoIds));
return ResponseDTO.ok();
}
@Operation(summary = "清空登录日志", description = "暂时不支持")
@PreAuthorize("@permission.has('monitor:logininfor:remove')")
@AccessLog(title = "登录日志", businessType = BusinessTypeEnum.CLEAN)
@DeleteMapping("/clean")
public ResponseDTO<Void> clean() {
return ResponseDTO.fail(ErrorCode.Business.UNSUPPORTED_OPERATION);
}
}

View File

@@ -1,118 +0,0 @@
package com.agileboot.admin.controller.system;
import cn.hutool.core.lang.tree.Tree;
import com.agileboot.common.core.base.BaseController;
import com.agileboot.common.core.dto.ResponseDTO;
import com.agileboot.domain.system.menu.MenuApplicationService;
import com.agileboot.domain.system.menu.command.AddMenuCommand;
import com.agileboot.domain.system.menu.command.UpdateMenuCommand;
import com.agileboot.domain.system.menu.dto.MenuDTO;
import com.agileboot.domain.system.menu.query.MenuQuery;
import com.agileboot.infrastructure.annotations.AccessLog;
import com.agileboot.infrastructure.security.AuthenticationUtils;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.orm.common.enums.BusinessTypeEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.PositiveOrZero;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 菜单信息
*
* @author valarchie
*/
@Tag(name = "菜单API", description = "菜单相关的增删查改")
@RestController
@RequestMapping("/system/menu")
@Validated
@RequiredArgsConstructor
public class SysMenuController extends BaseController {
@NonNull
MenuApplicationService menuApplicationService;
/**
* 获取菜单列表
*/
@Operation(summary = "菜单列表")
@PreAuthorize("@permission.has('system:menu:list')")
@GetMapping("/list")
public ResponseDTO<List<MenuDTO>> list(MenuQuery query) {
List<MenuDTO> menuList = menuApplicationService.getMenuList(query);
return ResponseDTO.ok(menuList);
}
/**
* 根据菜单编号获取详细信息
*/
@Operation(summary = "菜单详情")
@PreAuthorize("@permission.has('system:menu:query')")
@GetMapping(value = "/{menuId}")
public ResponseDTO<MenuDTO> getInfo(@PathVariable @NotNull @PositiveOrZero Long menuId) {
MenuDTO menu = menuApplicationService.getMenuInfo(menuId);
return ResponseDTO.ok(menu);
}
/**
* 获取菜单下拉树列表
*/
@Operation(summary = "菜单列表(树级)", description = "菜单树级下拉框")
@GetMapping("/dropdownList")
public ResponseDTO<List<Tree<Long>>> dropdownList() {
LoginUser loginUser = AuthenticationUtils.getLoginUser();
List<Tree<Long>> dropdownList = menuApplicationService.getDropdownList(loginUser);
return ResponseDTO.ok(dropdownList);
}
/**
* 新增菜单
*/
@Operation(summary = "添加菜单")
@PreAuthorize("@permission.has('system:menu:add')")
@AccessLog(title = "菜单管理", businessType = BusinessTypeEnum.ADD)
@PostMapping
public ResponseDTO<Void> add(@RequestBody AddMenuCommand addCommand) {
menuApplicationService.addMenu(addCommand);
return ResponseDTO.ok();
}
/**
* 修改菜单
*/
@Operation(summary = "编辑菜单")
@PreAuthorize("@permission.has('system:menu:edit')")
@AccessLog(title = "菜单管理", businessType = BusinessTypeEnum.MODIFY)
@PutMapping
public ResponseDTO<Void> edit(@RequestBody UpdateMenuCommand updateCommand) {
menuApplicationService.updateMenu(updateCommand);
return ResponseDTO.ok();
}
/**
* 删除菜单
*/
@Operation(summary = "删除菜单")
@PreAuthorize("@permission.has('system:menu:remove')")
@AccessLog(title = "菜单管理", businessType = BusinessTypeEnum.DELETE)
@DeleteMapping("/{menuId}")
public ResponseDTO<Void> remove(@PathVariable("menuId") Long menuId) {
menuApplicationService.remove(menuId);
return ResponseDTO.ok();
}
}

View File

@@ -1,121 +0,0 @@
package com.agileboot.admin.controller.system;
import com.agileboot.common.core.base.BaseController;
import com.agileboot.common.core.dto.ResponseDTO;
import com.agileboot.common.core.page.PageDTO;
import com.agileboot.domain.common.command.BulkOperationCommand;
import com.agileboot.domain.system.notice.NoticeApplicationService;
import com.agileboot.domain.system.notice.command.NoticeAddCommand;
import com.agileboot.domain.system.notice.command.NoticeUpdateCommand;
import com.agileboot.domain.system.notice.dto.NoticeDTO;
import com.agileboot.domain.system.notice.query.NoticeQuery;
import com.agileboot.infrastructure.annotations.AccessLog;
import com.agileboot.infrastructure.annotations.Unrepeatable;
import com.agileboot.orm.common.enums.BusinessTypeEnum;
import com.baomidou.dynamic.datasource.annotation.DS;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Positive;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 公告 信息操作处理
*
* @author valarchie
*/
@Tag(name = "公告API", description = "公告相关的增删查改")
@RestController
@RequestMapping("/system/notice")
@Validated
@RequiredArgsConstructor
public class SysNoticeController extends BaseController {
@NonNull
private NoticeApplicationService noticeApplicationService;
/**
* 获取通知公告列表
*/
@Operation(summary = "公告列表")
@PreAuthorize("@permission.has('system:notice:list')")
@GetMapping("/list")
public ResponseDTO<PageDTO<NoticeDTO>> list(NoticeQuery query) {
PageDTO<NoticeDTO> pageDTO = noticeApplicationService.getNoticeList(query);
return ResponseDTO.ok(pageDTO);
}
/**
* 获取通知公告列表
* 从从库获取数据 例子 仅供参考
*/
@Operation(summary = "公告列表(从数据库从库获取)", description = "演示主从库的例子")
@DS("slave")
@PreAuthorize("@permission.has('system:notice:list')")
@GetMapping("/listFromSlave")
public ResponseDTO<PageDTO<NoticeDTO>> listFromSlave(NoticeQuery query) {
PageDTO<NoticeDTO> pageDTO = noticeApplicationService.getNoticeList(query);
return ResponseDTO.ok(pageDTO);
}
/**
* 根据通知公告编号获取详细信息
*/
@Operation(summary = "公告详情")
@PreAuthorize("@permission.has('system:notice:query')")
@GetMapping(value = "/{noticeId}")
public ResponseDTO<NoticeDTO> getInfo(@PathVariable @NotNull @Positive Long noticeId) {
return ResponseDTO.ok(noticeApplicationService.getNoticeInfo(noticeId));
}
/**
* 新增通知公告
*/
@Operation(summary = "添加公告")
@Unrepeatable(interval = 60)
@PreAuthorize("@permission.has('system:notice:add')")
@AccessLog(title = "通知公告", businessType = BusinessTypeEnum.ADD)
@PostMapping
public ResponseDTO<Void> add(@RequestBody NoticeAddCommand addCommand) {
noticeApplicationService.addNotice(addCommand);
return ResponseDTO.ok();
}
/**
* 修改通知公告
*/
@Operation(summary = "修改公告")
@PreAuthorize("@permission.has('system:notice:edit')")
@AccessLog(title = "通知公告", businessType = BusinessTypeEnum.MODIFY)
@PutMapping
public ResponseDTO<Void> edit(@RequestBody NoticeUpdateCommand updateCommand) {
noticeApplicationService.updateNotice(updateCommand);
return ResponseDTO.ok();
}
/**
* 删除通知公告
*/
@Operation(summary = "删除公告")
@PreAuthorize("@permission.has('system:notice:remove')")
@AccessLog(title = "通知公告", businessType = BusinessTypeEnum.DELETE)
@DeleteMapping("/{noticeIds}")
public ResponseDTO<Void> remove(@PathVariable List<Integer> noticeIds) {
noticeApplicationService.deleteNotice(new BulkOperationCommand<>(noticeIds));
return ResponseDTO.ok();
}
}

View File

@@ -1,75 +0,0 @@
package com.agileboot.admin.controller.system;
import com.agileboot.common.core.base.BaseController;
import com.agileboot.common.core.dto.ResponseDTO;
import com.agileboot.common.core.page.PageDTO;
import com.agileboot.common.exception.error.ErrorCode;
import com.agileboot.common.utils.poi.CustomExcelUtil;
import com.agileboot.domain.common.command.BulkOperationCommand;
import com.agileboot.domain.system.operationlog.OperationLogApplicationService;
import com.agileboot.domain.system.operationlog.dto.OperationLogDTO;
import com.agileboot.domain.system.operationlog.query.OperationLogQuery;
import com.agileboot.infrastructure.annotations.AccessLog;
import com.agileboot.orm.common.enums.BusinessTypeEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 操作日志记录
*
* @author valarchie
*/
@Tag(name = "操作日志API", description = "操作日志相关接口")
@RestController
@RequestMapping("/operationLog")
@RequiredArgsConstructor
public class SysOperationLogController extends BaseController {
@NonNull
private OperationLogApplicationService operationLogApplicationService;
@Operation(summary = "操作日志列表")
@PreAuthorize("@permission.has('monitor:operlog:list')")
@GetMapping("/list")
public ResponseDTO<PageDTO<OperationLogDTO>> list(OperationLogQuery query) {
PageDTO<OperationLogDTO> pageDTO = operationLogApplicationService.getOperationLogList(query);
return ResponseDTO.ok(pageDTO);
}
@Operation(summary = "操作日志导出")
@AccessLog(title = "操作日志", businessType = BusinessTypeEnum.EXPORT)
@PreAuthorize("@permission.has('monitor:operlog:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, OperationLogQuery query) {
PageDTO<OperationLogDTO> pageDTO = operationLogApplicationService.getOperationLogList(query);
CustomExcelUtil.writeToResponse(pageDTO.getRows(), OperationLogDTO.class, response);
}
@Operation(summary = "删除操作日志")
@AccessLog(title = "操作日志", businessType = BusinessTypeEnum.DELETE)
@PreAuthorize("@permission.has('monitor:operlog:remove')")
@DeleteMapping("/{operationIds}")
public ResponseDTO<Void> remove(@PathVariable List<Long> operationIds) {
operationLogApplicationService.deleteOperationLog(new BulkOperationCommand<>(operationIds));
return ResponseDTO.ok();
}
@Operation(summary = "清空操作日志", description = "暂未支持")
@AccessLog(title = "操作日志", businessType = BusinessTypeEnum.CLEAN)
@PreAuthorize("@permission.has('monitor:operlog:remove')")
@DeleteMapping("/clean")
public ResponseDTO<Void> clean() {
return ResponseDTO.fail(ErrorCode.Business.UNSUPPORTED_OPERATION);
}
}

View File

@@ -1,114 +0,0 @@
package com.agileboot.admin.controller.system;
import com.agileboot.common.core.base.BaseController;
import com.agileboot.common.core.dto.ResponseDTO;
import com.agileboot.common.core.page.PageDTO;
import com.agileboot.common.utils.poi.CustomExcelUtil;
import com.agileboot.domain.common.command.BulkOperationCommand;
import com.agileboot.domain.system.post.PostApplicationService;
import com.agileboot.domain.system.post.command.AddPostCommand;
import com.agileboot.domain.system.post.command.UpdatePostCommand;
import com.agileboot.domain.system.post.dto.PostDTO;
import com.agileboot.domain.system.post.query.PostQuery;
import com.agileboot.infrastructure.annotations.AccessLog;
import com.agileboot.orm.common.enums.BusinessTypeEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 岗位信息操作处理
*
* @author ruoyi
*/
@Tag(name = "职位API", description = "职位相关的增删查改")
@RestController
@RequestMapping("/system/post")
@Validated
@RequiredArgsConstructor
public class SysPostController extends BaseController {
@NonNull
private PostApplicationService postApplicationService;
/**
* 获取岗位列表
*/
@Operation(summary = "职位列表")
@PreAuthorize("@permission.has('system:post:list')")
@GetMapping("/list")
public ResponseDTO<PageDTO<PostDTO>> list(PostQuery query) {
PageDTO<PostDTO> pageDTO = postApplicationService.getPostList(query);
return ResponseDTO.ok(pageDTO);
}
@Operation(summary = "职位列表导出")
@AccessLog(title = "岗位管理", businessType = BusinessTypeEnum.EXPORT)
@PreAuthorize("@permission.has('system:post:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, PostQuery query) {
PageDTO<PostDTO> pageDTO = postApplicationService.getPostList(query);
CustomExcelUtil.writeToResponse(pageDTO.getRows(), PostDTO.class, response);
}
/**
* 根据岗位编号获取详细信息
*/
@Operation(summary = "职位详情")
@PreAuthorize("@permission.has('system:post:query')")
@GetMapping(value = "/{postId}")
public ResponseDTO<PostDTO> getInfo(@PathVariable Long postId) {
PostDTO post = postApplicationService.getPostInfo(postId);
return ResponseDTO.ok(post);
}
/**
* 新增岗位
*/
@Operation(summary = "添加职位")
@PreAuthorize("@permission.has('system:post:add')")
@AccessLog(title = "岗位管理", businessType = BusinessTypeEnum.ADD)
@PostMapping
public ResponseDTO<Void> add(@RequestBody AddPostCommand addCommand) {
postApplicationService.addPost(addCommand);
return ResponseDTO.ok();
}
/**
* 修改岗位
*/
@Operation(summary = "修改职位")
@PreAuthorize("@permission.has('system:post:edit')")
@AccessLog(title = "岗位管理", businessType = BusinessTypeEnum.MODIFY)
@PutMapping
public ResponseDTO<Void> edit(@RequestBody UpdatePostCommand updateCommand) {
postApplicationService.updatePost(updateCommand);
return ResponseDTO.ok();
}
/**
* 删除岗位
*/
@Operation(summary = "删除职位")
@PreAuthorize("@permission.has('system:post:remove')")
@AccessLog(title = "岗位管理", businessType = BusinessTypeEnum.DELETE)
@DeleteMapping("/{postIds}")
public ResponseDTO<Void> remove(@PathVariable List<Long> postIds) {
postApplicationService.deletePost(new BulkOperationCommand<>(postIds));
return ResponseDTO.ok();
}
}

View File

@@ -1,99 +0,0 @@
package com.agileboot.admin.controller.system;
import com.agileboot.common.constant.Constants.UploadSubDir;
import com.agileboot.common.core.base.BaseController;
import com.agileboot.common.core.dto.ResponseDTO;
import com.agileboot.common.exception.ApiException;
import com.agileboot.common.exception.error.ErrorCode;
import com.agileboot.common.utils.file.FileUploadUtils;
import com.agileboot.domain.common.dto.UploadFileDTO;
import com.agileboot.domain.system.user.UserApplicationService;
import com.agileboot.domain.system.user.command.UpdateProfileCommand;
import com.agileboot.domain.system.user.command.UpdateUserAvatarCommand;
import com.agileboot.domain.system.user.command.UpdateUserPasswordCommand;
import com.agileboot.domain.system.user.dto.UserProfileDTO;
import com.agileboot.infrastructure.annotations.AccessLog;
import com.agileboot.infrastructure.security.AuthenticationUtils;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.orm.common.enums.BusinessTypeEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
/**
* 个人信息 业务处理
*
* @author ruoyi
*/
@Tag(name = "个人信息API", description = "个人信息相关接口")
@RestController
@RequestMapping("/system/user/profile")
@RequiredArgsConstructor
public class SysProfileController extends BaseController {
@NonNull
private UserApplicationService userApplicationService;
/**
* 个人信息
*/
@Operation(summary = "获取个人信息")
@GetMapping
public ResponseDTO<UserProfileDTO> profile() {
LoginUser user = AuthenticationUtils.getLoginUser();
UserProfileDTO userProfile = userApplicationService.getUserProfile(user.getUserId());
return ResponseDTO.ok(userProfile);
}
/**
* 修改用户
*/
@Operation(summary = "修改个人信息")
@AccessLog(title = "个人信息", businessType = BusinessTypeEnum.MODIFY)
@PutMapping
public ResponseDTO<Void> updateProfile(@RequestBody UpdateProfileCommand command) {
LoginUser loginUser = AuthenticationUtils.getLoginUser();
command.setUserId(loginUser.getUserId());
userApplicationService.updateUserProfile(command);
return ResponseDTO.ok();
}
/**
* 重置密码
*/
@Operation(summary = "重置个人密码")
@AccessLog(title = "个人信息", businessType = BusinessTypeEnum.MODIFY)
@PutMapping("/password")
public ResponseDTO<Void> updatePassword(@RequestBody UpdateUserPasswordCommand command) {
LoginUser loginUser = AuthenticationUtils.getLoginUser();
command.setUserId(loginUser.getUserId());
userApplicationService.updatePasswordBySelf(loginUser, command);
return ResponseDTO.ok();
}
/**
* 头像上传
*/
@Operation(summary = "修改个人头像")
@AccessLog(title = "用户头像", businessType = BusinessTypeEnum.MODIFY)
@PostMapping("/avatar")
public ResponseDTO<UploadFileDTO> avatar(@RequestParam("avatarfile") MultipartFile file) {
if (file.isEmpty()) {
throw new ApiException(ErrorCode.Business.USER_UPLOAD_FILE_FAILED);
}
LoginUser loginUser = AuthenticationUtils.getLoginUser();
String avatarUrl = FileUploadUtils.upload(UploadSubDir.AVATAR_PATH, file);
userApplicationService.updateUserAvatar(new UpdateUserAvatarCommand(loginUser.getUserId(), avatarUrl));
return ResponseDTO.ok(new UploadFileDTO(avatarUrl));
}
}

View File

@@ -1,199 +0,0 @@
package com.agileboot.admin.controller.system;
import com.agileboot.common.core.base.BaseController;
import com.agileboot.common.core.dto.ResponseDTO;
import com.agileboot.common.core.page.PageDTO;
import com.agileboot.common.utils.poi.CustomExcelUtil;
import com.agileboot.domain.system.role.RoleApplicationService;
import com.agileboot.domain.system.role.command.AddRoleCommand;
import com.agileboot.domain.system.role.command.UpdateDataScopeCommand;
import com.agileboot.domain.system.role.command.UpdateRoleCommand;
import com.agileboot.domain.system.role.command.UpdateStatusCommand;
import com.agileboot.domain.system.role.dto.RoleDTO;
import com.agileboot.domain.system.role.query.AllocatedRoleQuery;
import com.agileboot.domain.system.role.query.RoleQuery;
import com.agileboot.domain.system.role.query.UnallocatedRoleQuery;
import com.agileboot.domain.system.user.dto.UserDTO;
import com.agileboot.infrastructure.annotations.AccessLog;
import com.agileboot.orm.common.enums.BusinessTypeEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 角色信息
*
* @author valarchie
*/
@Tag(name = "角色API", description = "角色相关的增删查改")
@RestController
@RequestMapping("/system/role")
@Validated
@RequiredArgsConstructor
public class SysRoleController extends BaseController {
@NonNull
private RoleApplicationService roleApplicationService;
@Operation(summary = "角色列表")
@PreAuthorize("@permission.has('system:role:list')")
@GetMapping("/list")
public ResponseDTO<PageDTO<RoleDTO>> list(RoleQuery query) {
PageDTO<RoleDTO> pageDTO = roleApplicationService.getRoleList(query);
return ResponseDTO.ok(pageDTO);
}
@Operation(summary = "角色列表导出")
@AccessLog(title = "角色管理", businessType = BusinessTypeEnum.EXPORT)
@PreAuthorize("@permission.has('system:role:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, RoleQuery query) {
PageDTO<RoleDTO> pageDTO = roleApplicationService.getRoleList(query);
CustomExcelUtil.writeToResponse(pageDTO.getRows(), RoleDTO.class, response);
}
/**
* 根据角色编号获取详细信息
*/
@Operation(summary = "角色详情")
@PreAuthorize("@permission.has('system:role:query')")
@GetMapping(value = "/{roleId}")
public ResponseDTO<RoleDTO> getInfo(@PathVariable @NotNull Long roleId) {
RoleDTO roleInfo = roleApplicationService.getRoleInfo(roleId);
return ResponseDTO.ok(roleInfo);
}
/**
* 新增角色
*/
@Operation(summary = "添加角色")
@PreAuthorize("@permission.has('system:role:add')")
@AccessLog(title = "角色管理", businessType = BusinessTypeEnum.ADD)
@PostMapping
public ResponseDTO<Void> add(@RequestBody AddRoleCommand addCommand) {
roleApplicationService.addRole(addCommand);
return ResponseDTO.ok();
}
/**
* 移除角色
*/
@Operation(summary = "删除角色")
@PreAuthorize("@permission.has('system:role:remove')")
@AccessLog(title = "角色管理", businessType = BusinessTypeEnum.ADD)
@DeleteMapping(value = "/{roleId}")
public ResponseDTO<Void> remove(@PathVariable("roleId") List<Long> roleIds) {
roleApplicationService.deleteRoleByBulk(roleIds);
return ResponseDTO.ok();
}
/**
* 修改保存角色
*/
@Operation(summary = "修改角色")
@PreAuthorize("@permission.has('system:role:edit')")
@AccessLog(title = "角色管理", businessType = BusinessTypeEnum.MODIFY)
@PutMapping
public ResponseDTO<Void> edit(@Validated @RequestBody UpdateRoleCommand updateCommand) {
roleApplicationService.updateRole(updateCommand);
return ResponseDTO.ok();
}
/**
* 修改保存数据权限
*/
@Operation(summary = "修改角色数据权限")
@PreAuthorize("@permission.has('system:role:edit')")
@AccessLog(title = "角色管理", businessType = BusinessTypeEnum.MODIFY)
@PutMapping("/{roleId}/dataScope")
public ResponseDTO<Void> dataScope(@PathVariable("roleId") Long roleId,
@RequestBody UpdateDataScopeCommand command) {
command.setRoleId(roleId);
roleApplicationService.updateDataScope(command);
return ResponseDTO.ok();
}
/**
* 角色状态修改
*/
@Operation(summary = "修改角色状态")
@PreAuthorize("@permission.has('system:role:edit')")
@AccessLog(title = "角色管理", businessType = BusinessTypeEnum.MODIFY)
@PutMapping("/{roleId}/status")
public ResponseDTO<Void> changeStatus(@PathVariable("roleId") Long roleId,
@RequestBody UpdateStatusCommand command) {
command.setRoleId(roleId);
roleApplicationService.updateStatus(command);
return ResponseDTO.ok();
}
/**
* 查询已分配用户角色列表
*/
@Operation(summary = "已关联该角色的用户列表")
@PreAuthorize("@permission.has('system:role:list')")
@GetMapping("/{roleId}/allocated/list")
public ResponseDTO<PageDTO<UserDTO>> allocatedUserList(@PathVariable("roleId") Long roleId,
AllocatedRoleQuery query) {
query.setRoleId(roleId);
PageDTO<UserDTO> page = roleApplicationService.getAllocatedUserList(query);
return ResponseDTO.ok(page);
}
/**
* 查询未分配用户角色列表
*/
@Operation(summary = "未关联该角色的用户列表")
@PreAuthorize("@permission.has('system:role:list')")
@GetMapping("/{roleId}/unallocated/list")
public ResponseDTO<PageDTO<UserDTO>> unallocatedUserList(@PathVariable("roleId") Long roleId,
UnallocatedRoleQuery query) {
query.setRoleId(roleId);
PageDTO<UserDTO> page = roleApplicationService.getUnallocatedUserList(query);
return ResponseDTO.ok(page);
}
/**
* 批量取消授权用户
*/
@Operation(summary = "批量解除角色和用户的关联")
@PreAuthorize("@permission.has('system:role:edit')")
@AccessLog(title = "角色管理", businessType = BusinessTypeEnum.GRANT)
@DeleteMapping("/users/{userIds}/grant/bulk")
public ResponseDTO<Void> deleteRoleOfUserByBulk(@PathVariable("userIds") List<Long> userIds) {
roleApplicationService.deleteRoleOfUserByBulk(userIds);
return ResponseDTO.ok();
}
/**
* 批量选择用户授权
*/
@Operation(summary = "批量添加用户和角色关联")
@PreAuthorize("@permission.has('system:role:edit')")
@AccessLog(title = "角色管理", businessType = BusinessTypeEnum.GRANT)
@PostMapping("/{roleId}/users/{userIds}/grant/bulk")
public ResponseDTO<Void> addRoleForUserByBulk(@PathVariable("roleId") Long roleId,
@PathVariable("userIds") List<Long> userIds) {
roleApplicationService.addRoleOfUserByBulk(roleId, userIds);
return ResponseDTO.ok();
}
}

View File

@@ -1,172 +0,0 @@
package com.agileboot.admin.controller.system;
import cn.hutool.core.collection.ListUtil;
import com.agileboot.common.core.base.BaseController;
import com.agileboot.common.core.dto.ResponseDTO;
import com.agileboot.common.core.page.PageDTO;
import com.agileboot.common.utils.poi.CustomExcelUtil;
import com.agileboot.domain.common.command.BulkOperationCommand;
import com.agileboot.domain.system.user.UserApplicationService;
import com.agileboot.domain.system.user.command.AddUserCommand;
import com.agileboot.domain.system.user.command.ChangeStatusCommand;
import com.agileboot.domain.system.user.command.ResetPasswordCommand;
import com.agileboot.domain.system.user.command.UpdateUserCommand;
import com.agileboot.domain.system.user.dto.UserDTO;
import com.agileboot.domain.system.user.dto.UserDetailDTO;
import com.agileboot.domain.system.user.query.SearchUserQuery;
import com.agileboot.infrastructure.annotations.AccessLog;
import com.agileboot.infrastructure.security.AuthenticationUtils;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.orm.common.enums.BusinessTypeEnum;
import com.agileboot.orm.system.result.SearchUserDO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
/**
* 用户信息
*
* @author ruoyi
*/
@Tag(name = "用户API", description = "用户相关的增删查改")
@RestController
@RequestMapping("/system/user")
@RequiredArgsConstructor
public class SysUserController extends BaseController {
@NonNull
private UserApplicationService userApplicationService;
/**
* 获取用户列表
*/
@Operation(summary = "用户列表")
@PreAuthorize("@permission.has('system:user:list') AND @dataScope.checkDeptId(#query.deptId)")
@GetMapping("/list")
public ResponseDTO<PageDTO<UserDTO>> list(SearchUserQuery<SearchUserDO> query) {
PageDTO<UserDTO> page = userApplicationService.getUserList(query);
return ResponseDTO.ok(page);
}
@Operation(summary = "用户列表导出")
@AccessLog(title = "用户管理", businessType = BusinessTypeEnum.EXPORT)
@PreAuthorize("@permission.has('system:user:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, SearchUserQuery<SearchUserDO> query) {
PageDTO<UserDTO> userList = userApplicationService.getUserList(query);
CustomExcelUtil.writeToResponse(userList.getRows(), UserDTO.class, response);
}
@Operation(summary = "用户列表导入")
@AccessLog(title = "用户管理", businessType = BusinessTypeEnum.IMPORT)
@PreAuthorize("@permission.has('system:user:import')")
@PostMapping("/importData")
public ResponseDTO<Void> importData(MultipartFile file) {
List<AddUserCommand> commands = CustomExcelUtil.readFromRequest(AddUserCommand.class, file);
for (AddUserCommand command : commands) {
userApplicationService.addUser(command);
}
return ResponseDTO.ok();
}
/**
* 下载批量导入模板
*/
@Operation(summary = "用户导入excel下载")
@PostMapping("/downloadTemplate")
public void downloadTemplate(HttpServletResponse response) {
CustomExcelUtil.writeToResponse(ListUtil.toList(new AddUserCommand()), AddUserCommand.class, response);
}
/**
* 根据用户编号获取详细信息
*/
@Operation(summary = "用户详情")
@PreAuthorize("@permission.has('system:user:query')")
@GetMapping(value = {"/", "/{userId}"})
public ResponseDTO<UserDetailDTO> getUserDetailInfo(@PathVariable(value = "userId", required = false) Long userId) {
UserDetailDTO userDetailInfo = userApplicationService.getUserDetailInfo(userId);
return ResponseDTO.ok(userDetailInfo);
}
/**
* 新增用户
*/
@Operation(summary = "新增用户")
@PreAuthorize("@permission.has('system:user:add') AND @dataScope.checkDeptId(#command.deptId)")
@AccessLog(title = "用户管理", businessType = BusinessTypeEnum.ADD)
@PostMapping
public ResponseDTO<Void> add(@Validated @RequestBody AddUserCommand command) {
userApplicationService.addUser(command);
return ResponseDTO.ok();
}
/**
* 修改用户
*/
@Operation(summary = "修改用户")
@PreAuthorize("@permission.has('system:user:edit') AND @dataScope.checkUserId(#command.userId)")
@AccessLog(title = "用户管理", businessType = BusinessTypeEnum.MODIFY)
@PutMapping
public ResponseDTO<Void> edit(@Validated @RequestBody UpdateUserCommand command) {
userApplicationService.updateUser(command);
return ResponseDTO.ok();
}
/**
* 删除用户
*/
@Operation(summary = "删除用户")
@PreAuthorize("@permission.has('system:user:remove') AND @dataScope.checkUserIds(#userIds)")
@AccessLog(title = "用户管理", businessType = BusinessTypeEnum.DELETE)
@DeleteMapping("/{userIds}")
public ResponseDTO<Void> remove(@PathVariable List<Long> userIds) {
BulkOperationCommand<Long> bulkDeleteCommand = new BulkOperationCommand<>(userIds);
LoginUser loginUser = AuthenticationUtils.getLoginUser();
userApplicationService.deleteUsers(loginUser, bulkDeleteCommand);
return ResponseDTO.ok();
}
/**
* 重置密码
*/
@Operation(summary = "重置用户密码")
@PreAuthorize("@permission.has('system:user:resetPwd') AND @dataScope.checkUserId(#userId)")
@AccessLog(title = "用户管理", businessType = BusinessTypeEnum.MODIFY)
@PutMapping("/{userId}/password/reset")
public ResponseDTO<Void> resetPassword(@PathVariable Long userId, @RequestBody ResetPasswordCommand command) {
command.setUserId(userId);
userApplicationService.resetUserPassword(command);
return ResponseDTO.ok();
}
/**
* 状态修改
*/
@Operation(summary = "修改用户状态")
@PreAuthorize("@permission.has('system:user:edit') AND @dataScope.checkUserId(#command.userId)")
@AccessLog(title = "用户管理", businessType = BusinessTypeEnum.MODIFY)
@PutMapping("/{userId}/status")
public ResponseDTO<Void> changeStatus(@PathVariable Long userId, @RequestBody ChangeStatusCommand command) {
command.setUserId(userId);
userApplicationService.changeUserStatus(command);
return ResponseDTO.ok();
}
}

View File

@@ -1,46 +0,0 @@
package com.agileboot.admin.controller.tool;
import cn.hutool.core.net.URLEncodeUtil;
import cn.hutool.core.util.CharsetUtil;
import com.agileboot.common.config.AgileBootConfig;
import com.agileboot.common.core.base.BaseController;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
/**
* swagger 接口
* TODO Swagger这边权限拦截并没有生效需要改进
* PreAuthorize注解加在transfer接口上 获取不到登录用户 iframe请求header中没有token
* @author valarchie
*/
@Tag(name = "文档API", description = "角色相关接口")
@RestController
public class SwaggerController extends BaseController {
/**
* TODO 这个接口没有触发, 后续看如何改进, 应该把权限拦截放在下面的接口
*/
@Operation(summary = "文档首页")
@PreAuthorize("@permission.has('tool:swagger:view')")
@GetMapping("/tool/swagger")
public String index() {
return redirect("/doc.html");
}
/**
* 访问首页,提示语
*/
@Operation(summary = "文档接口数据")
@GetMapping("/v3/api-docs/{url}")
public void transfer(HttpServletResponse response, @PathVariable String url) throws IOException {
response.sendRedirect(AgileBootConfig.getApiDocsPathPrefix() + "/v3/api-docs/" + URLEncodeUtil.encode(url,
CharsetUtil.CHARSET_UTF_8));
}
}

View File

@@ -1,49 +0,0 @@
# 开发环境配置
server:
# 服务器的HTTP端口默认为8080
port: 8080
servlet:
# 应用的访问路径
context-path: /
tomcat:
# tomcat的URI编码
uri-encoding: UTF-8
# 连接数满后的排队数默认为100
accept-count: 1000
threads:
# tomcat最大线程数默认为200
max: 800
# Tomcat启动初始化的线程数默认值10
min-spare: 100
# Spring配置 如果需要无Mysql 无Redis直接启动的话 dev改为test
# 生产环境把dev改为prod
spring:
profiles:
active: basic,dev
# 如果需要无Mysql 无Redis直接启动的话 可以将这两个参数置为true, 并且spring.profile.active: dev换成test
# redis的端口可能会被占用如果被占用请自己修改一下端口号
agileboot:
embedded:
mysql: false
redis: false
springdoc:
api-docs:
enabled: true
groups:
enabled: true
group-configs:
- group: '公共管理API'
packages-to-scan: com.agileboot.admin.controller.common
- group: '监控管理API'
packages-to-scan: com.agileboot.admin.controller.monitor
- group: '系统管理API'
packages-to-scan: com.agileboot.admin.controller.system
- group: '工具管理API'
packages-to-scan: com.agileboot.admin.controller.tool

View File

@@ -1,44 +0,0 @@
package com.agileboot.admin.config;
import com.agileboot.admin.AgileBootAdminApplication;
import com.agileboot.common.config.AgileBootConfig;
import com.agileboot.common.constant.Constants.UploadSubDir;
import java.io.File;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.jupiter.api.Assertions;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@SpringBootTest(classes = AgileBootAdminApplication.class)
@RunWith(SpringRunner.class)
public class AgileBootConfigTest {
@Resource
private AgileBootConfig config;
@Test
public void testConfig() {
String fileBaseDir = "D:\\agileboot\\profile";
Assertions.assertEquals("AgileBoot", config.getName());
Assertions.assertEquals("1.0.0", config.getVersion());
Assertions.assertEquals("2022", config.getCopyrightYear());
Assertions.assertTrue(config.isDemoEnabled());
Assertions.assertEquals(fileBaseDir, AgileBootConfig.getFileBaseDir());
Assertions.assertFalse(AgileBootConfig.isAddressEnabled());
Assertions.assertEquals("math", AgileBootConfig.getCaptchaType());
Assertions.assertEquals("math", AgileBootConfig.getCaptchaType());
Assertions.assertEquals(fileBaseDir + "\\import",
AgileBootConfig.getFileBaseDir() + File.separator + UploadSubDir.IMPORT_PATH);
Assertions.assertEquals(fileBaseDir + "\\avatar",
AgileBootConfig.getFileBaseDir() + File.separator + UploadSubDir.AVATAR_PATH);
Assertions.assertEquals(fileBaseDir + "\\download",
AgileBootConfig.getFileBaseDir() + File.separator + UploadSubDir.DOWNLOAD_PATH);
Assertions.assertEquals(fileBaseDir + "\\upload",
AgileBootConfig.getFileBaseDir() + File.separator + UploadSubDir.UPLOAD_PATH);
}
}

View File

@@ -1,32 +0,0 @@
package com.agileboot.api;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
/**
* 启动程序
* 定制banner.txt的网站
* http://patorjk.com/software/taag
* http://www.network-science.de/ascii/
* http://www.degraeve.com/img2txt.php
* http://life.chacuo.net/convertfont2char
* @author valarchie
*/
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@ComponentScan(basePackages = "com.agileboot.*")
public class AgileBooApiApplication {
public static void main(String[] args) {
SpringApplication.run(AgileBooApiApplication.class, args);
String successMsg = " ____ _ _ __ _ _ \n"
+ " / ___| | |_ __ _ _ __ | |_ _ _ _ __ ___ _ _ ___ ___ ___ ___ ___ / _| _ _ | || |\n"
+ " \\___ \\ | __|/ _` || '__|| __| | | | || '_ \\ / __|| | | | / __|/ __|/ _ \\/ __|/ __|| |_ | | | || || |\n"
+ " ___) || |_| (_| || | | |_ | |_| || |_) | \\__ \\| |_| || (__| (__| __/\\__ \\\\__ \\| _|| |_| || ||_|\n"
+ " |____/ \\__|\\__,_||_| \\__| \\__,_|| .__/ |___/ \\__,_| \\___|\\___|\\___||___/|___/|_| \\__,_||_|(_)\n"
+ " |_| ";
System.out.println(successMsg);
}
}

View File

@@ -1,25 +0,0 @@
package com.agileboot.api.controller;
import com.agileboot.common.core.base.BaseController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 调度日志操作处理
*
* @author ruoyi
*/
@RestController
@RequestMapping("/api/order")
public class OrderController extends BaseController {
/**
* 访问首页,提示语
*/
@RequestMapping("/")
public String index() {
return "暂无订单";
}
}

View File

@@ -1,28 +0,0 @@
# 开发环境配置
server:
# 服务器的HTTP端口默认为8080
port: 8090
servlet:
# 应用的访问路径
context-path: /
tomcat:
# tomcat的URI编码
uri-encoding: UTF-8
# 连接数满后的排队数默认为100
accept-count: 1000
threads:
# tomcat最大线程数默认为200
max: 800
# Tomcat启动初始化的线程数默认值10
min-spare: 100
# Spring配置
spring:
profiles:
active: basic,dev

View File

@@ -0,0 +1,52 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.agileboot</groupId>
<artifactId>agileboot</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>agileboot-boot-start</artifactId>
<dependencies>
<dependency>
<groupId>com.agileboot</groupId>
<artifactId>agileboot-system-base</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.agileboot</groupId>
<artifactId>wol-module-ai</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.agileboot</groupId>
<artifactId>wol-auth</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.agileboot</groupId>
<artifactId>wol-codegenerator</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,24 @@
package com.agileboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @Author cuiJiaWang
* @Create 2025-08-12 18:07
*/
@SpringBootApplication(scanBasePackages = "com.agileboot.*")
public class AgilebootBootApplication {
public static void main(String[] args) {
SpringApplication.run(AgilebootBootApplication.class, args);
String successMsg = " ____ _ _ __ _ _ \n"
+ " / ___| | |_ __ _ _ __ | |_ _ _ _ __ ___ _ _ ___ ___ ___ ___ ___ / _| _ _ | || |\n"
+ " \\___ \\ | __|/ _` || '__|| __| | | | || '_ \\ / __|| | | | / __|/ __|/ _ \\/ __|/ __|| |_ | | | || || |\n"
+ " ___) || |_| (_| || | | |_ | |_| || |_) | \\__ \\| |_| || (__| (__| __/\\__ \\\\__ \\| _|| |_| || ||_|\n"
+ " |____/ \\__|\\__,_||_| \\__| \\__,_|| .__/ |___/ \\__,_| \\___|\\___|\\___||___/|___/|_| \\__,_||_|(_)\n"
+ " |_| ";
System.out.println(successMsg);
}
}

View File

@@ -0,0 +1,79 @@
# 数据源配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
druid:
webStatFilter:
enabled: true
statViewServlet:
enabled: true
# 设置白名单,不填则允许所有访问
allow:
url-pattern: /druid/*
# 控制台管理用户名和密码
login-username: agileboot
login-password: 123456
filter:
stat:
enabled: true
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: true
wall:
config:
multi-statement-allow: true
dynamic:
primary: master
strict: false
druid:
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 10
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
datasource:
master:
url: jdbc:mysql://121.41.64.98:3306/agileboot?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&sslMode=REQUIRED
username: agileboot
password: 123456
data:
redis:
database: 3
host: 121.41.64.98
port: 6379
password: 'Wyy123123'
jasypt:
encryptor:
password: ${JASYPT_ENCRYPTOR_PASSWORD:}
# Sa-Token配置
sa-token:
# token名称 (同时也是cookie名称)
token-name: Authorization
# 开启内网服务调用鉴权(不允许越过gateway访问内网服务 保障服务安全)
check-same-token: false
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
is-concurrent: true
# 在多人登录同一账号时是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
is-share: true
# 是否输出操作日志
is-log: true
# jwt秘钥
jwt-secret-key: abcdefghijklmnopqrstuvwxyz

View File

@@ -0,0 +1,13 @@
server:
port: 18080
servlet:
context-path: /
tomcat:
uri-encoding: UTF-8 # tomcat的URI编码
accept-count: 1000 # 连接数满后的排队数默认为100
threads:
max: 800 # tomcat最大线程数默认为200
min-spare: 100 # Tomcat启动初始化的线程数默认值10
spring:
profiles:
active: dev

View File

@@ -0,0 +1,18 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.agileboot</groupId>
<artifactId>agileboot-cloud</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>agileboot-cloud-start</artifactId>
<dependencies>
<dependency>
<groupId>com.agileboot</groupId>
<artifactId>wol-common-web</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,11 @@
package com.agileboot;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @Author cuiJiaWang
* @Create 2025-08-12 17:35
*/
@SpringBootApplication
public class AgilebootCloudApplication {
}

15
agileboot-cloud/pom.xml Normal file
View File

@@ -0,0 +1,15 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.agileboot</groupId>
<artifactId>agileboot</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>agileboot-cloud</artifactId>
<packaging>pom</packaging>
<modules>
<module>agileboot-cloud-start</module>
</modules>
</project>

View File

@@ -5,10 +5,22 @@
<parent>
<artifactId>agileboot</artifactId>
<groupId>com.agileboot</groupId>
<version>${revision}</version>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<modules>
<module>wol-common-box</module>
<module>wol-common-core</module>
<module>wol-common-doc</module>
<module>wol-common-web</module>
<module>wol-common-mybatis</module>
<module>wol-common-redis</module>
<module>wol-common-json</module>
<module>wol-common-satoken</module>
</modules>
<packaging>pom</packaging>
<artifactId>agileboot-common</artifactId>
<description>
@@ -17,176 +29,78 @@
<dependencies>
<!-- Spring框架基本的核心工具 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<!-- SpringWeb模块 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<!-- spring security 安全认证 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- 自定义验证注解 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!--常用工具类 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- JSON工具类 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- io常用工具类 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-security</artifactId>-->
<!-- </dependency>-->
<!-- 文件上传工具类 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
</dependency>
<!-- excel工具 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>commons-fileupload</groupId>-->
<!-- <artifactId>commons-fileupload</artifactId>-->
<!-- </dependency>-->
<!-- yml解析器 -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.yaml</groupId>-->
<!-- <artifactId>snakeyaml</artifactId>-->
<!-- </dependency>-->
<!-- Token生成与解析-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>io.jsonwebtoken</groupId>-->
<!-- <artifactId>jjwt</artifactId>-->
<!-- </dependency>-->
<!-- Jaxb -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>javax.xml.bind</groupId>-->
<!-- <artifactId>jaxb-api</artifactId>-->
<!-- </dependency>-->
<!-- redis 缓存操作 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- pool 对象池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-data-redis</artifactId>-->
<!-- </dependency>-->
<!-- 解析客户端操作系统、浏览器等 -->
<dependency>
<groupId>eu.bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>eu.bitwalker</groupId>-->
<!-- <artifactId>UserAgentUtils</artifactId>-->
<!-- </dependency>-->
<!-- servlet包 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>it.ozimov</groupId>-->
<!-- <artifactId>embedded-redis</artifactId>-->
<!-- &lt;!&ndash; 不排除掉slf4j的话 会冲突&ndash;&gt;-->
<!-- <exclusions>-->
<!-- <exclusion>-->
<!-- <groupId>org.slf4j</groupId>-->
<!-- <artifactId>slf4j-simple</artifactId>-->
<!-- </exclusion>-->
<!-- &lt;!&ndash; 排除掉guava依赖以本项目的guava依赖为准 &ndash;&gt;-->
<!-- <exclusion>-->
<!-- <groupId>com.google.guava</groupId>-->
<!-- <artifactId>guava</artifactId>-->
<!-- </exclusion>-->
<!-- </exclusions>-->
<!-- </dependency>-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-parameter-names</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
</dependency>
<dependency>
<groupId>it.ozimov</groupId>
<artifactId>embedded-redis</artifactId>
<!-- 不排除掉slf4j的话 会冲突-->
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</exclusion>
<!-- 排除掉guava依赖以本项目的guava依赖为准 -->
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 多数据源 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.baomidou</groupId>-->
<!-- <artifactId>dynamic-datasource-spring-boot-starter</artifactId>-->
<!-- </dependency>-->
<!-- swagger注解 -->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</dependency>
<!--ENC加密-->
<!-- <dependency>-->
<!-- <groupId>com.github.ulisesbocchio</groupId>-->
<!-- <artifactId>jasypt-spring-boot-starter</artifactId>-->
<!-- <version>2.1.1</version>-->
<!-- </dependency>-->
</dependencies>

View File

@@ -1,86 +0,0 @@
package com.agileboot.common.constant;
/**
* 通用常量信息
*
* @author valarchie
*/
public class Constants {
private Constants() {
}
public static final int KB = 1024;
public static final int MB = KB * 1024;
public static final int GB = MB * 1024;
/**
* http请求
*/
public static final String HTTP = "http://";
/**
* https请求
*/
public static final String HTTPS = "https://";
public static class Token {
private Token() {
}
/**
* 令牌前缀
*/
public static final String TOKEN_PREFIX = "Bearer ";
/**
* 令牌前缀
*/
public static final String LOGIN_USER_KEY = "login_user_key";
}
public static class Captcha {
private Captcha() {
}
/**
* 令牌
*/
public static final String MATH_TYPE = "math";
/**
* 令牌前缀
*/
public static final String CHAR_TYPE = "char";
}
/**
* 资源映射路径 前缀
*/
public static final String RESOURCE_PREFIX = "profile";
public static class UploadSubDir {
private UploadSubDir() {
}
public static final String IMPORT_PATH = "import";
public static final String AVATAR_PATH = "avatar";
public static final String DOWNLOAD_PATH = "download";
public static final String UPLOAD_PATH = "upload";
}
}

View File

@@ -1,46 +0,0 @@
package com.agileboot.common.core.base;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import io.swagger.annotations.ApiModelProperty;
import java.util.Date;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* Entity基类
*
* @author valarchie
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class BaseEntity<T extends Model<?>> extends Model<T> {
@ApiModelProperty("创建者ID")
@TableField(value = "creator_id", fill = FieldFill.INSERT)
private Long creatorId;
@ApiModelProperty("创建时间")
@TableField(value = "create_time", fill = FieldFill.INSERT)
private Date createTime;
@ApiModelProperty("更新者ID")
@TableField(value = "updater_id", fill = FieldFill.UPDATE, updateStrategy = FieldStrategy.NOT_NULL)
private Long updaterId;
@ApiModelProperty("更新时间")
@TableField(value = "update_time", fill = FieldFill.UPDATE)
private Date updateTime;
/**
* deleted字段请在数据库中 设置为tinyInt 并且非null 默认值为0
*/
@ApiModelProperty("删除标志0代表存在 1代表删除")
@TableField("deleted")
@TableLogic
private Boolean deleted;
}

View File

@@ -1,62 +0,0 @@
package com.agileboot.common.core.dto;
import cn.hutool.core.util.StrUtil;
import com.agileboot.common.exception.ApiException;
import com.agileboot.common.exception.error.ErrorCode;
import com.agileboot.common.exception.error.ErrorCodeInterface;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* 响应信息主体
*
* @author valarchie
*/
@Data
@AllArgsConstructor
public class ResponseDTO<T> {
private Integer code;
private String msg;
private T data;
public static <T> ResponseDTO<T> ok() {
return build(null, ErrorCode.SUCCESS);
}
public static <T> ResponseDTO<T> ok(T data) {
return build(data, ErrorCode.SUCCESS);
}
public static <T> ResponseDTO<T> fail() {
return build(null, ErrorCode.FAIL);
}
public static <T> ResponseDTO<T> fail(T data) {
return build(data, ErrorCode.FAIL);
}
public static <T> ResponseDTO<T> fail(ErrorCodeInterface code) {
return build(null, code);
}
public static <T> ResponseDTO<T> fail(ErrorCodeInterface code, Object... args) {
return build(null, code, args);
}
public static <T> ResponseDTO<T> fail(ApiException exception) {
return build(exception.getErrorCode().code(), exception.getMessage());
}
public static <T> ResponseDTO<T> build(T data, ErrorCodeInterface code, Object... args) {
return new ResponseDTO<>(code.code(), StrUtil.format(code.message(), args), data);
}
public static <T> ResponseDTO<T> build(Integer code, String msg) {
return new ResponseDTO<>(code, msg, null);
}
}

View File

@@ -1,38 +0,0 @@
package com.agileboot.common.core.page;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import java.util.List;
import lombok.Data;
/**
* 分页模型类
* @author valarchie
*/
@Data
public class PageDTO<T> {
/**
* 总记录数
*/
private Long total;
/**
* 列表数据
*/
private List<T> rows;
public PageDTO(List<T> list) {
this.rows = list;
this.total = (long) list.size();
}
public PageDTO(Page<T> page) {
this.rows = page.getRecords();
this.total = page.getTotal();
}
public PageDTO(List<T> list, Long count) {
this.rows = list;
this.total = count;
}
}

View File

@@ -1,66 +0,0 @@
package com.agileboot.common.exception;
import cn.hutool.core.util.StrUtil;
import com.agileboot.common.exception.error.ErrorCodeInterface;
import com.agileboot.common.utils.i18n.MessageUtils;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
/**
* 统一异常类
* @author valarchie
*/
@EqualsAndHashCode(callSuper = true)
@Slf4j
@Data
public class ApiException extends RuntimeException{
protected ErrorCodeInterface errorCode;
protected String message;
protected Object[] args;
protected String formattedMessage;
protected String i18nFormattedMessage;
public ApiException(Throwable e, ErrorCodeInterface errorCode, Object... args) {
super(e);
fillErrorCode(errorCode, args);
}
public ApiException(ErrorCodeInterface errorCode, Object... args) {
fillErrorCode(errorCode, args);
}
public ApiException(ErrorCodeInterface errorCode) {
fillErrorCode(errorCode);
}
private void fillErrorCode(ErrorCodeInterface errorCode, Object... args) {
this.errorCode = errorCode;
this.message = errorCode.message();
this.args = args;
this.formattedMessage = StrUtil.format(this.message, args);
try {
this.i18nFormattedMessage = MessageUtils.message(errorCode.i18nKey(), args);
} catch (Exception e) {
log.error("could not found i18nMessage entry for key: " + errorCode.i18nKey());
}
}
@Override
public String getMessage() {
return i18nFormattedMessage != null ? i18nFormattedMessage : formattedMessage;
}
@Override
public String getLocalizedMessage() {
return i18nFormattedMessage;
}
}

View File

@@ -1,328 +0,0 @@
package com.agileboot.common.exception.error;
/**
* 错误码集合
*
* @author valarchie
*/
public enum ErrorCode implements ErrorCodeInterface {
/**
* 错误码集合
* 1~9999 为保留错误码 或者 常用错误码
* 10000~19999 为内部错误码
* 20000~29999 客户端错误码 (客户端异常调用之类的错误)
* 30000~39999 为第三方错误码 (代码正常,但是第三方异常)
* 40000~49999 为业务逻辑 错误码 (无异常,代码正常流转,并返回提示给用户)
* 由于系统内的错误码都是独一无二的所以错误码应该放在common包集中管理
*/
// -------------- 普通错误码 及保留错误码 ---------------
SUCCESS(0, "操作成功"),
FAIL(9999, "操作失败"),
UNKNOWN_ERROR(99999, "未知错误");
private final int code;
private final String msg;
ErrorCode(int code, String msg) {
this.code = code;
this.msg = msg;
}
@Override
public int code() {
return this.code;
}
@Override
public String message() {
return this.msg;
}
/**
* 40000~49999 为业务逻辑 错误码 (无代码异常,代码正常流转,并返回提示给用户)
*/
public enum Business implements ErrorCodeInterface {
// ----------------------------- Common --------------------------------------
OBJECT_NOT_FOUND(Module.COMMON, 1, "找不到ID为 {} 的 {}"),
UNSUPPORTED_OPERATION(Module.COMMON, 2, "不支持的操作"),
BULK_DELETE_IDS_IS_INVALID(Module.COMMON, 3, "批量参数ID列表为空"),
FILE_NOT_ALLOWED_TO_DOWNLOAD(Module.COMMON, 3, "文件名称({})非法,不允许下载"),
// ----------------------------- Permission -----------------------------------
FORBIDDEN_TO_MODIFY_ADMIN(Module.PERMISSION, 1, "不允许修改管理员的信息"),
NO_PERMISSION_TO_OPERATE(Module.PERMISSION, 2, "没有权限进行此操作,请联系管理员"),
// ----------------------------- Login -----------------------------------------
LOGIN_WRONG_USER_PASSWORD(Module.LOGIN, 1, "用户密码错误,请重输"),
LOGIN_ERROR(Module.LOGIN, 2, "登录失败:{}"),
LOGIN_CAPTCHA_CODE_WRONG(Module.LOGIN, 3, "验证码错误"),
LOGIN_CAPTCHA_CODE_EXPIRE(Module.LOGIN, 4, "验证码过期"),
LOGIN_CAPTCHA_CODE_NULL(Module.LOGIN, 5, "验证码为空"),
// ----------------------------- Upload -----------------------------------------
UPLOAD_FILE_TYPE_NOT_ALLOWED(Module.UPLOAD, 1, "不允许上传的文件类型,仅允许:{}"),
UPLOAD_FILE_NAME_EXCEED_MAX_LENGTH(Module.UPLOAD, 2, "文件名长度超过:{} "),
UPLOAD_FILE_SIZE_EXCEED_MAX_SIZE(Module.UPLOAD, 3, "文件名大小超过:{} MB"),
UPLOAD_IMPORT_EXCEL_FAILED(Module.UPLOAD, 4, "导入excel失败{}"),
UPLOAD_FILE_IS_EMPTY(Module.UPLOAD, 5, "上传文件为空"),
UPLOAD_FILE_FAILED(Module.UPLOAD, 6, "上传文件失败:{}"),
// ----------------------------- Config -----------------------------------------
CONFIG_VALUE_IS_NOT_ALLOW_TO_EMPTY(Module.CONFIG, 1, "参数键值不允许为空"),
CONFIG_VALUE_IS_NOT_IN_OPTIONS(Module.CONFIG, 2, "参数键值不存在列表中"),
// ------------------------------- Post --------------------------------------------
POST_NAME_IS_NOT_UNIQUE(Module.POST, 1, "岗位名称:{}, 已存在"),
POST_CODE_IS_NOT_UNIQUE(Module.POST, 2, "岗位编号:{}, 已存在"),
POST_ALREADY_ASSIGNED_TO_USER_CAN_NOT_BE_DELETED(Module.POST, 3, "职位已分配给用户,请先取消分配再删除"),
// ------------------------------- Dept ---------------------------------------------
DEPT_NAME_IS_NOT_UNIQUE(Module.DEPT, 1, "部门名称:{}, 已存在"),
DEPT_PARENT_ID_IS_NOT_ALLOWED_SELF(Module.DEPT, 2, "父级部门不能选择自己"),
DEPT_STATUS_ID_IS_NOT_ALLOWED_CHANGE(Module.DEPT, 3, "子部门还有正在启用的部门,暂时不能停用该部门"),
DEPT_EXIST_CHILD_DEPT_NOT_ALLOW_DELETE(Module.DEPT, 4, "该部门存在下级部门不允许删除"),
DEPT_EXIST_LINK_USER_NOT_ALLOW_DELETE(Module.DEPT, 5, "该部门存在关联的用户不允许删除"),
DEPT_PARENT_DEPT_NO_EXIST_OR_DISABLED(Module.DEPT, 6, "该父级部门不存在或已停用"),
// ------------------------------- Menu -------------------------------------------------
MENU_NAME_IS_NOT_UNIQUE(Module.MENU, 1, "新增菜单:{} 失败,菜单名称已存在"),
MENU_EXTERNAL_LINK_MUST_BE_HTTP(Module.MENU, 2, "菜单外链必须以 http(s)://开头"),
MENU_PARENT_ID_NOT_ALLOW_SELF(Module.MENU, 3, "父级菜单不能选择自身"),
MENU_EXIST_CHILD_MENU_NOT_ALLOW_DELETE(Module.MENU, 4, "存在子菜单不允许删除"),
MENU_ALREADY_ASSIGN_TO_ROLE_NOT_ALLOW_DELETE(Module.MENU, 5, "菜单已分配给角色,不允许"),
// -------------------------------- Role -------------------------------------------------
ROLE_NAME_IS_NOT_UNIQUE(Module.ROLE, 1, "角色名称:{}, 已存在"),
ROLE_KEY_IS_NOT_UNIQUE(Module.ROLE, 2, "角色标识:{}, 已存在"),
ROLE_DATA_SCOPE_DUPLICATED_DEPT(Module.ROLE, 3, "重复的部门id"),
ROLE_ALREADY_ASSIGN_TO_USER(Module.ROLE, 4, "角色已分配给用户,请先取消分配,再删除角色"),
ROLE_IS_NOT_AVAILABLE(Module.ROLE, 5, "角色:{} 已禁用,无法分配给用户"),
// ---------------------------------- User -----------------------------------------------
USER_NON_EXIST(Module.USER, 1, "登录用户:{} 不存在"),
USER_IS_DISABLE(Module.USER, 2, "对不起, 您的账号:{} 已停用"),
USER_CACHE_IS_EXPIRE(Module.USER, 3, "用户缓存信息已经过期"),
USER_FAIL_TO_GET_USER_ID(Module.USER, 3, "获取用户ID失败"),
USER_FAIL_TO_GET_DEPT_ID(Module.USER, 4, "获取用户部门ID失败"),
USER_FAIL_TO_GET_ACCOUNT(Module.USER, 5, "获取用户账户失败"),
USER_FAIL_TO_GET_USER_INFO(Module.USER, 6, "获取用户信息失败"),
USER_IMPORT_DATA_IS_NULL(Module.USER, 7, "导入的用户为空"),
USER_PHONE_NUMBER_IS_NOT_UNIQUE(Module.USER, 8, "该电话号码已被其他用户占用"),
USER_EMAIL_IS_NOT_UNIQUE(Module.USER, 9, "该邮件地址已被其他用户占用"),
USER_PASSWORD_IS_NOT_CORRECT(Module.USER, 10, "用户密码错误"),
USER_NEW_PASSWORD_IS_THE_SAME_AS_OLD(Module.USER, 11, "用户新密码与旧密码相同"),
USER_UPLOAD_FILE_FAILED(Module.USER, 12, "用户上传文件失败"),
USER_NAME_IS_NOT_UNIQUE(Module.USER, 13, "用户名已被其他用户占用"),
USER_CURRENT_USER_CAN_NOT_BE_DELETE(Module.USER, 14, "当前用户不允许被删除"),
USER_ADMIN_CAN_NOT_BE_MODIFY(Module.USER, 15, "管理员不允许做任何修改"),
;
private final int code;
private final String msg;
private static final int BASE_CODE = 40000;
Business(Module module, int code, String msg) {
this.code = BASE_CODE + module.code() + code;
this.msg = msg;
}
@Override
public int code() {
return this.code;
}
@Override
public String message() {
return this.msg;
}
}
/**
* 30000~39999是外部错误码 比如调用支付失败
*/
public enum External implements ErrorCodeInterface {
/**
* 支付宝调用失败
*/
FAIL_TO_PAY_ON_ALIPAY(Module.COMMON, 1, "支付宝调用失败");
private final int code;
private final String msg;
private static final int BASE_CODE = 30000;
External(Module module, int code, String msg) {
this.code = BASE_CODE + module.code() + code;
this.msg = msg;
}
@Override
public int code() {
return this.code;
}
@Override
public String message() {
return this.msg;
}
}
/**
* 20000~29999是客户端错误码
*/
public enum Client implements ErrorCodeInterface {
/**
* 客户端错误码
*/
COMMON_FORBIDDEN_TO_CALL(Module.COMMON, 1, "禁止调用"),
COMMON_REQUEST_TOO_OFTEN(Module.COMMON, 2, "调用太过频繁"),
COMMON_REQUEST_PARAMETERS_INVALID(Module.COMMON, 3, "请求参数异常,{}"),
COMMON_REQUEST_METHOD_INVALID(Module.COMMON, 4, "请求方式: {} 不支持"),
COMMON_REQUEST_RESUBMIT(Module.COMMON, 5, "请求重复提交"),
COMMON_NO_AUTHORIZATION(Module.PERMISSION, 1, "请求接口:{} 失败,用户未授权"),
;
private final int code;
private final String msg;
private static final int BASE_CODE = 20000;
Client(Module module, int code, String msg) {
this.code = BASE_CODE + module.code() + code;
this.msg = msg;
}
@Override
public int code() {
return this.code;
}
@Override
public String message() {
return this.msg;
}
}
/**
* 10000~19999是内部错误码 例如 框架有问题之类的
*/
public enum Internal implements ErrorCodeInterface {
/**
* 内部错误码
*/
INVALID_PARAMETER(Module.COMMON, 1, "参数异常:{}"),
UNKNOWN_ERROR(Module.COMMON, 2, "未知异常, 请查看系统日志"),
GET_ENUM_FAILED(Module.COMMON, 3, "获取枚举类型失败, 枚举类: {}"),
GET_CACHE_FAILED(Module.COMMON, 4, "获取缓存失败"),
INTERNAL_ERROR(Module.COMMON, 5, "系统内部错误:{}"),
LOGIN_CAPTCHA_GENERATE_FAIL(Module.LOGIN, 1, "验证码生成失败"),
INVALID_TOKEN(Module.PERMISSION, 1, "token异常"),
DB_INTERNAL_ERROR(Module.DB, 1, "数据库异常: {}"),
;
private final int code;
private final String msg;
private static final int BASE_CODE = 10000;
Internal(Module module, int code, String msg) {
this.code = BASE_CODE + module.code() + code;
this.msg = msg;
}
@Override
public int code() {
return this.code;
}
@Override
public String message() {
return this.msg;
}
}
}

View File

@@ -1,73 +0,0 @@
package com.agileboot.common.exception.error;
/**
* 系统内的模块
* @author valarchie
*/
public enum Module {
/**
* 普通模块
*/
COMMON(0),
/**
* 权限模块
*/
PERMISSION(1),
/**
* 登录模块
*/
LOGIN(2),
/**
* 数据库模块
*/
DB(3),
/**
* 上传
*/
UPLOAD(4),
/**
* 用户
*/
USER(5),
/**
* 配置
*/
CONFIG(6),
/**
* 职位
*/
POST(7),
/**
* 部门
*/
DEPT(8),
/**
* 菜单
*/
MENU(9),
/**
* 角色
*/
ROLE(10),
;
private final int code;
Module(int code) { this.code = code * 100; }
public int code() {return code; }
}

View File

@@ -1,29 +0,0 @@
package com.agileboot.common.core.exception;
import org.junit.Assert;
import org.junit.Test;
public class ApiExceptionTest {
@Test
public void testVarargsWithArrayArgs() {
String errorMsg = "these parameters are null: %s, %s, %s.";
Object[] array = new Object[] { "param1" , "param2" , "param3"};
String formatWithArray = String.format(errorMsg, array);
String formatWithVarargs = String.format(errorMsg, "param1", "param2", "param3");
Assert.assertEquals(formatWithVarargs, formatWithArray);
}
@Test
public void testVarargsWithNullArgs() {
String errorMsg = "these parameters are null: %s, %s, %s.";
String format = String.format(errorMsg, "param1", null, null);
Assert.assertEquals("these parameters are null: param1, null, null.", format);
}
}

View File

@@ -1,14 +0,0 @@
package com.agileboot.common.exception.error;
import com.agileboot.common.exception.error.ErrorCode.Client;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
class ErrorCodeInterfaceTest {
@Test
void testI18nKey() {
String i18nKey = Client.COMMON_FORBIDDEN_TO_CALL.i18nKey();
Assertions.assertEquals("20001_COMMON_FORBIDDEN_TO_CALL", i18nKey);
}
}

View File

@@ -1,119 +0,0 @@
package com.agileboot.common.utils.file;
import cn.hutool.core.util.StrUtil;
import com.agileboot.common.config.AgileBootConfig;
import com.agileboot.common.constant.Constants.UploadSubDir;
import com.agileboot.common.exception.ApiException;
import com.agileboot.common.exception.error.ErrorCode.Business;
import com.agileboot.common.exception.error.ErrorCode.Internal;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.web.multipart.MultipartFile;
class FileUploadUtilsTest {
@Test
void testIsAllowedExtension() {
String[] imageTypes = new String[]{"img", "gif"};
boolean isAllow = FileUploadUtils.isExtensionAllowed("img", imageTypes);
boolean isNotAllow = FileUploadUtils.isExtensionAllowed("png", imageTypes);
Assertions.assertTrue(isAllow);
Assertions.assertFalse(isNotAllow);
}
@Test
void testIsAllowedExtensionWhenNull() {
String[] imageTypes = null;
boolean isAllow = FileUploadUtils.isExtensionAllowed("img", imageTypes);
Assertions.assertTrue(isAllow);
}
@Test
void testGetRelativeFileUrl() {
String relativeFilePath = FileUploadUtils.getRelativeFileUrl(UploadSubDir.UPLOAD_PATH, "test.jpg");
Assertions.assertEquals("/profile/upload/test.jpg", relativeFilePath);
}
@Test
void testSaveFileToLocal() {
MultipartFile fileMock = Mockito.mock(MultipartFile.class);
ApiException exceptionWithNullSubDir = Assertions.assertThrows(ApiException.class,
() -> FileUploadUtils.saveFileToLocal(fileMock, "", ""));
ApiException exceptionWitEmptyFileName = Assertions.assertThrows(ApiException.class,
() -> FileUploadUtils.saveFileToLocal(fileMock, "", ""));
Assertions.assertEquals(Internal.INVALID_PARAMETER, exceptionWithNullSubDir.getErrorCode());
Assertions.assertEquals(Internal.INVALID_PARAMETER, exceptionWitEmptyFileName.getErrorCode());
}
@Test
void testIsAllowedUploadWhenFileNameTooLong() {
MultipartFile fileMock = Mockito.mock(MultipartFile.class);
String longFileName = "this is a very very long sentence, this is a very very long sentence, "
+ "this is a very very long sentence, this is a very very long sentence, ";
Mockito.when(fileMock.getOriginalFilename()).thenReturn(longFileName);
ApiException exception = Assertions.assertThrows(ApiException.class,
() -> FileUploadUtils.isAllowedUpload(fileMock, null));
Assertions.assertEquals(Business.UPLOAD_FILE_NAME_EXCEED_MAX_LENGTH, exception.getErrorCode());
}
@Test
void testIsAllowedUploadWhenFileTooBig() {
MultipartFile fileMock = Mockito.mock(MultipartFile.class);
Mockito.when(fileMock.getOriginalFilename()).thenReturn("test.jpg");
Mockito.when(fileMock.getSize()).thenReturn(FileUploadUtils.MAX_FILE_SIZE + 1);
ApiException exception = Assertions.assertThrows(ApiException.class,
() -> FileUploadUtils.isAllowedUpload(fileMock, null));
Assertions.assertEquals(Business.UPLOAD_FILE_SIZE_EXCEED_MAX_SIZE, exception.getErrorCode());
}
@Test
void testisAllowDownload() {
Assertions.assertFalse(FileUploadUtils.isAllowDownload("../test.jpg"));
Assertions.assertFalse(FileUploadUtils.isAllowDownload("../test.exe"));
}
@Test
void testGetFileExtension() {
MultipartFile fileMock = Mockito.mock(MultipartFile.class);
Mockito.when(fileMock.getOriginalFilename()).thenReturn("test.jpg");
String fileExtension = FileUploadUtils.getFileExtension(fileMock);
Assertions.assertEquals("jpg", fileExtension);
}
@Test
void testGenerateFilename() {
String fileName = "test.jpg";
MultipartFile fileMock = Mockito.mock(MultipartFile.class);
Mockito.when(fileMock.getOriginalFilename()).thenReturn(fileName);
String randomFileName = FileUploadUtils.generateFilename(fileMock);
String[] nameParts = randomFileName.split("_");
Assertions.assertEquals("test", nameParts[1]);
Assertions.assertTrue(StrUtil.endWith(nameParts[2], ".jpg"));
}
@Test
void getFileAbsolutePath() {
AgileBootConfig agileBootConfig = new AgileBootConfig();
agileBootConfig.setFileBaseDir("D:\\agileboot");
String fileAbsolutePath = FileUploadUtils.getFileAbsolutePath(UploadSubDir.AVATAR_PATH, "test.jpg");
Assertions.assertEquals("D:\\agileboot\\profile\\avatar\\test.jpg", fileAbsolutePath);
}
}

View File

@@ -1,65 +0,0 @@
package com.agileboot.common.utils.ip;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
class IpRegionUtilTest {
@Test
void testGetIpRegion() {
IpRegion ipRegion = IpRegionUtil.getIpRegion("110.81.189.80");
Assertions.assertEquals("中国", ipRegion.getCountry());
Assertions.assertEquals("福建省", ipRegion.getProvince());
Assertions.assertEquals("泉州市", ipRegion.getCity());
}
@Test
void testGetIpRegionWhenLocalHost() {
IpRegion ipRegion = IpRegionUtil.getIpRegion("127.0.0.1");
Assertions.assertEquals("内网IP", ipRegion.briefLocation());
}
@Test
void testGetIpRegionWithIpv6() {
IpRegion ipRegion = IpRegionUtil.getIpRegion("2001:0DB8:0000:0023:0008:0800:200C:417A");
Assertions.assertNotNull(ipRegion);
Assertions.assertNull(ipRegion.getCountry());
Assertions.assertEquals("未知 未知", ipRegion.briefLocation());
}
@Test
void testGetIpRegionWithEmpty() {
IpRegion ipRegion = IpRegionUtil.getIpRegion("");
Assertions.assertNotNull(ipRegion);
Assertions.assertNull(ipRegion.getCountry());
Assertions.assertEquals("未知 未知", ipRegion.briefLocation());
}
@Test
void testGetIpRegionWithNull() {
IpRegion ipRegion = IpRegionUtil.getIpRegion(null);
Assertions.assertNotNull(ipRegion);
Assertions.assertNull(ipRegion.getCountry());
Assertions.assertEquals("未知 未知", ipRegion.briefLocation());
}
@Test
void testGetIpRegionWithWrongIpString() {
IpRegion ipRegion = IpRegionUtil.getIpRegion("xsdfwefsfsd");
Assertions.assertNotNull(ipRegion);
Assertions.assertNull(ipRegion.getCountry());
Assertions.assertEquals("未知 未知", ipRegion.briefLocation());
}
@Test
void getBriefLocationByIp() {
String briefLocationByIp = IpRegionUtil.getBriefLocationByIp("110.81.189.80");
Assertions.assertEquals("福建省 泉州市", briefLocationByIp);
}
}

View File

@@ -1,41 +0,0 @@
package com.agileboot.common.utils.ip;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
class IpUtilTest {
@Test
void isInnerIp() {
boolean innerIp1 = IpUtil.isLocalHost("127.0.0.1");
boolean innerIp2 = IpUtil.isLocalHost("0:0:0:0:0:0:0:1");
boolean innerIp3 = IpUtil.isLocalHost("localhost");
boolean innerIp4 = IpUtil.isLocalHost("192.168.1.1");
boolean innerIp5 = IpUtil.isLocalHost("10.32.1.1");
boolean innerIp6 = IpUtil.isLocalHost("172.16.1.1");
boolean notInnerIP = IpUtil.isLocalHost("110.81.189.80");
Assertions.assertTrue(innerIp1);
Assertions.assertTrue(innerIp2);
Assertions.assertTrue(innerIp3);
Assertions.assertTrue(innerIp4);
Assertions.assertTrue(innerIp5);
Assertions.assertTrue(innerIp6);
Assertions.assertFalse(notInnerIP);
}
@Test
void isLocalHost() {
boolean localHost1 = IpUtil.isLocalHost("127.0.0.1");
boolean localHost2 = IpUtil.isLocalHost("0:0:0:0:0:0:0:1");
boolean localHost4 = IpUtil.isLocalHost("localhost");
boolean notLocalHost = IpUtil.isLocalHost("110.81.189.80");
Assertions.assertTrue(localHost1);
Assertions.assertTrue(localHost2);
Assertions.assertTrue(localHost4);
Assertions.assertFalse(notLocalHost);
}
}

View File

@@ -1,52 +0,0 @@
package com.agileboot.common.utils.ip;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
class OfflineIpRegionUtilTest {
@Test
void testGetIpRegionWhenIpv4() {
IpRegion ipRegion = OfflineIpRegionUtil.getIpRegion("110.81.189.80");
Assertions.assertEquals("中国", ipRegion.getCountry());
Assertions.assertEquals("福建省", ipRegion.getProvince());
Assertions.assertEquals("泉州市", ipRegion.getCity());
}
@Test
void testGetIpRegionWithIpv6() {
IpRegion region = Assertions.assertDoesNotThrow(() ->
OfflineIpRegionUtil.getIpRegion("2001:0DB8:0000:0023:0008:0800:200C:417A")
);
Assertions.assertNull(region);
}
@Test
void testGetIpRegionWithEmpty() {
IpRegion region = Assertions.assertDoesNotThrow(() ->
OfflineIpRegionUtil.getIpRegion("")
);
Assertions.assertNull(region);
}
@Test
void testGetIpRegionWithNull() {
IpRegion region = Assertions.assertDoesNotThrow(() ->
OfflineIpRegionUtil.getIpRegion(null)
);
Assertions.assertNull(region);
}
@Test
void testGetIpRegionWithWrongIpString() {
IpRegion region = Assertions.assertDoesNotThrow(() ->
OfflineIpRegionUtil.getIpRegion("asfdsfdsff")
);
Assertions.assertNull(region);
}
}

View File

@@ -1,63 +0,0 @@
package com.agileboot.common.utils.ip;
import com.agileboot.common.config.AgileBootConfig;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class OnlineIpRegionUtilTest {
@BeforeEach
public void enableOnlineAddressQuery() {
AgileBootConfig agileBootConfig = new AgileBootConfig();
agileBootConfig.setAddressEnabled(true);
}
@Test
void getIpRegionWithIpv6() {
IpRegion region = Assertions.assertDoesNotThrow(() ->
OnlineIpRegionUtil.getIpRegion("ABCD:EF01:2345:6789:ABCD:EF01:2345:6789")
);
Assertions.assertNull(region);
}
@Test
void getIpRegionWithIpv4() {
IpRegion ipRegion = OnlineIpRegionUtil.getIpRegion("120.42.247.130");
Assertions.assertEquals("福建省", ipRegion.getProvince());
Assertions.assertEquals("泉州市", ipRegion.getCity());
}
@Test
void getIpRegionWithEmpty() {
IpRegion region = Assertions.assertDoesNotThrow(() ->
OnlineIpRegionUtil.getIpRegion("")
);
Assertions.assertNull(region);
}
@Test
void getIpRegionWithNull() {
IpRegion region = Assertions.assertDoesNotThrow(() ->
OnlineIpRegionUtil.getIpRegion(null)
);
Assertions.assertNull(region);
}
@Test
void getIpRegionWithWrongIpString() {
IpRegion region = Assertions.assertDoesNotThrow(() ->
OnlineIpRegionUtil.getIpRegion("seffsdfsdf")
);
Assertions.assertNull(region);
}
}

View File

@@ -1,61 +0,0 @@
package com.agileboot.common.utils.jackson;
import cn.hutool.core.date.DateUtil;
import java.math.BigDecimal;
import java.math.BigInteger;
import org.junit.Assert;
import org.junit.Test;
/**
* @author duanxinyuan 2019/1/21 18:17
*/
public class JacksonUtilTest {
@Test
public void testObjectToJson() {
Person person = Person.newPerson();
String jacksonStr = JacksonUtil.to(person);
Assert.assertEquals(DateUtil.formatDateTime(person.getDate()), JacksonUtil.getAsString(jacksonStr, "date"));
Assert.assertEquals(DateUtil.formatLocalDateTime(person.getLocalDateTime()),
JacksonUtil.getAsString(jacksonStr, "localDateTime"));
Assert.assertEquals(person.getName(), JacksonUtil.getAsString(jacksonStr, "name"));
Assert.assertEquals(person.getAge(), JacksonUtil.getAsInt(jacksonStr, "age"));
Assert.assertEquals(person.isMan(), JacksonUtil.getAsBoolean(jacksonStr, "man"));
Assert.assertEquals(person.getMoney(), JacksonUtil.getAsBigDecimal(jacksonStr, "money"));
Assert.assertEquals(person.getTrait(), JacksonUtil.getAsList(jacksonStr, "trait", String.class));
Assert.assertNotNull(JacksonUtil.getAsString(jacksonStr, "name"));
}
/**
* 测试兼容情况
*/
@Test
public void testAllPrimitiveTypeToJson() {
String json = "{\n"
+ "\"code\": \"200\",\n"
+ "\"id\": \"2001215464647687987\",\n"
+ "\"message\": \"success\",\n"
+ "\"amount\": \"1.12345\",\n"
+ "\"amount1\": \"0.12345\",\n"
+ "\"isSuccess\": \"true\",\n"
+ "\"isSuccess1\": \"1\",\n"
+ "\"key\": \"8209167202090377654857374178856064487200234961995543450245362822537162918731039965956758726661669012305745755921310000297396309887550627402157318910581311\"\n"
+ "}";
Assert.assertEquals(200, JacksonUtil.getAsInt(json, "code"));
Assert.assertEquals(2001215464647687987L,JacksonUtil.getAsLong(json, "id"));
Assert.assertEquals("success", JacksonUtil.getAsString(json, "message"));
Assert.assertEquals(new BigDecimal("1.12345"), JacksonUtil.getAsBigDecimal(json, "amount"));
Assert.assertEquals(new BigDecimal("0.12345"), JacksonUtil.getAsBigDecimal(json, "amount1"));
Assert.assertEquals(1.12345d, JacksonUtil.getAsDouble(json, "amount"), 0.00001);
Assert.assertEquals(0.12345d, JacksonUtil.getAsDouble(json, "amount1"), 0.00001);
Assert.assertTrue(JacksonUtil.getAsBoolean(json, "isSuccess"));
Assert.assertTrue(JacksonUtil.getAsBoolean(json, "isSuccess1"));
Assert.assertEquals(new BigInteger(
"8209167202090377654857374178856064487200234961995543450245362822537162918731039965956758726661669012305745755921310000297396309887550627402157318910581311"),
JacksonUtil.getAsBigInteger(json, "key"));
Assert.assertEquals("1", JacksonUtil.getAsString(json, "isSuccess1"));
}
}

View File

@@ -1,42 +0,0 @@
package com.agileboot.common.utils.jackson;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import lombok.Data;
/**
* @author duanxinyuan
* 2018/6/29 14:17
*/
@Data
public class Person {
public String name;
public Date date;
public LocalDateTime localDateTime;
public int age;
public BigDecimal money;
public boolean man;
public ArrayList<String> trait;
public HashMap<String, String> cards;
public static Person newPerson() {
Person person = new Person();
person.name = "张三";
person.date = new Date();
person.localDateTime = LocalDateTime.now();
person.age = 100;
person.money = BigDecimal.valueOf(500.21);
person.man = true;
person.trait = new ArrayList<>();
person.trait.add("淡然");
person.trait.add("温和");
person.cards = new HashMap<>();
person.cards.put("身份证", "4a6d456as");
person.cards.put("建行卡", "649874545");
return person;
}
}

View File

@@ -1,40 +0,0 @@
package com.agileboot.common.utils.poi;
import cn.hutool.core.io.FileUtil;
import cn.hutool.http.HtmlUtil;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
class CustomExcelUtilTest {
@Test
void testImportAndExport() {
PostDTO post1 = new PostDTO(1L, "admin1", "管理员1", "1", "无备注", "1", "正常");
PostDTO post2 = new PostDTO(2L, "admin2", "管理员2<script>alert(1)</script>", "2", "无备注", "1", "正常");
List<PostDTO> postDTOList = new ArrayList<>();
postDTOList.add(post1);
postDTOList.add(post2);
File file = FileUtil.createTempFile();
CustomExcelUtil.writeToOutputStream(postDTOList, PostDTO.class, FileUtil.getOutputStream(file));
List<PostDTO> postListFromExcel = CustomExcelUtil.readFromInputStream(PostDTO.class, FileUtil.getInputStream(file));
PostDTO post1fromExcel = postListFromExcel.get(0);
PostDTO post2fromExcel = postListFromExcel.get(1);
Assertions.assertEquals(post1.getPostId(), post1fromExcel.getPostId());
Assertions.assertEquals(post1.getPostCode(), post1fromExcel.getPostCode());
Assertions.assertEquals(post2.getPostId(), post2fromExcel.getPostId());
Assertions.assertEquals(post2.getPostCode(), post2fromExcel.getPostCode());
// 检查脚本注入的字符串是否被去除
Assertions.assertNotEquals(post2.getPostName(), post2fromExcel.getPostName());
Assertions.assertEquals(HtmlUtil.cleanHtmlTag(post2.getPostName()), post2fromExcel.getPostName());
}
}

View File

@@ -1,37 +0,0 @@
package com.agileboot.common.utils.poi;
import com.agileboot.common.annotation.ExcelColumn;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Data
@EqualsAndHashCode
public class PostDTO {
@ExcelColumn(name = "岗位ID")
private Long postId;
@ExcelColumn(name = "岗位编码")
private String postCode;
@ExcelColumn(name = "岗位名称")
private String postName;
@ExcelColumn(name = "岗位排序")
private String postSort;
@ExcelColumn(name = "备注")
private String remark;
private String status;
@ExcelColumn(name = "状态")
private String statusStr;
}

View File

@@ -1,46 +0,0 @@
package com.agileboot.common.utils.time;
import java.util.Calendar;
import java.util.Date;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
class DatePickUtilTest {
@Test
void testGetBeginOfTheDay() {
Date beginOfTheDay = DatePickUtil.getBeginOfTheDay(new Date());
Calendar instance = Calendar.getInstance();
instance.setTime(beginOfTheDay);
Assertions.assertEquals(0, instance.get(Calendar.HOUR));
Assertions.assertEquals(0, instance.get(Calendar.MINUTE));
Assertions.assertEquals(0, instance.get(Calendar.SECOND));
}
@Test
void testGetBeginOfTheDayWhenNull() {
Assertions.assertDoesNotThrow(() -> DatePickUtil.getBeginOfTheDay(null)
);
}
@Test
void testGetEndOfTheDay() {
Date endOfTheDay = DatePickUtil.getEndOfTheDay(new Date());
Calendar instance = Calendar.getInstance();
instance.setTime(endOfTheDay);
Assertions.assertEquals(23, instance.get(Calendar.HOUR_OF_DAY));
Assertions.assertEquals(59, instance.get(Calendar.MINUTE));
Assertions.assertEquals(59, instance.get(Calendar.SECOND));
}
@Test
void testGetEndOfTheDayWhenNull() {
Assertions.assertDoesNotThrow(() -> DatePickUtil.getEndOfTheDay(null)
);
}
}

View File

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.agileboot</groupId>
<artifactId>wol-common-box</artifactId>
<version>${revision}</version>
<packaging>pom</packaging>
<properties>
<revision>1.0.0</revision>
</properties>
<dependencyManagement>
<dependencies>
<!-- 核心模块 -->
<dependency>
<groupId>com.agileboot</groupId>
<artifactId>wol-common-core</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.agileboot</groupId>
<artifactId>wol-common-doc</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.agileboot</groupId>
<artifactId>wol-common-mybatis</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.agileboot</groupId>
<artifactId>wol-common-redis</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.agileboot</groupId>
<artifactId>wol-common-web</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.agileboot</groupId>
<artifactId>wol-common-json</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.agileboot</groupId>
<artifactId>wol-common-satoken</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>

View File

@@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.agileboot</groupId>
<artifactId>agileboot-common</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>wol-common-core</artifactId>
<dependencies>
<!-- Spring框架基本的核心工具 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<!-- servlet包 -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
</dependency>
<!-- SpringWeb模块 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<!-- pool 对象池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- 自定义验证注解 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
</dependency>
<!-- excel工具 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</dependency>
<!-- io常用工具类 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<!--常用工具类 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-parameter-names</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
</dependency>
<!--ENC加密-->
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<!-- swagger注解 -->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,4 +1,4 @@
package com.agileboot.common.annotation;
package com.agileboot.common.core.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -1,4 +1,4 @@
package com.agileboot.common.annotation;
package com.agileboot.common.core.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -1,6 +1,6 @@
package com.agileboot.common.config;
package com.agileboot.common.core.config;
import com.agileboot.common.constant.Constants;
import com.agileboot.common.core.constant.Constants;
import java.io.File;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -8,7 +8,7 @@ import org.springframework.stereotype.Component;
/**
* 读取项目相关配置
*
* TODO 移走 不合适放在这里common包底下
* @author valarchie
*/
@Component
@@ -56,7 +56,7 @@ public class AgileBootConfig {
*/
private static String rsaPrivateKey;
private static String apiDocsPathPrefix;
private static String apiPrefix;
public static String getFileBaseDir() {
return fileBaseDir;
@@ -66,12 +66,12 @@ public class AgileBootConfig {
AgileBootConfig.fileBaseDir = fileBaseDir + File.separator + Constants.RESOURCE_PREFIX;
}
public static String getApiDocsPathPrefix() {
return apiDocsPathPrefix;
public static String getApiPrefix() {
return apiPrefix;
}
public void setApiDocsPathPrefix(String apiDocsPathPrefix) {
AgileBootConfig.apiDocsPathPrefix = apiDocsPathPrefix;
public void setApiPrefix(String apiDocsPathPrefix) {
AgileBootConfig.apiPrefix = apiDocsPathPrefix;
}
public static boolean isAddressEnabled() {

View File

@@ -0,0 +1,126 @@
package com.agileboot.common.core.constant;
/**
* 通用常量信息
*
* @author ruoyi
*/
public interface Constants {
int KB = 1024;
int MB = KB * 1024;
int GB = MB * 1024;
/**
* 资源映射路径 前缀
*/
String RESOURCE_PREFIX = "profile";
/**
* UTF-8 字符集
*/
String UTF8 = "UTF-8";
/**
* GBK 字符集
*/
String GBK = "GBK";
/**
* www主域
*/
String WWW = "www.";
/**
* http请求
*/
String HTTP = "http://";
/**
* https请求
*/
String HTTPS = "https://";
/**
* 通用成功标识
*/
String SUCCESS = "0";
String NORMAL = "0"; // 正常状态
/**
* 通用失败标识
*/
String FAIL = "1";
String DISABLE = "1"; // 异常/停用状态
/**
* 登录成功
*/
String LOGIN_SUCCESS = "Success";
/**
* 注销
*/
String LOGOUT = "Logout";
/**
* 注册
*/
String REGISTER = "Register";
/**
* 登录失败
*/
String LOGIN_FAIL = "Error";
/**
* 验证码有效期(分钟)
*/
Integer CAPTCHA_EXPIRATION = 2;
/**
* 顶级部门id
*/
Long TOP_PARENT_ID = 0L;
/**
* 超级管理员ID
*/
Long SUPER_ADMIN_ID = 1L;
/**
* 超级管理员角色 roleKey
*/
String SUPER_ADMIN_ROLE_KEY = "superadmin";
/**
* 租户管理员角色 roleKey
*/
String TENANT_ADMIN_ROLE_KEY = "admin";
/**
* 租户管理员角色名称
*/
String TENANT_ADMIN_ROLE_NAME = "管理员";
/**
* 默认租户ID
*/
String DEFAULT_TENANT_ID = "000000";
interface Cache {
/**
* 全局 redis key (业务无关的key)
*/
String GLOBAL_REDIS_KEY = "global:";
/**
* 登录账户密码错误次数 redis key
*/
String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
/**
* 验证码 redis key
*/
String CAPTCHA_CODE_KEY = GLOBAL_REDIS_KEY + "captcha_codes:";
}
}

View File

@@ -0,0 +1,93 @@
package com.agileboot.common.core.constant;
/**
* 返回状态码
*
* @author Lion Li
*/
public interface HttpStatus {
/**
* 操作成功
*/
int SUCCESS = 200;
/**
* 对象创建成功
*/
int CREATED = 201;
/**
* 请求已经被接受
*/
int ACCEPTED = 202;
/**
* 操作已经执行成功,但是没有返回数据
*/
int NO_CONTENT = 204;
/**
* 资源已被移除
*/
int MOVED_PERM = 301;
/**
* 重定向
*/
int SEE_OTHER = 303;
/**
* 资源没有被修改
*/
int NOT_MODIFIED = 304;
/**
* 参数列表错误(缺少,格式不匹配)
*/
int BAD_REQUEST = 400;
/**
* 未授权
*/
int UNAUTHORIZED = 401;
/**
* 访问受限,授权过期
*/
int FORBIDDEN = 403;
/**
* 资源,服务未找到
*/
int NOT_FOUND = 404;
/**
* 不允许的http方法
*/
int BAD_METHOD = 405;
/**
* 资源冲突,或者资源被锁
*/
int CONFLICT = 409;
/**
* 不支持的数据,媒体类型
*/
int UNSUPPORTED_TYPE = 415;
/**
* 系统内部错误
*/
int ERROR = 500;
/**
* 接口未实现
*/
int NOT_IMPLEMENTED = 501;
/**
* 系统警告消息
*/
int WARN = 601;
}

View File

@@ -0,0 +1,120 @@
package com.agileboot.common.core.core;
import com.agileboot.common.core.constant.HttpStatus;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
/**
* 响应信息主体
*
* @author Lion Li
*/
@Data
@NoArgsConstructor
public class R<T> implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 成功
*/
public static final int SUCCESS = 200;
/**
* 失败
*/
public static final int FAIL = 500;
/**
* 消息状态码
*/
private int code;
/**
* 消息内容
*/
private String msg;
/**
* 数据对象
*/
private T data;
public static <T> R<T> ok() {
return restResult(null, SUCCESS, "操作成功");
}
public static <T> R<T> ok(T data) {
return restResult(data, SUCCESS, "操作成功");
}
public static <T> R<T> ok(String msg) {
return restResult(null, SUCCESS, msg);
}
public static <T> R<T> ok(String msg, T data) {
return restResult(data, SUCCESS, msg);
}
public static <T> R<T> fail() {
return restResult(null, FAIL, "操作失败");
}
public static <T> R<T> fail(String msg) {
return restResult(null, FAIL, msg);
}
public static <T> R<T> fail(T data) {
return restResult(data, FAIL, "操作失败");
}
public static <T> R<T> fail(String msg, T data) {
return restResult(data, FAIL, msg);
}
public static <T> R<T> fail(int code, String msg) {
return restResult(null, code, msg);
}
/**
* 返回警告消息
*
* @param msg 返回内容
* @return 警告消息
*/
public static <T> R<T> warn(String msg) {
return restResult(null, HttpStatus.WARN, msg);
}
/**
* 返回警告消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 警告消息
*/
public static <T> R<T> warn(String msg, T data) {
return restResult(data, HttpStatus.WARN, msg);
}
private static <T> R<T> restResult(T data, int code, String msg) {
R<T> r = new R<>();
r.setCode(code);
r.setData(data);
r.setMsg(msg);
return r;
}
public static <T> Boolean isError(R<T> ret) {
return !isSuccess(ret);
}
public static <T> Boolean isSuccess(R<T> ret) {
return R.SUCCESS == ret.getCode();
}
}

View File

@@ -1,4 +1,4 @@
package com.agileboot.common.core.base;
package com.agileboot.common.core.core.base;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;

View File

@@ -1,4 +1,4 @@
package com.agileboot.orm.common.interfaces;
package com.agileboot.common.core.enums;
/**
* @author valarchie
@@ -18,7 +18,7 @@ public interface BasicEnum<T>{
* 获取枚举的描述
* @return 描述
*/
String description();
String getDesc();
}

View File

@@ -1,9 +1,8 @@
package com.agileboot.orm.common.util;
package com.agileboot.common.core.enums;
import cn.hutool.core.convert.Convert;
import com.agileboot.common.exception.ApiException;
import com.agileboot.common.exception.error.ErrorCode;
import com.agileboot.orm.common.interfaces.BasicEnum;
import com.agileboot.common.core.exception.ApiException;
import com.agileboot.common.core.exception.error.ErrorCode;
import java.util.Objects;
@@ -55,7 +54,7 @@ public class BasicEnumUtil {
public static <E extends Enum<E>> String getDescriptionByValue(Class<E> enumClass, Object value) {
E basicEnum = fromValueSafely(enumClass, value);
if (basicEnum != null) {
return ((BasicEnum<?>) basicEnum).description();
return ((BasicEnum<?>) basicEnum).getDesc();
}
return UNKNOWN;
}

View File

@@ -1,4 +1,4 @@
package com.agileboot.orm.common.interfaces;
package com.agileboot.common.core.enums;
/**
* 字典类型 接口
@@ -10,6 +10,6 @@ public interface DictionaryEnum<T> extends BasicEnum<T> {
* 获取css标签
* @return css标签
*/
String cssTag();
String getCssTag();
}

View File

@@ -0,0 +1,44 @@
package com.agileboot.common.core.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 登录类型
*
* @author Lion Li
*/
@Getter
@AllArgsConstructor
public enum LoginType {
/**
* 密码登录
*/
PASSWORD("user.password.retry.limit.exceed", "user.password.retry.limit.count"),
/**
* 短信登录
*/
SMS("sms.code.retry.limit.exceed", "sms.code.retry.limit.count"),
/**
* 邮箱登录
*/
EMAIL("email.code.retry.limit.exceed", "email.code.retry.limit.count"),
/**
* 小程序登录
*/
XCX("", "");
/**
* 登录重试超出限制提示
*/
final String retryLimitExceed;
/**
* 登录重试限制计数提示
*/
final String retryLimitCount;
}

View File

@@ -0,0 +1,39 @@
package com.agileboot.common.core.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
/**
* 用户类型
*
* @author Lion Li
*/
@Getter
@AllArgsConstructor
public enum UserType {
/**
* 后台系统用户
*/
SYS_USER("sys_user"),
/**
* 移动客户端用户
*/
APP_USER("app_user");
/**
* 用户类型标识(用于 token、权限识别等
*/
private final String userType;
public static UserType getUserType(String str) {
for (UserType value : values()) {
if (StringUtils.contains(str, value.getUserType())) {
return value;
}
}
throw new RuntimeException("'UserType' not found By " + str);
}
}

View File

@@ -0,0 +1,36 @@
package com.agileboot.common.core.enums.common;
import com.agileboot.common.core.enums.dictionary.CssTag;
import com.agileboot.common.core.enums.dictionary.Dictionary;
import com.agileboot.common.core.enums.DictionaryEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 对应sys_operation_log的business_type
*
* @author valarchie
*/
@Getter
@AllArgsConstructor
@Dictionary(name = "sysOperationLog.businessType")
public enum BusinessTypeEnum implements DictionaryEnum<Integer> {
/**
* 操作类型
*/
OTHER(0, "其他操作", CssTag.INFO),
ADD(1, "添加", CssTag.PRIMARY),
MODIFY(2, "修改", CssTag.PRIMARY),
DELETE(3, "删除", CssTag.DANGER),
GRANT(4, "授权", CssTag.PRIMARY),
EXPORT(5, "导出", CssTag.WARNING),
IMPORT(6, "导入", CssTag.WARNING),
FORCE_LOGOUT(7, "强退", CssTag.DANGER),
CLEAN(8, "清空", CssTag.DANGER),
;
private final Integer value;
private final String desc;
private final String cssTag;
}

View File

@@ -0,0 +1,29 @@
package com.agileboot.common.core.enums.common;
import com.agileboot.common.core.enums.DictionaryEnum;
import com.agileboot.common.core.enums.dictionary.CssTag;
import com.agileboot.common.core.enums.dictionary.Dictionary;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 对应sys_user的sex字段
*
* @author valarchie
*/
@Getter
@AllArgsConstructor
@Dictionary(name = "sysUser.sex")
public enum GenderEnum implements DictionaryEnum<Integer> {
/**
* 用户性别
*/
MALE(1, "", CssTag.PRIMARY),
FEMALE(2, "", CssTag.PRIMARY),
UNKNOWN(0, "未知", CssTag.PRIMARY);
private final Integer value;
private final String desc;
private final String cssTag;
}

View File

@@ -0,0 +1,30 @@
package com.agileboot.common.core.enums.common;
import com.agileboot.common.core.enums.DictionaryEnum;
import com.agileboot.common.core.enums.dictionary.CssTag;
import com.agileboot.common.core.enums.dictionary.Dictionary;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 用户状态
*
* @author valarchie
*/
// TODO 表记得改成LoginLog
@Dictionary(name = "sysLoginLog.status")
@Getter
@AllArgsConstructor
public enum LoginStatusEnum implements DictionaryEnum<Integer> {
/**
* status of user
*/
LOGIN_SUCCESS(1, "登录成功", CssTag.SUCCESS),
LOGOUT(2, "退出成功", CssTag.INFO),
REGISTER(3, "注册", CssTag.PRIMARY),
LOGIN_FAIL(0, "登录失败", CssTag.DANGER);
private final Integer value;
private final String desc;
private final String cssTag;
}

View File

@@ -0,0 +1,25 @@
package com.agileboot.common.core.enums.common;
import com.agileboot.common.core.enums.BasicEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author valarchie
*/
@Deprecated
@Getter
@AllArgsConstructor
public enum MenuComponentEnum implements BasicEnum<Integer> {
/**
* 菜单组件类型
*/
LAYOUT(1, "Layout"),
PARENT_VIEW(2, "ParentView"),
INNER_LINK(3, "InnerLink");
private final Integer value;
private final String desc;
}

View File

@@ -0,0 +1,26 @@
package com.agileboot.common.core.enums.common;
import com.agileboot.common.core.enums.BasicEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author valarchie
* 对应 sys_menu表的menu_type字段
*/
@Getter
@AllArgsConstructor
public enum MenuTypeEnum implements BasicEnum<Integer> {
/**
* 菜单类型
*/
MENU(1, "页面"),
CATALOG(2, "目录"),
IFRAME(3, "内嵌Iframe"),
OUTSIDE_LINK_REDIRECT(4, "外链跳转");
private final Integer value;
private final String desc;
}

View File

@@ -0,0 +1,29 @@
package com.agileboot.common.core.enums.common;
import com.agileboot.common.core.enums.DictionaryEnum;
import com.agileboot.common.core.enums.dictionary.CssTag;
import com.agileboot.common.core.enums.dictionary.Dictionary;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 对应sys_notice的 status字段
*
* @author valarchie
*/
@Dictionary(name = "sysNotice.status")
@Getter
@AllArgsConstructor
public enum NoticeStatusEnum implements DictionaryEnum<Integer> {
/**
* 通知状态
*/
OPEN(1, "正常", CssTag.PRIMARY),
CLOSE(0, "关闭", CssTag.DANGER);
private final Integer value;
private final String desc;
private final String cssTag;
}

View File

@@ -0,0 +1,39 @@
package com.agileboot.common.core.enums.common;
import com.agileboot.common.core.enums.DictionaryEnum;
import com.agileboot.common.core.enums.dictionary.CssTag;
import com.agileboot.common.core.enums.dictionary.Dictionary;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 对应sys_notice的 notice_type字段
* 名称一般由对应的表名.字段构成
* 全局的话使用common作为表名
*
* @author valarchie
*/
@Dictionary(name = "sysNotice.noticeType")
@Getter
@AllArgsConstructor
public enum NoticeTypeEnum implements DictionaryEnum<Integer> {
/**
* 通知类型
*/
NOTIFICATION(1, "通知", CssTag.WARNING),
ANNOUNCEMENT(2, "公告", CssTag.SUCCESS);
private final Integer value;
private final String desc;
private final String cssTag;
public static Integer getDescByValue(Integer value) {
for (NoticeTypeEnum item : values()) {
if (item.value.equals(value)) {
return item.value;
}
}
return null;
}
}

View File

@@ -0,0 +1,29 @@
package com.agileboot.common.core.enums.common;
import com.agileboot.common.core.enums.DictionaryEnum;
import com.agileboot.common.core.enums.dictionary.CssTag;
import com.agileboot.common.core.enums.dictionary.Dictionary;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 对应sys_operation_log的status字段
*
* @author valarchie
*/
@Dictionary(name = "sysOperationLog.status")
@Getter
@AllArgsConstructor
public enum OperationStatusEnum implements DictionaryEnum<Integer> {
/**
* 操作状态
*/
SUCCESS(1, "成功", CssTag.PRIMARY),
FAIL(0, "失败", CssTag.DANGER);
private final Integer value;
private final String desc;
private final String cssTag;
}

View File

@@ -0,0 +1,29 @@
package com.agileboot.common.core.enums.common;
import com.agileboot.common.core.enums.BasicEnum;
import com.agileboot.common.core.enums.dictionary.Dictionary;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 操作者类型
*
* @author valarchie
*/
@Getter
@AllArgsConstructor
@Dictionary(name = "sysOperationLog.operatorType")
public enum OperatorTypeEnum implements BasicEnum<Integer> {
/**
* 菜单类型
*/
OTHER(1, "其他"),
WEB(2, "Web用户"),
MOBILE(3, "手机端用户");
private final Integer value;
private final String desc;
}

View File

@@ -0,0 +1,29 @@
package com.agileboot.common.core.enums.common;
import com.agileboot.common.core.enums.BasicEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* Http Method
*
* @author valarchie
*/
@Getter
@AllArgsConstructor
public enum RequestMethodEnum implements BasicEnum<Integer> {
/**
* 菜单类型
*/
GET(1, "GET"),
POST(2, "POST"),
PUT(3, "PUT"),
DELETE(4, "DELETE"),
UNKNOWN(-1, "UNKNOWN");
private final Integer value;
private final String desc;
}

View File

@@ -0,0 +1,37 @@
package com.agileboot.common.core.enums.common;
import com.agileboot.common.core.enums.DictionaryEnum;
import com.agileboot.common.core.enums.dictionary.CssTag;
import com.agileboot.common.core.enums.dictionary.Dictionary;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 除非表有特殊指明的话,一般用这个枚举代表 status字段
*
* @author valarchie
*/
@Dictionary(name = "common.status")
@Getter
@AllArgsConstructor
public enum StatusEnum implements DictionaryEnum<Integer> {
/**
* 开关状态
*/
ENABLE(1, "正常", CssTag.PRIMARY),
DISABLE(0, "停用", CssTag.DANGER);
private final Integer value;
private final String desc;
private final String cssTag;
public static Integer getDescByValue(Integer value) {
for (StatusEnum item : StatusEnum.values()) {
if (item.value.equals(value)) {
return item.value;
}
}
return null;
}
}

View File

@@ -0,0 +1,29 @@
package com.agileboot.common.core.enums.common;
import com.agileboot.common.core.enums.DictionaryEnum;
import com.agileboot.common.core.enums.dictionary.CssTag;
import com.agileboot.common.core.enums.dictionary.Dictionary;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 对应sys_user的status字段
*
* @author valarchie
*/
@AllArgsConstructor
@Getter
@Dictionary(name = "sysUser.status")
public enum UserStatusEnum implements DictionaryEnum<Integer> {
/**
* 用户账户状态
*/
NORMAL(1, "正常", CssTag.PRIMARY),
DISABLED(2, "禁用", CssTag.DANGER),
FROZEN(3, "冻结", CssTag.WARNING);
private final Integer value;
private final String desc;
private final String cssTag;
}

View File

@@ -0,0 +1,30 @@
package com.agileboot.common.core.enums.common;
import com.agileboot.common.core.enums.DictionaryEnum;
import com.agileboot.common.core.enums.dictionary.CssTag;
import com.agileboot.common.core.enums.dictionary.Dictionary;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 对应sys_menu表的is_visible字段
*
* @author valarchie
*/
@Deprecated
@Dictionary(name = "sysMenu.isVisible")
@Getter
@AllArgsConstructor
public enum VisibleStatusEnum implements DictionaryEnum<Integer> {
/**
* 显示与否
*/
SHOW(1, "显示", CssTag.PRIMARY),
HIDE(0, "隐藏", CssTag.DANGER);
private final Integer value;
private final String desc;
private final String cssTag;
}

View File

@@ -0,0 +1,28 @@
package com.agileboot.common.core.enums.common;
import com.agileboot.common.core.enums.DictionaryEnum;
import com.agileboot.common.core.enums.dictionary.CssTag;
import com.agileboot.common.core.enums.dictionary.Dictionary;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 系统内代表是与否的枚举
*
* @author valarchie
*/
@Dictionary(name = "common.yesOrNo")
@Getter
@AllArgsConstructor
public enum YesOrNoEnum implements DictionaryEnum<Integer> {
/**
* 是与否
*/
YES(1, "", CssTag.PRIMARY),
NO(0, "", CssTag.DANGER);
private final Integer value;
private final String desc;
private final String cssTag;
}

View File

@@ -1,4 +1,4 @@
package com.agileboot.orm.common;
package com.agileboot.common.core.enums.dictionary;
/**
* Css 样式
@@ -6,8 +6,7 @@ package com.agileboot.orm.common;
*/
public class CssTag {
public static final String NONE = "";
public static final String PRIMARY = "primary";
public static final String PRIMARY = "";
public static final String DANGER = "danger";
public static final String WARNING = "warning";
public static final String SUCCESS = "success";

View File

@@ -1,12 +1,10 @@
package com.agileboot.infrastructure.cache.map;
package com.agileboot.common.core.enums.dictionary;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import com.agileboot.orm.common.annotations.Dictionary;
import com.agileboot.orm.common.enums.*;
import com.agileboot.orm.common.interfaces.DictionaryEnum;
import com.agileboot.orm.common.result.DictionaryData;
import com.agileboot.common.core.enums.DictionaryEnum;
import com.agileboot.common.core.enums.common.*;
import java.util.Arrays;
import java.util.List;
@@ -19,11 +17,11 @@ import java.util.stream.Collectors;
*
* @author valarchie
*/
public class MapCache {
public class DictCache {
private static final Map<String, List<DictionaryData>> DICTIONARY_CACHE = MapUtil.newHashMap(128);
private MapCache() {
private DictCache() {
}
static {
@@ -31,7 +29,7 @@ public class MapCache {
}
private static void initDictionaryCache() {
// TODO 这个可以做成自动扫描
loadInCache(BusinessTypeEnum.values());
loadInCache(YesOrNoEnum.values());
loadInCache(StatusEnum.values());
@@ -41,7 +39,7 @@ public class MapCache {
loadInCache(OperationStatusEnum.values());
loadInCache(LoginStatusEnum.values());
loadInCache(VisibleStatusEnum.values());
loadInCache(UserStatusEnum.values());
}

View File

@@ -1,4 +1,4 @@
package com.agileboot.orm.common.annotations;
package com.agileboot.common.core.enums.dictionary;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;

View File

@@ -1,6 +1,6 @@
package com.agileboot.orm.common.result;
package com.agileboot.common.core.enums.dictionary;
import com.agileboot.orm.common.interfaces.DictionaryEnum;
import com.agileboot.common.core.enums.DictionaryEnum;
import lombok.Data;
/**
@@ -17,9 +17,9 @@ public class DictionaryData {
@SuppressWarnings("rawtypes")
public DictionaryData(DictionaryEnum enumType) {
if (enumType != null) {
this.label = enumType.description();
this.label = enumType.getDesc();
this.value = (Integer) enumType.getValue();
this.cssTag = enumType.cssTag();
this.cssTag = enumType.getCssTag();
}
}

View File

@@ -0,0 +1,75 @@
package com.agileboot.common.core.exception;
import cn.hutool.core.util.StrUtil;
import com.agileboot.common.core.exception.error.ErrorCodeInterface;
import com.agileboot.common.core.utils.i18n.MessageUtils;
import java.util.HashMap;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
/**
* 统一异常类
*
* @author valarchie
*/
@EqualsAndHashCode(callSuper = true)
@Slf4j
@Data
public class ApiException extends RuntimeException {
protected ErrorCodeInterface errorCode;
protected String message;
protected String i18nMessage;
/**
* 如果有一些特殊的数据 可以放在这个payload里面
* 有时候错误的返回信息太少 不便前端处理的话 可以放在这个payload字段当中
* 比如你做了一个大批量操作操作ID为1~10的实体 其中1~5成功 6~10失败
* 你可以将这些相关信息放在这个payload中
*/
protected HashMap<String, Object> payload;
public ApiException(ErrorCodeInterface errorCode) {
fillErrorCode(errorCode);
}
public ApiException(ErrorCodeInterface errorCode, Object... args) {
fillErrorCode(errorCode, args);
}
/**
* 注意 如果是try catch的情况下捕获异常 并转为ApiException的话 一定要填入Throwable e
* @param e 捕获到的原始异常
* @param errorCode 错误码
* @param args 错误详细信息参数
*/
public ApiException(Throwable e, ErrorCodeInterface errorCode, Object... args) {
super(e);
fillErrorCode(errorCode, args);
}
private void fillErrorCode(ErrorCodeInterface errorCode, Object... args) {
this.errorCode = errorCode;
this.message = StrUtil.format(errorCode.message(), args);
try {
this.i18nMessage = MessageUtils.message(errorCode.i18nKey(), args);
} catch (Exception e) {
log.error("could not found i18nMessage entry for key: " + errorCode.i18nKey());
}
}
@Override
public String getMessage() {
return i18nMessage != null ? i18nMessage : message;
}
@Override
public String getLocalizedMessage() {
return i18nMessage != null ? i18nMessage : message;
}
}

View File

@@ -0,0 +1,55 @@
package com.agileboot.common.core.exception;
import cn.hutool.core.text.StrFormatter;
import com.agileboot.common.core.exception.error.ErrorCodeInterface;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.io.Serial;
/**
* @Author cuiJiaWang
* @Create 2025-08-12 16:32
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
public class BizException extends RuntimeException {
@Serial
private static final long serialVersionUID = 1L;
/**
* 错误码
*/
private Integer code;
/**
* 错误提示
*/
private String message;
public BizException(String message) {
this.message = message;
}
public BizException(ErrorCodeInterface errorCode) {
this.code = errorCode.code();
this.message = errorCode.message();
}
public BizException(String message, Integer code) {
this.message = message;
this.code = code;
}
public BizException(String message, Object... args) {
this.message = StrFormatter.format(message, args);
}
public BizException(ErrorCodeInterface errorCode, Object... args) {
this.message = StrFormatter.format(errorCode.message(), args);
}
}

View File

@@ -0,0 +1,52 @@
package com.agileboot.common.core.exception;
import cn.hutool.core.text.StrFormatter;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.io.Serial;
/**
* 业务异常(支持占位符 {}
*
* @author ruoyi
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
public final class ServiceException extends RuntimeException {
@Serial
private static final long serialVersionUID = 1L;
/**
* 错误码
*/
private Integer code;
/**
* 错误提示
*/
private String message;
/**
* 错误明细,内部调试错误
*/
private String detailMessage;
public ServiceException(String message) {
this.message = message;
}
public ServiceException(String message, Integer code) {
this.message = message;
this.code = code;
}
public ServiceException(String message, Object... args) {
this.message = StrFormatter.format(message, args);
}
}

View File

@@ -0,0 +1,410 @@
package com.agileboot.common.core.exception.error;
import org.springframework.util.Assert;
/**
* 错误码集合
*
* @author valarchie
*/
public enum ErrorCode implements ErrorCodeInterface {
/**
* 错误码集合
* ******以下是旧的设计****
* 1~9999 为保留错误码 或者 常用错误码
* 10000~19999 为内部错误码
* 20000~29999 客户端错误码 (客户端异常调用之类的错误)
* 30000~39999 为第三方错误码 (代码正常,但是第三方异常)
* 40000~49999 为业务逻辑 错误码 (无异常,代码正常流转,并返回提示给用户)
* 由于系统内的错误码都是独一无二的所以错误码应该放在common包集中管理
* ---------------------------
* 旧的设计的缺陷,比如内部错误码其实并不会很多 但是占用了1~9999的序列其实是不必要的。
* 而且错误码不一定位数一定要相同。比如腾讯的微信接口错误码的位数就并不相同。按照常理错误码的数量大小应该是:
* 内部错误码< 客户端错误码< 第三方错误码< 业务错误码
* 所以我们应该尽可能的把错误码的数量留给业务错误码
* ---------------------------
* *******新的设计**********
* 1~99 为内部错误码(框架本身的错误)
* 100~999 客户端错误码 (客户端异常调用之类的错误)
* 1000~9999为第三方错误码 (代码正常,但是第三方异常)
* 10000~99999 为业务逻辑 错误码 (无异常,代码正常流转,并返回提示给用户)
* 由于系统内的错误码都是独一无二的所以错误码应该放在common包集中管理
* ---------------------------
* 总体设计就是值越小 错误严重性越高
* 目前10000~19999是初始系统内嵌功能使用的错误码后续开发者可以直接使用20000以上的错误码作为业务错误码
*/
SUCCESS(0, "操作成功", "SUCCESS"),
FAILED(99999, "操作失败", "FAILED");
private final int code;
private final String msg;
private final String i18nKey;
ErrorCode(int code, String msg, String i18nKey) {
this.code = code;
this.msg = msg;
this.i18nKey = i18nKey;
}
@Override
public int code() {
return this.code;
}
@Override
public String message() {
return this.msg;
}
@Override
public String i18nKey() {
return this.i18nKey;
}
/**
* 10000~99999 为业务逻辑 错误码 (无代码异常,代码正常流转,并返回提示给用户)
* 1XX01 XX是代表模块的意思 比如10101 01是Permission模块
* 错误码的命名最好以模块为开头 比如 NOT_ALLOWED_TO_OPERATE前面加上PERMISSION = PERMISSION_NOT_ALLOWED_TO_OPERATE
*/
public enum Business implements ErrorCodeInterface {
// ----------------------------- COMMON --------------------------------------
COMMON_OBJECT_NOT_FOUND(10001, "找不到ID为 {} 的 {}", "Business.OBJECT_NOT_FOUND"),
COMMON_UNSUPPORTED_OPERATION(10002, "不支持的操作", "Business.UNSUPPORTED_OPERATION"),
COMMON_BULK_DELETE_IDS_IS_INVALID(10003, "批量参数ID列表为空", "Business.BULK_DELETE_IDS_IS_INVALID"),
COMMON_FILE_NOT_ALLOWED_TO_DOWNLOAD(10004, "文件名称({})非法,不允许下载", "Business.FILE_NOT_ALLOWED_TO_DOWNLOAD"),
// ----------------------------- PERMISSION -----------------------------------
PERMISSION_FORBIDDEN_TO_MODIFY_ADMIN(10101, "不允许修改管理员的信息", "Business.FORBIDDEN_TO_MODIFY_ADMIN"),
PERMISSION_NOT_ALLOWED_TO_OPERATE(10202, "没有权限进行此操作,请联系管理员", "Business.NO_PERMISSION_TO_OPERATE"),
// ----------------------------- LOGIN -----------------------------------------
LOGIN_WRONG_USER_PASSWORD(10201, "用户密码错误,请重输", "Business.LOGIN_WRONG_USER_PASSWORD"),
LOGIN_ERROR(10202, "登录失败:{}", "Business.LOGIN_ERROR"),
LOGIN_CAPTCHA_CODE_WRONG(10203, "验证码错误", "Business.LOGIN_CAPTCHA_CODE_WRONG"),
LOGIN_CAPTCHA_CODE_EXPIRE(10204, "验证码过期", "Business.LOGIN_CAPTCHA_CODE_EXPIRE"),
LOGIN_CAPTCHA_CODE_NULL(10205, "验证码为空", "Business.LOGIN_CAPTCHA_CODE_NULL"),
// ----------------------------- UPLOAD -----------------------------------------
UPLOAD_FILE_TYPE_NOT_ALLOWED(10401, "不允许上传的文件类型,仅允许:{}", "Business.UPLOAD_FILE_TYPE_NOT_ALLOWED"),
UPLOAD_FILE_NAME_EXCEED_MAX_LENGTH(10402, "文件名长度超过:{} ", "Business.UPLOAD_FILE_NAME_EXCEED_MAX_LENGTH"),
UPLOAD_FILE_SIZE_EXCEED_MAX_SIZE(10403, "文件名大小超过:{} MB", "Business.UPLOAD_FILE_SIZE_EXCEED_MAX_SIZE"),
UPLOAD_IMPORT_EXCEL_FAILED(10404, "导入excel失败{}", "Business.UPLOAD_IMPORT_EXCEL_FAILED"),
UPLOAD_FILE_IS_EMPTY(10405, "上传文件为空", "Business.UPLOAD_FILE_IS_EMPTY"),
UPLOAD_FILE_FAILED(10406, "上传文件失败:{}", "Business.UPLOAD_FILE_FAILED"),
// ----------------------------- CONFIG -----------------------------------------
CONFIG_VALUE_IS_NOT_ALLOW_TO_EMPTY(10601, "参数键值不允许为空", "Business.CONFIG_VALUE_IS_NOT_ALLOW_TO_EMPTY"),
CONFIG_VALUE_IS_NOT_IN_OPTIONS(10602, "参数键值不存在列表中", "Business.CONFIG_VALUE_IS_NOT_IN_OPTIONS"),
// ------------------------------- POST --------------------------------------------
POST_NAME_IS_NOT_UNIQUE(10701, "岗位名称:{}, 已存在", "Business.POST_NAME_IS_NOT_UNIQUE"),
POST_CODE_IS_NOT_UNIQUE(10702, "岗位编号:{}, 已存在", "Business.POST_CODE_IS_NOT_UNIQUE"),
POST_ALREADY_ASSIGNED_TO_USER_CAN_NOT_BE_DELETED(10703, "职位已分配给用户,请先取消分配再删除", "Business.POST_ALREADY_ASSIGNED_TO_USER_CAN_NOT_BE_DELETED"),
// ------------------------------- DEPT ---------------------------------------------
DEPT_NAME_IS_NOT_UNIQUE(10801, "部门名称:{}, 已存在", "Business.DEPT_NAME_IS_NOT_UNIQUE"),
DEPT_PARENT_ID_IS_NOT_ALLOWED_SELF(10802, "父级部门不能选择自己", "Business.DEPT_PARENT_ID_IS_NOT_ALLOWED_SELF"),
DEPT_STATUS_ID_IS_NOT_ALLOWED_CHANGE(10803, "子部门还有正在启用的部门,暂时不能停用该部门", "Business.DEPT_STATUS_ID_IS_NOT_ALLOWED_CHANGE"),
DEPT_EXIST_CHILD_DEPT_NOT_ALLOW_DELETE(10804, "该部门存在下级部门不允许删除", "Business.DEPT_EXIST_CHILD_DEPT_NOT_ALLOW_DELETE"),
DEPT_EXIST_LINK_USER_NOT_ALLOW_DELETE(10805, "该部门存在关联的用户不允许删除", "Business.DEPT_EXIST_LINK_USER_NOT_ALLOW_DELETE"),
DEPT_PARENT_DEPT_NO_EXIST_OR_DISABLED(10806, "该父级部门不存在或已停用", "Business.DEPT_PARENT_DEPT_NO_EXIST_OR_DISABLED"),
// ------------------------------- MENU -------------------------------------------------
MENU_NAME_IS_NOT_UNIQUE(10901, "新增菜单:{} 失败,菜单名称已存在", "Business.MENU_NAME_IS_NOT_UNIQUE"),
MENU_EXTERNAL_LINK_MUST_BE_HTTP(10902, "菜单外链必须以 http(s)://开头", "Business.MENU_EXTERNAL_LINK_MUST_BE_HTTP"),
MENU_PARENT_ID_NOT_ALLOW_SELF(10903, "父级菜单不能选择自身", "Business.MENU_PARENT_ID_NOT_ALLOW_SELF"),
MENU_EXIST_CHILD_MENU_NOT_ALLOW_DELETE(10904, "存在子菜单不允许删除", "Business.MENU_EXIST_CHILD_MENU_NOT_ALLOW_DELETE"),
MENU_ALREADY_ASSIGN_TO_ROLE_NOT_ALLOW_DELETE(10905, "菜单已分配给角色,不允许", "Business.MENU_ALREADY_ASSIGN_TO_ROLE_NOT_ALLOW_DELETE"),
MENU_NOT_ALLOWED_TO_CREATE_BUTTON_ON_IFRAME_OR_OUT_LINK(10906, "不允许在Iframe和外链跳转类型下创建按钮", "Business.MENU_ONLY_ALLOWED_TO_CREATE_BUTTON_ON_PAGE"),
MENU_ONLY_ALLOWED_TO_CREATE_SUB_MENU_IN_CATALOG(10907, "只允许在目录类型底下创建子菜单", "Business.MENU_ONLY_ALLOWED_TO_CREATE_SUB_MENU_IN_CATALOG"),
MENU_CAN_NOT_CHANGE_MENU_TYPE(10908, "不允许更改菜单的类型", "Business.MENU_CAN_NOT_CHANGE_MENU_TYPE"),
// -------------------------------- ROLE -------------------------------------------------
ROLE_NAME_IS_NOT_UNIQUE(11001, "角色名称:{}, 已存在", "Business.ROLE_NAME_IS_NOT_UNIQUE"),
ROLE_KEY_IS_NOT_UNIQUE(11002, "角色标识:{}, 已存在", "Business.ROLE_KEY_IS_NOT_UNIQUE"),
ROLE_DATA_SCOPE_DUPLICATED_DEPT(11003, "重复的部门id", "Business.ROLE_DATA_SCOPE_DUPLICATED_DEPT"),
ROLE_ALREADY_ASSIGN_TO_USER(11004, "角色:{} 已分配给用户,请先取消分配,再删除角色", "Business.ROLE_ALREADY_ASSIGN_TO_USER"),
ROLE_IS_NOT_AVAILABLE(11005, "角色:{} 已禁用,无法分配给用户", "Business.ROLE_IS_NOT_AVAILABLE"),
// ---------------------------------- USER -----------------------------------------------
USER_NON_EXIST(10501, "登录用户:{} 不存在", "Business.USER_NON_EXIST"),
USER_IS_DISABLE(10502, "对不起, 您的账号:{} 已停用", "Business.USER_IS_DISABLE"),
USER_CACHE_IS_EXPIRE(11003, "用户缓存信息已经过期", "Business.USER_CACHE_IS_EXPIRE"),
USER_FAIL_TO_GET_USER_ID(11004, "获取用户ID失败", "Business.USER_FAIL_TO_GET_USER_ID"),
USER_FAIL_TO_GET_DEPT_ID(10504, "获取用户部门ID失败", "Business.USER_FAIL_TO_GET_DEPT_ID"),
USER_FAIL_TO_GET_ACCOUNT(10505, "获取用户账户失败", "Business.USER_FAIL_TO_GET_ACCOUNT"),
USER_FAIL_TO_GET_USER_INFO(10506, "获取用户信息失败", "Business.USER_FAIL_TO_GET_USER_INFO"),
USER_IMPORT_DATA_IS_NULL(10507, "导入的用户为空", "Business.USER_IMPORT_DATA_IS_NULL"),
USER_PHONE_NUMBER_IS_NOT_UNIQUE(10508, "该电话号码已被其他用户占用", "Business.USER_PHONE_NUMBER_IS_NOT_UNIQUE"),
USER_EMAIL_IS_NOT_UNIQUE(10509, "该邮件地址已被其他用户占用", "Business.USER_EMAIL_IS_NOT_UNIQUE"),
USER_PASSWORD_IS_NOT_CORRECT(10510, "用户密码错误", "Business.USER_PASSWORD_IS_NOT_CORRECT"),
USER_NEW_PASSWORD_IS_THE_SAME_AS_OLD(10511, "用户新密码与旧密码相同", "Business.USER_NEW_PASSWORD_IS_THE_SAME_AS_OLD"),
USER_UPLOAD_FILE_FAILED(10512, "用户上传文件失败", "Business.USER_UPLOAD_FILE_FAILED"),
USER_NAME_IS_NOT_UNIQUE(10513, "用户名已被其他用户占用", "Business.USER_NAME_IS_NOT_UNIQUE"),
USER_CURRENT_USER_CAN_NOT_BE_DELETE(10514, "当前用户不允许被删除", "Business.USER_CURRENT_USER_CAN_NOT_BE_DELETE"),
USER_ADMIN_CAN_NOT_BE_MODIFY(10515, "管理员不允许做任何修改", "Business.USER_ADMIN_CAN_NOT_BE_MODIFY"),
;
private final int code;
private final String msg;
private final String i18nKey;
Business(int code, String msg, String i18nKey) {
Assert.isTrue(code > 10000 && code < 99999,
"错误码code值定义失败Business错误码code值范围在10000~99099之间请查看ErrorCode.Business类当前错误码码为" + name());
String errorTypeName = this.getClass().getSimpleName();
Assert.isTrue(i18nKey != null && i18nKey.startsWith(errorTypeName),
String.format("错误码i18nKey值定义失败%s错误码i18nKey值必须以%s开头当前错误码为%s", errorTypeName, errorTypeName, name()));
this.code = code;
this.msg = msg;
this.i18nKey = i18nKey;
}
@Override
public int code() {
return this.code;
}
@Override
public String message() {
return this.msg;
}
@Override
public String i18nKey() {
return i18nKey;
}
}
/**
* 1000~9999是外部错误码 比如调用支付失败
*/
public enum External implements ErrorCodeInterface {
/**
* 支付宝调用失败
*/
FAIL_TO_PAY_ON_ALIPAY(1001, "支付宝调用失败", "External.FAIL_TO_PAY_ON_ALIPAY");
private final int code;
private final String msg;
private final String i18nKey;
External(int code, String msg, String i18nKey) {
Assert.isTrue(code > 1000 && code < 9999,
"错误码code值定义失败External错误码code值范围在1000~9999之间请查看ErrorCode.External类当前错误码码为" + name());
String errorTypeName = this.getClass().getSimpleName();
Assert.isTrue(i18nKey != null && i18nKey.startsWith(errorTypeName),
String.format("错误码i18nKey值定义失败%s错误码i18nKey值必须以%s开头当前错误码为%s", errorTypeName, errorTypeName, name()));
this.code = code;
this.msg = msg;
this.i18nKey = i18nKey;
}
@Override
public int code() {
return this.code;
}
@Override
public String message() {
return this.msg;
}
@Override
public String i18nKey() {
return this.i18nKey;
}
}
/**
* 100~999是客户端错误码
* 客户端如 Web+小程序+手机端 调用出错
* 可能由于参数问题或者授权问题或者调用过去频繁
*/
public enum Client implements ErrorCodeInterface {
COMMON_FORBIDDEN_TO_CALL(101, "禁止调用", "Client.COMMON_FORBIDDEN_TO_CALL"),
COMMON_REQUEST_TOO_OFTEN(102, "调用太过频繁", "Client.COMMON_REQUEST_TOO_OFTEN"),
COMMON_REQUEST_PARAMETERS_INVALID(103, "请求参数异常,{}", "Client.COMMON_REQUEST_PARAMETERS_INVALID"),
COMMON_REQUEST_METHOD_INVALID(104, "请求方式: {} 不支持", "Client.COMMON_REQUEST_METHOD_INVALID"),
COMMON_REQUEST_RESUBMIT(105, "请求重复提交", "Client.COMMON_REQUEST_RESUBMIT"),
COMMON_NO_AUTHORIZATION(106, "请求接口:{} 失败,用户未授权", "Client.COMMON_NO_AUTHORIZATION"),
INVALID_TOKEN(107, "token异常", "Client.INVALID_TOKEN"),
TOKEN_PROCESS_FAILED(108, "token处理失败{}", "Client.TOKEN_PROCESS_FAILED"),
;
private final int code;
private final String msg;
private final String i18nKey;
Client(int code, String msg, String i18nKey) {
Assert.isTrue(code > 100 && code < 999,
"错误码code值定义失败Client错误码code值范围在100~999之间请查看ErrorCode.Client类当前错误码码为" + name());
String errorTypeName = this.getClass().getSimpleName();
Assert.isTrue(i18nKey != null && i18nKey.startsWith(errorTypeName),
String.format("错误码i18nKey值定义失败%s错误码i18nKey值必须以%s开头当前错误码为%s", errorTypeName, errorTypeName, name()));
this.code = code;
this.msg = msg;
this.i18nKey = i18nKey;
}
@Override
public int code() {
return this.code;
}
@Override
public String message() {
return this.msg;
}
@Override
public String i18nKey() {
return this.i18nKey;
}
}
/**
* 0~99是内部错误码 例如 框架内部问题之类的
*/
public enum Internal implements ErrorCodeInterface {
/**
* 内部错误码
*/
INVALID_PARAMETER(1, "参数异常:{}", "Internal.INVALID_PARAMETER"),
/**
* 该错误主要用于返回 未知的异常大部分是RuntimeException 程序未能捕获 未能预料的错误
*/
INTERNAL_ERROR(2, "系统内部错误:{}", "Internal.INTERNAL_ERROR"),
GET_ENUM_FAILED(3, "获取枚举类型失败, 枚举类:{}", "Internal.GET_ENUM_FAILED"),
GET_CACHE_FAILED(4, "获取缓存失败:{}", "Internal.GET_CACHE_FAILED"),
DB_INTERNAL_ERROR(5, "数据库异常", "Internal.DB_INTERNAL_ERROR"),
LOGIN_CAPTCHA_GENERATE_FAIL(7, "验证码生成失败", "Internal.LOGIN_CAPTCHA_GENERATE_FAIL"),
EXCEL_PROCESS_ERROR(8, "excel处理失败{}", "Internal.EXCEL_PROCESS_ERROR"),
;
private final int code;
private final String msg;
private final String i18nKey;
Internal(int code, String msg, String i18nKey) {
Assert.isTrue(code < 100,
"错误码code值定义失败Internal错误码code值范围在100~999之间请查看ErrorCode.Internal类当前错误码码为" + name());
String errorTypeName = this.getClass().getSimpleName();
Assert.isTrue(i18nKey != null && i18nKey.startsWith(errorTypeName),
String.format("错误码i18nKey值定义失败%s错误码i18nKey值必须以%s开头当前错误码为%s", errorTypeName, errorTypeName, name()));
this.code = code;
this.msg = msg;
this.i18nKey = i18nKey;
}
@Override
public int code() {
return this.code;
}
@Override
public String message() {
return this.msg;
}
@Override
public String i18nKey() {
return this.i18nKey;
}
}
}

View File

@@ -1,16 +1,10 @@
package com.agileboot.common.exception.error;
package com.agileboot.common.core.exception.error;
/**
* @author valarchie
*/
public interface ErrorCodeInterface {
/**
* 返回错误码名称
* @return 枚举名称
*/
String name();
/**
* 返回错误码
* @return 错误码
@@ -27,8 +21,6 @@ public interface ErrorCodeInterface {
* i18n资源文件的key, 详见messages.properties文件
* @return key
*/
default String i18nKey() {
return code() + "_" + name();
}
String i18nKey();
}

View File

@@ -0,0 +1,31 @@
package com.agileboot.common.core.factory;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.DefaultPropertySourceFactory;
import org.springframework.core.io.support.EncodedResource;
import java.io.IOException;
/**
* yml 配置源工厂
*
* @author Lion Li
*/
public class YmlPropertySourceFactory extends DefaultPropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
String sourceName = resource.getResource().getFilename();
if (StringUtils.isNotBlank(sourceName) && StringUtils.endsWithAny(sourceName, ".yml", ".yaml")) {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(resource.getResource());
factory.afterPropertiesSet();
return new PropertiesPropertySource(sourceName, factory.getObject());
}
return super.createPropertySource(name, resource);
}
}

View File

@@ -1,12 +1,13 @@
package com.agileboot.common.utils;
package com.agileboot.common.core.utils;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
@@ -14,6 +15,7 @@ import java.io.IOException;
*
* @author ruoyi
*/
@Slf4j
public class ServletHolderUtil {
private ServletHolderUtil() {
@@ -52,7 +54,7 @@ public class ServletHolderUtil {
response.setCharacterEncoding("utf-8");
response.getWriter().print(string);
} catch (IOException e) {
e.printStackTrace();
log.error("返回response失败", e);
}
}
@@ -71,5 +73,24 @@ public class ServletHolderUtil {
}
/**
* 获取客户端IP地址兼容代理头
*/
public static String getClientIp() {
HttpServletRequest request = getRequest();
String xForwardedFor = request.getHeader("X-Forwarded-For");
if (StrUtil.isNotEmpty(xForwardedFor)) {
// 可能存在多个IP取第一个
int commaIndex = xForwardedFor.indexOf(',');
return commaIndex > 0 ? xForwardedFor.substring(0, commaIndex).trim() : xForwardedFor.trim();
}
String realIp = request.getHeader("X-Real-IP");
if (StrUtil.isNotEmpty(realIp)) {
return realIp.trim();
}
return request.getRemoteAddr();
}
}

View File

@@ -0,0 +1,36 @@
package com.agileboot.common.core.utils;
import cn.hutool.extra.spring.SpringUtil;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.Validator;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import java.util.Set;
/**
* Validator 校验框架工具
*
* @author Lion Li
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ValidatorUtils {
private static final Validator VALID = SpringUtil.getBean(Validator.class);
/**
* 对给定对象进行参数校验,并根据指定的校验组进行校验
*
* @param object 要进行校验的对象
* @param groups 校验组
* @throws ConstraintViolationException 如果校验不通过,则抛出参数校验异常
*/
public static <T> void validate(T object, Class<?>... groups) {
Set<ConstraintViolation<T>> validate = VALID.validate(object, groups);
if (!validate.isEmpty()) {
throw new ConstraintViolationException("参数校验异常", validate);
}
}
}

View File

@@ -1,4 +1,4 @@
package com.agileboot.common.utils.file;
package com.agileboot.common.core.utils.file;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
@@ -7,12 +7,12 @@ import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import com.agileboot.common.config.AgileBootConfig;
import com.agileboot.common.constant.Constants;
import com.agileboot.common.exception.ApiException;
import com.agileboot.common.exception.error.ErrorCode;
import com.agileboot.common.exception.error.ErrorCode.Business;
import com.agileboot.common.exception.error.ErrorCode.Internal;
import com.agileboot.common.core.config.AgileBootConfig;
import com.agileboot.common.core.constant.Constants;
import com.agileboot.common.core.exception.ApiException;
import com.agileboot.common.core.exception.error.ErrorCode;
import com.agileboot.common.core.exception.error.ErrorCode.Business;
import com.agileboot.common.core.exception.error.ErrorCode.Internal;
import org.apache.commons.io.FilenameUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.util.MimeType;

View File

@@ -1,4 +1,4 @@
package com.agileboot.common.utils.i18n;
package com.agileboot.common.core.utils.i18n;
import cn.hutool.extra.spring.SpringUtil;
import org.springframework.context.MessageSource;
@@ -7,7 +7,7 @@ import org.springframework.context.i18n.LocaleContextHolder;
/**
* 获取i18n资源文件
*
* @author ruoyi
* @author valarchie
*/
public class MessageUtils {

View File

@@ -1,4 +1,4 @@
package com.agileboot.common.utils.ip;
package com.agileboot.common.core.utils.ip;
import cn.hutool.core.text.CharSequenceUtil;
import lombok.AllArgsConstructor;

View File

@@ -1,4 +1,4 @@
package com.agileboot.common.utils.ip;
package com.agileboot.common.core.utils.ip;
import cn.hutool.core.util.StrUtil;

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