128 Commits

Author SHA1 Message Date
疯狂的狮子Li
267ff79b0c 😴发布 4.8.2 正式进入维护状态 2023-11-27 13:23:41 +08:00
疯狂的狮子Li
a6f62ca86f 🎃 发布 4.8.1 稳定性增强 修复部分bug 2023-09-25 10:42:58 +08:00
疯狂的狮子Li
8a692ed45a 🎃 发布 4.8.0 新增 sms4j 短信融合 2023-07-10 11:06:58 +08:00
疯狂的狮子li
6f6ac2c0cf ⚔ 发布 4.7.0 稳定性版本 2023-05-08 09:54:23 +08:00
疯狂的狮子li
36ac478624 🎇发布 4.6.0 新增 数据库加解密 与 通用翻译 功能 2023-03-13 10:10:47 +08:00
疯狂的狮子li
f196010416 fix 修复 新版本 Redisson 存在与 boot 2.X 的兼容性问题 2023-01-12 15:17:16 +08:00
疯狂的狮子li
173862360e 🧧发布 4.5.0 新春版 2023-01-12 09:55:50 +08:00
疯狂的狮子Li
34574c5bf7 发布 4.4.0 正式版 2022-11-28 14:42:17 +08:00
疯狂的狮子li
02e9ac799d 🐬发布 4.3.1 修复了一些问题建议升级 2022-10-24 14:36:47 +08:00
疯狂的狮子li
0f237ef7ed fix 修复 日志转换非json数据导致报错 2022-09-13 18:28:55 +08:00
疯狂的狮子li
817da4d2b8 fix 修复 用户导入存在则更新不生效 2022-09-13 18:28:44 +08:00
疯狂的狮子li
ee48cd7d01 🐣发布 4.3.0 正式版 2022-09-13 16:31:26 +08:00
疯狂的狮子Li
c5f4dec559 发布 v4.2.0 2022-06-28 22:51:57 +08:00
疯狂的狮子li
e0527b3350 Merge remote-tracking branch 'origin/fast' into fast 2022-04-24 14:09:28 +08:00
疯狂的狮子li
d5520817bd 发布 4.1.0 2022-04-24 14:09:19 +08:00
疯狂的狮子Li
7c04240317 fix 修复 数据权限 从 aop 切换到 拦截器 导致获取代理失败问题 2022-03-28 21:03:52 +08:00
疯狂的狮子li
2cf283b8c6 发布 4.0.1 2022-03-01 10:37:26 +08:00
疯狂的狮子li
0e81a7c342 fix 修复 minio 适配 https 导致的问题 2022-02-18 14:08:21 +08:00
疯狂的狮子li
6fa53ebe31 fix 修复 minio 适配 https 导致的问题 2022-02-18 14:08:01 +08:00
疯狂的狮子li
356f7ec184 Merge remote-tracking branch 'origin/fast' into fast 2022-02-18 11:38:12 +08:00
疯狂的狮子li
400ecdf0ab 发布 4.0.0 2022-02-18 11:37:21 +08:00
疯狂的狮子Li
28916bd384 fix 修复 数据权限 缓存方法名错误问题 2022-01-26 10:33:49 +00:00
疯狂的狮子li
dafb7477f6 update 注释遗漏 老版本数据权限 2021-12-28 14:30:31 +08:00
疯狂的狮子li
55e3e93199 发布 v3.5.0-release 正式版 2021-12-28 11:00:10 +08:00
疯狂的狮子li
5857db7c5a fix 修复代码生成 导出注解错误 2021-12-13 10:04:33 +08:00
疯狂的狮子li
5674d4a618 update 更改前端工程文件版本号
(cherry picked from commit 255b5f2f07)
2021-11-30 11:12:47 +08:00
疯狂的狮子Li
fd45cdb882 update 补全漏提交文件 2021-11-29 22:07:22 +08:00
疯狂的狮子li
c76ab64e8a 发布 v3.4.0 2021-11-29 14:26:23 +08:00
疯狂的狮子Li
d81377a2ed fix 由于 fast 单体版 代码统一管理 无法排除 quartz 导致运行异常 故优先删除 quartz 相关代码 2021-11-07 20:28:01 +08:00
疯狂的狮子Li
23cb4eef33 fix 修复通用实体 传参无法接收问题 2021-11-02 22:46:05 +08:00
疯狂的狮子li
45e2672e26 fix 修复 xxl-job-admin 部署问题 2021-11-01 13:50:22 +08:00
疯狂的狮子Li
b98112fd92 fix 修复 SysOss、SysOssConfig 未继承 BaseEntity 基础实体问题 2021-10-31 21:33:54 +08:00
疯狂的狮子li
4d12424378 发布 v3.3.0 2021-10-29 09:18:18 +08:00
疯狂的狮子li
6def4aa84d fix 修复 多数据源aop语法错误 2021-09-28 14:40:03 +08:00
疯狂的狮子li
9351cc4426 发布 v3.2.0 2021-09-28 10:09:53 +08:00
疯狂的狮子li
242a74a8ae update 移除无用依赖 2021-09-26 18:04:40 +08:00
疯狂的狮子li
ad566e9283 update 回滚 配置检测拦截是否有效SQL 因不通用 2021-09-09 17:41:04 +08:00
疯狂的狮子li
5a0136a655 发布 v3.1.0 2021-09-07 14:25:55 +08:00
疯狂的狮子Li
33033d7d78 !85 fix OssFactory编译报错
Merge pull request !85 from dawn9117/N/A
2021-09-02 08:27:51 +00:00
dawn9117
57ff78d7aa fix OssFactory编译报错 2021-09-02 08:26:17 +00:00
疯狂的狮子Li
849a131982 !81 fast版 oss上传出错
Merge pull request !81 from 李魁哲/lkz
2021-08-21 02:28:59 +00:00
李魁哲
a66bd96a31 !3 oss上传文件报错
Merge pull request !3 from 李魁哲/N/A
2021-08-21 01:55:23 +00:00
李魁哲
44dfbd24a8 oss上传文件报错 2021-08-21 01:54:56 +00:00
李魁哲
de658c307d !2 21231
Merge pull request !2 from 李魁哲/fast
2021-08-20 10:00:22 +00:00
李魁哲
01f3a94406 Merge branch 'lkz' of gitee.com:lkz9773/RuoYi-Vue-Plus into fast 2021-08-20 10:00:03 +00:00
疯狂的狮子li
20d6a893cb fix 修复 excel 导入与 class 未对应问题 2021-08-20 17:02:18 +08:00
李魁哲
4e6057d01e !1 3.00
* update 优化 OSS 模块与上传组件 异常处理
* fix 修复 OSS配置清空被过滤问题
* fix 修复 新版本说明 标签错误
* fix 修复 富文本图片路径错误问题
* fix 修复 minio 无 perfix 问题
* 发布 v3.0.0
* update 降级 minio 依赖版本
* update service 统一使用 ServicePlusImpl
2021-08-20 08:52:13 +00:00
疯狂的狮子li
879f18f6f0 update 优化 OSS 模块与上传组件 异常处理 2021-08-18 19:19:12 +08:00
疯狂的狮子li
12e69e946e fix 修复 OSS配置清空被过滤问题 2021-08-18 18:25:17 +08:00
疯狂的狮子li
d4758aae1e fix 修复 新版本说明 标签错误
(cherry picked from commit 96c4c4da56)
2021-08-18 16:56:04 +08:00
疯狂的狮子li
05ca59a525 fix 修复 富文本图片路径错误问题
(cherry picked from commit cf4b49ca3b)
2021-08-18 14:50:31 +08:00
疯狂的狮子li
ba018d0d6c fix 修复 minio 无 perfix 问题 2021-08-18 14:15:55 +08:00
疯狂的狮子li
c206f938ba 发布 v3.0.0 2021-08-18 11:45:51 +08:00
疯狂的狮子li
3294390407 update 降级 minio 依赖版本
(cherry picked from commit a6bde3c5da)
2021-07-30 14:18:13 +08:00
疯狂的狮子li
39e3152ed0 update service 统一使用 ServicePlusImpl 2021-07-28 14:43:21 +08:00
疯狂的狮子li
2b3ac89fa1 fix 修复 jdk8 与 jdk11 差异问题 2021-07-28 11:57:34 +08:00
疯狂的狮子li
3f3a7db544 发布 v2.6.0 2021-07-28 11:32:30 +08:00
疯狂的狮子li
a3e781915e fix 修复多数据源druid全局配置缩进错误 引起无效配置问题 2021-07-24 18:24:29 +08:00
疯狂的狮子li
dc5c5c292e remove 移除无用配置
(cherry picked from commit aad482a7e0)
2021-07-20 11:15:33 +08:00
疯狂的狮子li
fc1864c52e remove 删除无用文档与脚本
(cherry picked from commit 50b7421f28)
2021-07-20 11:14:56 +08:00
疯狂的狮子li
8e8520060d 发布 v2.5.2 2021-07-20 11:03:57 +08:00
疯狂的狮子li
51d1e3c8c1 发布 v2.5.1 针对 v2.5.0 版本新特性bug修复 2021-07-13 13:57:44 +08:00
疯狂的狮子li
49c2809895 Merge remote-tracking branch 'origin/fast' into fast 2021-07-12 11:36:47 +08:00
疯狂的狮子li
007a6d0c88 发布 v2.5.0 2021-07-12 11:36:37 +08:00
疯狂的狮子Li
a77ee34a73 update README.md. 2021-06-25 08:01:35 +00:00
疯狂的狮子li
7e3bbb4aab update 更新文档 提问四部曲 2021-06-24 17:13:39 +08:00
疯狂的狮子li
17ed4adb90 update 更新文档 提问四部曲 2021-06-24 17:11:14 +08:00
朱杰
4e93575c94 update 修改readme加入提问四部曲 2021-06-24 17:11:13 +08:00
疯狂的狮子li
0e67a487c3 fix 相对路径下载问题 2021-06-24 15:43:46 +08:00
疯狂的狮子li
31e4735dcb 发布 v2.4.0 2021-06-24 09:52:40 +08:00
疯狂的狮子li
03c459e5a3 同步 dev 分支 2021-06-23 10:02:55 +08:00
疯狂的狮子li
3e5b850e25 发布 v2.3.2 2021-06-11 10:00:05 +08:00
疯狂的狮子li
801f7cd8f7 发布 2.3.1 2021-06-04 16:20:12 +08:00
疯狂的狮子li
d87eb34352 Merge remote-tracking branch 'origin/fast' into fast 2021-06-01 10:53:36 +08:00
疯狂的狮子li
59ef30b156 发布 2.3.0 2021-06-01 10:53:30 +08:00
疯狂的狮子Li
47e2a3e116 fix 修复数据权限编写错误 2021-05-29 21:49:35 +08:00
疯狂的狮子li
76aa006db5 update 还原数据权限修改 2021-05-29 19:49:22 +08:00
疯狂的狮子li
fab58a4f77 发布 2.2.1 2021-05-29 19:23:45 +08:00
疯狂的狮子li
96cdd2490d 同步dev分支 2021-05-26 16:52:24 +08:00
疯狂的狮子li
a90a5e9cd9 Merge remote-tracking branch 'origin/fast' into fast
# Conflicts:
#	README.md
2021-05-26 16:51:22 +08:00
疯狂的狮子li
08b339b25e 同步dev分支 2021-05-26 16:51:01 +08:00
疯狂的狮子li
002c7ffca5 update 更新捐献二维码 2021-05-25 20:45:56 +08:00
疯狂的狮子li
a42ef126cd 版本更新 v2.2.0 2021-05-25 14:31:52 +08:00
疯狂的狮子li
8a94526110 发版 2.1.2 2021-05-21 18:00:40 +08:00
疯狂的狮子li
33c6fdfaa9 发布 v2.1.1 2021-05-18 11:50:29 +08:00
疯狂的狮子li
403c12eb9c 版本更新 v2.1.0 2021-05-15 14:45:47 +08:00
疯狂的狮子li
687d746b1b 正式发布 v2.0.0 2021-05-14 21:39:30 +08:00
疯狂的狮子li
b608002e89 版本更新 v1.0.2 2021-05-13 09:25:56 +08:00
疯狂的狮子li
fe8a2b401c 版本更新 v1.0.1 2021-05-11 17:46:48 +08:00
疯狂的狮子li
4a4d8f7123 正式发布 1.0.0 2021-05-10 15:32:46 +08:00
疯狂的狮子li
92008ff2d7 update 更新作者二维码 2021-05-08 23:56:36 +08:00
疯狂的狮子li
3fbf0a8e9e Merge remote-tracking branch 'origin/fast' into fast 2021-05-08 23:37:35 +08:00
疯狂的狮子li
0cbcc56cd6 fix 修复数据权限问题 2021-05-08 23:36:50 +08:00
疯狂的狮子li
ea7b309211 fix 日志时间sql符号转换问题 2021-05-08 17:07:41 +08:00
疯狂的狮子li
d945cb4a30 fix 日志时间sql符号转换问题 2021-05-08 16:56:52 +08:00
疯狂的狮子li
ab3e04f3ad update 项目地址项目名 2021-05-06 17:45:27 +08:00
疯狂的狮子li
2b5f30b88b fix 部门权限问题 2021-04-28 15:59:04 +08:00
疯狂的狮子li
9cb68a350b fix 日志时间问题 2021-04-28 11:52:38 +08:00
疯狂的狮子li
14a9df8b7e update 修改MP验证策略 NOT_NULL -> NOT_EMPTY 2021-04-25 10:40:32 +08:00
疯狂的狮子li
661325e4c5 同步ruoyi 2021-04-25 09:46:49 +08:00
疯狂的狮子li
017faa99c2 update 重写MP注入器 2021-04-25 09:20:39 +08:00
疯狂的狮子li
dbe6494b6c update 屏蔽用户密码返回 2021-04-23 16:01:32 +08:00
疯狂的狮子li
789dab5138 update 补全实体类 注入注解 2021-04-22 21:11:04 +08:00
疯狂的狮子li
e48d5fadc5 add 集成 spring-boot-admin 全方位监控 2021-04-22 15:50:42 +08:00
疯狂的狮子li
70492a9715 update mp 化 2021-04-22 10:11:39 +08:00
疯狂的狮子li
a3ee939ebb fix feign熔断问题 2021-04-22 09:33:36 +08:00
疯狂的狮子li
bd07a69712 fix 代码生成器编辑问题 2021-04-19 19:01:03 +08:00
疯狂的狮子li
58d08f0ecf fix Feign 熔断不生效 bug 2021-04-19 17:52:00 +08:00
疯狂的狮子li
af07590fd3 Merge branch 'master' of https://gitee.com/y_project/RuoYi-Vue into fast
 Conflicts:
	pom.xml
	ruoyi-ui/src/assets/styles/ruoyi.scss
	ruoyi-ui/src/components/ThemePicker/index.vue
	ruoyi-ui/src/layout/components/Settings/index.vue
	ruoyi-ui/src/store/modules/settings.js
	ruoyi/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java
	ruoyi/src/main/java/com/ruoyi/generator/util/VelocityInitializer.java
2021-04-19 17:48:30 +08:00
疯狂的狮子li
b36b9ac788 Merge branch 'master' of https://gitee.com/y_project/RuoYi-Vue into fast
 Conflicts:
	ruoyi/src/main/resources/vm/vue/index-tree.vue.vm
2021-04-16 11:34:02 +08:00
疯狂的狮子li
76d49217bb fix 表名上传错误 2021-04-16 11:31:36 +08:00
疯狂的狮子li
5b06ff45c5 update 导出 Excel 工作表的名称修改 2021-04-14 14:37:27 +08:00
疯狂的狮子li
d4fdcb0894 update 完成所有原生功能使用 Mybatis-Plus 与 Lombok 重写 2021-04-14 13:46:41 +08:00
疯狂的狮子li
f28029fade Merge branch 'master' of https://gitee.com/y_project/RuoYi-Vue into fast
 Conflicts:
	ruoyi-generator/src/main/resources/vm/java/controller.java.vm
	ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm
	ruoyi-ui/src/assets/styles/ruoyi.scss
	ruoyi-ui/src/assets/styles/sidebar.scss
	ruoyi-ui/src/layout/components/Navbar.vue
	ruoyi-ui/src/layout/components/Settings/index.vue
	ruoyi-ui/src/layout/components/TagsView/index.vue
	ruoyi-ui/src/settings.js
	ruoyi-ui/src/store/getters.js
	ruoyi-ui/src/store/modules/permission.js
	ruoyi-ui/src/store/modules/settings.js
	ruoyi-ui/src/store/modules/tagsView.js
	ruoyi-ui/src/views/monitor/druid/index.vue
	ruoyi/src/main/resources/application-prod.yml
2021-04-14 13:33:01 +08:00
疯狂的狮子li
6aa03ce709 fix bo缺包问题 2021-04-12 10:38:34 +08:00
疯狂的狮子li
89f30d9235 update Date参数接收Bo实体格式转换 2021-04-09 11:50:44 +08:00
疯狂的狮子li
e8bb56938e Merge branch 'master' of https://gitee.com/y_project/RuoYi-Vue into fast
 Conflicts:
	ruoyi-ui/src/assets/styles/ruoyi.scss
	ruoyi-ui/src/utils/zipdownload.js
	ruoyi/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java
	ruoyi/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java
	ruoyi/src/main/resources/mapper/system/SysRoleMapper.xml
	ruoyi/src/main/resources/mapper/system/SysUserMapper.xml
2021-04-08 17:19:25 +08:00
疯狂的狮子li
43d7949246 fix 字节转换 bug 2021-04-08 16:42:03 +08:00
疯狂的狮子li
307c4984a9 update 默认增加editBo主键生成 2021-04-08 16:30:28 +08:00
疯狂的狮子li
fb6290e481 fix controller 接口路径问题 2021-04-04 20:02:42 +08:00
疯狂的狮子li
24be6a0b7a fix 代码生成器问题 2021-04-04 11:29:40 +08:00
疯狂的狮子li
bbc8a2c062 fix 父类少包问题 2021-04-04 11:29:20 +08:00
疯狂的狮子li
aaa6b7ed3c fix remove 方法类型错误 2021-04-03 17:01:23 +08:00
疯狂的狮子li
a4448fef0a fix Page 路径导入 2021-04-02 23:07:57 +08:00
疯狂的狮子li
4ef331cf80 add 添加多模块分支 2021-04-02 16:15:29 +08:00
疯狂的狮子li
b8806360f8 add 添加单模块分支 2021-04-02 16:13:31 +08:00
疯狂的狮子li
fad9a8a168 add 添加单模块分支 2021-04-02 16:12:58 +08:00
疯狂的狮子li
2ba304819d init 单模块项目 2021-04-02 15:59:05 +08:00
937 changed files with 40826 additions and 11955 deletions

View File

@@ -10,7 +10,7 @@ end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
[*.{json,yml}]
[*.{json,yml,yaml}]
indent_size = 2
[*.md]

View File

@@ -1,13 +1,49 @@
### 使用版本
### 使用版本(未按照模板填写直接删除)
- jdk版本(带上尾号): 例如 1.8.0_202
- 框架版本(项目启动时输出的版本号): 例如 4.4.0
- 其他依赖版本(你觉得有必要的):
### 问题前提
> 功能不好用 不会用 是否已经看过项目文档
> 项目运行报错 是否已经拿着报错信息去百度 常见报错百度百度足以
> 是否搜索过其他issue 一些已经解决的问题 会在issue内留下解决方法
> 无法线上解决或者与框架无关的问题的欢迎加VIP群跟作者一对一谈
### 异常模块
> 此报错都涉及到那些系统模块
例如 ruoyi-system ruoyi-auth 等等
### 问题描述
> 越详细越容易直击问题所在
已知: XXX功能不好用 或 XXX数据不正常 等等
### 希望结果
> 想知道你觉得怎么样是正常或者合理的
希望功能可以有XXX结果 或者 XXX现象
### 重现步骤
> 作者并不知道这个问题是如何出现的
### 报错信息(截图为主 请勿发混乱格式)
- 1
- 2
- 3
### 相关代码与报错信息(请勿发混乱格式)
> 代码可按照如下形式提供或者截图均可 越详细越好
> 大多数问题都是 代码编写错误问题 逻辑问题 或者用法错误等问题
```java
public class XXX {
}
```

View File

@@ -0,0 +1,50 @@
name: Bug 反馈
description: 当你中发现了一个 Bug导致应用崩溃或抛出异常或者有一个组件存在问题或者某些地方看起来不对劲。
title: "[Bug]: "
labels: ["bug"]
body:
- type: textarea
id: version
attributes:
label: 版本
description: 你当前正在使用我们软件的哪个版本(pom文件内的版本号)
value: |
jdk版本(带上尾号): 例如 1.8.0
框架版本(项目启动时输出的版本号): 例如 4.4.0
其他依赖版本(你觉得有必要的):
validations:
required: true
- type: checkboxes
attributes:
label: 功能不好用不会用是否已经看过项目文档?
options:
- label: https://plus-doc.dromara.org
required: true
- type: checkboxes
attributes:
label: 这个问题是否已经存在?
options:
- label: 我已经搜索过现有的问题 (https://gitee.com/dromara/RuoYi-Vue-Plus/issues)
required: true
- type: textarea
attributes:
label: 希望结果
description: 想知道你觉得怎么样是正常或者合理的。
validations:
required: true
- type: markdown
attributes:
label: 如何复现
description: 请详细告诉我们如何复现你遇到的问题
value: |
如涉及代码 可提供一个最小代码示例 并使用```附上它 或者截图均可 越详细越好<br>
大多数问题都是 代码编写错误问题 逻辑问题 或者用法错误等问题
validations:
required: true
- type: textarea
attributes:
label: 相关代码与报错信息(请勿发混乱格式)
description: 如果可以的话,上传任何关于 bug 的截图。
value: |
[在这里上传图片]

View File

@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: RuoYi-Vue-Plus 文档中心
url: https://plus-doc.dromara.org
about: 提供 RuoYi-Vue-Plus 搭建使用指南、平台基本开发使用方式、介绍、基础知识和常见问题解答

View File

@@ -0,0 +1,43 @@
name: 功能建议
description: 对本项目提出一个功能建议
title: "[功能建议]: "
labels: ["enhancement"]
body:
- type: markdown
attributes:
value: |
感谢提出功能建议我们将仔细考虑请持续关注该issues在加入计划后我们会有贡献者设置为负责人同时状态成为进行中。
- type: textarea
id: related-problem
attributes:
label: 你的功能建议是否和某个问题相关?
description: 清晰并简洁地描述问题是什么,例如,当我...时,我总是感到困扰。
validations:
required: false
- type: textarea
id: desired-solution
attributes:
label: 你希望看到什么解决方案?
description: 清晰并简洁地描述你希望发生的事情。
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: 你考虑过哪些替代方案?
description: 清晰并简洁地描述你考虑过的任何替代解决方案或功能。
validations:
required: false
- type: textarea
id: additional-context
attributes:
label: 你有其他上下文或截图吗?
description: 在此处添加有关功能请求的任何其他上下文或截图。
validations:
required: false
- type: checkboxes
attributes:
label: 意向参与贡献
options:
- label: 我有意向参与具体功能的开发实现并将代码贡献回到上游社区
required: false

View File

@@ -1,7 +1,7 @@
### 更改目的 解决了什么问题
### 更改目的 解决了什么问题(请提交到dev分支)
### 描述 做了哪些改动
### 改动逻辑 这么写的思路(让作者更好的理解你的意图)
### 测试 都做了哪些测试(未经过测试不采纳)

View File

@@ -0,0 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="ruoyi-monitor-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
<deployment type="dockerfile">
<settings>
<option name="imageTag" value="ruoyi/ruoyi-monitor-admin:4.8.2" />
<option name="buildOnly" value="true" />
<option name="sourceFilePath" value="ruoyi-extend/ruoyi-monitor-admin/Dockerfile" />
</settings>
</deployment>
<method v="2" />
</configuration>
</component>

12
.run/ruoyi-server.run.xml Normal file
View File

@@ -0,0 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="ruoyi-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
<deployment type="dockerfile">
<settings>
<option name="imageTag" value="ruoyi/ruoyi-server:4.8.2" />
<option name="buildOnly" value="true" />
<option name="sourceFilePath" value="ruoyi-admin/Dockerfile" />
</settings>
</deployment>
<method v="2" />
</configuration>
</component>

View File

@@ -0,0 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="ruoyi-xxl-job-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
<deployment type="dockerfile">
<settings>
<option name="imageTag" value="ruoyi/ruoyi-xxl-job-admin:4.8.2" />
<option name="buildOnly" value="true" />
<option name="sourceFilePath" value="ruoyi-extend/ruoyi-xxl-job-admin/Dockerfile" />
</settings>
</deployment>
<method v="2" />
</configuration>
</component>

244
README.md
View File

@@ -1,65 +1,122 @@
<img src="https://foruda.gitee.com/images/1679673773341074847/178e8451_1766278.png" width="50%" height="50%">
<div style="height: 10px; clear: both;"></div>
- - -
## 版本状态说明
由于 springboot 2.X 与 vue 2.X 官方均宣布停止维护, 故而 框架 4.X 版本 进入维护状态(只处理问题不更新功能)
停止维护时间预计: 2024年6-10月具体根据使用人数动态决定, 此版本已经相当稳定 即便不更新功能也不影响使用
如果依旧选择使用 jdk8 或者 jdk11 可以放心使用此版本, 如果希望使用 jdk17 或者 jdk21 可以选择使用 5.X 分支
## 平台简介
[![码云Gitee](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/badge/star.svg?theme=blue)](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus)
[![GitHub](https://img.shields.io/github/stars/JavaLionLi/RuoYi-Vue-Plus.svg?style=social&label=Stars)](https://github.com/JavaLionLi/RuoYi-Vue-Plus)
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/blob/master/LICENSE)
[![码云Gitee](https://gitee.com/dromara/RuoYi-Vue-Plus/badge/star.svg?theme=blue)](https://gitee.com/dromara/RuoYi-Vue-Plus)
[![GitHub](https://img.shields.io/github/stars/JavaLionLi/RuoYi-Vue-Plus.svg?style=social&label=Stars)](https://github.com/dromara/RuoYi-Vue-Plus)
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/master/LICENSE)
[![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
<br>
[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-4.0.1-success.svg)](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus)
[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-2.5-blue.svg)]()
[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-4.8.2-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus)
[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-2.7-blue.svg)]()
[![JDK-8+](https://img.shields.io/badge/JDK-8-green.svg)]()
[![JDK-11](https://img.shields.io/badge/JDK-11-green.svg)]()
> RuoYi-Vue-Plus 是重写 RuoYi-Vue 针对 `分布式集群` 场景全方位升级(不兼容原框架)
> 系统演示: [传送门](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/系统演示?sort_id=4836388)
> 项目代码、文档 均开源免费可商用 遵循开源协议在项目中保留开源协议文件即可<br>
活到老写到老 为兴趣而开源 为学习而开源 为让大家真正可以学到技术而开源
| 功能介绍 | 使用技术 | 文档地址 | 特性注意事项 |
|----------|---------------------|---------------------------------------------------------------------------------------------------|----------------------------|
| 当前框架 | RuoYi-Vue-Plus | [RuoYi-Vue-Plus文档](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages) | 重写RuoYi-Vue全方位升级(不兼容原框架) |
| 微服务分支 | RuoYi-Cloud-Plus | [微服务分支地址](https://gitee.com/JavaLionLi/RuoYi-Cloud-Plus) | 重写RuoYi-Cloud全方位升级(不兼容原框架) |
| 单体分支 | RuoYi-Vue-Plus-fast | [fast分支地址](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/tree/fast/) | 单体应用结构 |
| Vue3分支 | RuoYi-Vue-Plus-UI | [UI地址](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus-UI) | 由于组件还未完善 仅供学习 |
| 原框架 | RuoYi-Vue | [RuoYi-Vue官网](http://ruoyi.vip/) | 定期同步需要的功能 |
| 前端开发框架 | Vue、Element UI | [Element UI官网](https://element.eleme.cn/#/zh-CN) | |
| 后端开发框架 | SpringBoot | [SpringBoot官网](https://spring.io/projects/spring-boot/#learn) | |
| 容器框架 | Undertow | [Undertow官网](https://undertow.io/) | 基于 XNIO 的高性能容器 |
| 权限认证框架 | Sa-Token、Jwt | [Sa-Token官网](https://sa-token.dev33.cn/) | 强解耦、强扩展 |
| 关系数据库 | MySQL | [MySQL官网](https://dev.mysql.com/) | 适配 8.X 最低 5.7 |
| 缓存数据库 | Redis | [Redis官网](https://redis.io/) | 适配 6.X 最低 4.X |
| 数据库框架 | Mybatis-Plus | [Mybatis-Plus文档](https://baomidou.com/guide/) | 快速 CRUD 增加开发效率 |
| 数据库框架 | p6spy | [p6spy官网](https://p6spy.readthedocs.io/) | 更强劲的 SQL 分析 |
| 多数据源框架 | dynamic-datasource | [dynamic-ds文档](https://www.kancloud.cn/tracy5546/dynamic-datasource/content) | 支持主从与多种类数据库异构 |
| 序列化框架 | Jackson | [Jackson官网](https://github.com/FasterXML/jackson) | 统一使用 jackson 高效可靠 |
| Redis客户端 | Redisson | [Redisson文档](https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95) | 支持单机、集群配置 |
| 分布式限流 | Redisson | [Redisson文档](https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95) | 全局、请求IP、集群ID 多种限流 |
| 分布式队列 | Redisson | [Redisson文档](https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95) | 普通队列、延迟队列、优先队列 等 |
| 分布式锁 | Lock4j | [Lock4j官网](https://gitee.com/baomidou/lock4j) | 注解锁、工具锁 多种多样 |
| 分布式幂等 | Redisson | [Lock4j文档](https://gitee.com/baomidou/lock4j) | 拦截重复提交 |
| 分布式日志 | TLog | [TLog文档](https://yomahub.com/tlog/docs) | 支持跟踪链路日志记录、性能分析、链路排查 |
| 分布式任务调度 | Xxl-Job | [Xxl-Job官网](https://www.xuxueli.com/xxl-job/) | 高性能 高可靠 易扩展 |
| 文件存储 | Minio | [Minio文档](https://docs.min.io/) | 本地存储 |
| 文件存储 | 七牛、阿里、腾讯 | [OSS使用文档](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages?sort_id=4359146&doc_id=1469725) | 云存储 |
| 监控框架 | SpringBoot-Admin | [SpringBoot-Admin文档](https://codecentric.github.io/spring-boot-admin/current/) | 全方位服务监控 |
| 校验框架 | Validation | [Validation文档](https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/) | 增强接口安全性、严谨性 支持国际化 |
| Excel框架 | Alibaba EasyExcel | [EasyExcel文档](https://www.yuque.com/easyexcel/doc/easyexcel) | 性能优异 扩展性强 |
| 文档框架 | Knife4j | [Knife4j文档](https://doc.xiaominfo.com/knife4j/documentation/) | 美化接口文档 |
| 工具类框架 | Hutool、Lombok | [Hutool文档](https://www.hutool.cn/docs/) | 减少代码冗余 增加安全性 |
| 代码生成器 | 适配MP、Knife4j规范化代码 | [Hutool文档](https://www.hutool.cn/docs/) | 一键生成前后端代码 |
| 部署方式 | Docker | [Docker文档](https://docs.docker.com/) | 容器编排 一键部署业务集群 |
| 国际化 | SpringMessage | [SpringMVC文档](https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc) | Spring标准国际化方案 |
> 系统演示: [传送门](https://gitee.com/dromara/RuoYi-Vue-Plus/wikis/pages?sort_id=4836388&doc_id=1469725)
# 本框架与RuoYi的功能差异
| 功能 | 本框架 | RuoYi |
|-------------|-------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------|
| 前端项目 | 基于vue3-element-admin开源项目重写<br/>Vue3 + TS + ElementPlus | 基于Vue2/Vue3 + JS |
| 后端项目结构 | 采用插件化 + 扩展包形式 结构解耦 易于扩展 | 模块相互注入耦合严重难以扩展 |
| 后端代码风格 | 严格遵守Alibaba规范与项目统一配置的代码格式化 | 代码书写与常规结构不同阅读障碍大 |
| Web容器 | 采用 Undertow 基于 XNIO 的高性能容器 | 采用 Tomcat |
| 权限认证 | 采用 Sa-Token、Jwt 静态使用功能齐全 低耦合 高扩展 | Spring Security 配置繁琐扩展性极差 |
| 权限注解 | 采用 Sa-Token 支持注解 登录校验、角色校验、权限校验、二级认证校验、HttpBasic校验、忽略校验<br/>角色与权限校验支持多种条件 如 `AND` `OR``权限 OR 角色` 等复杂表达式 | 只支持是否存在匹配 |
| 关系数据库支持 | 原生支持 MySQL、Oracle、PostgreSQL、SQLServer<br/>可同时使用异构切换 | 支持 Mysql、Oracle 不支持同时使用、不支持异构切换 |
| 缓存数据库 | 支持 Redis 5-7 支持大部分新功能特性 如 分布式限流、分布式队列 | Redis 简单 get set 支持 |
| Redis客户端 | 采用 Redisson Redis官方推荐 基于Netty的客户端工具<br/>支持Redis 90%以上的命令 底层优化规避很多不正确的用法 例如: keys被转换为scan<br/>支持单机、哨兵、单主集群、多主集群等模式 | Lettuce + RedisTemplate 支持模式少 工具使用繁琐<br/>连接池采用 common-pool Bug多经常性出问题 |
| 缓存注解 | 采用 Spring-Cache 注解 对其扩展了实现支持了更多功能<br/>例如 过期时间 最大空闲时间 组最大长度等 只需一个注解即可完成数据自动缓存 | 需手动编写Redis代码逻辑 |
| ORM框架 | 采用 Mybatis-Plus 基于对象几乎不用写SQL全java操作 功能强大插件众多<br/>例如多租户插件 分页插件 乐观锁插件等等 | 采用 Mybatis 基于XML需要手写SQL |
| SQL监控 | 采用 p6spy 可输出完整SQL与执行时间监控 | log输出 需手动拼接sql与参数无法快速查看调试问题 |
| 数据分页 | 采用 Mybatis-Plus 分页插件<br/>框架对其进行了扩展 对象化分页对象 支持多种方式传参 支持前端多排序 复杂排序 | 采用 PageHelper 仅支持单查询分页 参数只能从param传 只能单排序 功能扩展性差 体验不好 |
| 数据权限 | 采用 Mybatis-Plus 插件 自行分析拼接SQL 无感式过滤<br/>只需为Mapper设置好注解条件 支持多种自定义 不限于部门角色 | 采用 注解+aop 实现 基于部门角色 生成的sql兼容性差 不支持其他业务扩展<br/>生成sql后需手动拼接到具体业务sql上 对于多个Mapper查询不起作用 |
| 数据脱敏 | 采用 注解 + jackson 序列化期间脱敏 支持不同模块不同的脱敏条件<br/>支持多种策略 如身份证、手机号、地址、邮箱、银行卡等 可自行扩展 | 无 |
| 数据加解密 | 采用 注解 + mybatis 拦截器 对存取数据期间自动加解密<br/>支持多种策略 如BASE64、AES、RSA、SM2、SM4等 | 无 |
| 数据翻译 | 采用 注解 + jackson 序列化期间动态修改数据 数据进行翻译<br/>支持多种模式: `映射翻译` `直接翻译` `其他扩展条件翻译` 接口化两步即可完成自定义扩展 内置多种翻译实现 | 无 |
| 多数据源框架 | 采用 dynamic-datasource 支持世面大部分数据库<br/>通过yml配置即可动态管理异构不同种类的数据库 也可通过前端页面添加数据源<br/>支持spel表达式从请求头参数等条件切换数据源 | 基于 druid 手动编写代码配置数据源 配置繁琐 支持性差 |
| 多数据源事务 | 采用 dynamic-datasource 支持多数据源不同种类的数据库事务回滚 | 不支持 |
| 数据库连接池 | 采用 HikariCP Spring官方内置连接池 配置简单 以性能与稳定性闻名天下 | 采用 druid bug众多 社区维护差 活跃度低 配置众多繁琐性能一般 |
| 数据库主键 | 采用 雪花ID 基于时间戳的 有序增长 唯一ID 再也不用为分库分表 数据合并主键冲突重复而发愁 | 采用 数据库自增ID 支持数据量有限 不支持多数据源主键唯一 |
| WebSocket协议 | 基于 Spring 封装的 WebSocket 协议 扩展了Token鉴权与分布式会话同步 不再只是基于单机的废物 | 无 |
| 序列化 | 采用 Jackson Spring官方内置序列化 靠谱!!! | 采用 fastjson bugjson 远近闻名 |
| 分布式幂等 | 参考美团GTIS防重系统简化实现(细节可看文档) | 手动编写注解基于aop实现 |
| 分布式任务调度 | 采用 Xxl-Job 天生支持分布式 统一的管理中心 | 采用 Quartz 基于数据库锁性能差 集群需要做很多配置与改造 |
| 文件存储 | 采用 Minio 分布式文件存储 天生支持多机、多硬盘、多分片、多副本存储<br/>支持权限管理 安全可靠 文件可加密存储 | 采用 本机文件存储 文件裸漏 易丢失泄漏 不支持集群有单点效应 |
| 云存储 | 采用 AWS S3 协议客户端 支持 七牛、阿里、腾讯 等一切支持S3协议的厂家 | 不支持 |
| 短信 | 采用 sms4j 短信融合包 支持数十种短信厂家 只需在yml配置好厂家密钥即可使用 可多厂家共用 | 不支持 |
| 邮件 | 采用 mail-api 通用协议支持大部分邮件厂商 | 不支持 |
| 接口文档 | 采用 SpringDoc、javadoc 无注解零入侵基于java注释<br/>只需把注释写好 无需再写一大堆的文档注解了 | 采用 Springfox 已停止维护 需要编写大量的注解来支持文档生成 |
| 校验框架 | 采用 Validation 支持注解与工具类校验 注解支持国际化 | 仅支持注解 且注解不支持国际化 |
| Excel框架 | 采用 Alibaba EasyExcel 基于插件化<br/>框架对其增加了很多功能 例如 自动合并相同内容 自动排列布局 字典翻译等 | 基于 POI 手写实现 功能有限 复杂 扩展性差 |
| 工具类框架 | 采用 Hutool、Lombok 上百种工具覆盖90%的使用需求 基于注解自动生成 get set 等简化框架大量代码 | 手写工具稳定性差易出问题 工具数量有限 代码臃肿需自己手写 get set 等 |
| 监控框架 | 采用 SpringBoot-Admin 基于SpringBoot官方 actuator 探针机制<br/>实时监控服务状态 框架还为其扩展了在线日志查看监控 | 无 |
| 链路追踪 | 采用 Apache SkyWalking 还在为请求不知道去哪了 到哪出了问题而烦恼吗<br/>用了它即可实时查看请求经过的每一处每一个节点 | 无 |
| 代码生成器 | 只需设计好表结构 一键生成所有crud代码与页面<br/>降低80%的开发量 把精力都投入到业务设计上<br/>框架为其适配MP、SpringDoc规范化代码 同时支持动态多数据源代码生成 | 代码生成原生结构 只支持单数据源生成 |
| 部署方式 | 支持 Docker 编排 一键搭建所有环境 让开发人员从此不再为搭建环境而烦恼 | 原生jar部署 其他环境需手动下载安装 自行搭建 |
| 项目路径修改 | 提供详细的修改方案文档 并为其做了一些改动 非常简单即可修改成自己想要的 | 需要做很多改造 文档说明有限 |
| 国际化 | 基于请求头动态返回不同语种的文本内容 开发难度低 有对应的工具类 支持大部分注解内容国际化 | 只提供基础功能 其他需自行编写扩展 |
| 代码单例测试 | 提供单例测试 使用方式编写方法与maven多环境单测插件 | 只提供基础功能 其他需自行编写扩展 |
| Demo案例 | 提供框架功能的实际使用案例 单独一个模块提供了很多很全 | 无 |
## 本框架与RuoYi的业务差异
| 业务 | 功能说明 | 本框架 | RuoYi |
|--------|-----------------------------------------|-----|------------------|
| 用户管理 | 用户的管理配置 如:新增用户、分配用户所属部门、角色、岗位等 | 支持 | 支持 |
| 部门管理 | 配置系统组织机构(公司、部门、小组) 树结构展现支持数据权限 | 支持 | 支持 |
| 岗位管理 | 配置系统用户所属担任职务 | 支持 | 支持 |
| 菜单管理 | 配置系统菜单、操作权限、按钮权限标识等 | 支持 | 支持 |
| 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分 | 支持 | 支持 |
| 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 | 支持 | 支持 |
| 参数管理 | 对系统动态配置常用参数 | 支持 | 支持 |
| 通知公告 | 系统通知公告信息发布维护 | 支持 | 支持 |
| 操作日志 | 系统正常操作日志记录和查询 系统异常信息日志记录和查询 | 支持 | 支持 |
| 登录日志 | 系统登录日志记录查询包含登录异常 | 支持 | 支持 |
| 文件管理 | 系统文件展示、上传、下载、删除等管理 | 支持 | 无 |
| 文件配置管理 | 系统文件上传、下载所需要的配置信息动态添加、修改、删除等管理 | 支持 | 无 |
| 在线用户管理 | 已登录系统的在线用户信息监控与强制踢出操作 | 支持 | 支持 |
| 定时任务 | 运行报表、任务管理(添加、修改、删除)、日志管理、执行器管理等 | 支持 | 仅支持任务与日志管理 |
| 代码生成 | 多数据源前后端代码的生成java、html、xml、sql支持CRUD下载 | 支持 | 仅支持单数据源 |
| 系统接口 | 根据业务代码自动生成相关的api接口文档 | 支持 | 支持 |
| 服务监控 | 监视集群系统CPU、内存、磁盘、堆栈、在线日志、Spring相关配置等 | 支持 | 仅支持单机CPU、内存、磁盘监控 |
| 缓存监控 | 对系统的缓存信息查询,命令统计等。 | 支持 | 支持 |
| 在线构建器 | 拖动表单元素生成相应的HTML代码。 | 支持 | 支持 |
| 使用案例 | 系统的一些功能案例 | 支持 | 不支持 |
## 参考文档
使用框架前请仔细阅读文档重点注意事项
<br>
>[初始化项目 必看](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/关于初始化项目?sort_id=4164117)
>>[https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/关于初始化项目?sort_id=4164117](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/关于初始化项目?sort_id=4164117)
>[初始化项目 必看](https://gitee.com/dromara/RuoYi-Vue-Plus/wikis/pages?sort_id=4164117&doc_id=1469725)
>>[https://gitee.com/dromara/RuoYi-Vue-Plus/wikis/pages?sort_id=4164117&doc_id=1469725](https://gitee.com/dromara/RuoYi-Vue-Plus/wikis/pages?sort_id=4164117&doc_id=1469725)
>
>[部署项目 必看](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/关于应用部署?sort_id=4219382)
>>[https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/关于应用部署?sort_id=4219382](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/关于应用部署?sort_id=4219382)
>[专栏与视频 入门必看](https://gitee.com/dromara/RuoYi-Vue-Plus/wikis/pages?sort_id=5473272&doc_id=1469725)
>>[https://gitee.com/dromara/RuoYi-Vue-Plus/wikis/pages?sort_id=5473272&doc_id=1469725](https://gitee.com/dromara/RuoYi-Vue-Plus/wikis/pages?sort_id=5473272&doc_id=1469725)
>
>[参考文档 Wiki](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages)
>>[https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages)
>[部署项目 必看](https://gitee.com/dromara/RuoYi-Vue-Plus/wikis/pages?sort_id=4219382&doc_id=1469725)
>>[https://gitee.com/dromara/RuoYi-Vue-Plus/wikis/pages?sort_id=4219382&doc_id=1469725](https://gitee.com/dromara/RuoYi-Vue-Plus/wikis/pages?sort_id=4219382&doc_id=1469725)
>
>[参考文档 Wiki](https://gitee.com/dromara/RuoYi-Vue-Plus/wikis/pages)
>>[https://gitee.com/dromara/RuoYi-Vue-Plus/wikis/pages](https://gitee.com/dromara/RuoYi-Vue-Plus/wikis/pages)
## 软件架构图
@@ -73,81 +130,42 @@
### 其他
* 同步升级 RuoYi-Vue
* GitHub 地址 [RuoYi-Vue-Plus-github](https://github.com/JavaLionLi/RuoYi-Vue-Plus)
* 单模块 分支 [RuoYi-Vue-Plus-fast](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/tree/fast/)
* GitHub 地址 [RuoYi-Vue-Plus-github](https://github.com/dromara/RuoYi-Vue-Plus)
* 单模块 分支 [RuoYi-Vue-Plus-fast](https://gitee.com/dromara/RuoYi-Vue-Plus/tree/fast/)
* 微服务 分支 [RuoYi-Cloud-Plus](https://gitee.com/JavaLionLi/RuoYi-Cloud-Plus)
* 用户扩展项目 [扩展项目列表](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages?sort_id=4478302&doc_id=1469725)
* 用户扩展项目 [扩展项目列表](https://gitee.com/dromara/RuoYi-Vue-Plus/wikis/pages?sort_id=4478302&doc_id=1469725)
## 加群与捐献
>[加群与捐献](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/加群与捐献?sort_id=4104598)
>>[https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/加群与捐献?sort_id=4104598](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/加群与捐献?sort_id=4104598)
>[加群与捐献](https://gitee.com/dromara/RuoYi-Vue-Plus/wikis/加群与捐献?sort_id=4104598)
>>[https://gitee.com/dromara/RuoYi-Vue-Plus/wikis/加群与捐献?sort_id=4104598](https://gitee.com/dromara/RuoYi-Vue-Plus/wikis/加群与捐献?sort_id=4104598)
## 捐献作者
作者为兼职做开源,平时还需要工作,如果帮到了您可以请作者吃个盒饭
<img src="https://images.gitee.com/uploads/images/2022/0218/213734_b1b8197f_1766278.jpeg" width="300px" height="450px" />
<img src="https://images.gitee.com/uploads/images/2021/0525/101713_3d18b119_1766278.jpeg" width="300px" height="450px" />
## 业务功能
| 功能 | 介绍 |
|---|---|
| 用户管理 | 用户是系统操作者,该功能主要完成系统用户配置。 |
| 部门管理 | 配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。 |
| 岗位管理 | 配置系统用户所属担任职务。 |
| 菜单管理 | 配置系统菜单,操作权限,按钮权限标识等。 |
| 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分。 |
| 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护。 |
| 参数管理 | 对系统动态配置常用参数。 |
| 通知公告 | 系统通知公告信息发布维护。 |
| 操作日志 | 系统正常操作日志记录和查询;系统异常信息日志记录和查询。 |
| 登录日志 | 系统登录日志记录查询包含登录异常。 |
| 文件管理 | 系统文件上传、下载等管理。 |
| 定时任务 | 在线(添加、修改、删除)任务调度包含执行结果日志。 |
| 代码生成 | 前后端代码的生成java、html、xml、sql支持CRUD下载 。 |
| 系统接口 | 根据业务代码自动生成相关的api接口文档。 |
| 服务监控 | 监视集群系统CPU、内存、磁盘、堆栈、在线日志、Spring相关配置等。 |
| 缓存监控 | 对系统的缓存信息查询,命令统计等。 |
| 在线构建器 | 拖动表单元素生成相应的HTML代码。 |
| 连接池监视 | 监视当前系统数据库连接池状态可进行分析SQL找出系统性能瓶颈。 |
| 使用案例 | 系统的一些功能案例 |
## 演示图例
<table border="1" cellpadding="1" cellspacing="1" style="width:500px">
<tbody>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-972235bcbe3518dedd351ff0e2ee7d1031c.png" width="1920" /></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-5e0097702fa91e2e36391de8127676a7fa1.png" width="1920" /></td>
</tr>
<tr>
<td>
<p><img src="https://oscimg.oschina.net/oscnet/up-e56e3828f48cd9886d88731766f06d5f3c1.png" width="1920" /></p>
</td>
<td><img src="https://oscimg.oschina.net/oscnet/up-0715990ea1a9f254ec2138fcd063c1f556a.png" width="1920" /></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-eaf5417ccf921bb64abb959e3d8e290467f.png" width="1920" /></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-fc285cf33095ebf8318de6999af0f473861.png" width="1920" /></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-60c83fd8bd61c29df6dbf47c88355e9c272.png" width="1920" /></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-7f731948c8b73c7d90f67f9e1c7a534d5c3.png" width="1920" /></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-e4de89b5e2d20c52d3c3a47f9eb88eb8526.png" width="1920" /></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-8791d823a508eb90e67c604f36f57491a67.png" width="1920" /></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-4589afd99982ead331785299b894174feb6.png" width="1920" /></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-8ea177cdacaea20995daf2f596b15232561.png" width="1920" /></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-32d1d04c55c11f74c9129fbbc58399728c4.png" width="1920" /></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-04fa118f7631b7ae6fd72299ca0a1430a63.png" width="1920" /></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-fe7e85b65827802bfaadf3acd42568b58c7.png" width="1920" /></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-eff2b02a54f8188022d8498cfe6af6fcc06.png" width="1920" /></td>
</tr>
</tbody>
</table>
| | |
|--------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------|
| ![输入图片说明](https://foruda.gitee.com/images/1680077524361362822/270bb429_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680077619939771291/989bf9b6_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680077681751513929/1c27c5bd_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680077721559267315/74d63e23_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680077765638904515/1b75d4a6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078026375951297/eded7a4b_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078237104531207/0eb1b6a7_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078254306078709/5931e22f_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078287971528493/0b9af60a_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078308138770249/8d3b6696_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078352553634393/db5ef880_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078378238393374/601e4357_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078414983206024/2aae27c1_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078446738419874/ecce7d59_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078475971341775/149e8634_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078491666717143/3fadece7_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078558863188826/fb8ced2a_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078574561685461/ae68a0b2_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078594932772013/9d8bfec6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078626493093532/fcfe4ff6_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078643608812515/0295bd4f_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078685196286463/d7612c81_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078703877318597/56fce0bc_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078716586545643/b6dbd68f_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078734103217688/eb1e6aa6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078759131415480/73c525d8_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078779416197879/75e3ed02_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078802329118061/77e10915_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078893627848351/34a1c342_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078928175016986/f126ec4a_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078941718318363/b68a0f72_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078963175518631/3bb769a1_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680078982294090567/b31c343d_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680079000642440444/77ca82a9_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680079020995074177/03b7d52e_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680079039367822173/76811806_1766278.png "屏幕截图") |
| ![输入图片说明](https://foruda.gitee.com/images/1680079274333484664/4dfdc7c0_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680079290467458224/d6715fcf_1766278.png "屏幕截图") |

323
pom.xml
View File

@@ -6,55 +6,76 @@
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-vue-plus</artifactId>
<version>4.0.1</version>
<version>4.8.2</version>
<name>RuoYi-Vue-Plus</name>
<url>https://gitee.com/JavaLionLi/RuoYi-Vue-Plus</url>
<url>https://gitee.com/dromara/RuoYi-Vue-Plus</url>
<description>RuoYi-Vue-Plus后台管理系统</description>
<properties>
<ruoyi-vue-plus.version>4.0.1</ruoyi-vue-plus.version>
<spring-boot.version>2.6.4</spring-boot.version>
<ruoyi-vue-plus.version>4.8.2</ruoyi-vue-plus.version>
<spring-boot.version>2.7.18</spring-boot.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
<druid.version>1.2.8</druid.version>
<knife4j.version>3.0.3</knife4j.version>
<swagger-annotations.version>1.5.22</swagger-annotations.version>
<poi.version>4.1.2</poi.version>
<easyexcel.version>3.0.5</easyexcel.version>
<cglib.version>3.3.0</cglib.version>
<spring-boot.mybatis>2.2.2</spring-boot.mybatis>
<springdoc.version>1.6.15</springdoc.version>
<poi.version>5.2.3</poi.version>
<easyexcel.version>3.3.2</easyexcel.version>
<velocity.version>2.3</velocity.version>
<satoken.version>1.29.0</satoken.version>
<mybatis-plus.version>3.5.1</mybatis-plus.version>
<satoken.version>1.37.0</satoken.version>
<mybatis-plus.version>3.5.4</mybatis-plus.version>
<p6spy.version>3.9.1</p6spy.version>
<hutool.version>5.7.21</hutool.version>
<okhttp.version>4.9.2</okhttp.version>
<spring-boot-admin.version>2.6.2</spring-boot-admin.version>
<redisson.version>3.16.8</redisson.version>
<lock4j.version>2.2.1</lock4j.version>
<dynamic-ds.version>3.5.0</dynamic-ds.version>
<tlog.version>1.3.6</tlog.version>
<xxl-job.version>2.3.0</xxl-job.version>
<!-- jdk11 缺失依赖 jaxb-->
<jaxb.version>3.0.1</jaxb.version>
<hutool.version>5.8.22</hutool.version>
<okhttp.version>4.10.0</okhttp.version>
<spring-boot-admin.version>2.7.11</spring-boot-admin.version>
<redisson.version>3.20.1</redisson.version>
<lock4j.version>2.2.3</lock4j.version>
<dynamic-ds.version>3.5.2</dynamic-ds.version>
<alibaba-ttl.version>2.14.2</alibaba-ttl.version>
<xxl-job.version>2.4.0</xxl-job.version>
<lombok.version>1.18.30</lombok.version>
<bouncycastle.version>1.72</bouncycastle.version>
<!-- 离线IP地址定位库 -->
<ip2region.version>2.7.0</ip2region.version>
<!-- OSS 配置 -->
<qiniu.version>7.9.3</qiniu.version>
<aliyun.oss.version>3.14.0</aliyun.oss.version>
<qcloud.cos.version>5.6.68</qcloud.cos.version>
<minio.version>8.3.7</minio.version>
<!-- docker 配置 -->
<docker.registry.url>localhost</docker.registry.url>
<docker.registry.host>http://${docker.registry.url}:2375</docker.registry.host>
<docker.namespace>ruoyi</docker.namespace>
<docker.plugin.version>1.2.2</docker.plugin.version>
<aws-java-sdk-s3.version>1.12.540</aws-java-sdk-s3.version>
<!-- SMS 配置 -->
<sms4j.version>2.2.0</sms4j.version>
</properties>
<profiles>
<profile>
<id>local</id>
<properties>
<!-- 环境标识,需要与配置文件的名称相对应 -->
<profiles.active>local</profiles.active>
<logging.level>info</logging.level>
</properties>
</profile>
<profile>
<id>dev</id>
<properties>
<!-- 环境标识,需要与配置文件的名称相对应 -->
<profiles.active>dev</profiles.active>
<logging.level>info</logging.level>
</properties>
<activation>
<!-- 默认环境 -->
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>prod</id>
<properties>
<profiles.active>prod</profiles.active>
<logging.level>warn</logging.level>
</properties>
</profile>
</profiles>
<!-- 依赖声明 -->
<dependencyManagement>
<dependencies>
@@ -77,47 +98,39 @@
<scope>import</scope>
</dependency>
<!-- 阿里数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-webmvc-core</artifactId>
<version>${springdoc.version}</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
<exclusions>
<exclusion>
<artifactId>swagger-annotations</artifactId>
<groupId>io.swagger</groupId>
</exclusion>
</exclusions>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-javadoc</artifactId>
<version>${springdoc.version}</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>${swagger-annotations.version}</version>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<!-- excel工具 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>${easyexcel.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
@@ -125,12 +138,6 @@
</exclusions>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>${cglib.version}</version>
</dependency>
<!-- velocity代码生成使用模板 -->
<dependency>
<groupId>org.apache.velocity</groupId>
@@ -149,13 +156,12 @@
<groupId>cn.dev33</groupId>
<artifactId>sa-token-jwt</artifactId>
<version>${satoken.version}</version>
</dependency>
<!-- jdk11 缺失依赖 jaxb-->
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>${jaxb.version}</version>
<exclusions>
<exclusion>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- dynamic-datasource 多数据源-->
@@ -170,11 +176,7 @@
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-extension</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!-- sql性能分析插件 -->
<dependency>
<groupId>p6spy</groupId>
@@ -188,6 +190,19 @@
<version>${okhttp.version}</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
<version>${aws-java-sdk-s3.version}</version>
</dependency>
<!--短信sms4j-->
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-spring-boot-starter</artifactId>
<version>${sms4j.version}</version>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
@@ -204,7 +219,19 @@
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>${redisson.version}</version>
<exclusions>
<exclusion>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-data-30</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-data-27</artifactId>
<version>${redisson.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>lock4j-redisson-spring-boot-starter</artifactId>
@@ -219,79 +246,31 @@
</dependency>
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>tlog-web-spring-boot-starter</artifactId>
<version>${tlog.version}</version>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>${alibaba-ttl.version}</version>
</dependency>
<!-- 离线IP地址定位库 ip2region -->
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>tlog-xxljob-spring-boot-starter</artifactId>
<version>${tlog.version}</version>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>${ip2region.version}</version>
</dependency>
<!-- 定时任务 -->
<!-- 加密包引入 -->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-job</artifactId>
<version>${ruoyi-vue-plus.version}</version>
</dependency>
<!-- 代码生成-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-generator</artifactId>
<version>${ruoyi-vue-plus.version}</version>
</dependency>
<!-- 核心模块-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-framework</artifactId>
<version>${ruoyi-vue-plus.version}</version>
</dependency>
<!-- 系统模块-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-system</artifactId>
<version>${ruoyi-vue-plus.version}</version>
</dependency>
<!-- 通用工具-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
<version>${ruoyi-vue-plus.version}</version>
</dependency>
<!-- OSS对象存储模块 -->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-oss</artifactId>
<version>${ruoyi-vue-plus.version}</version>
</dependency>
<!-- demo模块 -->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-demo</artifactId>
<version>${ruoyi-vue-plus.version}</version>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15to18</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<modules>
<module>ruoyi-admin</module>
<module>ruoyi-framework</module>
<module>ruoyi-system</module>
<module>ruoyi-job</module>
<module>ruoyi-generator</module>
<module>ruoyi-common</module>
<module>ruoyi-demo</module>
<module>ruoyi</module>
<module>ruoyi-extend</module>
<module>ruoyi-oss</module>
</modules>
<packaging>pom</packaging>
@@ -305,6 +284,36 @@
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
<annotationProcessorPaths>
<path>
<groupId>com.github.therapi</groupId>
<artifactId>therapi-runtime-javadoc-scribe</artifactId>
<version>0.15.0</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring-boot.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<!-- 单元测试使用 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<argLine>-Dfile.encoding=UTF-8</argLine>
<!-- 根据打包环境执行对应的@Tag测试方法 -->
<groups>${profiles.active}</groups>
<!-- 排除标签 -->
<excludedGroups>exclude</excludedGroups>
</configuration>
</plugin>
</plugins>
@@ -331,8 +340,8 @@
<repositories>
<repository>
<id>public</id>
<name>aliyun nexus</name>
<url>https://maven.aliyun.com/repository/public/</url>
<name>huawei nexus</name>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
<releases>
<enabled>true</enabled>
</releases>
@@ -342,8 +351,8 @@
<pluginRepositories>
<pluginRepository>
<id>public</id>
<name>aliyun nexus</name>
<url>https://maven.aliyun.com/repository/public/</url>
<name>huawei nexus</name>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
<releases>
<enabled>true</enabled>
</releases>
@@ -353,40 +362,6 @@
</pluginRepository>
</pluginRepositories>
<profiles>
<profile>
<id>local</id>
<properties>
<!-- 环境标识,需要与配置文件的名称相对应 -->
<profiles.active>local</profiles.active>
<logging.level>debug</logging.level>
<knife4j.production>false</knife4j.production>
<endpoints.include>'*'</endpoints.include>
</properties>
</profile>
<profile>
<id>dev</id>
<properties>
<!-- 环境标识,需要与配置文件的名称相对应 -->
<profiles.active>dev</profiles.active>
<logging.level>debug</logging.level>
<knife4j.production>false</knife4j.production>
<endpoints.include>'*'</endpoints.include>
</properties>
<activation>
<!-- 默认环境 -->
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>prod</id>
<properties>
<profiles.active>prod</profiles.active>
<logging.level>warn</logging.level>
<knife4j.production>true</knife4j.production>
<endpoints.include>health, info, logfile</endpoints.include>
</properties>
</profile>
</profiles>
</project>

View File

@@ -1,15 +0,0 @@
FROM anapsix/alpine-java:8_server-jre_unlimited
MAINTAINER Lion Li
RUN mkdir -p /ruoyi/server
RUN mkdir -p /ruoyi/server/logs
RUN mkdir -p /ruoyi/server/temp
WORKDIR /ruoyi/server
EXPOSE 8080
ADD ./target/ruoyi-admin.jar ./app.jar
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]

View File

@@ -1,117 +0,0 @@
<?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">
<parent>
<artifactId>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId>
<version>4.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>ruoyi-admin</artifactId>
<description>
web服务入口
</description>
<dependencies>
<!-- spring-boot-devtools -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional> <!-- 表示依赖不会传递 -->
</dependency>
<!-- Mysql驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 核心模块-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-framework</artifactId>
</dependency>
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-system</artifactId>
</dependency>
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-job</artifactId>
</dependency>
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-oss</artifactId>
</dependency>
<!-- 代码生成-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-generator</artifactId>
</dependency>
<!-- demo模块 -->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-demo</artifactId>
</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>
<configuration>
<fork>true</fork> <!-- 如果没有该配置devtools不会生效 -->
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<warName>${project.artifactId}</warName>
</configuration>
</plugin>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>${docker.plugin.version}</version>
<configuration>
<imageName>${docker.namespace}/ruoyi-server:${project.version}</imageName>
<dockerDirectory>${project.basedir}</dockerDirectory>
<dockerHost>${docker.registry.host}</dockerHost>
<registryUrl>${docker.registry.url}</registryUrl>
<serverId>${docker.registry.url}</serverId>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,86 +0,0 @@
package com.ruoyi.web.controller.common;
import cn.hutool.captcha.AbstractCaptcha;
import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.IdUtil;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.enums.CaptchaType;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.redis.RedisUtils;
import com.ruoyi.common.utils.reflect.ReflectUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.framework.config.properties.CaptchaProperties;
import com.ruoyi.system.service.ISysConfigService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* 验证码操作处理
*
* @author Lion Li
*/
@Api(value = "验证码操作处理", tags = {"验证码管理"})
@RequiredArgsConstructor
@RestController
public class CaptchaController {
private final CaptchaProperties captchaProperties;
private final ISysConfigService configService;
/**
* 生成验证码
*/
@ApiOperation("生成验证码")
@GetMapping("/captchaImage")
public R<Map<String, Object>> getCode() {
Map<String, Object> ajax = new HashMap<>();
boolean captchaOnOff = configService.selectCaptchaOnOff();
ajax.put("captchaOnOff", captchaOnOff);
if (!captchaOnOff) {
return R.ok(ajax);
}
// 保存验证码信息
String uuid = IdUtil.simpleUUID();
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
// 生成验证码
CaptchaType captchaType = captchaProperties.getType();
boolean isMath = CaptchaType.MATH == captchaType;
Integer length = isMath ? captchaProperties.getNumberLength() : captchaProperties.getCharLength();
CodeGenerator codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), length);
AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz());
captcha.setGenerator(codeGenerator);
captcha.createCode();
String code = isMath ? getCodeResult(captcha.getCode()) : captcha.getCode();
RedisUtils.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
ajax.put("uuid", uuid);
ajax.put("img", captcha.getImageBase64());
return R.ok(ajax);
}
private String getCodeResult(String capStr) {
int numberLength = captchaProperties.getNumberLength();
int a = Convert.toInt(StringUtils.substring(capStr, 0, numberLength).trim());
char operator = capStr.charAt(numberLength);
int b = Convert.toInt(StringUtils.substring(capStr, numberLength + 1, numberLength + 1 + numberLength).trim());
switch (operator) {
case '*':
return Convert.toStr(a * b);
case '+':
return Convert.toStr(a + b);
case '-':
return Convert.toStr(a - b);
default:
return StringUtils.EMPTY;
}
}
}

View File

@@ -1,56 +0,0 @@
package com.ruoyi.web.controller.monitor;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.utils.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.connection.RedisServerCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.*;
/**
* 缓存监控
*
* @author Lion Li
*/
@Api(value = "缓存监控", tags = {"缓存监控管理"})
@RequiredArgsConstructor
@RestController
@RequestMapping("/monitor/cache")
public class CacheController {
private final RedisTemplate<String, String> redisTemplate;
@ApiOperation("获取缓存监控详细信息")
@SaCheckPermission("monitor:cache:list")
@GetMapping()
public R<Map<String, Object>> getInfo() throws Exception {
Properties info = (Properties) redisTemplate.execute((RedisCallback<Object>) RedisServerCommands::info);
Properties commandStats = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info("commandstats"));
Object dbSize = redisTemplate.execute((RedisCallback<Object>) RedisServerCommands::dbSize);
Map<String, Object> result = new HashMap<>(3);
result.put("info", info);
result.put("dbSize", dbSize);
List<Map<String, String>> pieList = new ArrayList<>();
if (commandStats != null) {
commandStats.stringPropertyNames().forEach(key -> {
Map<String, String> data = new HashMap<>(2);
String property = commandStats.getProperty(key);
data.put("name", StringUtils.removeStart(key, "cmdstat_"));
data.put("value", StringUtils.substringBetween(property, "calls=", ",usec"));
pieList.add(data);
});
}
result.put("commandStats", pieList);
return R.ok(result);
}
}

View File

@@ -1,154 +0,0 @@
--- # 监控配置
spring:
boot:
admin:
# Spring Boot Admin Client 客户端的相关配置
client:
# 增加客户端开关
enabled: true
# 设置 Spring Boot Admin Server 地址
url: http://localhost:9090/admin
instance:
service-host-type: IP
username: ruoyi
password: 123456
--- # xxl-job 配置
xxl:
job:
# 执行器开关
enabled: true
# 调度中心地址:如调度中心集群部署存在多个地址则用逗号分隔。
admin-addresses: http://localhost:9100/xxl-job-admin
# 执行器通讯TOKEN非空时启用
access-token: xxl-job
# 执行器配置
executor:
# 执行器AppName执行器心跳注册分组依据为空则关闭自动注册
appname: xxl-job-executor
# 执行器端口号 执行器从9101开始往后写
port: 9101
# 执行器注册默认IP:PORT
address:
# 执行器IP默认自动获取IP
ip:
# 执行器运行日志文件存储磁盘路径
logpath: ./logs/xxl-job
# 执行器日志文件保存天数大于3生效
logretentiondays: 30
--- # 数据源配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
dynamic:
# 性能分析插件(有性能损耗 不建议生产环境使用)
p6spy: true
# 设置默认的数据源或者数据源组,默认值即为 master
primary: master
datasource:
# 主库数据源
master:
driverClassName: com.mysql.cj.jdbc.Driver
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
username: root
password: root
# 从库数据源
slave:
lazy: true
driverClassName: com.mysql.cj.jdbc.Driver
url:
username:
password:
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
# 注意这个值和druid原生不一致默认启动了stat
filters: stat
--- # druid 配置
spring:
datasource:
druid:
webStatFilter:
enabled: true
statViewServlet:
enabled: true
# 设置白名单,不填则允许所有访问
allow:
url-pattern: /druid/*
# 控制台管理用户名和密码
login-username: ruoyi
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
--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
spring:
redis:
# 地址
host: localhost
# 端口默认为6379
port: 6379
# 数据库索引
database: 0
# 密码
password:
# 连接超时时间
timeout: 10s
# 是否开启ssl
ssl: false
redisson:
# 线程池数量
threads: 4
# Netty线程池数量
nettyThreads: 8
# 传输模式
transportMode: "NIO"
# 单节点配置
singleServerConfig:
# 客户端名称
clientName: ${ruoyi.name}
# 最小空闲连接数
connectionMinimumIdleSize: 8
# 连接池大小
connectionPoolSize: 32
# 连接空闲超时,单位:毫秒
idleConnectionTimeout: 10000
# 命令等待超时,单位:毫秒
timeout: 3000
# 如果尝试在此限制之内发送成功,则开始启用 timeout 计时。
retryAttempts: 3
# 命令重试发送时间间隔,单位:毫秒
retryInterval: 1500
# 发布和订阅连接池大小
subscriptionConnectionPoolSize: 50

View File

@@ -1,161 +0,0 @@
--- # 配置临时路径存储
spring:
servlet:
multipart:
# 临时文件存储位置 避免临时文件被系统清理报错
location: /ruoyi/server/temp
--- # 监控配置
spring:
boot:
admin:
# Spring Boot Admin Client 客户端的相关配置
client:
# 增加客户端开关
enabled: true
# 设置 Spring Boot Admin Server 地址
url: http://172.30.0.90:9090/admin
instance:
service-host-type: IP
username: ruoyi
password: 123456
--- # xxl-job 配置
xxl:
job:
# 执行器开关
enabled: true
# 调度中心地址:如调度中心集群部署存在多个地址则用逗号分隔。
admin-addresses: http://172.30.0.92:9100/xxl-job-admin
# 执行器通讯TOKEN非空时启用
access-token: xxl-job
# 执行器配置
executor:
# 执行器AppName执行器心跳注册分组依据为空则关闭自动注册
appname: xxl-job-executor
# 执行器端口号 执行器从9101开始往后写
port: 9101
# 执行器注册默认IP:PORT
address:
# 执行器IP默认自动获取IP
ip:
# 执行器运行日志文件存储磁盘路径
logpath: ./logs/xxl-job
# 执行器日志文件保存天数大于3生效
logretentiondays: 30
--- # 数据源配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
dynamic:
# 性能分析插件(有性能损耗 不建议生产环境使用)
p6spy: false
# 设置默认的数据源或者数据源组,默认值即为 master
primary: master
datasource:
# 主库数据源
master:
driverClassName: com.mysql.cj.jdbc.Driver
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
url: jdbc:mysql://172.30.0.36:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
username: root
password: root
# 从库数据源
slave:
lazy: true
driverClassName: com.mysql.cj.jdbc.Driver
url:
username:
password:
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
# 注意这个值和druid原生不一致默认启动了stat
filters: stat
--- # druid 配置
spring:
datasource:
druid:
webStatFilter:
enabled: true
statViewServlet:
enabled: true
# 设置白名单,不填则允许所有访问
allow:
url-pattern: /druid/*
# 控制台管理用户名和密码
login-username: ruoyi
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
--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
spring:
redis:
# 地址
host: 172.30.0.48
# 端口默认为6379
port: 6379
# 数据库索引
database: 0
# 密码
password:
# 连接超时时间
timeout: 10s
# 是否开启ssl
ssl: false
redisson:
# 线程池数量
threads: 16
# Netty线程池数量
nettyThreads: 32
# 传输模式
transportMode: "NIO"
# 单节点配置
singleServerConfig:
# 客户端名称
clientName: ${ruoyi.name}
# 最小空闲连接数
connectionMinimumIdleSize: 32
# 连接池大小
connectionPoolSize: 64
# 连接空闲超时,单位:毫秒
idleConnectionTimeout: 10000
# 命令等待超时,单位:毫秒
timeout: 3000
# 如果尝试在此限制之内发送成功,则开始启用 timeout 计时。
retryAttempts: 3
# 命令重试发送时间间隔,单位:毫秒
retryInterval: 1500
# 发布和订阅连接池大小
subscriptionConnectionPoolSize: 50

View File

@@ -1,169 +0,0 @@
<?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">
<parent>
<artifactId>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId>
<version>4.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-common</artifactId>
<description>
common通用工具
</description>
<dependencies>
<!-- Spring框架基本的核心工具 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<!-- SpringWeb模块 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<!-- Sa-Token 权限认证, 在线文档http://sa-token.dev33.cn/ -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
</dependency>
<!-- Sa-Token 整合 jwt -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-jwt</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>
<!-- excel工具 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
</dependency>
<!-- yml解析器 -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>
<!-- jdk11 缺失依赖 jaxb-->
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
</dependency>
<!-- servlet包 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-extension</artifactId>
</dependency>
<!-- dynamic-datasource 多数据源-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-http</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-captcha</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-jwt</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-extra</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</dependency>
<!-- 自动生成YML配置关联JSON文件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<!--redisson-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>lock4j-redisson-spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,126 +0,0 @@
package com.ruoyi.common.constant;
/**
* 通用常量信息
*
* @author ruoyi
*/
public interface Constants {
/**
* UTF-8 字符集
*/
String UTF8 = "UTF-8";
/**
* GBK 字符集
*/
String GBK = "GBK";
/**
* http请求
*/
String HTTP = "http://";
/**
* https请求
*/
String HTTPS = "https://";
/**
* 通用成功标识
*/
String SUCCESS = "0";
/**
* 通用失败标识
*/
String FAIL = "1";
/**
* 登录成功
*/
String LOGIN_SUCCESS = "Success";
/**
* 注销
*/
String LOGOUT = "Logout";
/**
* 注册
*/
String REGISTER = "Register";
/**
* 登录失败
*/
String LOGIN_FAIL = "Error";
/**
* 验证码 redis key
*/
String CAPTCHA_CODE_KEY = "captcha_codes:";
/**
* 登录用户 redis key
*/
public static final String LOGIN_TOKEN_KEY = "Authorization:login:token:";
/**
* 在线用户 redis key
*/
public static final String ONLINE_TOKEN_KEY = "online_tokens:";
/**
* 防重提交 redis key
*/
String REPEAT_SUBMIT_KEY = "repeat_submit:";
/**
* 限流 redis key
*/
String RATE_LIMIT_KEY = "rate_limit:";
/**
* 验证码有效期(分钟)
*/
Integer CAPTCHA_EXPIRATION = 2;
/**
* 登陆错误 redis key
*/
String LOGIN_ERROR = "login_error:";
/**
* 登录错误次数
*/
Integer LOGIN_ERROR_NUMBER = 5;
/**
* 登录错误限制时间(分钟)
*/
Integer LOGIN_ERROR_LIMIT_TIME = 10;
/**
* 令牌
*/
String TOKEN = "token";
/**
* 令牌前缀
*/
String LOGIN_USER_KEY = "login_user_key";
/**
* 参数管理 cache key
*/
String SYS_CONFIG_KEY = "sys_config:";
/**
* 字典管理 cache key
*/
String SYS_DICT_KEY = "sys_dict:";
}

View File

@@ -1,91 +0,0 @@
package com.ruoyi.common.core.domain;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.sql.SqlUtil;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
/**
* 分页查询实体类
*
* @author Lion Li
*/
@Data
public class PageQuery implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 分页大小
*/
@ApiModelProperty("分页大小")
private Integer pageSize;
/**
* 当前页数
*/
@ApiModelProperty("当前页数")
private Integer pageNum;
/**
* 排序列
*/
@ApiModelProperty("排序列")
private String orderByColumn;
/**
* 排序的方向desc或者asc
*/
@ApiModelProperty(value = "排序的方向", example = "asc,desc")
private String isAsc;
/**
* 当前记录起始索引 默认值
*/
public static final int DEFAULT_PAGE_NUM = 1;
/**
* 每页显示记录数 默认值 默认查全部
*/
public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE;
public <T> Page<T> build() {
Integer pageNum = ObjectUtil.defaultIfNull(getPageNum(), DEFAULT_PAGE_NUM);
Integer pageSize = ObjectUtil.defaultIfNull(getPageSize(), DEFAULT_PAGE_SIZE);
if (pageNum <= 0) {
pageNum = DEFAULT_PAGE_NUM;
}
Page<T> page = new Page<>(pageNum, pageSize);
OrderItem orderItem = buildOrderItem();
if (ObjectUtil.isNotNull(orderItem)) {
page.addOrder(orderItem);
}
return page;
}
private OrderItem buildOrderItem() {
// 兼容前端排序类型
if ("ascending".equals(isAsc)) {
isAsc = "asc";
} else if ("descending".equals(isAsc)) {
isAsc = "desc";
}
if (StringUtils.isNotBlank(orderByColumn)) {
String orderBy = SqlUtil.escapeOrderBySql(orderByColumn);
orderBy = StringUtils.toUnderScoreCase(orderBy);
if ("asc".equals(isAsc)) {
return OrderItem.asc(orderBy);
} else if ("desc".equals(isAsc)) {
return OrderItem.desc(orderBy);
}
}
return null;
}
}

View File

@@ -1,14 +0,0 @@
package com.ruoyi.common.core.service;
import javax.servlet.http.HttpServletRequest;
/**
* 通用 系统访问日志
*
* @author Lion Li
*/
public interface LogininforService {
void recordLogininfor(String username, String status, String message,
HttpServletRequest request, Object... args);
}

View File

@@ -1,15 +0,0 @@
package com.ruoyi.common.core.service;
import com.ruoyi.common.core.domain.dto.OperLogDTO;
import org.springframework.scheduling.annotation.Async;
/**
* 通用 操作日志
*
* @author Lion Li
*/
public interface OperLogService {
@Async
void recordOper(OperLogDTO operLogDTO);
}

View File

@@ -1,26 +0,0 @@
package com.ruoyi.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 线程池 拒绝策略 泛型
*
* @author Lion Li
*/
@Getter
@AllArgsConstructor
public enum ThreadPoolRejectedPolicy {
CALLER_RUNS_POLICY("调用方执行", ThreadPoolExecutor.CallerRunsPolicy.class),
DISCARD_OLDEST_POLICY("放弃最旧的", ThreadPoolExecutor.DiscardOldestPolicy.class),
DISCARD_POLICY("丢弃", ThreadPoolExecutor.DiscardPolicy.class),
ABORT_POLICY("中止", ThreadPoolExecutor.AbortPolicy.class);
private final String name;
private final Class<? extends RejectedExecutionHandler> clazz;
}

View File

@@ -1,47 +0,0 @@
package com.ruoyi.common.helper;
import cn.hutool.core.util.ObjectUtil;
import com.ruoyi.common.utils.ServletUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
/**
* 数据权限助手
*
* @author Lion Li
* @version 3.5.0
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@SuppressWarnings("unchecked cast")
public class DataPermissionHelper {
private static final String DATA_PERMISSION_KEY = "data:permission";
public static <T> T getVariable(String key) {
Map<String, Object> context = getContext();
return (T) context.get(key);
}
public static void setVariable(String key, Object value) {
Map<String, Object> context = getContext();
context.put(key, value);
}
public static Map<String, Object> getContext() {
HttpServletRequest request = ServletUtils.getRequest();
Object attribute = request.getAttribute(DATA_PERMISSION_KEY);
if (ObjectUtil.isNull(attribute)) {
request.setAttribute(DATA_PERMISSION_KEY, new HashMap<>());
attribute = request.getAttribute(DATA_PERMISSION_KEY);
}
if (attribute instanceof Map) {
return (Map<String, Object>) attribute;
}
throw new NullPointerException("data permission context type exception");
}
}

View File

@@ -1,124 +0,0 @@
package com.ruoyi.common.utils;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.extra.cglib.CglibUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.Map;
/**
* bean深拷贝工具(基于 cglib 性能优异)
* <p>
* 重点 cglib 不支持 拷贝到链式对象
* 例如: 源对象 拷贝到 目标(链式对象)
* 请区分好`浅拷贝`和`深拷贝`再做使用
*
* @author Lion Li
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class BeanCopyUtils {
/**
* 单对象基于class创建拷贝
*
* @param source 数据来源实体
* @param desc 描述对象 转换后的对象
* @return desc
*/
public static <T, V> V copy(T source, Class<V> desc) {
if (ObjectUtil.isNull(source)) {
return null;
}
if (ObjectUtil.isNull(desc)) {
return null;
}
return CglibUtil.copy(source, desc);
}
/**
* 单对象基于对象创建拷贝
*
* @param source 数据来源实体
* @param desc 转换后的对象
* @return desc
*/
public static <T, V> V copy(T source, V desc) {
if (ObjectUtil.isNull(source)) {
return null;
}
if (ObjectUtil.isNull(desc)) {
return null;
}
CglibUtil.copy(source, desc);
return desc;
}
/**
* 列表对象基于class创建拷贝
*
* @param sourceList 数据来源实体列表
* @param desc 描述对象 转换后的对象
* @return desc
*/
public static <T, V> List<V> copyList(List<T> sourceList, Class<V> desc) {
if (ObjectUtil.isNull(sourceList)) {
return null;
}
if (CollUtil.isEmpty(sourceList)) {
return CollUtil.newArrayList();
}
return CglibUtil.copyList(sourceList, () -> ReflectUtil.newInstanceIfPossible(desc));
}
/**
* bean拷贝到map
*
* @param bean 数据来源实体
* @return map对象
*/
public static <T> Map<String, Object> copyToMap(T bean) {
if (ObjectUtil.isNull(bean)) {
return null;
}
return CglibUtil.toMap(bean);
}
/**
* map拷贝到bean
*
* @param map 数据来源
* @param beanClass bean类
* @return bean对象
*/
public static <T> T mapToBean(Map<String, Object> map, Class<T> beanClass) {
if (MapUtil.isEmpty(map)) {
return null;
}
if (ObjectUtil.isNull(beanClass)) {
return null;
}
return CglibUtil.toBean(map, beanClass);
}
/**
* map拷贝到bean
*
* @param map 数据来源
* @param bean bean对象
* @return bean对象
*/
public static <T> T mapToBean(Map<String, Object> map, T bean) {
if (MapUtil.isEmpty(map)) {
return null;
}
if (ObjectUtil.isNull(bean)) {
return null;
}
return CglibUtil.fillBean(map, bean);
}
}

View File

@@ -1,60 +0,0 @@
package com.ruoyi.common.utils.ip;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.net.NetUtil;
import cn.hutool.http.HtmlUtil;
import cn.hutool.http.HttpUtil;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.common.utils.StringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
/**
* 获取地址类
*
* @author Lion Li
*/
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class AddressUtils {
// IP地址查询
public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp";
// 未知地址
public static final String UNKNOWN = "XX XX";
public static String getRealAddressByIP(String ip) {
String address = UNKNOWN;
if (StringUtils.isBlank(ip)) {
return address;
}
// 内网不查询
ip = "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : HtmlUtil.cleanHtmlTag(ip);
if (NetUtil.isInnerIP(ip)) {
return "内网IP";
}
if (RuoYiConfig.isAddressEnabled()) {
try {
String rspStr = HttpUtil.createGet(IP_URL)
.body("ip=" + ip + "&json=true", Constants.GBK)
.execute()
.body();
if (StringUtils.isEmpty(rspStr)) {
log.error("获取地理位置异常 {}", ip);
return UNKNOWN;
}
Dict obj = JsonUtils.parseMap(rspStr);
String region = obj.getStr("pro");
String city = obj.getStr("city");
return String.format("%s %s", region, city);
} catch (Exception e) {
log.error("获取地理位置异常 {}", ip);
}
}
return UNKNOWN;
}
}

View File

@@ -1,158 +0,0 @@
package com.ruoyi.common.utils.poi;
import cn.hutool.core.util.IdUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.ruoyi.common.convert.ExcelBigNumberConvert;
import com.ruoyi.common.excel.DefaultExcelListener;
import com.ruoyi.common.excel.ExcelListener;
import com.ruoyi.common.excel.ExcelResult;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* Excel相关处理
*
* @author Lion Li
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ExcelUtil {
/**
* 同步导入(适用于小数据量)
*
* @param is 输入流
* @return 转换后集合
*/
public static <T> List<T> importExcel(InputStream is, Class<T> clazz) {
return EasyExcel.read(is).head(clazz).autoCloseStream(false).sheet().doReadSync();
}
/**
* 使用校验监听器 异步导入 同步返回
*
* @param is 输入流
* @param clazz 对象类型
* @param isValidate 是否 Validator 检验 默认为是
* @return 转换后集合
*/
public static <T> ExcelResult<T> importExcel(InputStream is, Class<T> clazz, boolean isValidate) {
DefaultExcelListener<T> listener = new DefaultExcelListener<>(isValidate);
EasyExcel.read(is, clazz, listener).sheet().doRead();
return listener.getExcelResult();
}
/**
* 使用自定义监听器 异步导入 自定义返回
*
* @param is 输入流
* @param clazz 对象类型
* @param listener 自定义监听器
* @return 转换后集合
*/
public static <T> ExcelResult<T> importExcel(InputStream is, Class<T> clazz, ExcelListener<T> listener) {
EasyExcel.read(is, clazz, listener).sheet().doRead();
return listener.getExcelResult();
}
/**
* 导出excel
*
* @param list 导出数据集合
* @param sheetName 工作表的名称
* @return 结果
*/
public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz, HttpServletResponse response) {
try {
String filename = encodingFilename(sheetName);
response.reset();
FileUtils.setAttachmentResponseHeader(response, filename);
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8");
ServletOutputStream os = response.getOutputStream();
EasyExcel.write(os, clazz)
.autoCloseStream(false)
// 自动适配
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
// 大数值自动转换 防止失真
.registerConverter(new ExcelBigNumberConvert())
.sheet(sheetName).doWrite(list);
} catch (IOException e) {
throw new RuntimeException("导出Excel异常");
}
}
/**
* 解析导出值 0=男,1=女,2=未知
*
* @param propertyValue 参数值
* @param converterExp 翻译注解
* @param separator 分隔符
* @return 解析后值
*/
public static String convertByExp(String propertyValue, String converterExp, String separator) {
StringBuilder propertyString = new StringBuilder();
String[] convertSource = converterExp.split(",");
for (String item : convertSource) {
String[] itemArray = item.split("=");
if (StringUtils.containsAny(separator, propertyValue)) {
for (String value : propertyValue.split(separator)) {
if (itemArray[0].equals(value)) {
propertyString.append(itemArray[1] + separator);
break;
}
}
} else {
if (itemArray[0].equals(propertyValue)) {
return itemArray[1];
}
}
}
return StringUtils.stripEnd(propertyString.toString(), separator);
}
/**
* 反向解析值 男=0,女=1,未知=2
*
* @param propertyValue 参数值
* @param converterExp 翻译注解
* @param separator 分隔符
* @return 解析后值
*/
public static String reverseByExp(String propertyValue, String converterExp, String separator) {
StringBuilder propertyString = new StringBuilder();
String[] convertSource = converterExp.split(",");
for (String item : convertSource) {
String[] itemArray = item.split("=");
if (StringUtils.containsAny(separator, propertyValue)) {
for (String value : propertyValue.split(separator)) {
if (itemArray[1].equals(value)) {
propertyString.append(itemArray[0] + separator);
break;
}
}
} else {
if (itemArray[1].equals(propertyValue)) {
return itemArray[0];
}
}
}
return StringUtils.stripEnd(propertyString.toString(), separator);
}
/**
* 编码文件名
*/
public static String encodingFilename(String filename) {
return IdUtil.fastSimpleUUID() + "_" + filename + ".xlsx";
}
}

View File

@@ -1,28 +0,0 @@
<?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">
<parent>
<artifactId>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId>
<version>4.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-demo</artifactId>
<description>
demo模块
</description>
<dependencies>
<!-- 通用工具-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,16 +0,0 @@
package com.ruoyi.demo.controller.queue;
import java.util.Comparator;
/**
* 比较器 注意不允许使用 内部类或匿名类或lambda表达式 会找不到类
*
* @author Lion Li
* @version 3.6.0
*/
public class PriorityDemoComparator implements Comparator<PriorityDemo> {
@Override
public int compare(PriorityDemo pd1, PriorityDemo pd2) {
return Integer.compare(pd1.getOrderNum(), pd2.getOrderNum());
}
}

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId>
<version>4.0.1</version>
<version>4.8.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-extend</artifactId>

View File

@@ -2,7 +2,6 @@ FROM anapsix/alpine-java:8_server-jre_unlimited
MAINTAINER Lion Li
RUN mkdir -p /ruoyi/monitor
RUN mkdir -p /ruoyi/monitor/logs
WORKDIR /ruoyi/monitor

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>ruoyi-extend</artifactId>
<groupId>com.ruoyi</groupId>
<version>4.0.1</version>
<version>4.8.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
@@ -59,25 +59,6 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>${docker.plugin.version}</version>
<configuration>
<imageName>${docker.namespace}/${project.artifactId}:${project.version}</imageName>
<dockerDirectory>${project.basedir}</dockerDirectory>
<dockerHost>${docker.registry.host}</dockerHost>
<registryUrl>${docker.registry.url}</registryUrl>
<serverId>${docker.registry.url}</serverId>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
</plugins>
</build>

View File

@@ -1,10 +1,10 @@
package com.ruoyi.monitor.admin.config;
import de.codecentric.boot.admin.server.config.AdminServerProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
/**
@@ -12,9 +12,8 @@ import org.springframework.security.web.authentication.SavedRequestAwareAuthenti
*
* @author Lion Li
*/
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
public class SecurityConfig {
private final String adminContextPath;
@@ -22,27 +21,30 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
this.adminContextPath = adminServerProperties.getContextPath();
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
@Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setTargetUrlParameter("redirectTo");
successHandler.setDefaultTargetUrl(adminContextPath + "/");
// admin监控 用户鉴权
httpSecurity.authorizeRequests()
//授予对所有静态资产和登录页面的公共访问权限。
.antMatchers(adminContextPath + "/assets/**").permitAll()
.antMatchers(adminContextPath + "/login").permitAll()
.antMatchers("/actuator").permitAll()
.antMatchers("/actuator/**").permitAll()
//必须对每个其他请求进行身份验证
.anyRequest().authenticated().and()
//配置登录和注销
return httpSecurity
.headers().frameOptions().disable()
.and().authorizeRequests()
.antMatchers(adminContextPath + "/assets/**"
, adminContextPath + "/login"
, "/actuator"
, "/actuator/**"
).permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage(adminContextPath + "/login")
.successHandler(successHandler).and()
.logout().logoutUrl(adminContextPath + "/logout").and()
//启用HTTP-Basic支持。这是Spring Boot Admin Client注册所必需的
.httpBasic().and().csrf().disable()
.headers().frameOptions().disable();
.logout().logoutUrl(adminContextPath + "/logout")
.and()
.httpBasic().and()
.csrf()
.disable()
.build();
}
}

View File

@@ -1,14 +0,0 @@
--- # 监控配置
spring:
boot:
admin:
# Spring Boot Admin Client 客户端的相关配置
client:
# 增加客户端开关
enabled: true
# 设置 Spring Boot Admin Server 地址
url: http://localhost:9090/admin
instance:
service-host-type: IP
username: ruoyi
password: 123456

View File

@@ -1,14 +0,0 @@
--- # 监控配置
spring:
boot:
admin:
# Spring Boot Admin Client 客户端的相关配置
client:
# 增加客户端开关
enabled: true
# 设置 Spring Boot Admin Server 地址
url: http://172.30.0.90:9090/admin
instance:
service-host-type: IP
username: ruoyi
password: 123456

View File

@@ -6,6 +6,9 @@ spring:
profiles:
active: @profiles.active@
logging:
config: classpath:logback-plus.xml
--- # 监控中心服务端配置
spring:
security:
@@ -14,18 +17,29 @@ spring:
password: 123456
boot:
admin:
ui:
title: RuoYi-Vue-Plus服务监控中心
context-path: /admin
--- # Actuator 监控端点的配置项
management:
endpoints:
web:
# Actuator 提供的 API 接口的根目录。默认为 /actuator
base-path: /actuator
exposure:
# 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。
# 生产环境不建议放开所有 根据项目需求放开即可
include: @endpoints.include@
include: '*'
endpoint:
health:
show-details: ALWAYS
logfile:
external-file: ./logs/ruoyi-monitor-admin.log
--- # 监控配置
spring.boot.admin.client:
# 增加客户端开关
enabled: true
# 设置 Spring Boot Admin Server 地址
url: http://localhost:9090/admin
instance:
service-host-type: IP
username: ruoyi
password: 123456

View File

@@ -2,7 +2,6 @@ FROM anapsix/alpine-java:8_server-jre_unlimited
MAINTAINER Lion Li
RUN mkdir -p /ruoyi/xxljob
RUN mkdir -p /ruoyi/xxljob/logs
WORKDIR /ruoyi/xxljob

View File

@@ -4,14 +4,12 @@
<parent>
<artifactId>ruoyi-extend</artifactId>
<groupId>com.ruoyi</groupId>
<version>4.0.1</version>
<version>4.8.2</version>
</parent>
<artifactId>ruoyi-xxl-job-admin</artifactId>
<packaging>jar</packaging>
<properties>
<mybatis-spring-boot-starter.version>2.1.4</mybatis-spring-boot-starter.version>
<mysql-connector-java.version>8.0.23</mysql-connector-java.version>
</properties>
<dependencyManagement>
@@ -62,13 +60,12 @@
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring-boot-starter.version}</version>
<version>${spring-boot.mybatis}</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector-java.version}</version>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<dependency>
@@ -99,27 +96,6 @@
</execution>
</executions>
</plugin>
<!-- docker -->
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>${docker.plugin.version}</version>
<configuration>
<!-- made of '[a-z0-9-_.]' -->
<imageName>${docker.namespace}/${project.artifactId}:${project.version}</imageName>
<dockerDirectory>${project.basedir}</dockerDirectory>
<dockerHost>${docker.registry.host}</dockerHost>
<registryUrl>${docker.registry.url}</registryUrl>
<serverId>${docker.registry.url}</serverId>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
</plugins>
</build>

View File

@@ -1,5 +1,6 @@
package com.xxl.job.admin.controller;
import com.xxl.job.admin.controller.annotation.PermissionLimit;
import com.xxl.job.admin.core.model.XxlJobGroup;
import com.xxl.job.admin.core.model.XxlJobRegistry;
import com.xxl.job.admin.core.util.I18nUtil;
@@ -35,12 +36,14 @@ public class JobGroupController {
private XxlJobRegistryDao xxlJobRegistryDao;
@RequestMapping
@PermissionLimit(adminuser = true)
public String index(Model model) {
return "jobgroup/jobgroup.index";
}
@RequestMapping("/pageList")
@ResponseBody
@PermissionLimit(adminuser = true)
public Map<String, Object> pageList(HttpServletRequest request,
@RequestParam(required = false, defaultValue = "0") int start,
@RequestParam(required = false, defaultValue = "10") int length,
@@ -60,6 +63,7 @@ public class JobGroupController {
@RequestMapping("/save")
@ResponseBody
@PermissionLimit(adminuser = true)
public ReturnT<String> save(XxlJobGroup xxlJobGroup) {
// valid
@@ -103,6 +107,7 @@ public class JobGroupController {
@RequestMapping("/update")
@ResponseBody
@PermissionLimit(adminuser = true)
public ReturnT<String> update(XxlJobGroup xxlJobGroup) {
// valid
if (xxlJobGroup.getAppname() == null || xxlJobGroup.getAppname().trim().length() == 0) {
@@ -171,6 +176,7 @@ public class JobGroupController {
@RequestMapping("/remove")
@ResponseBody
@PermissionLimit(adminuser = true)
public ReturnT<String> remove(int id) {
// valid
@@ -190,6 +196,7 @@ public class JobGroupController {
@RequestMapping("/loadById")
@ResponseBody
@PermissionLimit(adminuser = true)
public ReturnT<XxlJobGroup> loadById(int id) {
XxlJobGroup jobGroup = xxlJobGroupDao.load(id);
return jobGroup != null ? new ReturnT<XxlJobGroup>(jobGroup) : new ReturnT<XxlJobGroup>(ReturnT.FAIL_CODE, null);

View File

@@ -1,7 +1,7 @@
package com.xxl.job.admin.controller;
import com.xxl.job.admin.core.complete.XxlJobCompleter;
import com.xxl.job.admin.core.exception.XxlJobException;
import com.xxl.job.admin.core.complete.XxlJobCompleter;
import com.xxl.job.admin.core.model.XxlJobGroup;
import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.model.XxlJobLog;
@@ -130,22 +130,26 @@ public class JobLogController {
model.addAttribute("triggerCode", jobLog.getTriggerCode());
model.addAttribute("handleCode", jobLog.getHandleCode());
model.addAttribute("executorAddress" , jobLog.getExecutorAddress());
model.addAttribute("triggerTime" , jobLog.getTriggerTime().getTime());
model.addAttribute("logId", jobLog.getId());
return "joblog/joblog.detail";
}
@RequestMapping("/logDetailCat")
@ResponseBody
public ReturnT<LogResult> logDetailCat(String executorAddress, long triggerTime, long logId, int fromLineNum) {
public ReturnT<LogResult> logDetailCat(long logId, int fromLineNum) {
try {
ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(executorAddress);
ReturnT<LogResult> logResult = executorBiz.log(new LogParam(triggerTime, logId, fromLineNum));
// valid
XxlJobLog jobLog = xxlJobLogDao.load(logId); // todo, need to improve performance
if (jobLog == null) {
return new ReturnT<LogResult>(ReturnT.FAIL_CODE, I18nUtil.getString("joblog_logid_unvalid"));
}
// log cat
ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(jobLog.getExecutorAddress());
ReturnT<LogResult> logResult = executorBiz.log(new LogParam(jobLog.getTriggerTime().getTime(), logId, fromLineNum));
// is end
if (logResult.getContent() != null && logResult.getContent().getFromLineNum() > logResult.getContent().getToLineNum()) {
XxlJobLog jobLog = xxlJobLogDao.load(logId);
if (jobLog.getHandleCode() > 0) {
logResult.getContent().setEnd(true);
}

View File

@@ -37,7 +37,6 @@ public class CookieInterceptor implements AsyncHandlerInterceptor {
modelAndView.addObject("I18nUtil", FtlUtil.generateStaticModel(I18nUtil.class.getName()));
}
AsyncHandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
}

View File

@@ -27,7 +27,7 @@ public class PermissionInterceptor implements AsyncHandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (!(handler instanceof HandlerMethod)) {
return AsyncHandlerInterceptor.super.preHandle(request, response, handler);
return true; // proceed with the next interceptor
}
// if need login
@@ -53,7 +53,7 @@ public class PermissionInterceptor implements AsyncHandlerInterceptor {
request.setAttribute(LoginService.LOGIN_IDENTITY_KEY, loginUser);
}
return AsyncHandlerInterceptor.super.preHandle(request, response, handler);
return true; // proceed with the next interceptor
}
}

View File

@@ -1,8 +1,8 @@
package com.xxl.job.admin.controller.resolver;
import com.xxl.job.admin.core.exception.XxlJobException;
import com.xxl.job.admin.core.util.JacksonUtil;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.admin.core.util.JacksonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

View File

@@ -32,6 +32,7 @@ public class EmailJobAlarm implements JobAlarm {
*
* @param jobLog
*/
@Override
public boolean doAlarm(XxlJobInfo info, XxlJobLog jobLog) {
boolean alarmResult = true;

View File

@@ -47,7 +47,7 @@ public class XxlJobCompleter {
// 1、handle success, to trigger child job
String triggerChildMsg = null;
if (XxlJobContext.HANDLE_COCE_SUCCESS == xxlJobLog.getHandleCode()) {
if (XxlJobContext.HANDLE_CODE_SUCCESS == xxlJobLog.getHandleCode()) {
XxlJobInfo xxlJobInfo = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().loadById(xxlJobLog.getJobId());
if (xxlJobInfo != null && xxlJobInfo.getChildJobId() != null && xxlJobInfo.getChildJobId().trim().length() > 0) {
triggerChildMsg = "<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>" + I18nUtil.getString("jobconf_trigger_child_run") + "<<<<<<<<<<< </span><br>";

View File

@@ -23,6 +23,7 @@ import java.util.Arrays;
public class XxlJobAdminConfig implements InitializingBean, DisposableBean {
private static XxlJobAdminConfig adminConfig = null;
public static XxlJobAdminConfig getAdminConfig() {
return adminConfig;
}

View File

@@ -191,13 +191,11 @@ import java.util.TreeSet;
* </ul>
* </p>
*
*
* @author Sharada Jambula, James House
* @author Contributions from Mads Henderson
* @author Refactoring from CronTrigger to CronExpression by Aaron Craven
*
* <p>
* Borrowed from quartz v2.3.1
*
*/
public final class CronExpression implements Serializable, Cloneable {
@@ -217,6 +215,7 @@ public final class CronExpression implements Serializable, Cloneable {
protected static final Map<String, Integer> monthMap = new HashMap<String, Integer>(20);
protected static final Map<String, Integer> dayMap = new HashMap<String, Integer>(60);
static {
monthMap.put("JAN", 0);
monthMap.put("FEB", 1);
@@ -265,8 +264,7 @@ public final class CronExpression implements Serializable, Cloneable {
*
* @param cronExpression String representation of the cron expression the
* new object should represent
* @throws java.text.ParseException
* if the string expression cannot be parsed into a valid
* @throws ParseException if the string expression cannot be parsed into a valid
* <CODE>CronExpression</CODE>
*/
public CronExpression(String cronExpression) throws ParseException {
@@ -283,8 +281,7 @@ public final class CronExpression implements Serializable, Cloneable {
* Constructs a new {@code CronExpression} as a copy of an existing
* instance.
*
* @param expression
* The existing cron expression to be copied
* @param expression The existing cron expression to be copied
*/
public CronExpression(CronExpression expression) {
/*
@@ -1067,14 +1064,28 @@ public final class CronExpression implements Serializable, Cloneable {
int max = -1;
if (stopAt < startAt) {
switch (type) {
case SECOND : max = 60; break;
case MINUTE : max = 60; break;
case HOUR : max = 24; break;
case MONTH : max = 12; break;
case DAY_OF_WEEK : max = 7; break;
case DAY_OF_MONTH : max = 31; break;
case YEAR : throw new IllegalArgumentException("Start year must be less than stop year");
default : throw new IllegalArgumentException("Unexpected type encountered");
case SECOND:
max = 60;
break;
case MINUTE:
max = 60;
break;
case HOUR:
max = 24;
break;
case MONTH:
max = 12;
break;
case DAY_OF_WEEK:
max = 7;
break;
case DAY_OF_MONTH:
max = 31;
break;
case YEAR:
throw new IllegalArgumentException("Start year must be less than stop year");
default:
throw new IllegalArgumentException("Unexpected type encountered");
}
stopAt += max;
}
@@ -1280,7 +1291,7 @@ public final class CronExpression implements Serializable, Cloneable {
day = getLastDayOfMonth(mon, cl.get(Calendar.YEAR));
day -= lastdayOffset;
java.util.Calendar tcal = java.util.Calendar.getInstance(getTimeZone());
Calendar tcal = Calendar.getInstance(getTimeZone());
tcal.set(Calendar.SECOND, 0);
tcal.set(Calendar.MINUTE, 0);
tcal.set(Calendar.HOUR_OF_DAY, 0);
@@ -1316,7 +1327,7 @@ public final class CronExpression implements Serializable, Cloneable {
t = day;
day = daysOfMonth.first();
java.util.Calendar tcal = java.util.Calendar.getInstance(getTimeZone());
Calendar tcal = Calendar.getInstance(getTimeZone());
tcal.set(Calendar.SECOND, 0);
tcal.set(Calendar.MINUTE, 0);
tcal.set(Calendar.HOUR_OF_DAY, 0);
@@ -1580,9 +1591,9 @@ public final class CronExpression implements Serializable, Cloneable {
* @param hour the hour to set
*/
protected void setCalendarHour(Calendar cal, int hour) {
cal.set(java.util.Calendar.HOUR_OF_DAY, hour);
if (cal.get(java.util.Calendar.HOUR_OF_DAY) != hour && hour != 24) {
cal.set(java.util.Calendar.HOUR_OF_DAY, hour + 1);
cal.set(Calendar.HOUR_OF_DAY, hour);
if (cal.get(Calendar.HOUR_OF_DAY) != hour && hour != 24) {
cal.set(Calendar.HOUR_OF_DAY, hour + 1);
}
}

View File

@@ -7,6 +7,7 @@ public class XxlJobException extends RuntimeException {
public XxlJobException() {
}
public XxlJobException(String message) {
super(message);
}

View File

@@ -19,6 +19,7 @@ public class XxlJobGroup {
// registry list
private List<String> registryList; // 执行器地址列表(系统注册)
public List<String> getRegistryList() {
if (addressList != null && addressList.trim().length() > 0) {
registryList = new ArrayList<String>(Arrays.asList(addressList.split(",")));

View File

@@ -1,4 +1,4 @@
//package com.xxl.job.admin.core.jobbean;
package com.xxl.job.admin.core.old;//package com.xxl.job.admin.core.jobbean;
//
//import com.xxl.job.admin.core.thread.JobTriggerPoolHelper;
//import com.xxl.job.admin.core.trigger.TriggerTypeEnum;

View File

@@ -1,4 +1,4 @@
//package com.xxl.job.admin.core.schedule;
package com.xxl.job.admin.core.old;//package com.xxl.job.admin.core.schedule;
//
//import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
//import com.xxl.job.admin.core.jobbean.RemoteHttpJobBean;

View File

@@ -1,4 +1,4 @@
//package com.xxl.job.admin.core.quartz;
package com.xxl.job.admin.core.old;//package com.xxl.job.admin.core.quartz;
//
//import org.quartz.SchedulerConfigException;
//import org.quartz.spi.ThreadPool;

View File

@@ -30,6 +30,7 @@ public enum ExecutorRouteStrategyEnum {
public String getTitle() {
return title;
}
public ExecutorRouter getRouter() {
return router;
}

View File

@@ -23,6 +23,7 @@ public class ExecutorRouteConsistentHash extends ExecutorRouter {
/**
* get hash code on 2^32 ring (md5散列的方式计算hash值)
*
* @param key
* @return
*/

View File

@@ -12,7 +12,7 @@ import java.util.concurrent.ConcurrentMap;
* 单个JOB对应的每个执行器使用频率最低的优先被选举
* a(*)、LFU(Least Frequently Used):最不经常使用,频率/次数
* b、LRU(Least Recently Used):最近最久未使用,时间
*
* <p>
* Created by xuxueli on 17/3/10.
*/
public class ExecutorRouteLFU extends ExecutorRouter {

View File

@@ -14,7 +14,7 @@ import java.util.concurrent.ConcurrentMap;
* 单个JOB对应的每个执行器最久为使用的优先被选举
* a、LFU(Least Frequently Used):最不经常使用,频率/次数
* b(*)、LRU(Least Recently Used):最近最久未使用,时间
*
* <p>
* Created by xuxueli on 17/3/10.
*/
public class ExecutorRouteLRU extends ExecutorRouter {

View File

@@ -78,6 +78,7 @@ public class XxlJobScheduler {
// ---------------------- executor-client ----------------------
private static ConcurrentMap<String, ExecutorBiz> executorBizRepository = new ConcurrentHashMap<String, ExecutorBiz>();
public static ExecutorBiz getExecutorBiz(String address) throws Exception {
// valid
if (address == null || address.trim().length() == 0) {

View File

@@ -62,7 +62,7 @@ public class JobFailMonitorHelper {
// 2、fail alarm monitor
int newAlarmStatus = 0; // 告警状态0-默认、-1=锁定状态、1-无需告警、2-告警成功、3-告警失败
if (info != null && info.getAlarmEmail() != null && info.getAlarmEmail().trim().length() > 0) {
if (info != null) {
boolean alarmResult = XxlJobAdminConfig.getAdminConfig().getJobAlarmer().alarm(info, log);
newAlarmStatus = alarmResult ? 2 : 3;
} else {

View File

@@ -20,6 +20,7 @@ public class JobLogReportHelper {
private static Logger logger = LoggerFactory.getLogger(JobLogReportHelper.class);
private static JobLogReportHelper instance = new JobLogReportHelper();
public static JobLogReportHelper getInstance() {
return instance;
}
@@ -27,6 +28,7 @@ public class JobLogReportHelper {
private Thread logrThread;
private volatile boolean toStop = false;
public void start() {
logrThread = new Thread(new Runnable() {

View File

@@ -23,6 +23,7 @@ public class JobScheduleHelper {
private static Logger logger = LoggerFactory.getLogger(JobScheduleHelper.class);
private static JobScheduleHelper instance = new JobScheduleHelper();
public static JobScheduleHelper getInstance() {
return instance;
}

View File

@@ -19,7 +19,9 @@ public enum TriggerTypeEnum {
private TriggerTypeEnum(String title) {
this.title = title;
}
private String title;
public String getTitle() {
return title;
}

View File

@@ -30,15 +30,12 @@ public class XxlJobTrigger {
*
* @param jobId
* @param triggerType
* @param failRetryCount
* >=0: use this param
* @param failRetryCount >=0: use this param
* <0: use param from job info config
* @param executorShardingParam
* @param executorParam
* null: use job param
* @param executorParam null: use job param
* not null: cover job param
* @param addressList
* null: use executor addressList
* @param addressList null: use executor addressList
* not null: cover
*/
public static void trigger(int jobId,
@@ -200,6 +197,7 @@ public class XxlJobTrigger {
/**
* run executor
*
* @param triggerParam
* @param address
* @return

View File

@@ -23,6 +23,7 @@ public class I18nUtil {
private static Logger logger = LoggerFactory.getLogger(I18nUtil.class);
private static Properties prop = null;
public static Properties loadI18nProp() {
if (prop != null) {
return prop;

View File

@@ -21,10 +21,10 @@ import java.io.IOException;
public class JacksonUtil {
private static Logger logger = LoggerFactory.getLogger(JacksonUtil.class);
private final static ObjectMapper objectMapper = new ObjectMapper();
private final static ObjectMapper OBJECT_MAPPER = new ObjectMapper();
public static ObjectMapper getInstance() {
return objectMapper;
return OBJECT_MAPPER;
}
/**

View File

@@ -11,6 +11,7 @@ import java.util.concurrent.ConcurrentMap;
public class LocalCacheUtil {
private static ConcurrentMap<String, LocalCacheData> cacheRepository = new ConcurrentHashMap<String, LocalCacheData>(); // 类型建议用抽象父类,兼容性更好;
private static class LocalCacheData {
private String key;
private Object val;

View File

@@ -31,6 +31,7 @@ public class LoginService {
String tokenHex = new BigInteger(tokenJson.getBytes()).toString(16);
return tokenHex;
}
private XxlJobUser parseToken(String tokenHex) {
XxlJobUser xxlJobUser = null;
if (tokenHex != null) {
@@ -103,8 +104,5 @@ public class LoginService {
return null;
}
public static void main(String[] args) {
System.out.println("121312");
}
}

View File

@@ -1,9 +1,5 @@
--- # 监控配置
spring:
boot:
admin:
# Spring Boot Admin Client 客户端的相关配置
client:
spring.boot.admin.client:
# 增加客户端开关
enabled: true
# 设置 Spring Boot Admin Server 地址

View File

@@ -1,13 +1,9 @@
--- # 监控配置
spring:
boot:
admin:
# Spring Boot Admin Client 客户端的相关配置
client:
spring.boot.admin.client:
# 增加客户端开关
enabled: true
# 设置 Spring Boot Admin Server 地址
url: http://172.30.0.90:9090/admin
url: http://localhost:9090/admin
instance:
service-host-type: IP
username: ruoyi
@@ -18,7 +14,7 @@ spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://172.30.0.36:3306/ry-vue?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
url: jdbc:mysql://127.0.0.1:3306/ry-vue?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
username: root
password: root
hikari:

View File

@@ -16,6 +16,9 @@ spring:
resources:
static-locations: classpath:/static/
logging:
config: classpath:logback-plus.xml
--- # mybatis 配置
mybatis:
mapper-locations: classpath:/mybatis-mapper/*Mapper.xml
@@ -37,13 +40,11 @@ management:
enabled: false
endpoints:
web:
# Actuator 提供的 API 接口的根目录。默认为 /actuator
base-path: /actuator
exposure:
# 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。
# 生产环境不建议放开所有 根据项目需求放开即可
include: @endpoints.include@
include: '*'
endpoint:
health:
show-details: ALWAYS
logfile:
external-file: ./logs/ruoyi-xxl-job-admin.log

View File

@@ -1,6 +1,6 @@
admin_name=Scheduling Center
admin_name_full=Distributed Task Scheduling Platform XXL-JOB
admin_version=2.3.0
admin_version=2.4.0
admin_i18n=en
## system

View File

@@ -1,6 +1,6 @@
admin_name=任务调度中心
admin_name_full=分布式任务调度平台XXL-JOB
admin_version=2.3.0
admin_version=2.4.0
admin_i18n=
## system

View File

@@ -1,6 +1,6 @@
admin_name=任務調度中心
admin_name_full=分布式任務調度平臺XXL-JOB
admin_version=2.3.0
admin_version=2.4.0
admin_i18n=
## system

View File

@@ -25,8 +25,6 @@ $(function() {
async: false, // sync, make log ordered
url : base_url + '/joblog/logDetailCat',
data : {
"executorAddress":executorAddress,
"triggerTime":triggerTime,
"logId":logId,
"fromLineNum":fromLineNum
},

View File

@@ -62,8 +62,6 @@
// 参数
var triggerCode = '${triggerCode}';
var handleCode = '${handleCode}';
var executorAddress = '${executorAddress!}';
var triggerTime = '${triggerTime?c}';
var logId = '${logId}';
</script>
<script src="${request.contextPath}/static/js/joblog.detail.1.js"></script>

View File

@@ -1,78 +0,0 @@
<?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">
<parent>
<artifactId>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId>
<version>4.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-framework</artifactId>
<description>
framework框架核心
</description>
<dependencies>
<!-- SpringBoot Web容器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- web 容器使用 undertow 性能更强 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<!-- SpringBoot 拦截器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- 阿里数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<!-- sql性能分析插件 -->
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>
<!-- 系统模块-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
</dependency>
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>tlog-web-spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,65 +0,0 @@
package com.ruoyi.framework.aspectj;
import com.ruoyi.common.annotation.RateLimiter;
import com.ruoyi.common.enums.LimitType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.redis.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RateType;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* 限流处理
*
* @author Lion Li
*/
@Slf4j
@Aspect
@Component
public class RateLimiterAspect {
@Before("@annotation(rateLimiter)")
public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable {
int time = rateLimiter.time();
int count = rateLimiter.count();
String combineKey = getCombineKey(rateLimiter, point);
try {
RateType rateType = RateType.OVERALL;
if (rateLimiter.limitType() == LimitType.CLUSTER) {
rateType = RateType.PER_CLIENT;
}
long number = RedisUtils.rateLimiter(combineKey, rateType, count, time);
if (number == -1) {
throw new ServiceException("访问过于频繁,请稍候再试");
}
log.info("限制令牌 => {}, 剩余令牌 => {}, 缓存key => '{}'", count, number, combineKey);
} catch (ServiceException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException("服务器限流异常,请稍候再试");
}
}
public String getCombineKey(RateLimiter rateLimiter, JoinPoint point) {
StringBuilder stringBuffer = new StringBuilder(rateLimiter.key());
if (rateLimiter.limitType() == LimitType.IP) {
// 获取请求ip
stringBuffer.append(ServletUtils.getClientIP()).append("-");
} else if (rateLimiter.limitType() == LimitType.CLUSTER) {
// 获取客户端实例id
stringBuffer.append(RedisUtils.getClient().getId()).append("-");
}
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
Class<?> targetClass = method.getDeclaringClass();
stringBuffer.append(targetClass.getName()).append("-").append(method.getName());
return stringBuffer.toString();
}
}

View File

@@ -1,63 +0,0 @@
package com.ruoyi.framework.config;
import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
import com.alibaba.druid.util.Utils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.*;
import java.io.IOException;
/**
* druid 配置多数据源
*
* @author ruoyi
*/
@Configuration
public class DruidConfig {
/**
* 去除监控页面底部的广告
*/
@SuppressWarnings({"rawtypes", "unchecked"})
@Bean
@ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true")
public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties) {
// 获取web监控页面的参数
DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
// 提取common.js的配置路径
String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*";
String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");
final String filePath = "support/http/resources/js/common.js";
// 创建filter进行过滤
Filter filter = new Filter() {
@Override
public void init(javax.servlet.FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
chain.doFilter(request, response);
// 重置缓冲区,响应头不会被重置
// response.resetBuffer();
// 获取common.js
String text = Utils.readFromResource(filePath);
// 正则替换banner, 除去底部的广告信息
text = text.replaceAll("<a.*?banner\"></a><br/>", "");
text = text.replaceAll("powered.*?shrek.wang</a>", "");
response.getWriter().write(text);
}
@Override
public void destroy() {
}
};
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(filter);
registrationBean.addUrlPatterns(commonJsPattern);
return registrationBean;
}
}

View File

@@ -1,50 +0,0 @@
package com.ruoyi.framework.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.ruoyi.framework.jackson.BigNumberSerializer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.jackson.JacksonProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.TimeZone;
/**
* jackson 配置
*
* @author Lion Li
*/
@Slf4j
@Configuration
public class JacksonConfig {
@Primary
@Bean
public ObjectMapper getObjectMapper(Jackson2ObjectMapperBuilder builder, JacksonProperties jacksonProperties) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
// 全局配置序列化返回 JSON 处理
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, BigNumberSerializer.INSTANCE);
simpleModule.addSerializer(Long.TYPE, BigNumberSerializer.INSTANCE);
simpleModule.addSerializer(BigInteger.class, BigNumberSerializer.INSTANCE);
simpleModule.addSerializer(BigDecimal.class, ToStringSerializer.instance);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(jacksonProperties.getDateFormat());
simpleModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(formatter));
simpleModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(formatter));
objectMapper.registerModule(simpleModule);
objectMapper.setTimeZone(TimeZone.getDefault());
log.info("初始化 jackson 配置");
return objectMapper;
}
}

View File

@@ -1,179 +0,0 @@
package com.ruoyi.framework.config;
import cn.hutool.core.util.ObjectUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.config.properties.RedissonProperties;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.codec.JsonJacksonCodec;
import org.redisson.config.Config;
import org.redisson.spring.cache.CacheConfig;
import org.redisson.spring.cache.RedissonSpringCacheManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* redis配置
*
* @author Lion Li
*/
@Slf4j
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
private static final String REDIS_PROTOCOL_PREFIX = "redis://";
private static final String REDISS_PROTOCOL_PREFIX = "rediss://";
@Autowired
private RedisProperties redisProperties;
@Autowired
private RedissonProperties redissonProperties;
@Primary
@Bean(destroyMethod = "shutdown")
public RedissonClient redisson() {
String prefix = REDIS_PROTOCOL_PREFIX;
if (redisProperties.isSsl()) {
prefix = REDISS_PROTOCOL_PREFIX;
}
Config config = new Config();
config.setThreads(redissonProperties.getThreads())
.setNettyThreads(redissonProperties.getNettyThreads())
.setCodec(JsonJacksonCodec.INSTANCE)
.setTransportMode(redissonProperties.getTransportMode());
RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig();
if (ObjectUtil.isNotNull(singleServerConfig)) {
// 使用单机模式
config.useSingleServer()
.setAddress(prefix + redisProperties.getHost() + ":" + redisProperties.getPort())
.setConnectTimeout(((Long) redisProperties.getTimeout().toMillis()).intValue())
.setDatabase(redisProperties.getDatabase())
.setPassword(StringUtils.isNotBlank(redisProperties.getPassword()) ? redisProperties.getPassword() : null)
.setTimeout(singleServerConfig.getTimeout())
.setRetryAttempts(singleServerConfig.getRetryAttempts())
.setRetryInterval(singleServerConfig.getRetryInterval())
.setClientName(singleServerConfig.getClientName())
.setIdleConnectionTimeout(singleServerConfig.getIdleConnectionTimeout())
.setSubscriptionConnectionPoolSize(singleServerConfig.getSubscriptionConnectionPoolSize())
.setConnectionMinimumIdleSize(singleServerConfig.getConnectionMinimumIdleSize())
.setConnectionPoolSize(singleServerConfig.getConnectionPoolSize());
}
// 集群配置方式 参考下方注释
RedissonProperties.ClusterServersConfig clusterServersConfig = redissonProperties.getClusterServersConfig();
if (ObjectUtil.isNotNull(clusterServersConfig)) {
// 使用集群模式
String finalPrefix = prefix;
List<String> nodes = redisProperties.getCluster().getNodes()
.stream()
.map(node -> finalPrefix + node)
.collect(Collectors.toList());
config.useClusterServers()
.setConnectTimeout(((Long) redisProperties.getTimeout().toMillis()).intValue())
.setPassword(StringUtils.isNotBlank(redisProperties.getPassword()) ? redisProperties.getPassword() : null)
.setTimeout(clusterServersConfig.getTimeout())
.setRetryAttempts(clusterServersConfig.getRetryAttempts())
.setRetryInterval(clusterServersConfig.getRetryInterval())
.setClientName(clusterServersConfig.getClientName())
.setIdleConnectionTimeout(clusterServersConfig.getIdleConnectionTimeout())
.setPingConnectionInterval(clusterServersConfig.getPingConnectionInterval())
.setSubscriptionConnectionPoolSize(clusterServersConfig.getSubscriptionConnectionPoolSize())
.setMasterConnectionMinimumIdleSize(clusterServersConfig.getMasterConnectionMinimumIdleSize())
.setMasterConnectionPoolSize(clusterServersConfig.getMasterConnectionPoolSize())
.setSlaveConnectionMinimumIdleSize(clusterServersConfig.getSlaveConnectionMinimumIdleSize())
.setSlaveConnectionPoolSize(clusterServersConfig.getSlaveConnectionPoolSize())
.setReadMode(clusterServersConfig.getReadMode())
.setSubscriptionMode(clusterServersConfig.getSubscriptionMode())
.setNodeAddresses(nodes);
}
RedissonClient redissonClient = Redisson.create(config);
log.info("初始化 redis 配置");
return redissonClient;
}
/**
* 整合spring-cache
*/
@Bean
public CacheManager cacheManager(RedissonClient redissonClient) {
List<RedissonProperties.CacheGroup> cacheGroup = redissonProperties.getCacheGroup();
Map<String, CacheConfig> config = new HashMap<>();
for (RedissonProperties.CacheGroup group : cacheGroup) {
CacheConfig cacheConfig = new CacheConfig(group.getTtl(), group.getMaxIdleTime());
cacheConfig.setMaxSize(group.getMaxSize());
config.put(group.getGroupId(), cacheConfig);
}
return new RedissonSpringCacheManager(redissonClient, config, JsonJacksonCodec.INSTANCE);
}
/**
* redis集群配置 yml
*
* --- # redis 集群配置(单机与集群只能开启一个另一个需要注释掉)
* spring:
* redis:
* cluster:
* nodes:
* - 192.168.0.100:6379
* - 192.168.0.101:6379
* - 192.168.0.102:6379
* # 密码
* password:
* # 连接超时时间
* timeout: 10s
* # 是否开启ssl
* ssl: false
*
* redisson:
* # 线程池数量
* threads: 16
* # Netty线程池数量
* nettyThreads: 32
* # 传输模式
* transportMode: "NIO"
* # 集群配置
* clusterServersConfig:
* # 客户端名称
* clientName: ${ruoyi.name}
* # master最小空闲连接数
* masterConnectionMinimumIdleSize: 32
* # master连接池大小
* masterConnectionPoolSize: 64
* # slave最小空闲连接数
* slaveConnectionMinimumIdleSize: 32
* # slave连接池大小
* slaveConnectionPoolSize: 64
* # 连接空闲超时,单位:毫秒
* idleConnectionTimeout: 10000
* # ping连接间隔
* pingConnectionInterval: 1000
* # 命令等待超时,单位:毫秒
* timeout: 3000
* # 如果尝试在此限制之内发送成功,则开始启用 timeout 计时。
* retryAttempts: 3
* # 命令重试发送时间间隔,单位:毫秒
* retryInterval: 1500
* # 发布和订阅连接池大小
* subscriptionConnectionPoolSize: 50
* # 读取模式
* readMode: "SLAVE"
* # 订阅模式
* subscriptionMode: "MASTER"
*/
}

View File

@@ -1,72 +0,0 @@
package com.ruoyi.framework.config;
import cn.dev33.satoken.interceptor.SaAnnotationInterceptor;
import cn.dev33.satoken.interceptor.SaRouteInterceptor;
import cn.dev33.satoken.jwt.StpLogicJwtForStyle;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpLogic;
import cn.hutool.core.util.ObjectUtil;
import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.framework.config.properties.SecurityProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* sa-token 配置
*
* @author Lion Li
*/
@RequiredArgsConstructor
@Slf4j
@Configuration
public class SaTokenConfig implements WebMvcConfigurer {
private final SecurityProperties securityProperties;
/**
* 注册sa-token的拦截器
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册路由拦截器,自定义验证规则
registry.addInterceptor(new SaRouteInterceptor((request, response, handler) -> {
// 登录验证 -- 排除多个路径
SaRouter
// 获取所有的
.match("/**")
// 排除下不需要拦截的
.notMatch(securityProperties.getExcludes())
.check(() -> {
Long userId = LoginHelper.getUserId();
if (ObjectUtil.isNotNull(userId)) {
// 有效率影响 用于临时测试
// if (log.isDebugEnabled()) {
// log.debug("剩余有效时间: {}", StpUtil.getTokenTimeout());
// log.debug("临时有效时间: {}", StpUtil.getTokenActivityTimeout());
// }
}
});
}) {
@SuppressWarnings("all")
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
LoginHelper.clearCache();
}
}).addPathPatterns("/**");
registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**");
}
@Bean
public StpLogic getStpLogicJwt() {
// Sa-Token 整合 jwt (Style模式)
return new StpLogicJwtForStyle();
}
}

View File

@@ -1,160 +0,0 @@
package com.ruoyi.framework.config;
import cn.dev33.satoken.config.SaTokenConfig;
import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import com.github.xiaoymin.knife4j.spring.extension.OpenApiExtensionResolver;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.framework.config.properties.SwaggerProperties;
import io.swagger.models.auth.In;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.spring.web.plugins.WebFluxRequestHandlerProvider;
import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider;
import javax.annotation.PostConstruct;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/**
* Swagger 文档配置
*
* @author Lion Li
*/
@RequiredArgsConstructor
@Configuration
@EnableKnife4j
public class SwaggerConfig {
private final SwaggerProperties swaggerProperties;
private final SaTokenConfig saTokenConfig;
private final OpenApiExtensionResolver openApiExtensionResolver;
/**
* 用于适配springboot 2.6
*/
@Bean
@SuppressWarnings("all")
public BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
return new BeanPostProcessor() {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) {
customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
}
return bean;
}
private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {
mappings.removeIf(mapping -> mapping.getPatternParser() != null);
}
private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
try {
Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
field.setAccessible(true);
return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
};
}
/**
* 创建API
*/
@PostConstruct
public void createRestApi() {
for (SwaggerProperties.Groups group : swaggerProperties.getGroups()) {
String basePackage = group.getBasePackage();
Docket docket = new Docket(DocumentationType.OAS_30)
.enable(swaggerProperties.getEnabled())
// 用来创建该API的基本信息展示在文档的页面中自定义展示的信息
.apiInfo(apiInfo())
// 设置哪些接口暴露给Swagger展示
.select()
// 扫描所有有注解的api用这种方式更灵活
//.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
// 扫描指定包中的swagger注解
.apis(RequestHandlerSelectors.basePackage(basePackage))
// 扫描所有 .apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build()
.groupName(group.getName())
// 设置安全模式swagger可以设置访问token
.securitySchemes(securitySchemes())
.securityContexts(securityContexts())
.extensions(openApiExtensionResolver.buildExtensions(group.getName()))
.pathMapping(swaggerProperties.getPathMapping());
String beanName = StringUtils.substringAfterLast(basePackage, ".") + "Docket";
SpringUtils.registerBean(beanName, docket);
}
}
/**
* 安全模式这里指定token通过Authorization头请求头传递
*/
private List<SecurityScheme> securitySchemes() {
List<SecurityScheme> apiKeyList = new ArrayList<SecurityScheme>();
String header = saTokenConfig.getTokenName();
apiKeyList.add(new ApiKey(header, header, In.HEADER.toValue()));
return apiKeyList;
}
/**
* 安全上下文
*/
private List<SecurityContext> securityContexts() {
List<SecurityContext> securityContexts = new ArrayList<>();
securityContexts.add(
SecurityContext.builder()
.securityReferences(defaultAuth())
.operationSelector(o -> o.requestMappingPattern().matches("/.*"))
.build());
return securityContexts;
}
/**
* 默认的安全上引用
*/
private List<SecurityReference> defaultAuth() {
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
List<SecurityReference> securityReferences = new ArrayList<>();
securityReferences.add(new SecurityReference(saTokenConfig.getTokenName(), authorizationScopes));
return securityReferences;
}
/**
* 添加摘要信息
*/
private ApiInfo apiInfo() {
// 用ApiInfoBuilder进行定制
SwaggerProperties.Contact contact = swaggerProperties.getContact();
return new ApiInfoBuilder()
// 设置标题
.title(swaggerProperties.getTitle())
// 描述
.description(swaggerProperties.getDescription())
// 作者信息
.contact(new Contact(contact.getName(), contact.getUrl(), contact.getEmail()))
// 版本
.version(swaggerProperties.getVersion())
.build();
}
}

View File

@@ -1,18 +0,0 @@
package com.ruoyi.framework.config;
import com.yomahub.tlog.springboot.TLogWebAutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
/**
* 整合 TLog 框架配置
*
* @author Lion Li
* @since 3.3.0
*/
@Configuration
// 排除 web 自动配置 自定义实现
@EnableAutoConfiguration(exclude = TLogWebAutoConfiguration.class)
public class TLogConfig {
}

View File

@@ -1,22 +0,0 @@
package com.ruoyi.framework.config.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 重复提交 配置属性
*
* @author Lion Li
*/
@Data
@Component
@ConfigurationProperties(prefix = "repeat-submit")
public class RepeatSubmitProperties {
/**
* 间隔时间(毫秒)
*/
private int interval;
}

View File

@@ -1,92 +0,0 @@
package com.ruoyi.framework.config.properties;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* swagger 配置属性
*
* @author Lion Li
*/
@Data
@Component
@ConfigurationProperties(prefix = "swagger")
public class SwaggerProperties {
/**
* 文档开关
*/
private Boolean enabled;
/**
* 设置请求的统一前缀
*/
private String pathMapping;
/**
* 标头
*/
private String title;
/**
* 描述
*/
private String description;
/**
* 项目版本
*/
private String version;
/**
* 联系方式
*/
private Contact contact;
/**
* 组配置
*/
private List<Groups> groups;
@Data
@NoArgsConstructor
public static class Contact {
/**
* 联系人
*/
private String name;
/**
* 联系人url
*/
private String url;
/**
* 联系人email
*/
private String email;
}
@Data
@NoArgsConstructor
public static class Groups {
/**
* 组名
*/
private String name;
/**
* 基础包路径
*/
private String basePackage;
}
}

View File

@@ -1,34 +0,0 @@
<?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">
<parent>
<artifactId>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId>
<version>4.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-generator</artifactId>
<description>
generator代码生成
</description>
<dependencies>
<!--velocity代码生成使用模板 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
</dependency>
<!-- 通用工具-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,68 +0,0 @@
package com.ruoyi.generator.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.generator.domain.GenTableColumn;
import com.ruoyi.generator.mapper.GenTableColumnMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
/**
* 业务字段 服务层实现
*
* @author Lion Li
*/
@RequiredArgsConstructor
@Service
public class GenTableColumnServiceImpl implements IGenTableColumnService {
private final GenTableColumnMapper baseMapper;
/**
* 查询业务字段列表
*
* @param tableId 业务字段编号
* @return 业务字段集合
*/
@Override
public List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId) {
return baseMapper.selectList(new LambdaQueryWrapper<GenTableColumn>()
.eq(GenTableColumn::getTableId, tableId)
.orderByAsc(GenTableColumn::getSort));
}
/**
* 新增业务字段
*
* @param genTableColumn 业务字段信息
* @return 结果
*/
@Override
public int insertGenTableColumn(GenTableColumn genTableColumn) {
return baseMapper.insert(genTableColumn);
}
/**
* 修改业务字段
*
* @param genTableColumn 业务字段信息
* @return 结果
*/
@Override
public int updateGenTableColumn(GenTableColumn genTableColumn) {
return baseMapper.updateById(genTableColumn);
}
/**
* 删除业务字段对象
*
* @param ids 需要删除的数据ID
* @return 结果
*/
@Override
public int deleteGenTableColumnByIds(String ids) {
return baseMapper.deleteBatchIds(Arrays.asList(ids.split(",")));
}
}

View File

@@ -1,44 +0,0 @@
package com.ruoyi.generator.service;
import com.ruoyi.generator.domain.GenTableColumn;
import java.util.List;
/**
* 业务字段 服务层
*
* @author Lion Li
*/
public interface IGenTableColumnService {
/**
* 查询业务字段列表
*
* @param tableId 业务字段编号
* @return 业务字段集合
*/
List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId);
/**
* 新增业务字段
*
* @param genTableColumn 业务字段信息
* @return 结果
*/
int insertGenTableColumn(GenTableColumn genTableColumn);
/**
* 修改业务字段
*
* @param genTableColumn 业务字段信息
* @return 结果
*/
int updateGenTableColumn(GenTableColumn genTableColumn);
/**
* 删除业务字段信息
*
* @param ids 需要删除的数据ID
* @return 结果
*/
int deleteGenTableColumnByIds(String ids);
}

View File

@@ -1,38 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.generator.mapper.GenTableColumnMapper">
<resultMap type="GenTableColumn" id="GenTableColumnResult">
<id property="columnId" column="column_id" />
<result property="tableId" column="table_id" />
<result property="columnName" column="column_name" />
<result property="columnComment" column="column_comment" />
<result property="columnType" column="column_type" />
<result property="javaType" column="java_type" />
<result property="javaField" column="java_field" />
<result property="isPk" column="is_pk" />
<result property="isIncrement" column="is_increment" />
<result property="isRequired" column="is_required" />
<result property="isInsert" column="is_insert" />
<result property="isEdit" column="is_edit" />
<result property="isList" column="is_list" />
<result property="isQuery" column="is_query" />
<result property="queryType" column="query_type" />
<result property="htmlType" column="html_type" />
<result property="dictType" column="dict_type" />
<result property="sort" column="sort" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
</resultMap>
<select id="selectDbTableColumnsByName" parameterType="String" resultMap="GenTableColumnResult">
select column_name, (case when (is_nullable = 'no' <![CDATA[ && ]]> column_key != 'PRI') then '1' else null end) as is_required, (case when column_key = 'PRI' then '1' else '0' end) as is_pk, ordinal_position as sort, column_comment, (case when extra = 'auto_increment' then '1' else '0' end) as is_increment, column_type
from information_schema.columns where table_schema = (select database()) and table_name = (#{tableName})
order by ordinal_position
</select>
</mapper>

View File

@@ -1,176 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.generator.mapper.GenTableMapper">
<resultMap type="GenTable" id="GenTableResult">
<id property="tableId" column="table_id" />
<result property="tableName" column="table_name" />
<result property="tableComment" column="table_comment" />
<result property="subTableName" column="sub_table_name" />
<result property="subTableFkName" column="sub_table_fk_name" />
<result property="className" column="class_name" />
<result property="tplCategory" column="tpl_category" />
<result property="packageName" column="package_name" />
<result property="moduleName" column="module_name" />
<result property="businessName" column="business_name" />
<result property="functionName" column="function_name" />
<result property="functionAuthor" column="function_author" />
<result property="genType" column="gen_type" />
<result property="genPath" column="gen_path" />
<result property="options" column="options" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="remark" column="remark" />
<collection property="columns" javaType="java.util.List" resultMap="GenTableColumnResult" />
</resultMap>
<resultMap type="GenTableColumn" id="GenTableColumnResult">
<id property="columnId" column="column_id" />
<result property="tableId" column="table_id" />
<result property="columnName" column="column_name" />
<result property="columnComment" column="column_comment" />
<result property="columnType" column="column_type" />
<result property="javaType" column="java_type" />
<result property="javaField" column="java_field" />
<result property="isPk" column="is_pk" />
<result property="isIncrement" column="is_increment" />
<result property="isRequired" column="is_required" />
<result property="isInsert" column="is_insert" />
<result property="isEdit" column="is_edit" />
<result property="isList" column="is_list" />
<result property="isQuery" column="is_query" />
<result property="queryType" column="query_type" />
<result property="htmlType" column="html_type" />
<result property="dictType" column="dict_type" />
<result property="sort" column="sort" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
</resultMap>
<sql id="selectGenTableVo">
select table_id, table_name, table_comment, sub_table_name, sub_table_fk_name, class_name, tpl_category, package_name, module_name, business_name, function_name, function_author, gen_type, gen_path, options, create_by, create_time, update_by, update_time, remark from gen_table
</sql>
<select id="selectPageGenTableList" parameterType="GenTable" resultMap="GenTableResult">
<include refid="selectGenTableVo"/>
<where>
<if test="genTable.tableName != null and genTable.tableName != ''">
AND lower(table_name) like lower(concat('%', #{genTable.tableName}, '%'))
</if>
<if test="genTable.tableComment != null and genTable.tableComment != ''">
AND lower(table_comment) like lower(concat('%', #{genTable.tableComment}, '%'))
</if>
<if test="genTable.params.beginTime != null and genTable.params.beginTime != ''"><!-- 开始时间检索 -->
AND date_format(create_time,'%y%m%d') &gt;= date_format(#{genTable.params.beginTime},'%y%m%d')
</if>
<if test="genTable.params.endTime != null and genTable.params.endTime != ''"><!-- 结束时间检索 -->
AND date_format(create_time,'%y%m%d') &lt;= date_format(#{genTable.params.endTime},'%y%m%d')
</if>
</where>
</select>
<select id="selectPageDbTableList" parameterType="GenTable" resultMap="GenTableResult">
select table_name, table_comment, create_time, update_time from information_schema.tables
where table_schema = (select database())
AND table_name NOT LIKE 'xxl_job_%' AND table_name NOT LIKE 'gen_%'
AND table_name NOT IN (select table_name from gen_table)
<if test="genTable.tableName != null and genTable.tableName != ''">
AND lower(table_name) like lower(concat('%', #{genTable.tableName}, '%'))
</if>
<if test="genTable.tableComment != null and genTable.tableComment != ''">
AND lower(table_comment) like lower(concat('%', #{genTable.tableComment}, '%'))
</if>
<if test="genTable.params.beginTime != null and genTable.params.beginTime != ''"><!-- 开始时间检索 -->
AND date_format(create_time,'%y%m%d') &gt;= date_format(#{genTable.params.beginTime},'%y%m%d')
</if>
<if test="genTable.params.endTime != null and genTable.params.endTime != ''"><!-- 结束时间检索 -->
AND date_format(create_time,'%y%m%d') &lt;= date_format(#{genTable.params.endTime},'%y%m%d')
</if>
order by create_time desc
</select>
<select id="selectGenTableList" parameterType="GenTable" resultMap="GenTableResult">
<include refid="selectGenTableVo"/>
<where>
<if test="tableName != null and tableName != ''">
AND lower(table_name) like lower(concat('%', #{tableName}, '%'))
</if>
<if test="tableComment != null and tableComment != ''">
AND lower(table_comment) like lower(concat('%', #{tableComment}, '%'))
</if>
<if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
AND date_format(create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
</if>
<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
AND date_format(create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
</if>
</where>
</select>
<select id="selectDbTableList" parameterType="GenTable" resultMap="GenTableResult">
select table_name, table_comment, create_time, update_time from information_schema.tables
where table_schema = (select database())
AND table_name NOT LIKE 'xxl_job_%' AND table_name NOT LIKE 'gen_%'
AND table_name NOT IN (select table_name from gen_table)
<if test="tableName != null and tableName != ''">
AND lower(table_name) like lower(concat('%', #{tableName}, '%'))
</if>
<if test="tableComment != null and tableComment != ''">
AND lower(table_comment) like lower(concat('%', #{tableComment}, '%'))
</if>
<if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
AND date_format(create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
</if>
<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
AND date_format(create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
</if>
order by create_time desc
</select>
<select id="selectDbTableListByNames" resultMap="GenTableResult">
select table_name, table_comment, create_time, update_time from information_schema.tables
where table_name NOT LIKE 'xxl_job_%' and table_name NOT LIKE 'gen_%' and table_schema = (select database())
and table_name in
<foreach collection="array" item="name" open="(" separator="," close=")">
#{name}
</foreach>
</select>
<select id="selectTableByName" parameterType="String" resultMap="GenTableResult">
select table_name, table_comment, create_time, update_time from information_schema.tables
where table_comment <![CDATA[ <> ]]> '' and table_schema = (select database())
and table_name = #{tableName}
</select>
<select id="selectGenTableById" parameterType="Long" resultMap="GenTableResult">
SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark,
c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
FROM gen_table t
LEFT JOIN gen_table_column c ON t.table_id = c.table_id
where t.table_id = #{tableId} order by c.sort
</select>
<select id="selectGenTableByName" parameterType="String" resultMap="GenTableResult">
SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark,
c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
FROM gen_table t
LEFT JOIN gen_table_column c ON t.table_id = c.table_id
where t.table_name = #{tableName} order by c.sort
</select>
<select id="selectGenTableAll" parameterType="String" resultMap="GenTableResult">
SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.options, t.remark,
c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
FROM gen_table t
LEFT JOIN gen_table_column c ON t.table_id = c.table_id
order by c.sort
</select>
</mapper>

View File

@@ -1,3 +0,0 @@
java包使用 `.` 分割 resource 目录使用 `/` 分割
<br>
此文件目的 防止文件夹粘连找不到 `xml` 文件

View File

@@ -1,22 +0,0 @@
-- 菜单 SQL
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 'admin', sysdate(), '', null, '${functionName}菜单');
-- 按钮父菜单ID
SELECT @parentId := LAST_INSERT_ID();
-- 按钮 SQL
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('${functionName}查询', @parentId, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('${functionName}新增', @parentId, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('${functionName}修改', @parentId, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('${functionName}删除', @parentId, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('${functionName}导出', @parentId, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 'admin', sysdate(), '', null, '');

View File

@@ -1 +0,0 @@
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD>õ<EFBFBD><EFBFBD><EFBFBD>RuoYi-Vue3ǰ<33>ˣ<EFBFBD><CBA3><EFBFBD>ô<EFBFBD><C3B4>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>һ<EFBFBD>´<EFBFBD>Ŀ¼<C4BF><C2BC>ģ<EFBFBD><C4A3>index.vue.vm<76><6D>index-tree.vue.vm<76>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD>ϼ<EFBFBD>vueĿ¼<C4BF><C2BC>

View File

@@ -1,39 +0,0 @@
<?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">
<parent>
<artifactId>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId>
<version>4.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>ruoyi-job</artifactId>
<description>
任务调度
</description>
<dependencies>
<!-- 通用工具-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
</dependency>
<!-- xxl-job-core -->
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
</dependency>
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>tlog-xxljob-spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,55 +0,0 @@
<?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">
<parent>
<artifactId>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId>
<version>4.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-oss</artifactId>
<description>
OSS对象存储模块
</description>
<dependencies>
<!-- 通用工具-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
</dependency>
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>${qiniu.version}</version>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>${aliyun.oss.version}</version>
</dependency>
<dependency>
<groupId>com.qcloud</groupId>
<artifactId>cos_api</artifactId>
<version>${qcloud.cos.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>${minio.version}</version>
</dependency>
</dependencies>
</project>

View File

@@ -1,52 +0,0 @@
package com.ruoyi.oss.enumd;
import com.ruoyi.oss.service.impl.AliyunOssStrategy;
import com.ruoyi.oss.service.impl.MinioOssStrategy;
import com.ruoyi.oss.service.impl.QcloudOssStrategy;
import com.ruoyi.oss.service.impl.QiniuOssStrategy;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 对象存储服务商枚举
*
* @author Lion Li
*/
@Getter
@AllArgsConstructor
public enum OssEnumd {
/**
* 七牛云
*/
QINIU("qiniu", QiniuOssStrategy.class),
/**
* 阿里云
*/
ALIYUN("aliyun", AliyunOssStrategy.class),
/**
* 腾讯云
*/
QCLOUD("qcloud", QcloudOssStrategy.class),
/**
* minio
*/
MINIO("minio", MinioOssStrategy.class);
private final String value;
private final Class<?> beanClass;
public static OssEnumd find(String value) {
for (OssEnumd enumd : values()) {
if (enumd.getValue().equals(value)) {
return enumd;
}
}
return null;
}
}

View File

@@ -1,51 +0,0 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package com.ruoyi.oss.enumd;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* minio策略配置
*
* @author Lion Li
*/
@Getter
@AllArgsConstructor
public enum PolicyType {
/**
* 只读
*/
READ("read-only"),
/**
* 只写
*/
WRITE("write-only"),
/**
* 读写
*/
READ_WRITE("read-write");
/**
* 类型
*/
private final String type;
}

View File

@@ -1,79 +0,0 @@
package com.ruoyi.oss.factory;
import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.redis.RedisUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.oss.constant.OssConstant;
import com.ruoyi.oss.enumd.OssEnumd;
import com.ruoyi.oss.exception.OssException;
import com.ruoyi.oss.properties.OssProperties;
import com.ruoyi.oss.service.IOssStrategy;
import com.ruoyi.oss.service.abstractd.AbstractOssStrategy;
import lombok.extern.slf4j.Slf4j;
/**
* 文件上传Factory
*
* @author Lion Li
*/
@Slf4j
public class OssFactory {
/**
* 初始化工厂
*/
public static void init() {
log.info("初始化OSS工厂");
RedisUtils.subscribe(OssConstant.CACHE_CONFIG_KEY, String.class, type -> {
AbstractOssStrategy strategy = getStrategy(type);
// 未初始化不处理
if (strategy.isInit) {
refresh(type);
log.info("订阅刷新OSS配置 => " + type);
}
});
}
/**
* 获取默认实例
*/
public static IOssStrategy instance() {
// 获取redis 默认类型
String type = RedisUtils.getCacheObject(OssConstant.CACHE_CONFIG_KEY);
if (StringUtils.isEmpty(type)) {
throw new OssException("文件存储服务类型无法找到!");
}
return instance(type);
}
/**
* 根据类型获取实例
*/
public static IOssStrategy instance(String type) {
OssEnumd enumd = OssEnumd.find(type);
if (enumd == null) {
throw new OssException("文件存储服务类型无法找到!");
}
AbstractOssStrategy strategy = getStrategy(type);
if (!strategy.isInit) {
refresh(type);
}
return strategy;
}
private static void refresh(String type) {
Object json = RedisUtils.getCacheObject(OssConstant.SYS_OSS_KEY + type);
OssProperties properties = JsonUtils.parseObject(json.toString(), OssProperties.class);
if (properties == null) {
throw new OssException("系统异常, '" + type + "'配置信息不存在!");
}
getStrategy(type).init(properties);
}
private static AbstractOssStrategy getStrategy(String type) {
OssEnumd enumd = OssEnumd.find(type);
return (AbstractOssStrategy) SpringUtils.getBean(enumd.getBeanClass());
}
}

View File

@@ -1,66 +0,0 @@
package com.ruoyi.oss.service;
import com.ruoyi.oss.entity.UploadResult;
import com.ruoyi.oss.enumd.OssEnumd;
import java.io.InputStream;
/**
* 对象存储策略
*
* @author Lion Li
*/
public interface IOssStrategy {
void createBucket();
/**
* 获取服务商类型
* @return
*/
OssEnumd getServiceType();
/**
* 文件上传
*
* @param data 文件字节数组
* @param path 文件路径,包含文件名
* @return 返回http地址
*/
UploadResult upload(byte[] data, String path, String contentType);
/**
* 文件删除
*
* @param path 文件路径,包含文件名
*/
void delete(String path);
/**
* 文件上传
*
* @param data 文件字节数组
* @param suffix 后缀
* @return 返回http地址
*/
UploadResult uploadSuffix(byte[] data, String suffix, String contentType);
/**
* 文件上传
*
* @param inputStream 字节流
* @param path 文件路径,包含文件名
* @return 返回http地址
*/
UploadResult upload(InputStream inputStream, String path, String contentType);
/**
* 文件上传
*
* @param inputStream 字节流
* @param suffix 后缀
* @return 返回http地址
*/
UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType);
}

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