128 Commits

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

@ -0,0 +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

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

3
.gitignore vendored
View File

@ -25,6 +25,9 @@ target/
*.iml
*.ipr
### JRebel ###
rebel.xml
### NetBeans ###
nbproject/private/
build/*

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>

251
README.md
View File

@ -1,64 +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-3.4.0-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)]()
[![JDK-17](https://img.shields.io/badge/JDK-17-green.svg)]()
> RuoYi-Vue-Plus 是基于 RuoYi-Vue 针对 `分布式集群` 场景升级(不兼容原框架)
> 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全方位升级(不兼容原框架) |
| satoken分支 | RuoYi-Vue-Plus-satoken | [satoken分支地址](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/tree/satoken/) | 使用satoken重构权限鉴权(公测 可尝试上生产) |
| 单体分支 | RuoYi-Vue-Plus-fast | [fast分支地址](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/tree/fast/) | 单体应用结构 |
| 原框架 | 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/) | 基于 Netty 的高性能容器 |
| 权限认证框架 | Spring Security、Jwt | [SpringSecurity官网](https://spring.io/projects/spring-security#learn) | 支持多终端认证系统 |
| 关系数据库 | 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 多种限流 |
| 分布式锁 | 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/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)
>
>[部署项目 必看](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)
>
>[部署项目 必看](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)
>
>[参考文档 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)
>[参考文档 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)
## 软件架构图
@ -72,81 +130,42 @@
### 其他
* 同步升级 RuoYi-Vue
* GitHub 地址 [RuoYi-Vue-Plus-github](https://github.com/JavaLionLi/RuoYi-Vue-Plus)
* 单模块 fast 分支 [RuoYi-Vue-Plus-fast](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/tree/fast/)
* satoken 分支 [RuoYi-Vue-Plus-satoken](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/tree/satoken/)
* 用户扩展项目 [扩展项目列表](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages?sort_id=4478302&doc_id=1469725)
* 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/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/2021/0525/101654_451e4523_1766278.jpeg" width="300px" height="450px" />
<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 "屏幕截图") |

375
pom.xml
View File

@ -2,58 +2,80 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<modelVersion>4.0.0</modelVersion>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-vue-plus</artifactId>
<version>3.4.0</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>3.4.0</ruoyi-vue-plus.version>
<spring-boot.version>2.5.7</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.0</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>2.2.11</easyexcel.version>
<maven-jar-plugin.version>3.2.2</maven-jar-plugin.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>
<jwt.version>0.9.1</jwt.version>
<mybatis-plus.version>3.4.3.4</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.16</hutool.version>
<okhttp.version>4.9.2</okhttp.version>
<spring-boot-admin.version>2.5.4</spring-boot-admin.version>
<redisson.version>3.16.4</redisson.version>
<lock4j.version>2.2.1</lock4j.version>
<dynamic-ds.version>3.4.1</dynamic-ds.version>
<tlog.version>1.3.4</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.8.0</qiniu.version>
<aliyun.oss.version>3.13.1</aliyun.oss.version>
<qcloud.cos.version>5.6.58</qcloud.cos.version>
<minio.version>8.3.3</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>
@ -67,47 +89,48 @@
<scope>import</scope>
</dependency>
<!-- 阿里数据库连接池 -->
<!-- hutool 的依赖配置-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
<groupId>cn.hutool</groupId>
<artifactId>hutool-bom</artifactId>
<version>${hutool.version}</version>
<type>pom</type>
<scope>import</scope>
</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-webmvc-core</artifactId>
<version>${springdoc.version}</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>${swagger-annotations.version}</version>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-javadoc</artifactId>
<version>${springdoc.version}</version>
</dependency>
<!-- excel工具 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<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>
@ -122,18 +145,23 @@
<version>${velocity.version}</version>
</dependency>
<!-- Token生成与解析-->
<!-- Sa-Token 权限认证, 在线文档http://sa-token.dev33.cn/ -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jwt.version}</version>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>${satoken.version}</version>
</dependency>
<!-- jdk11 缺失依赖 jaxb-->
<!-- Sa-Token 整合 jwt -->
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>${jaxb.version}</version>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-jwt</artifactId>
<version>${satoken.version}</version>
<exclusions>
<exclusion>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- dynamic-datasource 多数据源-->
@ -148,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>
@ -160,18 +184,25 @@
<version>${p6spy.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<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>
@ -188,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>
@ -203,95 +246,31 @@
</dependency>
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>tlog-spring-boot-configuration</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-webroot</artifactId>
<version>${tlog.version}</version>
<exclusions>
<exclusion>
<artifactId>javassist</artifactId>
<groupId>org.javassist</groupId>
</exclusion>
<exclusion>
<artifactId>guava</artifactId>
<groupId>com.google.guava</groupId>
</exclusion>
</exclusions>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>${ip2region.version}</version>
</dependency>
<!-- 加密包引入 -->
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>tlog-xxl-job</artifactId>
<version>${tlog.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>
@ -300,18 +279,58 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<version>3.9.0</version>
<configuration>
<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>
<resources>
<resource>
<!--打包该目录下的 application.yml -->
<directory>src/main/resources</directory>
<!-- 关闭过滤 -->
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<!-- 引入所有 匹配文件进行过滤 -->
<includes>
<include>application*</include>
<include>bootstrap*</include>
<include>banner*</include>
</includes>
<!-- 启用过滤 即该资源中的变量将会被过滤器中的值替换 -->
<filtering>true</filtering>
</resource>
@ -321,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>
@ -332,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>
@ -343,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>3.4.0</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.0</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,87 +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.AjaxResult;
import com.ruoyi.common.enums.CaptchaType;
import com.ruoyi.common.utils.RedisUtils;
import com.ruoyi.common.utils.StringUtils;
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.beans.factory.annotation.Autowired;
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(onConstructor_ = @Autowired)
@RestController
public class CaptchaController {
private final CaptchaProperties captchaProperties;
private final ISysConfigService configService;
/**
* 生成验证码
*/
@ApiOperation("生成验证码")
@GetMapping("/captchaImage")
public AjaxResult<Map<String, Object>> getCode() {
Map<String, Object> ajax = new HashMap<>();
boolean captchaOnOff = configService.selectCaptchaOnOff();
ajax.put("captchaOnOff", captchaOnOff);
if (!captchaOnOff) {
return AjaxResult.success(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 AjaxResult.success(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,57 +0,0 @@
package com.ruoyi.web.controller.monitor;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisServerCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
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(onConstructor_ = @Autowired)
@RestController
@RequestMapping("/monitor/cache")
public class CacheController {
private final RedisTemplate<String, String> redisTemplate;
@ApiOperation("获取缓存监控详细信息")
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@GetMapping()
public AjaxResult<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 AjaxResult.success(result);
}
}

View File

@ -1,80 +0,0 @@
package com.ruoyi.web.controller.monitor;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.RedisUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.SysUserOnline;
import com.ruoyi.system.service.ISysUserOnlineService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* 在线用户监控
*
* @author Lion Li
*/
@Api(value = "在线用户监控", tags = {"在线用户监控管理"})
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@RestController
@RequestMapping("/monitor/online")
public class SysUserOnlineController extends BaseController {
private final ISysUserOnlineService userOnlineService;
@ApiOperation("在线用户列表")
@PreAuthorize("@ss.hasPermi('monitor:online:list')")
@GetMapping("/list")
public TableDataInfo<SysUserOnline> list(String ipaddr, String userName) {
Collection<String> keys = RedisUtils.keys(Constants.LOGIN_TOKEN_KEY + "*");
List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>();
for (String key : keys) {
LoginUser user = RedisUtils.getCacheObject(key);
if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName)) {
if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername())) {
userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));
}
} else if (StringUtils.isNotEmpty(ipaddr)) {
if (StringUtils.equals(ipaddr, user.getIpaddr())) {
userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
}
} else if (StringUtils.isNotEmpty(userName)) {
if (StringUtils.equals(userName, user.getUsername())) {
userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
}
} else {
userOnlineList.add(userOnlineService.loginUserToUserOnline(user));
}
}
Collections.reverse(userOnlineList);
userOnlineList.removeAll(Collections.singleton(null));
return PageUtils.buildDataInfo(userOnlineList);
}
/**
* 强退用户
*/
@ApiOperation("强退用户")
@PreAuthorize("@ss.hasPermi('monitor:online:forceLogout')")
@Log(title = "在线用户", businessType = BusinessType.FORCE)
@DeleteMapping("/{tokenId}")
public AjaxResult<Void> forceLogout(@PathVariable String tokenId) {
RedisUtils.deleteObject(Constants.LOGIN_TOKEN_KEY + tokenId);
return AjaxResult.success();
}
}

View File

@ -1,127 +0,0 @@
package com.ruoyi.web.controller.system;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.system.domain.SysConfig;
import com.ruoyi.system.service.ISysConfigService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* 参数配置 信息操作处理
*
* @author Lion Li
*/
@Validated
@Api(value = "参数配置控制器", tags = {"参数配置管理"})
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@RestController
@RequestMapping("/system/config")
public class SysConfigController extends BaseController {
private final ISysConfigService configService;
/**
* 获取参数配置列表
*/
@ApiOperation("获取参数配置列表")
@PreAuthorize("@ss.hasPermi('system:config:list')")
@GetMapping("/list")
public TableDataInfo<SysConfig> list(SysConfig config) {
return configService.selectPageConfigList(config);
}
@ApiOperation("导出参数配置列表")
@Log(title = "参数管理", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('system:config:export')")
@PostMapping("/export")
public void export(SysConfig config, HttpServletResponse response) {
List<SysConfig> list = configService.selectConfigList(config);
ExcelUtil.exportExcel(list, "参数数据", SysConfig.class, response);
}
/**
* 根据参数编号获取详细信息
*/
@ApiOperation("根据参数编号获取详细信息")
@PreAuthorize("@ss.hasPermi('system:config:query')")
@GetMapping(value = "/{configId}")
public AjaxResult<SysConfig> getInfo(@ApiParam("参数ID") @PathVariable Long configId) {
return AjaxResult.success(configService.selectConfigById(configId));
}
/**
* 根据参数键名查询参数值
*/
@ApiOperation("根据参数键名查询参数值")
@GetMapping(value = "/configKey/{configKey}")
public AjaxResult<Void> getConfigKey(@ApiParam("参数Key") @PathVariable String configKey) {
return AjaxResult.success(configService.selectConfigByKey(configKey));
}
/**
* 新增参数配置
*/
@ApiOperation("新增参数配置")
@PreAuthorize("@ss.hasPermi('system:config:add')")
@Log(title = "参数管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult<Void> add(@Validated @RequestBody SysConfig config) {
if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config))) {
return AjaxResult.error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在");
}
return toAjax(configService.insertConfig(config));
}
/**
* 修改参数配置
*/
@ApiOperation("修改参数配置")
@PreAuthorize("@ss.hasPermi('system:config:edit')")
@Log(title = "参数管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult<Void> edit(@Validated @RequestBody SysConfig config) {
if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config))) {
return AjaxResult.error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在");
}
return toAjax(configService.updateConfig(config));
}
/**
* 删除参数配置
*/
@ApiOperation("删除参数配置")
@PreAuthorize("@ss.hasPermi('system:config:remove')")
@Log(title = "参数管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{configIds}")
public AjaxResult<Void> remove(@ApiParam("参数ID串") @PathVariable Long[] configIds) {
configService.deleteConfigByIds(configIds);
return success();
}
/**
* 刷新参数缓存
*/
@ApiOperation("刷新参数缓存")
@PreAuthorize("@ss.hasPermi('system:config:remove')")
@Log(title = "参数管理", businessType = BusinessType.CLEAN)
@DeleteMapping("/refreshCache")
public AjaxResult<Void> refreshCache() {
configService.resetConfigCache();
return AjaxResult.success();
}
}

View File

@ -1,147 +0,0 @@
package com.ruoyi.web.controller.system;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.ArrayUtil;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.service.ISysDeptService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 部门信息
*
* @author Lion Li
*/
@Validated
@Api(value = "部门控制器", tags = {"部门管理"})
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@RestController
@RequestMapping("/system/dept")
public class SysDeptController extends BaseController {
private final ISysDeptService deptService;
/**
* 获取部门列表
*/
@ApiOperation("获取部门列表")
@PreAuthorize("@ss.hasPermi('system:dept:list')")
@GetMapping("/list")
public AjaxResult<List<SysDept>> list(SysDept dept) {
List<SysDept> depts = deptService.selectDeptList(dept);
return AjaxResult.success(depts);
}
/**
* 查询部门列表(排除节点)
*/
@ApiOperation("查询部门列表(排除节点)")
@PreAuthorize("@ss.hasPermi('system:dept:list')")
@GetMapping("/list/exclude/{deptId}")
public AjaxResult<List<SysDept>> excludeChild(@ApiParam("部门ID") @PathVariable(value = "deptId", required = false) Long deptId) {
List<SysDept> depts = deptService.selectDeptList(new SysDept());
depts.removeIf(d -> d.getDeptId().equals(deptId)
|| ArrayUtil.contains(StringUtils.split(d.getAncestors(), ","), deptId + ""));
return AjaxResult.success(depts);
}
/**
* 根据部门编号获取详细信息
*/
@ApiOperation("根据部门编号获取详细信息")
@PreAuthorize("@ss.hasPermi('system:dept:query')")
@GetMapping(value = "/{deptId}")
public AjaxResult<SysDept> getInfo(@ApiParam("部门ID") @PathVariable Long deptId) {
deptService.checkDeptDataScope(deptId);
return AjaxResult.success(deptService.selectDeptById(deptId));
}
/**
* 获取部门下拉树列表
*/
@ApiOperation("获取部门下拉树列表")
@GetMapping("/treeselect")
public AjaxResult<List<Tree<Long>>> treeselect(SysDept dept) {
List<SysDept> depts = deptService.selectDeptList(dept);
return AjaxResult.success(deptService.buildDeptTreeSelect(depts));
}
/**
* 加载对应角色部门列表树
*/
@ApiOperation("加载对应角色部门列表树")
@GetMapping(value = "/roleDeptTreeselect/{roleId}")
public AjaxResult<Map<String, Object>> roleDeptTreeselect(@ApiParam("角色ID") @PathVariable("roleId") Long roleId) {
List<SysDept> depts = deptService.selectDeptList(new SysDept());
Map<String, Object> ajax = new HashMap<>();
ajax.put("checkedKeys", deptService.selectDeptListByRoleId(roleId));
ajax.put("depts", deptService.buildDeptTreeSelect(depts));
return AjaxResult.success(ajax);
}
/**
* 新增部门
*/
@ApiOperation("新增部门")
@PreAuthorize("@ss.hasPermi('system:dept:add')")
@Log(title = "部门管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult<Void> add(@Validated @RequestBody SysDept dept) {
if (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept))) {
return AjaxResult.error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在");
}
return toAjax(deptService.insertDept(dept));
}
/**
* 修改部门
*/
@ApiOperation("修改部门")
@PreAuthorize("@ss.hasPermi('system:dept:edit')")
@Log(title = "部门管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult<Void> edit(@Validated @RequestBody SysDept dept) {
if (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept))) {
return AjaxResult.error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在");
} else if (dept.getParentId().equals(dept.getDeptId())) {
return AjaxResult.error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己");
} else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus())
&& deptService.selectNormalChildrenDeptById(dept.getDeptId()) > 0) {
return AjaxResult.error("该部门包含未停用的子部门!");
}
return toAjax(deptService.updateDept(dept));
}
/**
* 删除部门
*/
@ApiOperation("删除部门")
@PreAuthorize("@ss.hasPermi('system:dept:remove')")
@Log(title = "部门管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{deptId}")
public AjaxResult<Void> remove(@ApiParam("部门ID串") @PathVariable Long deptId) {
if (deptService.hasChildByDeptId(deptId)) {
return AjaxResult.error("存在下级部门,不允许删除");
}
if (deptService.checkDeptExistUser(deptId)) {
return AjaxResult.error("部门存在用户,不允许删除");
}
return toAjax(deptService.deleteDeptById(deptId));
}
}

View File

@ -1,125 +0,0 @@
package com.ruoyi.web.controller.system;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysDictType;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.system.service.ISysDictTypeService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* 数据字典信息
*
* @author Lion Li
*/
@Validated
@Api(value = "数据字典信息控制器", tags = {"数据字典信息管理"})
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@RestController
@RequestMapping("/system/dict/type")
public class SysDictTypeController extends BaseController {
private final ISysDictTypeService dictTypeService;
@ApiOperation("查询字典类型列表")
@PreAuthorize("@ss.hasPermi('system:dict:list')")
@GetMapping("/list")
public TableDataInfo<SysDictType> list(SysDictType dictType) {
return dictTypeService.selectPageDictTypeList(dictType);
}
@ApiOperation("导出字典类型列表")
@Log(title = "字典类型", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('system:dict:export')")
@PostMapping("/export")
public void export(SysDictType dictType, HttpServletResponse response) {
List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
ExcelUtil.exportExcel(list, "字典类型", SysDictType.class, response);
}
/**
* 查询字典类型详细
*/
@ApiOperation("查询字典类型详细")
@PreAuthorize("@ss.hasPermi('system:dict:query')")
@GetMapping(value = "/{dictId}")
public AjaxResult<SysDictType> getInfo(@ApiParam("字典ID") @PathVariable Long dictId) {
return AjaxResult.success(dictTypeService.selectDictTypeById(dictId));
}
/**
* 新增字典类型
*/
@ApiOperation("新增字典类型")
@PreAuthorize("@ss.hasPermi('system:dict:add')")
@Log(title = "字典类型", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult<Void> add(@Validated @RequestBody SysDictType dict) {
if (UserConstants.NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict))) {
return AjaxResult.error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在");
}
return toAjax(dictTypeService.insertDictType(dict));
}
/**
* 修改字典类型
*/
@ApiOperation("修改字典类型")
@PreAuthorize("@ss.hasPermi('system:dict:edit')")
@Log(title = "字典类型", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult<Void> edit(@Validated @RequestBody SysDictType dict) {
if (UserConstants.NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict))) {
return AjaxResult.error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在");
}
return toAjax(dictTypeService.updateDictType(dict));
}
/**
* 删除字典类型
*/
@ApiOperation("删除字典类型")
@PreAuthorize("@ss.hasPermi('system:dict:remove')")
@Log(title = "字典类型", businessType = BusinessType.DELETE)
@DeleteMapping("/{dictIds}")
public AjaxResult<Void> remove(@ApiParam("字典ID串") @PathVariable Long[] dictIds) {
dictTypeService.deleteDictTypeByIds(dictIds);
return success();
}
/**
* 刷新字典缓存
*/
@ApiOperation("刷新字典缓存")
@PreAuthorize("@ss.hasPermi('system:dict:remove')")
@Log(title = "字典类型", businessType = BusinessType.CLEAN)
@DeleteMapping("/refreshCache")
public AjaxResult<Void> refreshCache() {
dictTypeService.resetDictCache();
return AjaxResult.success();
}
/**
* 获取字典选择框列表
*/
@ApiOperation("获取字典选择框列表")
@GetMapping("/optionselect")
public AjaxResult<List<SysDictType>> optionselect() {
List<SysDictType> dictTypes = dictTypeService.selectDictTypeAll();
return AjaxResult.success(dictTypes);
}
}

View File

@ -1,94 +0,0 @@
package com.ruoyi.web.controller.system;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginBody;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.domain.vo.RouterVo;
import com.ruoyi.system.service.ISysMenuService;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.service.SysLoginService;
import com.ruoyi.system.service.SysPermissionService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 登录验证
*
* @author Lion Li
*/
@Validated
@Api(value = "登录验证控制器", tags = {"登录验证管理"})
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@RestController
public class SysLoginController {
private final SysLoginService loginService;
private final ISysMenuService menuService;
private final ISysUserService userService;
private final SysPermissionService permissionService;
/**
* 登录方法
*
* @param loginBody 登录信息
* @return 结果
*/
@ApiOperation("登录方法")
@PostMapping("/login")
public AjaxResult<Map<String, Object>> login(@RequestBody LoginBody loginBody) {
Map<String, Object> ajax = new HashMap<>();
// 生成令牌
String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
loginBody.getUuid());
ajax.put(Constants.TOKEN, token);
return AjaxResult.success(ajax);
}
/**
* 获取用户信息
*
* @return 用户信息
*/
@ApiOperation("获取用户信息")
@GetMapping("getInfo")
public AjaxResult<Map<String, Object>> getInfo() {
SysUser user = userService.selectUserById(SecurityUtils.getUserId());
// 角色集合
Set<String> roles = permissionService.getRolePermission(user);
// 权限集合
Set<String> permissions = permissionService.getMenuPermission(user);
Map<String, Object> ajax = new HashMap<>();
ajax.put("user", user);
ajax.put("roles", roles);
ajax.put("permissions", permissions);
return AjaxResult.success(ajax);
}
/**
* 获取路由信息
*
* @return 路由信息
*/
@ApiOperation("获取路由信息")
@GetMapping("getRouters")
public AjaxResult<List<RouterVo>> getRouters() {
Long userId = SecurityUtils.getUserId();
List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
return AjaxResult.success(menuService.buildMenus(menus));
}
}

View File

@ -1,133 +0,0 @@
package com.ruoyi.web.controller.system;
import cn.hutool.core.lang.tree.Tree;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.service.ISysMenuService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 菜单信息
*
* @author Lion Li
*/
@Validated
@Api(value = "菜单信息控制器", tags = {"菜单信息管理"})
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@RestController
@RequestMapping("/system/menu")
public class SysMenuController extends BaseController {
private final ISysMenuService menuService;
/**
* 获取菜单列表
*/
@ApiOperation("获取菜单列表")
@PreAuthorize("@ss.hasPermi('system:menu:list')")
@GetMapping("/list")
public AjaxResult<List<SysMenu>> list(SysMenu menu) {
List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
return AjaxResult.success(menus);
}
/**
* 根据菜单编号获取详细信息
*/
@ApiOperation("根据菜单编号获取详细信息")
@PreAuthorize("@ss.hasPermi('system:menu:query')")
@GetMapping(value = "/{menuId}")
public AjaxResult<SysMenu> getInfo(@ApiParam("菜单ID") @PathVariable Long menuId) {
return AjaxResult.success(menuService.selectMenuById(menuId));
}
/**
* 获取菜单下拉树列表
*/
@ApiOperation("获取菜单下拉树列表")
@GetMapping("/treeselect")
public AjaxResult<List<Tree<Long>>> treeselect(SysMenu menu) {
List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
return AjaxResult.success(menuService.buildMenuTreeSelect(menus));
}
/**
* 加载对应角色菜单列表树
*/
@ApiOperation("加载对应角色菜单列表树")
@GetMapping(value = "/roleMenuTreeselect/{roleId}")
public AjaxResult<Map<String, Object>> roleMenuTreeselect(@ApiParam("角色ID") @PathVariable("roleId") Long roleId) {
List<SysMenu> menus = menuService.selectMenuList(getUserId());
Map<String, Object> ajax = new HashMap<>();
ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId));
ajax.put("menus", menuService.buildMenuTreeSelect(menus));
return AjaxResult.success(ajax);
}
/**
* 新增菜单
*/
@ApiOperation("新增菜单")
@PreAuthorize("@ss.hasPermi('system:menu:add')")
@Log(title = "菜单管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult<Void> add(@Validated @RequestBody SysMenu menu) {
if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu))) {
return AjaxResult.error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
} else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) {
return AjaxResult.error("新增菜单'" + menu.getMenuName() + "'失败地址必须以http(s)://开头");
}
return toAjax(menuService.insertMenu(menu));
}
/**
* 修改菜单
*/
@ApiOperation("修改菜单")
@PreAuthorize("@ss.hasPermi('system:menu:edit')")
@Log(title = "菜单管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult<Void> edit(@Validated @RequestBody SysMenu menu) {
if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu))) {
return AjaxResult.error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
} else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) {
return AjaxResult.error("修改菜单'" + menu.getMenuName() + "'失败地址必须以http(s)://开头");
} else if (menu.getMenuId().equals(menu.getParentId())) {
return AjaxResult.error("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己");
}
return toAjax(menuService.updateMenu(menu));
}
/**
* 删除菜单
*/
@ApiOperation("删除菜单")
@PreAuthorize("@ss.hasPermi('system:menu:remove')")
@Log(title = "菜单管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{menuId}")
public AjaxResult<Void> remove(@ApiParam("菜单ID") @PathVariable("menuId") Long menuId) {
if (menuService.hasChildByMenuId(menuId)) {
return AjaxResult.error("存在子菜单,不允许删除");
}
if (menuService.checkMenuExistRole(menuId)) {
return AjaxResult.error("菜单已分配,不允许删除");
}
return toAjax(menuService.deleteMenuById(menuId));
}
}

View File

@ -1,142 +0,0 @@
package com.ruoyi.web.controller.system;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpException;
import cn.hutool.http.HttpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.validate.QueryGroup;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.oss.constant.OssConstant;
import com.ruoyi.system.domain.SysConfig;
import com.ruoyi.system.domain.SysOss;
import com.ruoyi.system.domain.bo.SysOssBo;
import com.ruoyi.system.domain.vo.SysOssVo;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysOssService;
import io.swagger.annotations.*;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotEmpty;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* 文件上传 控制层
*
* @author Lion Li
*/
@Validated
@Api(value = "OSS对象存储控制器", tags = {"OSS对象存储管理"})
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@RestController
@RequestMapping("/system/oss")
public class SysOssController extends BaseController {
private final ISysOssService iSysOssService;
private final ISysConfigService iSysConfigService;
/**
* 查询OSS对象存储列表
*/
@ApiOperation("查询OSS对象存储列表")
@PreAuthorize("@ss.hasPermi('system:oss:list')")
@GetMapping("/list")
public TableDataInfo<SysOssVo> list(@Validated(QueryGroup.class) SysOssBo bo) {
return iSysOssService.queryPageList(bo);
}
/**
* 上传OSS对象存储
*/
@ApiOperation("上传OSS对象存储")
@ApiImplicitParams({
@ApiImplicitParam(name = "file", value = "文件", dataTypeClass = File.class, required = true),
})
@PreAuthorize("@ss.hasPermi('system:oss:upload')")
@Log(title = "OSS对象存储", businessType = BusinessType.INSERT)
@RepeatSubmit
@PostMapping("/upload")
public AjaxResult<Map<String, String>> upload(@RequestPart("file") MultipartFile file) {
if (ObjectUtil.isNull(file)) {
throw new ServiceException("上传文件不能为空");
}
SysOss oss = iSysOssService.upload(file);
Map<String, String> map = new HashMap<>(2);
map.put("url", oss.getUrl());
map.put("fileName", oss.getFileName());
return AjaxResult.success(map);
}
@ApiOperation("下载OSS对象存储")
@PreAuthorize("@ss.hasPermi('system:oss:download')")
@GetMapping("/download/{ossId}")
public void download(@ApiParam("OSS对象ID") @PathVariable Long ossId, HttpServletResponse response) throws IOException {
SysOss sysOss = iSysOssService.getById(ossId);
if (ObjectUtil.isNull(sysOss)) {
throw new ServiceException("文件数据不存在!");
}
response.reset();
FileUtils.setAttachmentResponseHeader(response, sysOss.getOriginalName());
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8");
long data;
try {
data = HttpUtil.download(sysOss.getUrl(), response.getOutputStream(), false);
} catch (HttpException e) {
if (e.getMessage().contains("403")) {
throw new ServiceException("无读取权限, 请在对应的OSS开启'公有读'权限!");
} else {
throw new ServiceException(e.getMessage());
}
}
response.setContentLength(Convert.toInt(data));
}
/**
* 删除OSS对象存储
*/
@ApiOperation("删除OSS对象存储")
@PreAuthorize("@ss.hasPermi('system:oss:remove')")
@Log(title = "OSS对象存储", businessType = BusinessType.DELETE)
@DeleteMapping("/{ossIds}")
public AjaxResult<Void> remove(@ApiParam("OSS对象ID串")
@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ossIds) {
return toAjax(iSysOssService.deleteWithValidByIds(Arrays.asList(ossIds), true) ? 1 : 0);
}
/**
* 变更图片列表预览状态
*/
@ApiOperation("变更图片列表预览状态")
@PreAuthorize("@ss.hasPermi('system:oss:edit')")
@Log(title = "OSS对象存储", businessType = BusinessType.UPDATE)
@PutMapping("/changePreviewListResource")
public AjaxResult<Void> changePreviewListResource(@RequestBody String body) {
Map<String, Boolean> map = JsonUtils.parseMap(body);
SysConfig config = iSysConfigService.getOne(new LambdaQueryWrapper<SysConfig>()
.eq(SysConfig::getConfigKey, OssConstant.PEREVIEW_LIST_RESOURCE_KEY));
config.setConfigValue(map.get("previewListResource").toString());
return toAjax(iSysConfigService.updateConfig(config));
}
}

View File

@ -1,119 +0,0 @@
package com.ruoyi.web.controller.system;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.system.domain.SysPost;
import com.ruoyi.system.service.ISysPostService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* 岗位信息操作处理
*
* @author Lion Li
*/
@Validated
@Api(value = "岗位信息控制器", tags = {"岗位信息管理"})
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@RestController
@RequestMapping("/system/post")
public class SysPostController extends BaseController {
private final ISysPostService postService;
/**
* 获取岗位列表
*/
@ApiOperation("获取岗位列表")
@PreAuthorize("@ss.hasPermi('system:post:list')")
@GetMapping("/list")
public TableDataInfo<SysPost> list(SysPost post) {
return postService.selectPagePostList(post);
}
@ApiOperation("导出岗位列表")
@Log(title = "岗位管理", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('system:post:export')")
@PostMapping("/export")
public void export(SysPost post, HttpServletResponse response) {
List<SysPost> list = postService.selectPostList(post);
ExcelUtil.exportExcel(list, "岗位数据", SysPost.class, response);
}
/**
* 根据岗位编号获取详细信息
*/
@ApiOperation("根据岗位编号获取详细信息")
@PreAuthorize("@ss.hasPermi('system:post:query')")
@GetMapping(value = "/{postId}")
public AjaxResult<SysPost> getInfo(@ApiParam("岗位ID") @PathVariable Long postId) {
return AjaxResult.success(postService.selectPostById(postId));
}
/**
* 新增岗位
*/
@ApiOperation("新增岗位")
@PreAuthorize("@ss.hasPermi('system:post:add')")
@Log(title = "岗位管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult<Void> add(@Validated @RequestBody SysPost post) {
if (UserConstants.NOT_UNIQUE.equals(postService.checkPostNameUnique(post))) {
return AjaxResult.error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在");
} else if (UserConstants.NOT_UNIQUE.equals(postService.checkPostCodeUnique(post))) {
return AjaxResult.error("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在");
}
return toAjax(postService.insertPost(post));
}
/**
* 修改岗位
*/
@ApiOperation("修改岗位")
@PreAuthorize("@ss.hasPermi('system:post:edit')")
@Log(title = "岗位管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult<Void> edit(@Validated @RequestBody SysPost post) {
if (UserConstants.NOT_UNIQUE.equals(postService.checkPostNameUnique(post))) {
return AjaxResult.error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在");
} else if (UserConstants.NOT_UNIQUE.equals(postService.checkPostCodeUnique(post))) {
return AjaxResult.error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在");
}
return toAjax(postService.updatePost(post));
}
/**
* 删除岗位
*/
@ApiOperation("删除岗位")
@PreAuthorize("@ss.hasPermi('system:post:remove')")
@Log(title = "岗位管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{postIds}")
public AjaxResult<Void> remove(@ApiParam("岗位ID串") @PathVariable Long[] postIds) {
return toAjax(postService.deletePostByIds(postIds));
}
/**
* 获取岗位选择框列表
*/
@ApiOperation("获取岗位选择框列表")
@GetMapping("/optionselect")
public AjaxResult<List<SysPost>> optionselect() {
List<SysPost> posts = postService.selectPostAll();
return AjaxResult.success(posts);
}
}

View File

@ -1,135 +0,0 @@
package com.ruoyi.web.controller.system;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.service.TokenService;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.SysOss;
import com.ruoyi.system.service.ISysOssService;
import com.ruoyi.system.service.ISysUserService;
import io.swagger.annotations.*;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
/**
* 个人信息 业务处理
*
* @author Lion Li
*/
@Validated
@Api(value = "个人信息控制器", tags = {"个人信息管理"})
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@RestController
@RequestMapping("/system/user/profile")
public class SysProfileController extends BaseController {
private final ISysUserService userService;
private final TokenService tokenService;
private final ISysOssService iSysOssService;
/**
* 个人信息
*/
@ApiOperation("个人信息")
@GetMapping
public AjaxResult<Map<String, Object>> profile() {
LoginUser loginUser = getLoginUser();
SysUser user = userService.selectUserById(loginUser.getUserId());
Map<String, Object> ajax = new HashMap<>();
ajax.put("user", user);
ajax.put("roleGroup", userService.selectUserRoleGroup(loginUser.getUsername()));
ajax.put("postGroup", userService.selectUserPostGroup(loginUser.getUsername()));
return AjaxResult.success(ajax);
}
/**
* 修改用户
*/
@ApiOperation("修改用户")
@Log(title = "个人信息", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult<Void> updateProfile(@RequestBody SysUser user) {
if (StringUtils.isNotEmpty(user.getPhonenumber())
&& UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) {
return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
}
if (StringUtils.isNotEmpty(user.getEmail())
&& UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user))) {
return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
}
LoginUser loginUser = getLoginUser();
SysUser sysUser = userService.selectUserById(loginUser.getUserId());
user.setUserId(sysUser.getUserId());
user.setUserName(null);
user.setPassword(null);
if (userService.updateUserProfile(user) > 0) {
return AjaxResult.success();
}
return AjaxResult.error("修改个人信息异常,请联系管理员");
}
/**
* 重置密码
*/
@ApiOperation("重置密码")
@ApiImplicitParams({
@ApiImplicitParam(name = "oldPassword", value = "旧密码", paramType = "query", dataTypeClass = String.class),
@ApiImplicitParam(name = "newPassword", value = "新密码", paramType = "query", dataTypeClass = String.class)
})
@Log(title = "个人信息", businessType = BusinessType.UPDATE)
@PutMapping("/updatePwd")
public AjaxResult<Void> updatePwd(String oldPassword, String newPassword) {
LoginUser loginUser = getLoginUser();
String userName = loginUser.getUsername();
String password = loginUser.getPassword();
if (!SecurityUtils.matchesPassword(oldPassword, password)) {
return AjaxResult.error("修改密码失败,旧密码错误");
}
if (SecurityUtils.matchesPassword(newPassword, password)) {
return AjaxResult.error("新密码不能与旧密码相同");
}
if (userService.resetUserPwd(userName, SecurityUtils.encryptPassword(newPassword)) > 0) {
// 更新缓存用户密码
loginUser.setPassword(SecurityUtils.encryptPassword(newPassword));
tokenService.setLoginUser(loginUser);
return AjaxResult.success();
}
return AjaxResult.error("修改密码异常,请联系管理员");
}
/**
* 头像上传
*/
@ApiOperation("头像上传")
@ApiImplicitParams({
@ApiImplicitParam(name = "avatarfile", value = "用户头像", dataTypeClass = File.class, required = true),
})
@Log(title = "用户头像", businessType = BusinessType.UPDATE)
@PostMapping("/avatar")
public AjaxResult<Map<String, Object>> avatar(@RequestPart("avatarfile") MultipartFile file) {
Map<String, Object> ajax = new HashMap<>();
if (!file.isEmpty()) {
LoginUser loginUser = getLoginUser();
SysOss oss = iSysOssService.upload(file);
String avatar = oss.getUrl();
if (userService.updateUserAvatar(loginUser.getUsername(), avatar)) {
ajax.put("imgUrl", avatar);
return AjaxResult.success(ajax);
}
}
return AjaxResult.error("上传图片异常,请联系管理员", ajax);
}
}

View File

@ -1,223 +0,0 @@
package com.ruoyi.web.controller.system;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.service.TokenService;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.system.domain.SysUserRole;
import com.ruoyi.system.service.ISysRoleService;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.service.SysPermissionService;
import io.swagger.annotations.*;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* 角色信息
*
* @author Lion Li
*/
@Validated
@Api(value = "角色信息控制器", tags = {"角色信息管理"})
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@RestController
@RequestMapping("/system/role")
public class SysRoleController extends BaseController {
private final ISysRoleService roleService;
private final TokenService tokenService;
private final ISysUserService userService;
private final SysPermissionService permissionService;
@ApiOperation("查询角色信息列表")
@PreAuthorize("@ss.hasPermi('system:role:list')")
@GetMapping("/list")
public TableDataInfo<SysRole> list(SysRole role) {
return roleService.selectPageRoleList(role);
}
@ApiOperation("导出角色信息列表")
@Log(title = "角色管理", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('system:role:export')")
@PostMapping("/export")
public void export(SysRole role, HttpServletResponse response) {
List<SysRole> list = roleService.selectRoleList(role);
ExcelUtil.exportExcel(list, "角色数据", SysRole.class, response);
}
/**
* 根据角色编号获取详细信息
*/
@ApiOperation("根据角色编号获取详细信息")
@PreAuthorize("@ss.hasPermi('system:role:query')")
@GetMapping(value = "/{roleId}")
public AjaxResult<SysRole> getInfo(@ApiParam("角色ID") @PathVariable Long roleId) {
roleService.checkRoleDataScope(roleId);
return AjaxResult.success(roleService.selectRoleById(roleId));
}
/**
* 新增角色
*/
@ApiOperation("新增角色")
@PreAuthorize("@ss.hasPermi('system:role:add')")
@Log(title = "角色管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult<Void> add(@Validated @RequestBody SysRole role) {
if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role))) {
return AjaxResult.error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在");
} else if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role))) {
return AjaxResult.error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在");
}
return toAjax(roleService.insertRole(role));
}
/**
* 修改保存角色
*/
@ApiOperation("修改保存角色")
@PreAuthorize("@ss.hasPermi('system:role:edit')")
@Log(title = "角色管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult<Void> edit(@Validated @RequestBody SysRole role) {
roleService.checkRoleAllowed(role);
if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role))) {
return AjaxResult.error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在");
} else if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role))) {
return AjaxResult.error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在");
}
if (roleService.updateRole(role) > 0) {
// 更新缓存用户权限
LoginUser loginUser = getLoginUser();
SysUser sysUser = userService.selectUserById(loginUser.getUserId());
if (StringUtils.isNotNull(sysUser) && !sysUser.isAdmin()) {
loginUser.setPermissions(permissionService.getMenuPermission(sysUser));
tokenService.setLoginUser(loginUser);
}
return AjaxResult.success();
}
return AjaxResult.error("修改角色'" + role.getRoleName() + "'失败,请联系管理员");
}
/**
* 修改保存数据权限
*/
@ApiOperation("修改保存数据权限")
@PreAuthorize("@ss.hasPermi('system:role:edit')")
@Log(title = "角色管理", businessType = BusinessType.UPDATE)
@PutMapping("/dataScope")
public AjaxResult<Void> dataScope(@RequestBody SysRole role) {
roleService.checkRoleAllowed(role);
return toAjax(roleService.authDataScope(role));
}
/**
* 状态修改
*/
@ApiOperation("状态修改")
@PreAuthorize("@ss.hasPermi('system:role:edit')")
@Log(title = "角色管理", businessType = BusinessType.UPDATE)
@PutMapping("/changeStatus")
public AjaxResult<Void> changeStatus(@RequestBody SysRole role) {
roleService.checkRoleAllowed(role);
return toAjax(roleService.updateRoleStatus(role));
}
/**
* 删除角色
*/
@ApiOperation("删除角色")
@PreAuthorize("@ss.hasPermi('system:role:remove')")
@Log(title = "角色管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{roleIds}")
public AjaxResult<Void> remove(@ApiParam("岗位ID串") @PathVariable Long[] roleIds) {
return toAjax(roleService.deleteRoleByIds(roleIds));
}
/**
* 获取角色选择框列表
*/
@ApiOperation("获取角色选择框列表")
@PreAuthorize("@ss.hasPermi('system:role:query')")
@GetMapping("/optionselect")
public AjaxResult<List<SysRole>> optionselect() {
return AjaxResult.success(roleService.selectRoleAll());
}
/**
* 查询已分配用户角色列表
*/
@ApiOperation("查询已分配用户角色列表")
@PreAuthorize("@ss.hasPermi('system:role:list')")
@GetMapping("/authUser/allocatedList")
public TableDataInfo<SysUser> allocatedList(SysUser user) {
return userService.selectAllocatedList(user);
}
/**
* 查询未分配用户角色列表
*/
@ApiOperation("查询未分配用户角色列表")
@PreAuthorize("@ss.hasPermi('system:role:list')")
@GetMapping("/authUser/unallocatedList")
public TableDataInfo<SysUser> unallocatedList(SysUser user) {
return userService.selectUnallocatedList(user);
}
/**
* 取消授权用户
*/
@ApiOperation("取消授权用户")
@PreAuthorize("@ss.hasPermi('system:role:edit')")
@Log(title = "角色管理", businessType = BusinessType.GRANT)
@PutMapping("/authUser/cancel")
public AjaxResult<Void> cancelAuthUser(@RequestBody SysUserRole userRole) {
return toAjax(roleService.deleteAuthUser(userRole));
}
/**
* 批量取消授权用户
*/
@ApiOperation("批量取消授权用户")
@ApiImplicitParams({
@ApiImplicitParam(name = "roleId", value = "角色ID", paramType = "query", dataTypeClass = String.class),
@ApiImplicitParam(name = "userIds", value = "用户ID串", paramType = "query", dataTypeClass = String.class)
})
@PreAuthorize("@ss.hasPermi('system:role:edit')")
@Log(title = "角色管理", businessType = BusinessType.GRANT)
@PutMapping("/authUser/cancelAll")
public AjaxResult<Void> cancelAuthUserAll(Long roleId, Long[] userIds) {
return toAjax(roleService.deleteAuthUsers(roleId, userIds));
}
/**
* 批量选择用户授权
*/
@ApiOperation("批量选择用户授权")
@ApiImplicitParams({
@ApiImplicitParam(name = "roleId", value = "角色ID", paramType = "query", dataTypeClass = String.class),
@ApiImplicitParam(name = "userIds", value = "用户ID串", paramType = "query", dataTypeClass = String.class)
})
@PreAuthorize("@ss.hasPermi('system:role:edit')")
@Log(title = "角色管理", businessType = BusinessType.GRANT)
@PutMapping("/authUser/selectAll")
public AjaxResult<Void> selectAuthUserAll(Long roleId, Long[] userIds) {
return toAjax(roleService.insertAuthUsers(roleId, userIds));
}
}

View File

@ -1,231 +0,0 @@
package com.ruoyi.web.controller.system;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.excel.ExcelResult;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.system.domain.vo.SysUserExportVo;
import com.ruoyi.system.domain.vo.SysUserImportVo;
import com.ruoyi.system.listener.SysUserImportListener;
import com.ruoyi.system.service.ISysPostService;
import com.ruoyi.system.service.ISysRoleService;
import com.ruoyi.system.service.ISysUserService;
import io.swagger.annotations.*;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 用户信息
*
* @author Lion Li
*/
@Validated
@Api(value = "用户信息控制器", tags = {"用户信息管理"})
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@RestController
@RequestMapping("/system/user")
public class SysUserController extends BaseController {
private final ISysUserService userService;
private final ISysRoleService roleService;
private final ISysPostService postService;
/**
* 获取用户列表
*/
@ApiOperation("获取用户列表")
@PreAuthorize("@ss.hasPermi('system:user:list')")
@GetMapping("/list")
public TableDataInfo<SysUser> list(SysUser user) {
return userService.selectPageUserList(user);
}
@ApiOperation("导出用户列表")
@Log(title = "用户管理", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('system:user:export')")
@PostMapping("/export")
public void export(SysUser user, HttpServletResponse response) {
List<SysUser> list = userService.selectUserList(user);
List<SysUserExportVo> listVo = BeanUtil.copyToList(list, SysUserExportVo.class);
for (int i = 0; i < list.size(); i++) {
SysDept dept = list.get(i).getDept();
SysUserExportVo vo = listVo.get(i);
if (ObjectUtil.isNotEmpty(dept)) {
vo.setDeptName(dept.getDeptName());
vo.setLeader(dept.getLeader());
}
}
ExcelUtil.exportExcel(listVo, "用户数据", SysUserExportVo.class, response);
}
@ApiOperation("导入用户列表")
@ApiImplicitParams({
@ApiImplicitParam(name = "file", value = "导入文件", dataType = "java.io.File", required = true),
})
@Log(title = "用户管理", businessType = BusinessType.IMPORT)
@PreAuthorize("@ss.hasPermi('system:user:import')")
@PostMapping("/importData")
public AjaxResult<Void> importData(@RequestPart("file") MultipartFile file, boolean updateSupport) throws Exception {
ExcelResult<SysUserImportVo> result = ExcelUtil.importExcel(file.getInputStream(), SysUserImportVo.class, new SysUserImportListener(updateSupport));
return AjaxResult.success(result.getAnalysis());
}
@ApiOperation("下载导入模板")
@PostMapping("/importTemplate")
public void importTemplate(HttpServletResponse response) {
ExcelUtil.exportExcel(new ArrayList<>(), "用户数据", SysUserImportVo.class, response);
}
/**
* 根据用户编号获取详细信息
*/
@ApiOperation("根据用户编号获取详细信息")
@PreAuthorize("@ss.hasPermi('system:user:query')")
@GetMapping(value = {"/", "/{userId}"})
public AjaxResult<Map<String, Object>> getInfo(@ApiParam("用户ID") @PathVariable(value = "userId", required = false) Long userId) {
userService.checkUserDataScope(userId);
Map<String, Object> ajax = new HashMap<>();
List<SysRole> roles = roleService.selectRoleAll();
ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
ajax.put("posts", postService.selectPostAll());
if (StringUtils.isNotNull(userId)) {
ajax.put("user", userService.selectUserById(userId));
ajax.put("postIds", postService.selectPostListByUserId(userId));
ajax.put("roleIds", roleService.selectRoleListByUserId(userId));
}
return AjaxResult.success(ajax);
}
/**
* 新增用户
*/
@ApiOperation("新增用户")
@PreAuthorize("@ss.hasPermi('system:user:add')")
@Log(title = "用户管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult<Void> add(@Validated @RequestBody SysUser user) {
if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user.getUserName()))) {
return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
} else if (StringUtils.isNotEmpty(user.getPhonenumber())
&& UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) {
return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,手机号码已存在");
} else if (StringUtils.isNotEmpty(user.getEmail())
&& UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user))) {
return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在");
}
user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
return toAjax(userService.insertUser(user));
}
/**
* 修改用户
*/
@ApiOperation("修改用户")
@PreAuthorize("@ss.hasPermi('system:user:edit')")
@Log(title = "用户管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult<Void> edit(@Validated @RequestBody SysUser user) {
userService.checkUserAllowed(user);
if (StringUtils.isNotEmpty(user.getPhonenumber())
&& UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) {
return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
} else if (StringUtils.isNotEmpty(user.getEmail())
&& UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user))) {
return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
}
return toAjax(userService.updateUser(user));
}
/**
* 删除用户
*/
@ApiOperation("删除用户")
@PreAuthorize("@ss.hasPermi('system:user:remove')")
@Log(title = "用户管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{userIds}")
public AjaxResult<Void> remove(@ApiParam("角色ID串") @PathVariable Long[] userIds) {
if (ArrayUtil.contains(userIds, getUserId())) {
return error("当前用户不能删除");
}
return toAjax(userService.deleteUserByIds(userIds));
}
/**
* 重置密码
*/
@ApiOperation("重置密码")
@PreAuthorize("@ss.hasPermi('system:user:resetPwd')")
@Log(title = "用户管理", businessType = BusinessType.UPDATE)
@PutMapping("/resetPwd")
public AjaxResult<Void> resetPwd(@RequestBody SysUser user) {
userService.checkUserAllowed(user);
user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
return toAjax(userService.resetPwd(user));
}
/**
* 状态修改
*/
@ApiOperation("状态修改")
@PreAuthorize("@ss.hasPermi('system:user:edit')")
@Log(title = "用户管理", businessType = BusinessType.UPDATE)
@PutMapping("/changeStatus")
public AjaxResult<Void> changeStatus(@RequestBody SysUser user) {
userService.checkUserAllowed(user);
return toAjax(userService.updateUserStatus(user));
}
/**
* 根据用户编号获取授权角色
*/
@ApiOperation("根据用户编号获取授权角色")
@PreAuthorize("@ss.hasPermi('system:user:query')")
@GetMapping("/authRole/{userId}")
public AjaxResult<Map<String, Object>> authRole(@ApiParam("用户ID") @PathVariable("userId") Long userId) {
SysUser user = userService.selectUserById(userId);
List<SysRole> roles = roleService.selectRolesByUserId(userId);
Map<String, Object> ajax = new HashMap<>();
ajax.put("user", user);
ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
return AjaxResult.success(ajax);
}
/**
* 用户授权角色
*/
@ApiOperation("用户授权角色")
@ApiImplicitParams({
@ApiImplicitParam(name = "userId", value = "用户Id", paramType = "query", dataTypeClass = String.class),
@ApiImplicitParam(name = "roleIds", value = "角色ID串", paramType = "query", dataTypeClass = String.class)
})
@PreAuthorize("@ss.hasPermi('system:user:edit')")
@Log(title = "用户管理", businessType = BusinessType.GRANT)
@PutMapping("/authRole")
public AjaxResult<Void> insertAuthRole(Long userId, Long[] roleIds) {
userService.insertUserAuth(userId, roleIds);
return success();
}
}

View File

@ -1,158 +0,0 @@
--- # 监控配置
spring:
boot:
admin:
# Spring Boot Admin Client 客户端的相关配置
client:
# 增加客户端开关
enabled: true
# 设置 Spring Boot Admin Server 地址
url: http://localhost:9090/admin
instance:
prefer-ip: true # 注册实例时,优先使用 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
url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=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: 16
# Netty线程池数量
nettyThreads: 32
# 传输模式
transportMode: "NIO"
# 单节点配置
singleServerConfig:
# 客户端名称
clientName: ${ruoyi.name}
# 最小空闲连接数
connectionMinimumIdleSize: 32
# 连接池大小
connectionPoolSize: 64
# 连接空闲超时,单位:毫秒
idleConnectionTimeout: 10000
# 命令等待超时,单位:毫秒
timeout: 3000
# 如果尝试在此限制之内发送成功,则开始启用 timeout 计时。
retryAttempts: 3
# 命令重试发送时间间隔,单位:毫秒
retryInterval: 1500
# 发布和订阅连接的最小空闲连接数
subscriptionConnectionMinimumIdleSize: 1
# 发布和订阅连接池大小
subscriptionConnectionPoolSize: 50
# 单个连接最大订阅数量
subscriptionsPerConnection: 5
# DNS监测时间间隔单位毫秒
dnsMonitoringInterval: 5000

View File

@ -1,165 +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:
prefer-ip: true # 注册实例时,优先使用 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
url: jdbc:mysql://172.30.0.36:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=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
# 发布和订阅连接的最小空闲连接数
subscriptionConnectionMinimumIdleSize: 1
# 发布和订阅连接池大小
subscriptionConnectionPoolSize: 50
# 单个连接最大订阅数量
subscriptionsPerConnection: 5
# DNS监测时间间隔单位毫秒
dnsMonitoringInterval: 5000

View File

@ -1,96 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="log.path" value="./logs"/>
<property name="console.log.pattern"
value="%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/>
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="com.yomahub.tlog.core.enhance.logback.AspectLogbackEncoder">
<pattern>${console.log.pattern}</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<!-- 控制台输出 -->
<appender name="file_console" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-console.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-console.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大 1天 -->
<maxHistory>1</maxHistory>
</rollingPolicy>
<encoder class="com.yomahub.tlog.core.enhance.logback.AspectLogbackEncoder">
<pattern>${log.pattern}</pattern>
<charset>utf-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
</filter>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder class="com.yomahub.tlog.core.enhance.logback.AspectLogbackEncoder">
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder class="com.yomahub.tlog.core.enhance.logback.AspectLogbackEncoder">
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="com.ruoyi" level="info" />
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn" />
<root level="info">
<appender-ref ref="console" />
</root>
<!--系统操作日志-->
<root level="info">
<appender-ref ref="file_info" />
<appender-ref ref="file_error" />
<appender-ref ref="file_console" />
</root>
</configuration>

View File

@ -1,156 +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>3.4.0</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>
<!-- spring security 安全认证 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- 自定义验证注解 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!--常用工具类 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- JSON工具类 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- excel工具 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
</dependency>
<!-- yml解析器 -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>
<!-- Token生成与解析-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</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>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</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>
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>tlog-spring-boot-configuration</artifactId>
</dependency>
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>tlog-webroot</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,28 +0,0 @@
package com.ruoyi.common.annotation;
import java.lang.annotation.*;
/**
* 数据权限过滤注解
*
* @author ruoyi
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataScope {
/**
* 部门表的别名
*/
String deptAlias() default "";
/**
* 用户表的别名
*/
String userAlias() default "";
/**
* 是否过滤用户权限
*/
boolean isUser() default false;
}

View File

@ -1,23 +0,0 @@
package com.ruoyi.common.annotation;
import com.ruoyi.common.enums.DataSourceType;
import java.lang.annotation.*;
/**
* 自定义多数据源切换注解
* <p>
* 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准
*
* @author ruoyi
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface DataSource {
/**
* 切换数据源名称
*/
DataSourceType value() default DataSourceType.MASTER;
}

View File

@ -1,85 +0,0 @@
package com.ruoyi.common.captcha;
import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.core.math.Calculator;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.RandomUtil;
import com.ruoyi.common.utils.StringUtils;
/**
* 无符号计算生成器
*
* @author Lion Li
*/
public class UnsignedMathGenerator implements CodeGenerator {
private static final long serialVersionUID = -5514819971774091076L;
private static final String operators = "+-*";
/**
* 参与计算数字最大长度
*/
private final int numberLength;
/**
* 构造
*/
public UnsignedMathGenerator() {
this(2);
}
/**
* 构造
*
* @param numberLength 参与计算最大数字位数
*/
public UnsignedMathGenerator(int numberLength) {
this.numberLength = numberLength;
}
@Override
public String generate() {
final int limit = getLimit();
int min = RandomUtil.randomInt(limit);
int max = RandomUtil.randomInt(min, limit);
String number1 = Integer.toString(max);
String number2 = Integer.toString(min);
number1 = StringUtils.rightPad(number1, this.numberLength, CharUtil.SPACE);
number2 = StringUtils.rightPad(number2, this.numberLength, CharUtil.SPACE);
return number1 + RandomUtil.randomChar(operators) + number2 + '=';
}
@Override
public boolean verify(String code, String userInputCode) {
int result;
try {
result = Integer.parseInt(userInputCode);
} catch (NumberFormatException e) {
// 用户输入非数字
return false;
}
final int calculateResult = (int) Calculator.conversion(code);
return result == calculateResult;
}
/**
* 获取验证码长度
*
* @return 验证码长度
*/
public int getLength() {
return this.numberLength * 2 + 2;
}
/**
* 根据长度获取参与计算数字最大值
*
* @return 最大值
*/
private int getLimit() {
return Integer.parseInt("1" + StringUtils.repeat('0', this.numberLength));
}
}

View File

@ -1,136 +0,0 @@
package com.ruoyi.common.constant;
import io.jsonwebtoken.Claims;
/**
* 通用常量信息
*
* @author ruoyi
*/
public class Constants {
/**
* UTF-8 字符集
*/
public static final String UTF8 = "UTF-8";
/**
* GBK 字符集
*/
public static final String GBK = "GBK";
/**
* http请求
*/
public static final String HTTP = "http://";
/**
* https请求
*/
public static final String HTTPS = "https://";
/**
* 通用成功标识
*/
public static final String SUCCESS = "0";
/**
* 通用失败标识
*/
public static final String FAIL = "1";
/**
* 登录成功
*/
public static final String LOGIN_SUCCESS = "Success";
/**
* 注销
*/
public static final String LOGOUT = "Logout";
/**
* 注册
*/
public static final String REGISTER = "Register";
/**
* 登录失败
*/
public static final String LOGIN_FAIL = "Error";
/**
* 验证码 redis key
*/
public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
/**
* 登录用户 redis key
*/
public static final String LOGIN_TOKEN_KEY = "login_tokens:";
/**
* 防重提交 redis key
*/
public static final String REPEAT_SUBMIT_KEY = "repeat_submit:";
/**
* 限流 redis key
*/
public static final String RATE_LIMIT_KEY = "rate_limit:";
/**
* 验证码有效期(分钟)
*/
public static final Integer CAPTCHA_EXPIRATION = 2;
/**
* 令牌
*/
public static final String TOKEN = "token";
/**
* 令牌前缀
*/
public static final String TOKEN_PREFIX = "Bearer ";
/**
* 令牌前缀
*/
public static final String LOGIN_USER_KEY = "login_user_key";
/**
* 用户ID
*/
public static final String JWT_USERID = "userid";
/**
* 用户名称
*/
public static final String JWT_USERNAME = Claims.SUBJECT;
/**
* 用户头像
*/
public static final String JWT_AVATAR = "avatar";
/**
* 创建时间
*/
public static final String JWT_CREATED = "created";
/**
* 用户权限
*/
public static final String JWT_AUTHORITIES = "authorities";
/**
* 参数管理 cache key
*/
public static final String SYS_CONFIG_KEY = "sys_config:";
/**
* 字典管理 cache key
*/
public static final String SYS_DICT_KEY = "sys_dict:";
}

View File

@ -1,188 +0,0 @@
package com.ruoyi.common.constant;
/**
* 代码生成通用常量
*
* @author ruoyi
*/
public class GenConstants {
/**
* 单表(增删改查)
*/
public static final String TPL_CRUD = "crud";
/**
* 树表(增删改查)
*/
public static final String TPL_TREE = "tree";
/**
* 主子表(增删改查)
*/
public static final String TPL_SUB = "sub";
/**
* 树编码字段
*/
public static final String TREE_CODE = "treeCode";
/**
* 树父编码字段
*/
public static final String TREE_PARENT_CODE = "treeParentCode";
/**
* 树名称字段
*/
public static final String TREE_NAME = "treeName";
/**
* 上级菜单ID字段
*/
public static final String PARENT_MENU_ID = "parentMenuId";
/**
* 上级菜单名称字段
*/
public static final String PARENT_MENU_NAME = "parentMenuName";
/**
* 数据库字符串类型
*/
public static final String[] COLUMNTYPE_STR = {"char", "varchar", "nvarchar", "varchar2"};
/**
* 数据库文本类型
*/
public static final String[] COLUMNTYPE_TEXT = {"tinytext", "text", "mediumtext", "longtext"};
/**
* 数据库时间类型
*/
public static final String[] COLUMNTYPE_TIME = {"datetime", "time", "date", "timestamp"};
/**
* 数据库数字类型
*/
public static final String[] COLUMNTYPE_NUMBER = {"tinyint", "smallint", "mediumint", "int", "number", "integer",
"bit", "bigint", "float", "double", "decimal"};
/**
* BO对象 不需要添加字段
*/
public static final String[] COLUMNNAME_NOT_ADD = {"create_by", "create_time", "del_flag", "update_by",
"update_time", "version"};
/**
* BO对象 不需要编辑字段
*/
public static final String[] COLUMNNAME_NOT_EDIT = {"create_by", "create_time", "del_flag", "update_by",
"update_time", "version"};
/**
* VO对象 不需要返回字段
*/
public static final String[] COLUMNNAME_NOT_LIST = {"create_by", "create_time", "del_flag", "update_by",
"update_time", "version"};
/**
* BO对象 不需要查询字段
*/
public static final String[] COLUMNNAME_NOT_QUERY = {"id", "create_by", "create_time", "del_flag", "update_by",
"update_time", "remark", "version"};
/**
* Entity基类字段
*/
public static final String[] BASE_ENTITY = {"createBy", "createTime", "updateBy", "updateTime"};
/**
* Tree基类字段
*/
public static final String[] TREE_ENTITY = {"parentName", "parentId", "children"};
/**
* 文本框
*/
public static final String HTML_INPUT = "input";
/**
* 文本域
*/
public static final String HTML_TEXTAREA = "textarea";
/**
* 下拉框
*/
public static final String HTML_SELECT = "select";
/**
* 单选框
*/
public static final String HTML_RADIO = "radio";
/**
* 复选框
*/
public static final String HTML_CHECKBOX = "checkbox";
/**
* 日期控件
*/
public static final String HTML_DATETIME = "datetime";
/**
* 图片上传控件
*/
public static final String HTML_IMAGE_UPLOAD = "imageUpload";
/**
* 文件上传控件
*/
public static final String HTML_FILE_UPLOAD = "fileUpload";
/**
* 富文本控件
*/
public static final String HTML_EDITOR = "editor";
/**
* 字符串类型
*/
public static final String TYPE_STRING = "String";
/**
* 整型
*/
public static final String TYPE_INTEGER = "Integer";
/**
* 长整型
*/
public static final String TYPE_LONG = "Long";
/**
* 浮点型
*/
public static final String TYPE_DOUBLE = "Double";
/**
* 高精度计算类型
*/
public static final String TYPE_BIGDECIMAL = "BigDecimal";
/**
* 时间类型
*/
public static final String TYPE_DATE = "Date";
/**
* 模糊查询
*/
public static final String QUERY_LIKE = "LIKE";
/**
* 需要
*/
public static final String REQUIRE = "1";
}

View File

@ -1,112 +0,0 @@
package com.ruoyi.common.constant;
/**
* 用户常量信息
*
* @author ruoyi
*/
public class UserConstants {
/**
* 平台内系统用户的唯一标志
*/
public static final String SYS_USER = "SYS_USER";
/**
* 正常状态
*/
public static final String NORMAL = "0";
/**
* 异常状态
*/
public static final String EXCEPTION = "1";
/**
* 用户封禁状态
*/
public static final String USER_DISABLE = "1";
/**
* 角色封禁状态
*/
public static final String ROLE_DISABLE = "1";
/**
* 部门正常状态
*/
public static final String DEPT_NORMAL = "0";
/**
* 部门停用状态
*/
public static final String DEPT_DISABLE = "1";
/**
* 字典正常状态
*/
public static final String DICT_NORMAL = "0";
/**
* 是否为系统默认(是)
*/
public static final String YES = "Y";
/**
* 是否菜单外链(是)
*/
public static final String YES_FRAME = "0";
/**
* 是否菜单外链(否)
*/
public static final String NO_FRAME = "1";
/**
* 菜单类型(目录)
*/
public static final String TYPE_DIR = "M";
/**
* 菜单类型(菜单)
*/
public static final String TYPE_MENU = "C";
/**
* 菜单类型(按钮)
*/
public static final String TYPE_BUTTON = "F";
/**
* Layout组件标识
*/
public final static String LAYOUT = "Layout";
/**
* ParentView组件标识
*/
public final static String PARENT_VIEW = "ParentView";
/**
* InnerLink组件标识
*/
public final static String INNER_LINK = "InnerLink";
/**
* 校验返回结果码
*/
public final static String UNIQUE = "0";
public final static String NOT_UNIQUE = "1";
/**
* 用户名长度限制
*/
public static final int USERNAME_MIN_LENGTH = 2;
public static final int USERNAME_MAX_LENGTH = 20;
/**
* 密码长度限制
*/
public static final int PASSWORD_MIN_LENGTH = 5;
public static final int PASSWORD_MAX_LENGTH = 20;
}

View File

@ -1,51 +0,0 @@
package com.ruoyi.common.convert;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal;
/**
* 大数值转换
* Excel 数值长度位15位 大于15位的数值转换位字符串
*
* @author Lion Li
*/
@Slf4j
public class ExcelBigNumberConvert implements Converter<Long> {
@Override
public Class<Long> supportJavaTypeKey() {
return Long.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
@Override
public Long convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
return Convert.toLong(cellData.getData());
}
@Override
public CellData<Object> convertToExcelData(Long object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
if (ObjectUtil.isNotNull(object)) {
String str = Convert.toStr(object);
if (str.length() > 15) {
return new CellData<>(str);
}
}
CellData<Object> cellData = new CellData<>(new BigDecimal(object));
cellData.setType(CellDataTypeEnum.NUMBER);
return cellData;
}
}

View File

@ -1,71 +0,0 @@
package com.ruoyi.common.convert;
import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.convert.Convert;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.ruoyi.common.annotation.ExcelDictFormat;
import com.ruoyi.common.core.service.DictService;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.utils.spring.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Field;
/**
* 字典格式化转换处理
*
* @author Lion Li
*/
@Slf4j
public class ExcelDictConvert implements Converter<Object> {
@Override
public Class<Object> supportJavaTypeKey() {
return Object.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return null;
}
@Override
public Object convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
ExcelDictFormat anno = getAnnotation(contentProperty.getField());
String type = anno.dictType();
String label = cellData.getStringValue();
String value;
if (StringUtils.isBlank(type)) {
value = ExcelUtil.reverseByExp(label, anno.readConverterExp(), anno.separator());
} else {
value = SpringUtils.getBean(DictService.class).getDictValue(type, label, anno.separator());
}
return Convert.convert(contentProperty.getField().getType(), value);
}
@Override
public CellData<String> convertToExcelData(Object object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
if (StringUtils.isNull(object)) {
return new CellData<>("");
}
ExcelDictFormat anno = getAnnotation(contentProperty.getField());
String type = anno.dictType();
String value = Convert.toStr(object);
String label;
if (StringUtils.isBlank(type)) {
label = ExcelUtil.convertByExp(value, anno.readConverterExp(), anno.separator());
} else {
label = SpringUtils.getBean(DictService.class).getDictLabel(type, value, anno.separator());
}
return new CellData<>(label);
}
private ExcelDictFormat getAnnotation(Field field) {
return AnnotationUtil.getAnnotation(field, ExcelDictFormat.class);
}
}

View File

@ -1,97 +0,0 @@
package com.ruoyi.common.core.controller;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
/**
* web层通用数据处理
*
* @author ruoyi
*/
public class BaseController {
/**
* 返回成功
*/
public AjaxResult<Void> success() {
return AjaxResult.success();
}
/**
* 返回失败消息
*/
public AjaxResult<Void> error() {
return AjaxResult.error();
}
/**
* 返回成功消息
*/
public AjaxResult<Void> success(String message) {
return AjaxResult.success(message);
}
/**
* 返回失败消息
*/
public AjaxResult<Void> error(String message) {
return AjaxResult.error(message);
}
/**
* 响应返回结果
*
* @param rows 影响行数
* @return 操作结果
*/
protected AjaxResult<Void> toAjax(int rows) {
return rows > 0 ? AjaxResult.success() : AjaxResult.error();
}
/**
* 响应返回结果
*
* @param result 结果
* @return 操作结果
*/
protected AjaxResult<Void> toAjax(boolean result) {
return result ? success() : error();
}
/**
* 页面跳转
*/
public String redirect(String url) {
return StringUtils.format("redirect:{}", url);
}
/**
* 获取用户缓存信息
*/
public LoginUser getLoginUser() {
return SecurityUtils.getLoginUser();
}
/**
* 获取登录用户id
*/
public Long getUserId() {
return getLoginUser().getUserId();
}
/**
* 获取登录部门id
*/
public Long getDeptId() {
return getLoginUser().getDeptId();
}
/**
* 获取登录用户名
*/
public String getUsername() {
return getLoginUser().getUsername();
}
}

View File

@ -1,134 +0,0 @@
package com.ruoyi.common.core.domain;
import cn.hutool.http.HttpStatus;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
/**
* 操作消息提醒
*
* @author Lion Li
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@ApiModel("请求响应对象")
public class AjaxResult<T> {
private static final long serialVersionUID = 1L;
/**
* 状态码
*/
@ApiModelProperty("消息状态码")
private int code;
/**
* 返回内容
*/
@ApiModelProperty("消息内容")
private String msg;
/**
* 数据对象
*/
@ApiModelProperty("数据对象")
private T data;
/**
* 初始化一个新创建的 AjaxResult 对象
*
* @param code 状态码
* @param msg 返回内容
*/
public AjaxResult(int code, String msg) {
this.code = code;
this.msg = msg;
}
/**
* 返回成功消息
*
* @return 成功消息
*/
public static AjaxResult<Void> success() {
return AjaxResult.success("操作成功");
}
/**
* 返回成功数据
*
* @return 成功消息
*/
public static <T> AjaxResult<T> success(T data) {
return AjaxResult.success("操作成功", data);
}
/**
* 返回成功消息
*
* @param msg 返回内容
* @return 成功消息
*/
public static AjaxResult<Void> success(String msg) {
return AjaxResult.success(msg, null);
}
/**
* 返回成功消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 成功消息
*/
public static <T> AjaxResult<T> success(String msg, T data) {
return new AjaxResult<>(HttpStatus.HTTP_OK, msg, data);
}
/**
* 返回错误消息
*
* @return
*/
public static AjaxResult<Void> error() {
return AjaxResult.error("操作失败");
}
/**
* 返回错误消息
*
* @param msg 返回内容
* @return 警告消息
*/
public static AjaxResult<Void> error(String msg) {
return AjaxResult.error(msg, null);
}
/**
* 返回错误消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 警告消息
*/
public static <T> AjaxResult<T> error(String msg, T data) {
return new AjaxResult<>(HttpStatus.HTTP_INTERNAL_ERROR, msg, data);
}
/**
* 返回错误消息
*
* @param code 状态码
* @param msg 返回内容
* @return 警告消息
*/
public static AjaxResult<Void> error(int code, String msg) {
return new AjaxResult<>(code, msg, null);
}
}

View File

@ -1,68 +0,0 @@
package com.ruoyi.common.core.domain;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* Entity基类
*
* @author Lion Li
*/
@Data
@Accessors(chain = true)
public class BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 搜索值
*/
@ApiModelProperty(value = "搜索值")
@TableField(exist = false)
private String searchValue;
/**
* 创建者
*/
@ApiModelProperty(value = "创建者")
@TableField(fill = FieldFill.INSERT)
private String createBy;
/**
* 创建时间
*/
@ApiModelProperty(value = "创建时间")
@TableField(fill = FieldFill.INSERT)
private Date createTime;
/**
* 更新者
*/
@ApiModelProperty(value = "更新者")
@TableField(fill = FieldFill.INSERT_UPDATE)
private String updateBy;
/**
* 更新时间
*/
@ApiModelProperty(value = "更新时间")
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
/**
* 请求参数
*/
@ApiModelProperty(value = "请求参数")
@TableField(exist = false)
private Map<String, Object> params = new HashMap<>();
}

View File

@ -1,45 +0,0 @@
package com.ruoyi.common.core.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.util.ArrayList;
import java.util.List;
/**
* Tree基类
*
* @author Lion Li
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class TreeEntity extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 父菜单名称
*/
@TableField(exist = false)
@ApiModelProperty(value = "父菜单名称")
private String parentName;
/**
* 父菜单ID
*/
@ApiModelProperty(value = "父菜单ID")
private Long parentId;
/**
* 子部门
*/
@TableField(exist = false)
@ApiModelProperty(value = "子部门")
private List<?> children = new ArrayList<>();
}

View File

@ -1,93 +0,0 @@
package com.ruoyi.common.core.domain.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.core.domain.TreeEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
/**
* 部门表 sys_dept
*
* @author Lion Li
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("sys_dept")
@ApiModel("部门业务对象")
public class SysDept extends TreeEntity {
private static final long serialVersionUID = 1L;
/**
* 部门ID
*/
@ApiModelProperty(value = "部门id")
@TableId(value = "dept_id")
private Long deptId;
/**
* 部门名称
*/
@ApiModelProperty(value = "部门名称")
@NotBlank(message = "部门名称不能为空")
@Size(min = 0, max = 30, message = "部门名称长度不能超过30个字符")
private String deptName;
/**
* 显示顺序
*/
@ApiModelProperty(value = "显示顺序")
@NotBlank(message = "显示顺序不能为空")
private String orderNum;
/**
* 负责人
*/
@ApiModelProperty(value = "负责人")
private String leader;
/**
* 联系电话
*/
@ApiModelProperty(value = "联系电话")
@Size(min = 0, max = 11, message = "联系电话长度不能超过11个字符")
private String phone;
/**
* 邮箱
*/
@ApiModelProperty(value = "邮箱")
@Email(message = "邮箱格式不正确")
@Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")
private String email;
/**
* 部门状态:0正常,1停用
*/
@ApiModelProperty(value = "部门状态:0正常,1停用")
private String status;
/**
* 删除标志0代表存在 2代表删除
*/
@ApiModelProperty(value = "删除标志0代表存在 2代表删除")
@TableLogic
private String delFlag;
/**
* 祖级列表
*/
@ApiModelProperty(value = "祖级列表")
private String ancestors;
}

View File

@ -1,115 +0,0 @@
package com.ruoyi.common.core.domain.entity;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.annotation.ExcelDictFormat;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.convert.ExcelDictConvert;
import com.ruoyi.common.core.domain.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
/**
* 字典数据表 sys_dict_data
*
* @author Lion Li
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("sys_dict_data")
@ExcelIgnoreUnannotated
@ApiModel("字典数据业务对象")
public class SysDictData extends BaseEntity {
/**
* 字典编码
*/
@ApiModelProperty(value = "字典编码")
@ExcelProperty(value = "字典编码")
@TableId(value = "dict_code")
private Long dictCode;
/**
* 字典排序
*/
@ApiModelProperty(value = "字典排序")
@ExcelProperty(value = "字典排序")
private Long dictSort;
/**
* 字典标签
*/
@ApiModelProperty(value = "字典标签")
@ExcelProperty(value = "字典标签")
@NotBlank(message = "字典标签不能为空")
@Size(min = 0, max = 100, message = "字典标签长度不能超过100个字符")
private String dictLabel;
/**
* 字典键值
*/
@ApiModelProperty(value = "字典键值")
@ExcelProperty(value = "字典键值")
@NotBlank(message = "字典键值不能为空")
@Size(min = 0, max = 100, message = "字典键值长度不能超过100个字符")
private String dictValue;
/**
* 字典类型
*/
@ApiModelProperty(value = "字典类型")
@ExcelProperty(value = "字典类型")
@NotBlank(message = "字典类型不能为空")
@Size(min = 0, max = 100, message = "字典类型长度不能超过100个字符")
private String dictType;
/**
* 样式属性(其他样式扩展)
*/
@ApiModelProperty(value = "样式属性(其他样式扩展)")
@Size(min = 0, max = 100, message = "样式属性长度不能超过100个字符")
private String cssClass;
/**
* 表格字典样式
*/
@ApiModelProperty(value = "表格字典样式")
private String listClass;
/**
* 是否默认Y是 N否
*/
@ApiModelProperty(value = "是否默认Y是 N否")
@ExcelProperty(value = "是否默认", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "sys_yes_no")
private String isDefault;
/**
* 状态0正常 1停用
*/
@ApiModelProperty(value = "状态0正常 1停用")
@ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "sys_normal_disable")
private String status;
/**
* 备注
*/
@ApiModelProperty(value = "备注")
private String remark;
public boolean getDefault() {
return UserConstants.YES.equals(this.isDefault);
}
}

View File

@ -1,73 +0,0 @@
package com.ruoyi.common.core.domain.entity;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.annotation.ExcelDictFormat;
import com.ruoyi.common.convert.ExcelDictConvert;
import com.ruoyi.common.core.domain.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
/**
* 字典类型表 sys_dict_type
*
* @author Lion Li
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("sys_dict_type")
@ExcelIgnoreUnannotated
@ApiModel("字典类型业务对象")
public class SysDictType extends BaseEntity {
/**
* 字典主键
*/
@ApiModelProperty(value = "字典主键")
@ExcelProperty(value = "字典主键")
@TableId(value = "dict_id")
private Long dictId;
/**
* 字典名称
*/
@ApiModelProperty(value = "字典名称")
@ExcelProperty(value = "字典名称")
@NotBlank(message = "字典名称不能为空")
@Size(min = 0, max = 100, message = "字典类型名称长度不能超过100个字符")
private String dictName;
/**
* 字典类型
*/
@ApiModelProperty(value = "字典类型")
@ExcelProperty(value = "字典类型")
@NotBlank(message = "字典类型不能为空")
@Size(min = 0, max = 100, message = "字典类型类型长度不能超过100个字符")
private String dictType;
/**
* 状态0正常 1停用
*/
@ApiModelProperty(value = "状态0正常 1停用")
@ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "sys_normal_disable")
private String status;
/**
* 备注
*/
@ApiModelProperty(value = "备注")
private String remark;
}

View File

@ -1,120 +0,0 @@
package com.ruoyi.common.core.domain.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.core.domain.TreeEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
/**
* 菜单权限表 sys_menu
*
* @author Lion Li
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("sys_menu")
@ApiModel("菜单权限业务对象")
public class SysMenu extends TreeEntity {
/**
* 菜单ID
*/
@ApiModelProperty(value = "菜单ID")
@TableId(value = "menu_id")
private Long menuId;
/**
* 菜单名称
*/
@ApiModelProperty(value = "菜单名称")
@NotBlank(message = "菜单名称不能为空")
@Size(min = 0, max = 50, message = "菜单名称长度不能超过50个字符")
private String menuName;
/**
* 显示顺序
*/
@ApiModelProperty(value = "显示顺序")
@NotBlank(message = "显示顺序不能为空")
private String orderNum;
/**
* 路由地址
*/
@ApiModelProperty(value = "路由地址")
@Size(min = 0, max = 200, message = "路由地址不能超过200个字符")
private String path;
/**
* 组件路径
*/
@ApiModelProperty(value = "组件路径")
@Size(min = 0, max = 200, message = "组件路径不能超过255个字符")
private String component;
/**
* 路由参数
*/
@ApiModelProperty(value = "路由参数")
private String query;
/**
* 是否为外链0是 1否
*/
@ApiModelProperty(value = "是否为外链0是 1否")
private String isFrame;
/**
* 是否缓存0缓存 1不缓存
*/
@ApiModelProperty(value = "是否缓存0缓存 1不缓存")
private String isCache;
/**
* 类型M目录 C菜单 F按钮
*/
@ApiModelProperty(value = "类型M目录 C菜单 F按钮")
@NotBlank(message = "菜单类型不能为空")
private String menuType;
/**
* 显示状态0显示 1隐藏
*/
@ApiModelProperty(value = "显示状态0显示 1隐藏")
private String visible;
/**
* 菜单状态0显示 1隐藏
*/
@ApiModelProperty(value = "菜单状态0显示 1隐藏")
private String status;
/**
* 权限字符串
*/
@ApiModelProperty(value = "权限字符串")
@Size(min = 0, max = 100, message = "权限标识长度不能超过100个字符")
private String perms;
/**
* 菜单图标
*/
@ApiModelProperty(value = "菜单图标")
private String icon;
/**
* 备注
*/
@ApiModelProperty(value = "备注")
private String remark;
}

View File

@ -1,144 +0,0 @@
package com.ruoyi.common.core.domain.entity;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.annotation.ExcelDictFormat;
import com.ruoyi.common.convert.ExcelDictConvert;
import com.ruoyi.common.core.domain.BaseEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
/**
* 角色表 sys_role
*
* @author Lion Li
*/
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("sys_role")
@ExcelIgnoreUnannotated
public class SysRole extends BaseEntity {
/**
* 角色ID
*/
@ApiModelProperty(value = "角色ID")
@ExcelProperty(value = "角色序号")
@TableId(value = "role_id")
private Long roleId;
/**
* 角色名称
*/
@ApiModelProperty(value = "角色名称")
@ExcelProperty(value = "角色名称")
@NotBlank(message = "角色名称不能为空")
@Size(min = 0, max = 30, message = "角色名称长度不能超过30个字符")
private String roleName;
/**
* 角色权限
*/
@ApiModelProperty(value = "角色权限")
@ExcelProperty(value = "角色权限")
@NotBlank(message = "权限字符不能为空")
@Size(min = 0, max = 100, message = "权限字符长度不能超过100个字符")
private String roleKey;
/**
* 角色排序
*/
@ApiModelProperty(value = "角色排序")
@ExcelProperty(value = "角色排序")
@NotBlank(message = "显示顺序不能为空")
private String roleSort;
/**
* 数据范围1所有数据权限2自定义数据权限3本部门数据权限4本部门及以下数据权限5仅本人数据权限
*/
@ApiModelProperty(value = "数据范围1所有数据权限2自定义数据权限3本部门数据权限4本部门及以下数据权限5仅本人数据权限")
@ExcelProperty(value = "数据范围", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限")
private String dataScope;
/**
* 菜单树选择项是否关联显示( 0父子不互相关联显示 1父子互相关联显示
*/
@ApiModelProperty(value = "菜单树选择项是否关联显示( 0父子不互相关联显示 1父子互相关联显示")
private boolean menuCheckStrictly;
/**
* 部门树选择项是否关联显示0父子不互相关联显示 1父子互相关联显示
*/
@ApiModelProperty(value = "部门树选择项是否关联显示0父子不互相关联显示 1父子互相关联显示 ")
private boolean deptCheckStrictly;
/**
* 角色状态0正常 1停用
*/
@ApiModelProperty(value = "角色状态0正常 1停用")
@ExcelProperty(value = "角色状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "sys_common_status")
private String status;
/**
* 删除标志0代表存在 2代表删除
*/
@ApiModelProperty(value = "删除标志0代表存在 2代表删除")
@TableLogic
private String delFlag;
/**
* 备注
*/
@ApiModelProperty(value = "备注")
private String remark;
/**
* 用户是否存在此角色标识 默认不存在
*/
@ApiModelProperty(value = "用户是否存在此角色标识 默认不存在")
@TableField(exist = false)
private boolean flag = false;
/**
* 菜单组
*/
@ApiModelProperty(value = "菜单组")
@TableField(exist = false)
private Long[] menuIds;
/**
* 部门组(数据权限)
*/
@ApiModelProperty(value = "部门组(数据权限)")
@TableField(exist = false)
private Long[] deptIds;
public SysRole(Long roleId) {
this.roleId = roleId;
}
@ApiModelProperty(value = "是否管理员")
public boolean isAdmin() {
return isAdmin(this.roleId);
}
public static boolean isAdmin(Long roleId) {
return roleId != null && 1L == roleId;
}
}

View File

@ -1,184 +0,0 @@
package com.ruoyi.common.core.domain.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.ruoyi.common.core.domain.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.util.Date;
import java.util.List;
/**
* 用户对象 sys_user
*
* @author Lion Li
*/
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("sys_user")
@ApiModel("用户信息业务对象")
public class SysUser extends BaseEntity {
/**
* 用户ID
*/
@ApiModelProperty(value = "用户ID")
@TableId(value = "user_id")
private Long userId;
/**
* 部门ID
*/
@ApiModelProperty(value = "部门ID")
private Long deptId;
/**
* 用户账号
*/
@ApiModelProperty(value = "用户账号")
@NotBlank(message = "用户账号不能为空")
@Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符")
private String userName;
/**
* 用户昵称
*/
@ApiModelProperty(value = "用户昵称")
@Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符")
private String nickName;
/**
* 用户邮箱
*/
@ApiModelProperty(value = "用户邮箱")
@Email(message = "邮箱格式不正确")
@Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")
private String email;
/**
* 手机号码
*/
@ApiModelProperty(value = "手机号码")
private String phonenumber;
/**
* 用户性别
*/
@ApiModelProperty(value = "用户性别")
private String sex;
/**
* 用户头像
*/
@ApiModelProperty(value = "用户头像")
private String avatar;
/**
* 密码
*/
@ApiModelProperty(value = "密码")
@TableField(
insertStrategy = FieldStrategy.NOT_EMPTY,
updateStrategy = FieldStrategy.NOT_EMPTY,
whereStrategy = FieldStrategy.NOT_EMPTY
)
private String password;
@JsonIgnore
@JsonProperty
public String getPassword() {
return password;
}
/**
* 帐号状态0正常 1停用
*/
@ApiModelProperty(value = "帐号状态0正常 1停用")
private String status;
/**
* 删除标志0代表存在 2代表删除
*/
@ApiModelProperty(value = "删除标志0代表存在 2代表删除")
@TableLogic
private String delFlag;
/**
* 最后登录IP
*/
@ApiModelProperty(value = "最后登录IP")
private String loginIp;
/**
* 最后登录时间
*/
@ApiModelProperty(value = "最后登录时间")
private Date loginDate;
/**
* 备注
*/
@ApiModelProperty(value = "备注")
private String remark;
/**
* 部门对象
*/
@ApiModelProperty(value = "部门对象")
@TableField(exist = false)
private SysDept dept;
/**
* 角色对象
*/
@ApiModelProperty(value = "角色对象")
@TableField(exist = false)
private List<SysRole> roles;
/**
* 角色组
*/
@ApiModelProperty(value = "角色组")
@TableField(exist = false)
private Long[] roleIds;
/**
* 岗位组
*/
@ApiModelProperty(value = "岗位组")
@TableField(exist = false)
private Long[] postIds;
/**
* 角色ID
*/
@ApiModelProperty(value = "角色ID")
@TableField(exist = false)
private Long roleId;
public SysUser(Long userId) {
this.userId = userId;
}
@ApiModelProperty(value = "是否管理员")
public boolean isAdmin() {
return isAdmin(this.userId);
}
public static boolean isAdmin(Long userId) {
return userId != null && 1L == userId;
}
}

View File

@ -1,43 +0,0 @@
package com.ruoyi.common.core.domain.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 用户登录对象
*
* @author Lion Li
*/
@Data
@Accessors(chain = true)
@ApiModel("用户登录对象")
public class LoginBody {
/**
* 用户名
*/
@ApiModelProperty(value = "用户名")
private String username;
/**
* 用户密码
*/
@ApiModelProperty(value = "用户密码")
private String password;
/**
* 验证码
*/
@ApiModelProperty(value = "验证码")
private String code;
/**
* 唯一标识
*/
@ApiModelProperty(value = "唯一标识")
private String uuid = "";
}

View File

@ -1,151 +0,0 @@
package com.ruoyi.common.core.domain.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.Set;
/**
* 登录用户身份权限
*
* @author Lion Li
*/
@Data
@NoArgsConstructor
@Accessors(chain = true)
public class LoginUser implements UserDetails {
private static final long serialVersionUID = 1L;
/**
* 用户ID
*/
private Long userId;
/**
* 部门ID
*/
private Long deptId;
/**
* 用户唯一标识
*/
private String token;
/**
* 登录时间
*/
private Long loginTime;
/**
* 过期时间
*/
private Long expireTime;
/**
* 登录IP地址
*/
private String ipaddr;
/**
* 登录地点
*/
private String loginLocation;
/**
* 浏览器类型
*/
private String browser;
/**
* 操作系统
*/
private String os;
/**
* 权限列表
*/
private Set<String> permissions;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
public LoginUser(String username, String password, Set<String> permissions) {
this.username = username;
this.password = password;
this.permissions = permissions;
}
public LoginUser(Long userId, Long deptId, String username, String password, Set<String> permissions) {
this.userId = userId;
this.deptId = deptId;
this.username = username;
this.password = password;
this.permissions = permissions;
}
@JsonIgnore
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
/**
* 账户是否未过期,过期无法验证
*/
@JsonIgnore
@Override
public boolean isAccountNonExpired() {
return true;
}
/**
* 指定用户是否解锁,锁定的用户无法进行身份验证
*/
@JsonIgnore
@Override
public boolean isAccountNonLocked() {
return true;
}
/**
* 指示是否已过期的用户的凭据(密码),过期的凭据防止认证
*/
@JsonIgnore
@Override
public boolean isCredentialsNonExpired() {
return true;
}
/**
* 是否可用 ,禁用的用户不能身份验证
*/
@JsonIgnore
@Override
public boolean isEnabled() {
return true;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
}

View File

@ -1,21 +0,0 @@
package com.ruoyi.common.core.mybatisplus.core;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import java.util.Collection;
/**
* 自定义 Mapper 接口, 实现 自定义扩展
*
* @author Lion Li
* @since 2021-05-13
*/
public interface BaseMapperPlus<T> extends BaseMapper<T> {
/**
* 单sql批量插入( 全量填充 )
*/
int insertAll(@Param("list") Collection<T> batchList);
}

View File

@ -1,175 +0,0 @@
package com.ruoyi.common.core.mybatisplus.core;
import cn.hutool.core.bean.copier.CopyOptions;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.common.core.page.PagePlus;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
/**
* 自定义 Service 接口, 实现 数据库实体与 vo 对象转换返回
*
* @param <T> 数据实体类
* @param <V> vo类
* @author Lion Li
*/
public interface IServicePlus<T, V> extends IService<T> {
/**
* @param id 主键id
* @param copyOptions copy条件
* @return V对象
*/
V getVoById(Serializable id, CopyOptions copyOptions);
default V getVoById(Serializable id) {
return getVoById(id, new CopyOptions());
}
/**
* @param convertor 自定义转换器
*/
default V getVoById(Serializable id, Function<T, V> convertor) {
return convertor.apply(getById(id));
}
/**
* @param idList id列表
* @param copyOptions copy条件
* @return V对象
*/
List<V> listVoByIds(Collection<? extends Serializable> idList, CopyOptions copyOptions);
default List<V> listVoByIds(Collection<? extends Serializable> idList) {
return listVoByIds(idList, new CopyOptions());
}
/**
* @param convertor 自定义转换器
*/
default List<V> listVoByIds(Collection<? extends Serializable> idList,
Function<Collection<T>, List<V>> convertor) {
List<T> list = getBaseMapper().selectBatchIds(idList);
if (list == null) {
return null;
}
return convertor.apply(list);
}
/**
* @param columnMap 表字段 map 对象
* @param copyOptions copy条件
* @return V对象
*/
List<V> listVoByMap(Map<String, Object> columnMap, CopyOptions copyOptions);
default List<V> listVoByMap(Map<String, Object> columnMap) {
return listVoByMap(columnMap, new CopyOptions());
}
/**
* @param convertor 自定义转换器
*/
default List<V> listVoByMap(Map<String, Object> columnMap,
Function<Collection<T>, List<V>> convertor) {
List<T> list = getBaseMapper().selectByMap(columnMap);
if (list == null) {
return null;
}
return convertor.apply(list);
}
/**
* @param queryWrapper 查询条件
* @param copyOptions copy条件
* @return V对象
*/
V getVoOne(Wrapper<T> queryWrapper, CopyOptions copyOptions);
default V getVoOne(Wrapper<T> queryWrapper) {
return getVoOne(queryWrapper, new CopyOptions());
}
/**
* @param convertor 自定义转换器
*/
default V getVoOne(Wrapper<T> queryWrapper, Function<T, V> convertor) {
return convertor.apply(getOne(queryWrapper, true));
}
/**
* @param queryWrapper 查询条件
* @param copyOptions copy条件
* @return V对象
*/
List<V> listVo(Wrapper<T> queryWrapper, CopyOptions copyOptions);
default List<V> listVo(Wrapper<T> queryWrapper) {
return listVo(queryWrapper, new CopyOptions());
}
/**
* @param convertor 自定义转换器
*/
default List<V> listVo(Wrapper<T> queryWrapper, Function<Collection<T>, List<V>> convertor) {
List<T> list = getBaseMapper().selectList(queryWrapper);
if (list == null) {
return null;
}
return convertor.apply(list);
}
default List<V> listVo() {
return listVo(Wrappers.emptyWrapper());
}
/**
* @param convertor 自定义转换器
*/
default List<V> listVo(Function<Collection<T>, List<V>> convertor) {
return listVo(Wrappers.emptyWrapper(), convertor);
}
/**
* @param page 分页对象
* @param queryWrapper 查询条件
* @param copyOptions copy条件
* @return V对象
*/
PagePlus<T, V> pageVo(PagePlus<T, V> page, Wrapper<T> queryWrapper, CopyOptions copyOptions);
default PagePlus<T, V> pageVo(PagePlus<T, V> page, Wrapper<T> queryWrapper) {
return pageVo(page, queryWrapper, new CopyOptions());
}
/**
* @param convertor 自定义转换器
*/
default PagePlus<T, V> pageVo(PagePlus<T, V> page, Wrapper<T> queryWrapper,
Function<Collection<T>, List<V>> convertor) {
PagePlus<T, V> result = getBaseMapper().selectPage(page, queryWrapper);
return result.setRecordsVo(convertor.apply(result.getRecords()));
}
default PagePlus<T, V> pageVo(PagePlus<T, V> page) {
return pageVo(page, Wrappers.emptyWrapper());
}
/**
* @param convertor 自定义转换器
*/
default PagePlus<T, V> pageVo(PagePlus<T, V> page, Function<Collection<T>, List<V>> convertor) {
return pageVo(page, Wrappers.emptyWrapper(), convertor);
}
boolean saveAll(Collection<T> entityList);
boolean saveOrUpdateAll(Collection<T> entityList);
}

View File

@ -1,241 +0,0 @@
package com.ruoyi.common.core.mybatisplus.core;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.page.PagePlus;
import com.ruoyi.common.utils.BeanCopyUtils;
import com.ruoyi.common.utils.reflect.ReflectUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* IServicePlus 实现类
*
* @param <M> Mapper类
* @param <T> 数据实体类
* @param <V> vo类
* @author Lion Li
*/
@Slf4j
@SuppressWarnings("unchecked")
public class ServicePlusImpl<M extends BaseMapperPlus<T>, T, V> extends ServiceImpl<M, T> implements IServicePlus<T, V> {
@Autowired
protected M baseMapper;
@Override
public M getBaseMapper() {
return baseMapper;
}
protected Class<T> entityClass = currentModelClass();
@Override
public Class<T> getEntityClass() {
return entityClass;
}
protected Class<M> mapperClass = currentMapperClass();
protected Class<V> voClass = currentVoClass();
public Class<V> getVoClass() {
return voClass;
}
@Override
protected Class<M> currentMapperClass() {
return (Class<M>) ReflectionKit.getSuperClassGenericType(this.getClass(), ServicePlusImpl.class, 0);
}
@Override
protected Class<T> currentModelClass() {
return (Class<T>) ReflectionKit.getSuperClassGenericType(this.getClass(), ServicePlusImpl.class, 1);
}
protected Class<V> currentVoClass() {
return (Class<V>) ReflectionKit.getSuperClassGenericType(this.getClass(), ServicePlusImpl.class, 2);
}
/**
* 单条执行性能差 适用于列表对象内容不确定
*/
@Override
public boolean saveBatch(Collection<T> entityList, int batchSize) {
return super.saveBatch(entityList, batchSize);
}
@Override
public boolean saveOrUpdate(T entity) {
return super.saveOrUpdate(entity);
}
/**
* 单条执行性能差 适用于列表对象内容不确定
*/
@Override
public boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize) {
return super.saveOrUpdateBatch(entityList, batchSize);
}
@Override
public boolean updateBatchById(Collection<T> entityList, int batchSize) {
return super.updateBatchById(entityList, batchSize);
}
/**
* 单sql批量插入( 全量填充 无视数据库默认值 )
* 适用于无脑插入
*/
@Override
public boolean saveBatch(Collection<T> entityList) {
return saveBatch(entityList, DEFAULT_BATCH_SIZE);
}
@Override
public boolean saveOrUpdateBatch(Collection<T> entityList) {
return saveOrUpdateBatch(entityList, DEFAULT_BATCH_SIZE);
}
@Override
public boolean updateBatchById(Collection<T> entityList) {
return updateBatchById(entityList, DEFAULT_BATCH_SIZE);
}
/**
* 单sql批量插入( 全量填充 )
*/
@Override
public boolean saveAll(Collection<T> entityList) {
if (CollUtil.isEmpty(entityList)) {
return false;
}
return baseMapper.insertAll(entityList) == entityList.size();
}
/**
* 全量保存或更新 ( 按主键区分 )
*/
@Override
public boolean saveOrUpdateAll(Collection<T> entityList) {
if (CollUtil.isEmpty(entityList)) {
return false;
}
TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass);
Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!");
String keyProperty = tableInfo.getKeyProperty();
Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!");
List<T> addList = new ArrayList<>();
List<T> updateList = new ArrayList<>();
int row = 0;
for (T entity : entityList) {
Object id = ReflectUtils.invokeGetter(entity, keyProperty);
if (ObjectUtil.isNull(id)) {
addList.add(entity);
} else {
updateList.add(entity);
}
}
if (CollUtil.isNotEmpty(updateList) && updateBatchById(updateList)) {
row += updateList.size();
}
if (CollUtil.isNotEmpty(addList)) {
row += baseMapper.insertAll(addList);
}
return row == entityList.size();
}
/**
* 根据 ID 查询
*
* @param id 主键ID
*/
@Override
public V getVoById(Serializable id, CopyOptions copyOptions) {
T t = getBaseMapper().selectById(id);
return BeanCopyUtils.oneCopy(t, copyOptions, voClass);
}
/**
* 查询根据ID 批量查询)
*
* @param idList 主键ID列表
*/
@Override
public List<V> listVoByIds(Collection<? extends Serializable> idList, CopyOptions copyOptions) {
List<T> list = getBaseMapper().selectBatchIds(idList);
if (list == null) {
return null;
}
return BeanCopyUtils.listCopy(list, copyOptions, voClass);
}
/**
* 查询(根据 columnMap 条件)
*
* @param columnMap 表字段 map 对象
*/
@Override
public List<V> listVoByMap(Map<String, Object> columnMap, CopyOptions copyOptions) {
List<T> list = getBaseMapper().selectByMap(columnMap);
if (list == null) {
return null;
}
return BeanCopyUtils.listCopy(list, copyOptions, voClass);
}
/**
* 根据 Wrapper查询一条记录 <br/>
* <p>结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")</p>
*
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
*/
@Override
public V getVoOne(Wrapper<T> queryWrapper, CopyOptions copyOptions) {
T t = getOne(queryWrapper, true);
return BeanCopyUtils.oneCopy(t, copyOptions, voClass);
}
/**
* 查询列表
*
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
*/
@Override
public List<V> listVo(Wrapper<T> queryWrapper, CopyOptions copyOptions) {
List<T> list = getBaseMapper().selectList(queryWrapper);
if (list == null) {
return null;
}
return BeanCopyUtils.listCopy(list, copyOptions, voClass);
}
/**
* 翻页查询
*
* @param page 翻页对象
* @param queryWrapper 实体对象封装操作类
*/
@Override
public PagePlus<T, V> pageVo(PagePlus<T, V> page, Wrapper<T> queryWrapper, CopyOptions copyOptions) {
PagePlus<T, V> result = getBaseMapper().selectPage(page, queryWrapper);
List<V> volist = BeanCopyUtils.listCopy(result.getRecords(), copyOptions, voClass);
result.setRecordsVo(volist);
return result;
}
}

View File

@ -1,101 +0,0 @@
package com.ruoyi.common.core.mybatisplus.methods;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.ruoyi.common.utils.StringUtils;
import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
import java.util.List;
/**
* 单sql批量插入( 全量填充 )
*
* @author Lion Li
*/
public class InsertAll extends AbstractMethod {
private final static String[] FILL_PROPERTY = {"createTime", "createBy", "updateTime", "updateBy"};
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
final String sql = "<script>insert into %s %s values %s</script>";
final String fieldSql = prepareFieldSql(tableInfo);
final String valueSql = prepareValuesSqlForMysqlBatch(tableInfo);
KeyGenerator keyGenerator = new NoKeyGenerator();
String sqlMethod = "insertAll";
String keyProperty = null;
String keyColumn = null;
// 表包含主键处理逻辑,如果不包含主键当普通字段处理
if (StringUtils.isNotBlank(tableInfo.getKeyProperty())) {
if (tableInfo.getIdType() == IdType.AUTO) {
/** 自增主键 */
keyGenerator = new Jdbc3KeyGenerator();
keyProperty = tableInfo.getKeyProperty();
keyColumn = tableInfo.getKeyColumn();
} else {
if (null != tableInfo.getKeySequence()) {
keyGenerator = TableInfoHelper.genKeyGenerator(sqlMethod, tableInfo, builderAssistant);
keyProperty = tableInfo.getKeyProperty();
keyColumn = tableInfo.getKeyColumn();
}
}
}
final String sqlResult = String.format(sql, tableInfo.getTableName(), fieldSql, valueSql);
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlResult, modelClass);
return this.addInsertMappedStatement(mapperClass, modelClass, sqlMethod, sqlSource, keyGenerator, keyProperty, keyColumn);
}
private String prepareFieldSql(TableInfo tableInfo) {
StringBuilder fieldSql = new StringBuilder();
if (StringUtils.isNotBlank(tableInfo.getKeyColumn())) {
fieldSql.append(tableInfo.getKeyColumn()).append(",");
}
tableInfo.getFieldList().forEach(x -> fieldSql.append(x.getColumn()).append(","));
fieldSql.delete(fieldSql.length() - 1, fieldSql.length());
fieldSql.insert(0, "(");
fieldSql.append(")");
return fieldSql.toString();
}
private String prepareValuesSqlForMysqlBatch(TableInfo tableInfo) {
final StringBuilder valueSql = new StringBuilder();
valueSql.append("<foreach collection=\"list\" item=\"item\" index=\"index\" open=\"(\" separator=\"),(\" close=\")\">");
if (StringUtils.isNotBlank(tableInfo.getKeyColumn())) {
valueSql.append("\n#{item.").append(tableInfo.getKeyProperty()).append("},\n");
}
List<TableFieldInfo> fieldList = tableInfo.getFieldList();
int last = fieldList.size() - 1;
for (int i = 0; i < fieldList.size(); i++) {
String property = fieldList.get(i).getProperty();
if (!StringUtils.equalsAny(property, FILL_PROPERTY)) {
valueSql.append("<if test=\"item.").append(property).append(" != null\">");
valueSql.append("#{item.").append(property).append("}");
if (i != last) {
valueSql.append(",");
}
valueSql.append("</if>");
valueSql.append("<if test=\"item.").append(property).append(" == null\">");
valueSql.append("DEFAULT");
if (i != last) {
valueSql.append(",");
}
valueSql.append("</if>");
} else {
valueSql.append("#{item.").append(property).append("}");
if (i != last) {
valueSql.append(",");
}
}
}
valueSql.append("</foreach>");
return valueSql.toString();
}
}

View File

@ -1,156 +0,0 @@
package com.ruoyi.common.core.page;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* 分页 Page 增强对象
*
* @param <T> 数据库实体
* @param <K> vo实体
* @author Lion Li
*/
@Data
@Accessors(chain = true)
public class PagePlus<T,K> implements IPage<T> {
/**
* domain实体列表
*/
private List<T> records = Collections.emptyList();
/**
* vo实体列表
*/
private List<K> recordsVo = Collections.emptyList();
/**
* 总数
*/
private long total = 0L;
/**
* 页长度
*/
private long size = 10L;
/**
* 当前页
*/
private long current = 1L;
/**
* 排序字段信息
*/
private List<OrderItem> orders = new ArrayList<>();
/**
* 自动优化 COUNT SQL
*/
private boolean optimizeCountSql = true;
/**
* 是否进行 count 查询
*/
private boolean isSearchCount = true;
/**
* 是否命中count缓存
*/
private boolean hitCount = false;
/**
* countId
*/
private String countId;
/**
* 最大limit
*/
private Long maxLimit;
public PagePlus() {
}
public PagePlus(long current, long size) {
this(current, size, 0L);
}
public PagePlus(long current, long size, long total) {
this(current, size, total, true);
}
public PagePlus(long current, long size, boolean isSearchCount) {
this(current, size, 0L, isSearchCount);
}
public PagePlus(long current, long size, long total, boolean isSearchCount) {
if (current > 1L) {
this.current = current;
}
this.size = size;
this.total = total;
this.isSearchCount = isSearchCount;
}
@Override
public String countId() {
return this.getCountId();
}
@Override
public Long maxLimit() {
return this.getMaxLimit();
}
public PagePlus<T, K> addOrder(OrderItem... items) {
this.orders.addAll(Arrays.asList(items));
return this;
}
public PagePlus<T, K> addOrder(List<OrderItem> items) {
this.orders.addAll(items);
return this;
}
@Override
public List<OrderItem> orders() {
return this.getOrders();
}
@Override
public boolean optimizeCountSql() {
return this.optimizeCountSql;
}
@Override
public long getPages() {
// 解决 github issues/3208
return IPage.super.getPages();
}
public static <T,K> PagePlus<T,K> of(long current, long size) {
return of(current, size, 0);
}
public static <T,K> PagePlus<T,K> of(long current, long size, long total) {
return of(current, size, total, true);
}
public static <T,K> PagePlus<T,K> of(long current, long size, boolean searchCount) {
return of(current, size, 0, searchCount);
}
public static <T,K> PagePlus<T,K> of(long current, long size, long total, boolean searchCount) {
return new PagePlus<>(current, size, total, searchCount);
}
}

View File

@ -1,60 +0,0 @@
package com.ruoyi.common.core.page;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
/**
* 表格分页数据对象
*
* @author Lion Li
*/
@Data
@NoArgsConstructor
@Accessors(chain = true)
@ApiModel("分页响应对象")
public class TableDataInfo<T> implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 总记录数
*/
@ApiModelProperty("总记录数")
private long total;
/**
* 列表数据
*/
@ApiModelProperty("列表数据")
private List<T> rows;
/**
* 消息状态码
*/
@ApiModelProperty("消息状态码")
private int code;
/**
* 消息内容
*/
@ApiModelProperty("消息内容")
private String msg;
/**
* 分页
*
* @param list 列表数据
* @param total 总记录数
*/
public TableDataInfo(List<T> list, long total) {
this.rows = list;
this.total = total;
}
}

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,69 +0,0 @@
package com.ruoyi.common.core.service;
import com.ruoyi.common.core.domain.model.LoginUser;
import javax.servlet.http.HttpServletRequest;
/**
* token验证处理
*
* @author Lion Li
*/
public interface TokenService {
/**
* 获取用户身份信息
*
* @return 用户信息
*/
LoginUser getLoginUser(HttpServletRequest request);
/**
* 设置用户身份信息
*/
void setLoginUser(LoginUser loginUser);
/**
* 删除用户身份信息
*/
void delLoginUser(String token);
/**
* 创建令牌
*
* @param loginUser 用户信息
* @return 令牌
*/
String createToken(LoginUser loginUser);
/**
* 验证令牌有效期相差不足20分钟自动刷新缓存
*
* @param loginUser
* @return 令牌
*/
void verifyToken(LoginUser loginUser);
/**
* 刷新令牌有效期
*
* @param loginUser 登录信息
*/
void refreshToken(LoginUser loginUser);
/**
* 设置用户代理信息
*
* @param loginUser 登录信息
*/
void setUserAgent(LoginUser loginUser);
/**
* 从令牌中获取用户名
*
* @param token 令牌
* @return 用户名
*/
String getUsernameFromToken(String token);
}

View File

@ -1,28 +0,0 @@
package com.ruoyi.common.core.service;
import com.ruoyi.common.core.domain.entity.SysUser;
/**
* 通用 用户业务
*
* @author Lion Li
*/
public interface UserService {
/**
* 通过用户名查询用户
*
* @param userName 用户名
* @return 用户对象信息
*/
SysUser selectUserByUserName(String userName);
/**
* 通过用户ID查询用户
*
* @param userId 用户ID
* @return 用户对象信息
*/
SysUser selectUserById(Long userId);
}

View File

@ -1,25 +0,0 @@
package com.ruoyi.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 数据源
*
* @author Lion Li
*/
@AllArgsConstructor
public enum DataSourceType {
/**
* 主库
*/
MASTER("master"),
/**
* 从库
*/
SLAVE("slave");
@Getter
private final String source;
}

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,31 +0,0 @@
package com.ruoyi.common.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* token 配置属性
*
* @author Lion Li
*/
@Data
@Component
@ConfigurationProperties(prefix = "token")
public class TokenProperties {
/**
* 令牌自定义标识
*/
private String header;
/**
* 令牌秘钥
*/
private String secret;
/**
* 令牌有效期默认30分钟
*/
private int expireTime;
}

View File

@ -1,66 +0,0 @@
package com.ruoyi.common.utils;
import cn.hutool.core.bean.copier.BeanCopier;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import java.util.List;
import java.util.stream.Collectors;
/**
* bean深拷贝工具
*
* @author Lion Li
*/
public class BeanCopyUtils {
/**
* 单对象基于class创建拷贝
*
* @param source 数据来源实体
* @param copyOptions copy条件
* @param desc 描述对象 转换后的对象
* @return desc
*/
public static <T, V> V oneCopy(T source, CopyOptions copyOptions, Class<V> desc) {
V v = ReflectUtil.newInstanceIfPossible(desc);
return oneCopy(source, copyOptions, v);
}
/**
* 单对象基于对象创建拷贝
*
* @param source 数据来源实体
* @param copyOptions copy条件
* @param desc 转换后的对象
* @return desc
*/
public static <T, V> V oneCopy(T source, CopyOptions copyOptions, V desc) {
if (ObjectUtil.isNull(source)) {
return null;
}
return BeanCopier.create(source, desc, copyOptions).copy();
}
/**
* 列表对象基于class创建拷贝
*
* @param sourceList 数据来源实体列表
* @param copyOptions copy条件
* @param desc 描述对象 转换后的对象
* @return desc
*/
public static <T, V> List<V> listCopy(List<T> sourceList, CopyOptions copyOptions, Class<V> desc) {
if (ObjectUtil.isNull(sourceList)) {
return null;
}
if (CollUtil.isEmpty(sourceList)) {
return CollUtil.newArrayList();
}
return sourceList.stream()
.map(source -> oneCopy(source, copyOptions, desc))
.collect(Collectors.toList());
}
}

View File

@ -1,158 +0,0 @@
package com.ruoyi.common.utils;
import cn.hutool.core.collection.CollUtil;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysDictData;
import java.util.Collection;
import java.util.List;
/**
* 字典工具类
*
* @author ruoyi
* @deprecated 3.5.0 版本删除 迁移至 {@link com.ruoyi.common.core.service.DictService}
*/
@Deprecated
public class DictUtils {
/**
* 分隔符
*/
public static final String SEPARATOR = ",";
/**
* 设置字典缓存
*
* @param key 参数键
* @param dictDatas 字典数据列表
*/
public static void setDictCache(String key, List<SysDictData> dictDatas) {
RedisUtils.setCacheObject(getCacheKey(key), dictDatas);
}
/**
* 获取字典缓存
*
* @param key 参数键
* @return dictDatas 字典数据列表
*/
public static List<SysDictData> getDictCache(String key) {
List<SysDictData> dictDatas = RedisUtils.getCacheObject(getCacheKey(key));
if (StringUtils.isNotNull(dictDatas)) {
return dictDatas;
}
return null;
}
/**
* 根据字典类型和字典值获取字典标签
*
* @param dictType 字典类型
* @param dictValue 字典值
* @return 字典标签
*/
public static String getDictLabel(String dictType, String dictValue) {
return getDictLabel(dictType, dictValue, SEPARATOR);
}
/**
* 根据字典类型和字典标签获取字典值
*
* @param dictType 字典类型
* @param dictLabel 字典标签
* @return 字典值
*/
public static String getDictValue(String dictType, String dictLabel) {
return getDictValue(dictType, dictLabel, SEPARATOR);
}
/**
* 根据字典类型和字典值获取字典标签
*
* @param dictType 字典类型
* @param dictValue 字典值
* @param separator 分隔符
* @return 字典标签
*/
public static String getDictLabel(String dictType, String dictValue, String separator) {
StringBuilder propertyString = new StringBuilder();
List<SysDictData> datas = getDictCache(dictType);
if (StringUtils.containsAny(dictValue, separator) && CollUtil.isNotEmpty(datas)) {
for (SysDictData dict : datas) {
for (String value : dictValue.split(separator)) {
if (value.equals(dict.getDictValue())) {
propertyString.append(dict.getDictLabel() + separator);
break;
}
}
}
} else {
for (SysDictData dict : datas) {
if (dictValue.equals(dict.getDictValue())) {
return dict.getDictLabel();
}
}
}
return StringUtils.stripEnd(propertyString.toString(), separator);
}
/**
* 根据字典类型和字典标签获取字典值
*
* @param dictType 字典类型
* @param dictLabel 字典标签
* @param separator 分隔符
* @return 字典值
*/
public static String getDictValue(String dictType, String dictLabel, String separator) {
StringBuilder propertyString = new StringBuilder();
List<SysDictData> datas = getDictCache(dictType);
if (StringUtils.containsAny(dictLabel, separator) && CollUtil.isNotEmpty(datas)) {
for (SysDictData dict : datas) {
for (String label : dictLabel.split(separator)) {
if (label.equals(dict.getDictLabel())) {
propertyString.append(dict.getDictValue() + separator);
break;
}
}
}
} else {
for (SysDictData dict : datas) {
if (dictLabel.equals(dict.getDictLabel())) {
return dict.getDictValue();
}
}
}
return StringUtils.stripEnd(propertyString.toString(), separator);
}
/**
* 删除指定字典缓存
*
* @param key 字典键
*/
public static void removeDictCache(String key) {
RedisUtils.deleteObject(getCacheKey(key));
}
/**
* 清空字典缓存
*/
public static void clearDictCache() {
Collection<String> keys = RedisUtils.keys(Constants.SYS_DICT_KEY + "*");
RedisUtils.deleteObject(keys);
}
/**
* 设置cache key
*
* @param configKey 参数键
* @return 缓存键key
*/
public static String getCacheKey(String configKey) {
return Constants.SYS_DICT_KEY + configKey;
}
}

View File

@ -1,152 +0,0 @@
package com.ruoyi.common.utils;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpStatus;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.page.PagePlus;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.utils.sql.SqlUtil;
import java.util.List;
/**
* 分页工具
*
* @author Lion Li
*/
public class PageUtils {
/**
* 当前记录起始索引
*/
public static final String PAGE_NUM = "pageNum";
/**
* 每页显示记录数
*/
public static final String PAGE_SIZE = "pageSize";
/**
* 排序列
*/
public static final String ORDER_BY_COLUMN = "orderByColumn";
/**
* 排序的方向 "desc" 或者 "asc".
*/
public static final String IS_ASC = "isAsc";
/**
* 当前记录起始索引 默认值
*/
public static final int DEFAULT_PAGE_NUM = 1;
/**
* 每页显示记录数 默认值 默认查全部
*/
public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE;
/**
* 构建 plus 分页对象
*
* @param <T> domain 实体
* @param <K> vo 实体
* @return 分页对象
*/
public static <T, K> PagePlus<T, K> buildPagePlus() {
Integer pageNum = ServletUtils.getParameterToInt(PAGE_NUM, DEFAULT_PAGE_NUM);
Integer pageSize = ServletUtils.getParameterToInt(PAGE_SIZE, DEFAULT_PAGE_SIZE);
String orderByColumn = ServletUtils.getParameter(ORDER_BY_COLUMN);
String isAsc = ServletUtils.getParameter(IS_ASC);
if (pageNum <= 0) {
pageNum = DEFAULT_PAGE_NUM;
}
PagePlus<T, K> page = new PagePlus<>(pageNum, pageSize);
OrderItem orderItem = buildOrderItem(orderByColumn, isAsc);
if (ObjectUtil.isNotNull(orderItem)) {
page.addOrder(orderItem);
}
return page;
}
public static <T> Page<T> buildPage() {
return buildPage(null, null);
}
/**
* 构建 MP 普通分页对象
*
* @param <T> domain 实体
* @return 分页对象
*/
public static <T> Page<T> buildPage(String defaultOrderByColumn, String defaultIsAsc) {
Integer pageNum = ServletUtils.getParameterToInt(PAGE_NUM, DEFAULT_PAGE_NUM);
Integer pageSize = ServletUtils.getParameterToInt(PAGE_SIZE, DEFAULT_PAGE_SIZE);
String orderByColumn = ServletUtils.getParameter(ORDER_BY_COLUMN, defaultOrderByColumn);
String isAsc = ServletUtils.getParameter(IS_ASC, defaultIsAsc);
if (pageNum <= 0) {
pageNum = DEFAULT_PAGE_NUM;
}
Page<T> page = new Page<>(pageNum, pageSize);
OrderItem orderItem = buildOrderItem(orderByColumn, isAsc);
if (ObjectUtil.isNotNull(orderItem)) {
page.addOrder(orderItem);
}
return page;
}
private static OrderItem buildOrderItem(String orderByColumn, String isAsc) {
// 兼容前端排序类型
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;
}
public static <T, K> TableDataInfo<K> buildDataInfo(PagePlus<T, K> page) {
TableDataInfo<K> rspData = new TableDataInfo<>();
rspData.setCode(HttpStatus.HTTP_OK);
rspData.setMsg("查询成功");
rspData.setRows(page.getRecordsVo());
rspData.setTotal(page.getTotal());
return rspData;
}
public static <T> TableDataInfo<T> buildDataInfo(Page<T> page) {
TableDataInfo<T> rspData = new TableDataInfo<>();
rspData.setCode(HttpStatus.HTTP_OK);
rspData.setMsg("查询成功");
rspData.setRows(page.getRecords());
rspData.setTotal(page.getTotal());
return rspData;
}
public static <T> TableDataInfo<T> buildDataInfo(List<T> list) {
TableDataInfo<T> rspData = new TableDataInfo<>();
rspData.setCode(HttpStatus.HTTP_OK);
rspData.setMsg("查询成功");
rspData.setRows(list);
rspData.setTotal(list.size());
return rspData;
}
public static <T> TableDataInfo<T> buildDataInfo() {
TableDataInfo<T> rspData = new TableDataInfo<>();
rspData.setCode(HttpStatus.HTTP_OK);
rspData.setMsg("查询成功");
return rspData;
}
}

View File

@ -1,100 +0,0 @@
package com.ruoyi.common.utils;
import cn.hutool.http.HttpStatus;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.exception.ServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
* 安全服务工具类
*
* @author ruoyi
*/
public class SecurityUtils {
/**
* 用户ID
**/
public static Long getUserId() {
try {
return getLoginUser().getUserId();
} catch (Exception e) {
throw new ServiceException("获取用户ID异常", HttpStatus.HTTP_UNAUTHORIZED);
}
}
/**
* 获取部门ID
**/
public static Long getDeptId() {
try {
return getLoginUser().getDeptId();
} catch (Exception e) {
throw new ServiceException("获取部门ID异常", HttpStatus.HTTP_UNAUTHORIZED);
}
}
/**
* 获取用户账户
**/
public static String getUsername() {
try {
return getLoginUser().getUsername();
} catch (Exception e) {
throw new ServiceException("获取用户账户异常", HttpStatus.HTTP_UNAUTHORIZED);
}
}
/**
* 获取用户
**/
public static LoginUser getLoginUser() {
try {
return (LoginUser) getAuthentication().getPrincipal();
} catch (Exception e) {
throw new ServiceException("获取用户信息异常", HttpStatus.HTTP_UNAUTHORIZED);
}
}
/**
* 获取Authentication
*/
public static Authentication getAuthentication() {
return SecurityContextHolder.getContext().getAuthentication();
}
/**
* 生成BCryptPasswordEncoder密码
*
* @param password 密码
* @return 加密字符串
*/
public static String encryptPassword(String password) {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
return passwordEncoder.encode(password);
}
/**
* 判断密码是否相同
*
* @param rawPassword 真实密码
* @param encodedPassword 加密后字符
* @return 结果
*/
public static boolean matchesPassword(String rawPassword, String encodedPassword) {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
return passwordEncoder.matches(rawPassword, encodedPassword);
}
/**
* 是否为管理员
*
* @param userId 用户ID
* @return 结果
*/
public static boolean isAdmin(Long userId) {
return userId != null && 1L == userId;
}
}

View File

@ -1,354 +0,0 @@
package com.ruoyi.common.utils;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import java.util.*;
/**
* 字符串工具类
*
* @author Lion Li
*/
public class StringUtils extends org.apache.commons.lang3.StringUtils {
/**
* 获取参数不为空值
*
* @param value defaultValue 要判断的value
* @return value 返回值
*/
public static <T> T nvl(T value, T defaultValue) {
return ObjectUtil.defaultIfNull(value, defaultValue);
}
/**
* 获取参数不为空值
*
* @param str defaultValue 要判断的value
* @return value 返回值
*/
public static String blankToDefault(String str, String defaultValue) {
return StrUtil.blankToDefault(str, defaultValue);
}
/**
* * 判断一个Collection是否为空 包含ListSetQueue
*
* @param coll 要判断的Collection
* @return true为空 false非空
*/
public static boolean isEmpty(Collection<?> coll) {
return CollUtil.isEmpty(coll);
}
/**
* * 判断一个Collection是否非空包含ListSetQueue
*
* @param coll 要判断的Collection
* @return true非空 false
*/
public static boolean isNotEmpty(Collection<?> coll) {
return !isEmpty(coll);
}
/**
* * 判断一个对象数组是否为空
*
* @param objects 要判断的对象数组
* * @return true为空 false非空
*/
public static boolean isEmpty(Object[] objects) {
return ArrayUtil.isEmpty(objects);
}
/**
* * 判断一个对象数组是否非空
*
* @param objects 要判断的对象数组
* @return true非空 false
*/
public static boolean isNotEmpty(Object[] objects) {
return !isEmpty(objects);
}
/**
* * 判断一个对象是否为空
*
* @param object 要判断的对象数组
* * @return true为空 false非空
*/
public static boolean isEmpty(Object object) {
return ObjectUtil.isEmpty(object);
}
/**
* * 判断一个对象是否非空
*
* @param object 要判断的对象数组
* @return true非空 false
*/
public static boolean isNotEmpty(Object object) {
return !isEmpty(object);
}
/**
* * 判断一个Map是否为空
*
* @param map 要判断的Map
* @return true为空 false非空
*/
public static boolean isEmpty(Map<?, ?> map) {
return MapUtil.isEmpty(map);
}
/**
* * 判断一个Map是否为空
*
* @param map 要判断的Map
* @return true非空 false
*/
public static boolean isNotEmpty(Map<?, ?> map) {
return !isEmpty(map);
}
/**
* * 判断一个字符串是否为空串
*
* @param str String
* @return true为空 false非空
*/
public static boolean isEmpty(String str) {
return StrUtil.isEmpty(str);
}
/**
* * 判断一个字符串是否为非空串
*
* @param str String
* @return true非空串 false空串
*/
public static boolean isNotEmpty(String str) {
return !isEmpty(str);
}
/**
* * 判断一个对象是否为空
*
* @param object Object
* @return true为空 false非空
*/
public static boolean isNull(Object object) {
return ObjectUtil.isNull(object);
}
/**
* * 判断一个对象是否非空
*
* @param object Object
* @return true非空 false
*/
public static boolean isNotNull(Object object) {
return !isNull(object);
}
/**
* * 判断一个对象是否是数组类型Java基本型别的数组
*
* @param object 对象
* @return true是数组 false不是数组
*/
public static boolean isArray(Object object) {
return ArrayUtil.isArray(object);
}
/**
* 去空格
*/
public static String trim(String str) {
return StrUtil.trim(str);
}
/**
* 截取字符串
*
* @param str 字符串
* @param start 开始
* @return 结果
*/
public static String substring(final String str, int start) {
return substring(str, start, str.length());
}
/**
* 截取字符串
*
* @param str 字符串
* @param start 开始
* @param end 结束
* @return 结果
*/
public static String substring(final String str, int start, int end) {
return StrUtil.sub(str, start, end);
}
/**
* 格式化文本, {} 表示占位符<br>
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
* 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
* 例:<br>
* 通常使用format("this is {} for {}", "a", "b") -> this is a for b<br>
* 转义{} format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
* 转义\ format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
*
* @param template 文本模板,被替换的部分用 {} 表示
* @param params 参数值
* @return 格式化后的文本
*/
public static String format(String template, Object... params) {
return StrUtil.format(template, params);
}
/**
* 是否为http(s)://开头
*
* @param link 链接
* @return 结果
*/
public static boolean ishttp(String link) {
return Validator.isUrl(link);
}
/**
* 字符串转set
*
* @param str 字符串
* @param sep 分隔符
* @return set集合
*/
public static Set<String> str2Set(String str, String sep) {
return new HashSet<>(str2List(str, sep, true, false));
}
/**
* 字符串转list
*
* @param str 字符串
* @param sep 分隔符
* @param filterBlank 过滤纯空白
* @param trim 去掉首尾空白
* @return list集合
*/
public static List<String> str2List(String str, String sep, boolean filterBlank, boolean trim) {
List<String> list = new ArrayList<>();
if (isEmpty(str)) {
return list;
}
// 过滤空白字符串
if (filterBlank && isBlank(str)) {
return list;
}
String[] split = str.split(sep);
for (String string : split) {
if (filterBlank && isBlank(string)) {
continue;
}
if (trim) {
string = trim(string);
}
list.add(string);
}
return list;
}
/**
* 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写
*
* @param cs 指定字符串
* @param searchCharSequences 需要检查的字符串数组
* @return 是否包含任意一个字符串
*/
public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences) {
return StrUtil.containsAnyIgnoreCase(cs, searchCharSequences);
}
/**
* 驼峰转下划线命名
*/
public static String toUnderScoreCase(String str) {
return StrUtil.toUnderlineCase(str);
}
/**
* 是否包含字符串
*
* @param str 验证字符串
* @param strs 字符串组
* @return 包含返回true
*/
public static boolean inStringIgnoreCase(String str, String... strs) {
return StrUtil.equalsAnyIgnoreCase(str, strs);
}
/**
* 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如HELLO_WORLD->HelloWorld
*
* @param name 转换前的下划线大写方式命名的字符串
* @return 转换后的驼峰式命名的字符串
*/
public static String convertToCamelCase(String name) {
return StrUtil.upperFirst(StrUtil.toCamelCase(name));
}
/**
* 驼峰式命名法 例如user_name->userName
*/
public static String toCamelCase(String s) {
return StrUtil.toCamelCase(s);
}
/**
* 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
*
* @param str 指定字符串
* @param strs 需要检查的字符串数组
* @return 是否匹配
*/
public static boolean matches(String str, List<String> strs) {
if (isEmpty(str) || isEmpty(strs)) {
return false;
}
for (String pattern : strs) {
if (isMatch(pattern, str)) {
return true;
}
}
return false;
}
/**
* 判断url是否与规则配置:
* ? 表示单个字符;
* * 表示一层路径内的任意字符串,不可跨层级;
* ** 表示任意层路径;
*
* @param pattern 匹配规则
* @param url 需要匹配的url
* @return
*/
public static boolean isMatch(String pattern, String url) {
return ReUtil.isMatch(pattern, url);
}
@SuppressWarnings("unchecked")
public static <T> T cast(Object obj) {
return (T) obj;
}
}

View File

@ -1,58 +0,0 @@
package com.ruoyi.common.utils.ip;
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.extern.slf4j.Slf4j;
import java.util.Map;
/**
* 获取地址类
*
* @author Lion Li
*/
@Slf4j
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;
}
Map<String, String> obj = JsonUtils.parseMap(rspStr);
String region = obj.get("pro");
String city = obj.get("city");
return String.format("%s %s", region, city);
} catch (Exception e) {
log.error("获取地理位置异常 {}", ip);
}
}
return address;
}
}

View File

@ -1,155 +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 javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* Excel相关处理
*
* @author Lion Li
*/
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,33 +0,0 @@
package com.ruoyi.common.utils.sql;
import com.ruoyi.common.exception.UtilException;
import com.ruoyi.common.utils.StringUtils;
/**
* sql操作工具类
*
* @author ruoyi
*/
public class SqlUtil {
/**
* 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序)
*/
public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";
/**
* 检查字符,防止注入绕过
*/
public static String escapeOrderBySql(String value) {
if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value)) {
throw new UtilException("参数不符合规范,不能进行查询");
}
return value;
}
/**
* 验证 order by 语法是否符合规范
*/
public static boolean isValidOrderBySql(String value) {
return value.matches(SQL_PATTERN);
}
}

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>3.4.0</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,38 +0,0 @@
package com.ruoyi.demo.controller;
import com.ruoyi.common.core.domain.AjaxResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
/**
* swagger3 用法示例
*
* @author Lion Li
*/
@Api(value = "演示swagger3控制器", tags = {"演示swagger3接口"})
@RestController
@RequestMapping("/swagger/demo")
public class Swagger3DemoController {
/**
* 上传请求
* 必须使用 @RequestPart 注解标注为文件
* dataType 必须为 "java.io.File"
*/
@ApiOperation(value = "通用上传请求")
@ApiImplicitParams({
@ApiImplicitParam(name = "file", value = "文件", dataType = "java.io.File", required = true),
})
@PostMapping(value = "/upload")
public AjaxResult<String> upload(@RequestPart("file") MultipartFile file) {
return AjaxResult.success("操作成功", file.getOriginalFilename());
}
}

View File

@ -1,81 +0,0 @@
package com.ruoyi.demo.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.demo.domain.TestDemo;
import com.ruoyi.demo.service.ITestDemoService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
/**
* 测试批量方法
*
* @author Lion Li
* @date 2021-05-30
*/
@Api(value = "测试批量方法", tags = {"测试批量方法"})
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@RestController
@RequestMapping("/demo/batch")
public class TestBatchController extends BaseController {
private final ITestDemoService iTestDemoService;
/**
* 新增批量方法 可完美替代 saveBatch 秒级插入上万数据 (对mysql负荷较大)
*/
@ApiOperation(value = "新增批量方法")
@PostMapping("/add")
// @DataSource(DataSourceType.SLAVE)
public AjaxResult<Void> add() {
List<TestDemo> list = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
list.add(new TestDemo().setOrderNum(-1L).setTestKey("批量新增").setValue("测试新增"));
}
return toAjax(iTestDemoService.saveAll(list) ? 1 : 0);
}
/**
* 新增或更新 可完美替代 saveOrUpdateBatch 高性能
*/
@ApiOperation(value = "新增或更新批量方法")
@PostMapping("/addOrUpdate")
// @DataSource(DataSourceType.SLAVE)
public AjaxResult<Void> addOrUpdate() {
List<TestDemo> list = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
list.add(new TestDemo().setOrderNum(-1L).setTestKey("批量新增").setValue("测试新增"));
}
iTestDemoService.saveAll(list);
for (int i = 0; i < list.size(); i++) {
TestDemo testDemo = list.get(i);
testDemo.setTestKey("批量新增或修改").setValue("批量新增或修改");
if (i % 2 == 0) {
testDemo.setId(null);
}
}
return toAjax(iTestDemoService.saveOrUpdateAll(list) ? 1 : 0);
}
/**
* 删除批量方法
*/
@ApiOperation(value = "删除批量方法")
@DeleteMapping()
// @DataSource(DataSourceType.SLAVE)
public AjaxResult<Void> remove() {
return toAjax(iTestDemoService.remove(new LambdaQueryWrapper<TestDemo>()
.eq(TestDemo::getOrderNum, -1L)) ? 1 : 0);
}
}

View File

@ -1,94 +0,0 @@
package com.ruoyi.demo.domain.bo;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.*;
import java.util.Date;
import com.ruoyi.common.core.domain.BaseEntity;
/**
* 测试单表业务对象 test_demo
*
* @author Lion Li
* @date 2021-07-26
*/
@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel("测试单表业务对象")
public class TestDemoBo extends BaseEntity {
/**
* 主键
*/
@ApiModelProperty("主键")
@NotNull(message = "主键不能为空", groups = { EditGroup.class })
private Long id;
/**
* 部门id
*/
@ApiModelProperty("部门id")
@NotNull(message = "部门id不能为空", groups = { AddGroup.class, EditGroup.class })
private Long deptId;
/**
* 用户id
*/
@ApiModelProperty("用户id")
@NotNull(message = "用户id不能为空", groups = { AddGroup.class, EditGroup.class })
private Long userId;
/**
* 排序号
*/
@ApiModelProperty("排序号")
@NotNull(message = "排序号不能为空", groups = { AddGroup.class, EditGroup.class })
private Long orderNum;
/**
* key键
*/
@ApiModelProperty("key键")
@NotBlank(message = "key键不能为空", groups = { AddGroup.class, EditGroup.class })
private String testKey;
/**
* 值
*/
@ApiModelProperty("")
@NotBlank(message = "值不能为空", groups = { AddGroup.class, EditGroup.class })
private String value;
/**
* 分页大小
*/
@ApiModelProperty("分页大小")
private Integer pageSize;
/**
* 当前页数
*/
@ApiModelProperty("当前页数")
private Integer pageNum;
/**
* 排序列
*/
@ApiModelProperty("排序列")
private String orderByColumn;
/**
* 排序的方向desc或者asc
*/
@ApiModelProperty(value = "排序的方向", example = "asc,desc")
private String isAsc;
}

View File

@ -1,79 +0,0 @@
package com.ruoyi.demo.domain.bo;
import com.ruoyi.common.core.domain.TreeEntity;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* 测试树表业务对象 test_tree
*
* @author Lion Li
* @date 2021-07-26
*/
@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel("测试树表业务对象")
public class TestTreeBo extends TreeEntity {
/**
* 主键
*/
@ApiModelProperty("主键")
@NotNull(message = "主键不能为空", groups = { EditGroup.class })
private Long id;
/**
* 部门id
*/
@ApiModelProperty("部门id")
@NotNull(message = "部门id不能为空", groups = { AddGroup.class, EditGroup.class })
private Long deptId;
/**
* 用户id
*/
@ApiModelProperty("用户id")
@NotNull(message = "用户id不能为空", groups = { AddGroup.class, EditGroup.class })
private Long userId;
/**
* 树节点名
*/
@ApiModelProperty("树节点名")
@NotBlank(message = "树节点名不能为空", groups = { AddGroup.class, EditGroup.class })
private String treeName;
/**
* 分页大小
*/
@ApiModelProperty("分页大小")
private Integer pageSize;
/**
* 当前页数
*/
@ApiModelProperty("当前页数")
private Integer pageNum;
/**
* 排序列
*/
@ApiModelProperty("排序列")
private String orderByColumn;
/**
* 排序的方向desc或者asc
*/
@ApiModelProperty(value = "排序的方向", example = "asc,desc")
private String isAsc;
}

View File

@ -1,97 +0,0 @@
package com.ruoyi.demo.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
* 测试单表视图对象 test_demo
*
* @author Lion Li
* @date 2021-07-26
*/
@Data
@ApiModel("测试单表视图对象")
@ExcelIgnoreUnannotated
public class TestDemoVo {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@ExcelProperty(value = "主键")
@ApiModelProperty("主键")
private Long id;
/**
* 部门id
*/
@ExcelProperty(value = "部门id")
@ApiModelProperty("部门id")
private Long deptId;
/**
* 用户id
*/
@ExcelProperty(value = "用户id")
@ApiModelProperty("用户id")
private Long userId;
/**
* 排序号
*/
@ExcelProperty(value = "排序号")
@ApiModelProperty("排序号")
private Long orderNum;
/**
* key键
*/
@ExcelProperty(value = "key键")
@ApiModelProperty("key键")
private String testKey;
/**
* 值
*/
@ExcelProperty(value = "")
@ApiModelProperty("")
private String value;
/**
* 创建时间
*/
@ExcelProperty(value = "创建时间")
@ApiModelProperty("创建时间")
private Date createTime;
/**
* 创建人
*/
@ExcelProperty(value = "创建人")
@ApiModelProperty("创建人")
private String createBy;
/**
* 更新时间
*/
@ExcelProperty(value = "更新时间")
@ApiModelProperty("更新时间")
private Date updateTime;
/**
* 更新人
*/
@ExcelProperty(value = "更新人")
@ApiModelProperty("更新人")
private String updateBy;
}

View File

@ -1,68 +0,0 @@
package com.ruoyi.demo.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
* 测试树表视图对象 test_tree
*
* @author Lion Li
* @date 2021-07-26
*/
@Data
@ApiModel("测试树表视图对象")
@ExcelIgnoreUnannotated
public class TestTreeVo {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@ApiModelProperty("主键")
private Long id;
/**
* 父id
*/
@ExcelProperty(value = "父id")
@ApiModelProperty("父id")
private Long parentId;
/**
* 部门id
*/
@ExcelProperty(value = "部门id")
@ApiModelProperty("部门id")
private Long deptId;
/**
* 用户id
*/
@ExcelProperty(value = "用户id")
@ApiModelProperty("用户id")
private Long userId;
/**
* 树节点名
*/
@ExcelProperty(value = "树节点名")
@ApiModelProperty("树节点名")
private String treeName;
/**
* 创建时间
*/
@ExcelProperty(value = "创建时间")
@ApiModelProperty("创建时间")
private Date createTime;
}

View File

@ -1,20 +0,0 @@
package com.ruoyi.demo.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.mybatisplus.core.BaseMapperPlus;
import com.ruoyi.demo.domain.TestDemo;
import com.ruoyi.demo.domain.vo.TestDemoVo;
import org.apache.ibatis.annotations.Param;
/**
* 测试单表Mapper接口
*
* @author Lion Li
* @date 2021-07-26
*/
public interface TestDemoMapper extends BaseMapperPlus<TestDemo> {
Page<TestDemoVo> customPageList(@Param("page") Page<TestDemo> page, @Param("ew") Wrapper<TestDemo> wrapper);
}

View File

@ -1,14 +0,0 @@
package com.ruoyi.demo.mapper;
import com.ruoyi.common.core.mybatisplus.core.BaseMapperPlus;
import com.ruoyi.demo.domain.TestTree;
/**
* 测试树表Mapper接口
*
* @author Lion Li
* @date 2021-07-26
*/
public interface TestTreeMapper extends BaseMapperPlus<TestTree> {
}

View File

@ -1,62 +0,0 @@
package com.ruoyi.demo.service;
import com.ruoyi.demo.domain.TestDemo;
import com.ruoyi.demo.domain.vo.TestDemoVo;
import com.ruoyi.demo.domain.bo.TestDemoBo;
import com.ruoyi.common.core.mybatisplus.core.IServicePlus;
import com.ruoyi.common.core.page.TableDataInfo;
import java.util.Collection;
import java.util.List;
/**
* 测试单表Service接口
*
* @author Lion Li
* @date 2021-07-26
*/
public interface ITestDemoService extends IServicePlus<TestDemo, TestDemoVo> {
/**
* 查询单个
* @return
*/
TestDemoVo queryById(Long id);
/**
* 查询列表
*/
TableDataInfo<TestDemoVo> queryPageList(TestDemoBo bo);
/**
* 自定义分页查询
*/
TableDataInfo<TestDemoVo> customPageList(TestDemoBo bo);
/**
* 查询列表
*/
List<TestDemoVo> queryList(TestDemoBo bo);
/**
* 根据新增业务对象插入测试单表
* @param bo 测试单表新增业务对象
* @return
*/
Boolean insertByBo(TestDemoBo bo);
/**
* 根据编辑业务对象修改测试单表
* @param bo 测试单表编辑业务对象
* @return
*/
Boolean updateByBo(TestDemoBo bo);
/**
* 校验并删除数据
* @param ids 主键集合
* @param isValid 是否校验,true-删除前校验,false-不校验
* @return
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@ -1,50 +0,0 @@
package com.ruoyi.demo.service;
import com.ruoyi.demo.domain.TestTree;
import com.ruoyi.demo.domain.vo.TestTreeVo;
import com.ruoyi.demo.domain.bo.TestTreeBo;
import com.ruoyi.common.core.mybatisplus.core.IServicePlus;
import java.util.Collection;
import java.util.List;
/**
* 测试树表Service接口
*
* @author Lion Li
* @date 2021-07-26
*/
public interface ITestTreeService extends IServicePlus<TestTree, TestTreeVo> {
/**
* 查询单个
* @return
*/
TestTreeVo queryById(Long id);
/**
* 查询列表
*/
List<TestTreeVo> queryList(TestTreeBo bo);
/**
* 根据新增业务对象插入测试树表
* @param bo 测试树表新增业务对象
* @return
*/
Boolean insertByBo(TestTreeBo bo);
/**
* 根据编辑业务对象修改测试树表
* @param bo 测试树表编辑业务对象
* @return
*/
Boolean updateByBo(TestTreeBo bo);
/**
* 校验并删除数据
* @param ids 主键集合
* @param isValid 是否校验,true-删除前校验,false-不校验
* @return
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@ -1,108 +0,0 @@
package com.ruoyi.demo.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.ruoyi.common.utils.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.annotation.DataScope;
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
import com.ruoyi.common.core.page.PagePlus;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.demo.domain.TestDemo;
import com.ruoyi.demo.domain.bo.TestDemoBo;
import com.ruoyi.demo.domain.vo.TestDemoVo;
import com.ruoyi.demo.mapper.TestDemoMapper;
import com.ruoyi.demo.service.ITestDemoService;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 测试单表Service业务层处理
*
* @author Lion Li
* @date 2021-07-26
*/
@Service
public class TestDemoServiceImpl extends ServicePlusImpl<TestDemoMapper, TestDemo, TestDemoVo> implements ITestDemoService {
@Override
public TestDemoVo queryById(Long id) {
return getVoById(id);
}
@DataScope(isUser = true)
@Override
public TableDataInfo<TestDemoVo> queryPageList(TestDemoBo bo) {
PagePlus<TestDemo, TestDemoVo> result = pageVo(PageUtils.buildPagePlus(), buildQueryWrapper(bo));
return PageUtils.buildDataInfo(result);
}
/**
* 自定义分页查询
*/
@DataScope(isUser = true)
@Override
public TableDataInfo<TestDemoVo> customPageList(TestDemoBo bo) {
Page<TestDemoVo> result = baseMapper.customPageList(PageUtils.buildPage(), buildQueryWrapper(bo));
return PageUtils.buildDataInfo(result);
}
@DataScope(isUser = true)
@Override
public List<TestDemoVo> queryList(TestDemoBo bo) {
return listVo(buildQueryWrapper(bo));
}
private LambdaQueryWrapper<TestDemo> buildQueryWrapper(TestDemoBo bo) {
Map<String, Object> params = bo.getParams();
Object dataScope = params.get("dataScope");
LambdaQueryWrapper<TestDemo> lqw = Wrappers.lambdaQuery();
lqw.like(StringUtils.isNotBlank(bo.getTestKey()), TestDemo::getTestKey, bo.getTestKey());
lqw.eq(StringUtils.isNotBlank(bo.getValue()), TestDemo::getValue, bo.getValue());
lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
TestDemo::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
lqw.apply(dataScope != null && StringUtils.isNotBlank(dataScope.toString()),
dataScope != null ? dataScope.toString() : null);
return lqw;
}
@Override
public Boolean insertByBo(TestDemoBo bo) {
TestDemo add = BeanUtil.toBean(bo, TestDemo.class);
validEntityBeforeSave(add);
boolean flag = save(add);
if (flag) {
bo.setId(add.getId());
}
return flag;
}
@Override
public Boolean updateByBo(TestDemoBo bo) {
TestDemo update = BeanUtil.toBean(bo, TestDemo.class);
validEntityBeforeSave(update);
return updateById(update);
}
/**
* 保存前的数据校验
*
* @param entity 实体类数据
*/
private void validEntityBeforeSave(TestDemo entity) {
//TODO 做一些数据校验,如唯一约束
}
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
//TODO 做一些业务上的校验,判断是否需要校验
}
return removeByIds(ids);
}
}

View File

@ -1,88 +0,0 @@
package com.ruoyi.demo.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.annotation.DataScope;
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.demo.domain.TestTree;
import com.ruoyi.demo.domain.bo.TestTreeBo;
import com.ruoyi.demo.domain.vo.TestTreeVo;
import com.ruoyi.demo.mapper.TestTreeMapper;
import com.ruoyi.demo.service.ITestTreeService;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 测试树表Service业务层处理
*
* @author Lion Li
* @date 2021-07-26
*/
//@DataSource(DataSourceType.SLAVE) // 切换从库查询
@Service
public class TestTreeServiceImpl extends ServicePlusImpl<TestTreeMapper, TestTree, TestTreeVo> implements ITestTreeService {
@Override
public TestTreeVo queryById(Long id) {
return getVoById(id);
}
// @DataSource(DataSourceType.SLAVE) // 切换从库查询
@DataScope(isUser = true)
@Override
public List<TestTreeVo> queryList(TestTreeBo bo) {
return listVo(buildQueryWrapper(bo));
}
private LambdaQueryWrapper<TestTree> buildQueryWrapper(TestTreeBo bo) {
Map<String, Object> params = bo.getParams();
Object dataScope = params.get("dataScope");
LambdaQueryWrapper<TestTree> lqw = Wrappers.lambdaQuery();
lqw.like(StringUtils.isNotBlank(bo.getTreeName()), TestTree::getTreeName, bo.getTreeName());
lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
TestTree::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
lqw.apply(dataScope != null && StringUtils.isNotBlank(dataScope.toString()),
dataScope != null ? dataScope.toString() : null);
return lqw;
}
@Override
public Boolean insertByBo(TestTreeBo bo) {
TestTree add = BeanUtil.toBean(bo, TestTree.class);
validEntityBeforeSave(add);
boolean flag = save(add);
if (flag) {
bo.setId(add.getId());
}
return flag;
}
@Override
public Boolean updateByBo(TestTreeBo bo) {
TestTree update = BeanUtil.toBean(bo, TestTree.class);
validEntityBeforeSave(update);
return updateById(update);
}
/**
* 保存前的数据校验
*
* @param entity 实体类数据
*/
private void validEntityBeforeSave(TestTree entity) {
//TODO 做一些数据校验,如唯一约束
}
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
//TODO 做一些业务上的校验,判断是否需要校验
}
return removeByIds(ids);
}
}

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId>
<version>3.4.0</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>3.4.0</version>
<version>4.8.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
@ -34,6 +34,11 @@
<artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
@ -54,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

@ -11,9 +11,9 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MonitorAdminApplication {
public static void main(String[] args) {
SpringApplication.run(MonitorAdminApplication.class, args);
System.out.println("Admin 监控启动成功" );
}
public static void main(String[] args) {
SpringApplication.run(MonitorAdminApplication.class, args);
System.out.println("Admin 监控启动成功");
}
}

View File

@ -1,11 +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.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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;
/**
@ -13,38 +12,39 @@ import org.springframework.security.web.authentication.SavedRequestAwareAuthenti
*
* @author Lion Li
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, proxyTargetClass = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
public class SecurityConfig {
private final String adminContextPath;
private final String adminContextPath;
public SecurityConfig(AdminServerProperties adminServerProperties) {
this.adminContextPath = adminServerProperties.getContextPath();
}
public SecurityConfig(AdminServerProperties adminServerProperties) {
this.adminContextPath = adminServerProperties.getContextPath();
}
@Override
protected void configure(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").anonymous()
.antMatchers("/actuator/**").anonymous()
//必须对每个其他请求进行身份验证
.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();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setTargetUrlParameter("redirectTo");
successHandler.setDefaultTargetUrl(adminContextPath + "/");
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()
.httpBasic().and()
.csrf()
.disable()
.build();
}
}

View File

@ -0,0 +1,40 @@
package com.ruoyi.monitor.admin.notifier;
import de.codecentric.boot.admin.server.domain.entities.Instance;
import de.codecentric.boot.admin.server.domain.entities.InstanceRepository;
import de.codecentric.boot.admin.server.domain.events.InstanceEvent;
import de.codecentric.boot.admin.server.domain.events.InstanceStatusChangedEvent;
import de.codecentric.boot.admin.server.notify.AbstractEventNotifier;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
/**
* 自定义事件通知处理
*
* @author Lion Li
*/
@Slf4j
@Component
public class CustomNotifier extends AbstractEventNotifier {
protected CustomNotifier(InstanceRepository repository) {
super(repository);
}
@Override
@SuppressWarnings("all")
protected Mono<Void> doNotify(InstanceEvent event, Instance instance) {
return Mono.fromRunnable(() -> {
// 实例状态改变事件
if (event instanceof InstanceStatusChangedEvent) {
String registName = instance.getRegistration().getName();
String instanceId = event.getInstance().getValue();
String status = ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus();
log.info("Instance Status Change: [{}],[{}],[{}]", registName, instanceId, status);
}
});
}
}

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:
prefer-ip: true # 注册实例时,优先使用 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:
prefer-ip: true # 注册实例时,优先使用 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
@ -14,4 +13,4 @@ EXPOSE 9100
ADD ./target/ruoyi-xxl-job-admin.jar ./app.jar
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]

View File

@ -1,138 +1,102 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>ruoyi-extend</artifactId>
<groupId>com.ruoyi</groupId>
<version>3.4.0</version>
</parent>
<artifactId>ruoyi-xxl-job-admin</artifactId>
<packaging>jar</packaging>
<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>
<properties>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependencies>
<!-- starter-webspring-webmvc + autoconfigure + logback + yaml + tomcat -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- starter-testjunit + spring-test + mockito -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- starter-webspring-webmvc + autoconfigure + logback + yaml + tomcat -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- starter-testjunit + spring-test + mockito -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- freemarker-starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- freemarker-starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- mail-starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- mail-starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- starter-actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- starter-actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- mybatis-startermybatis + mybatis-spring + hikaridefault -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring-boot-starter.version}</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector-java.version}</version>
</dependency>
<!-- mybatis-startermybatis + mybatis-spring + hikaridefault -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${spring-boot.mybatis}</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>
<!-- xxl-job-core -->
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
</dependency>
<!-- xxl-job-core -->
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
</dependency>
</dependencies>
</dependencies>
<build>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<nonFilteredFileExtensions>
<nonFilteredFileExtension>ttf</nonFilteredFileExtension>
<nonFilteredFileExtension>jks</nonFilteredFileExtension>
<nonFilteredFileExtension>woff</nonFilteredFileExtension>
<nonFilteredFileExtension>woff2</nonFilteredFileExtension>
</nonFilteredFileExtensions>
</configuration>
</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>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -9,8 +9,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class XxlJobAdminApplication {
public static void main(String[] args) {
public static void main(String[] args) {
SpringApplication.run(XxlJobAdminApplication.class, args);
}
}
}
}

View File

@ -24,73 +24,74 @@ import java.util.Map;
/**
* index controller
*
* @author xuxueli 2015-12-19 16:13:16
*/
@Controller
public class IndexController {
@Resource
private XxlJobService xxlJobService;
@Resource
private LoginService loginService;
@Resource
private XxlJobService xxlJobService;
@Resource
private LoginService loginService;
@RequestMapping("/")
public String index(Model model) {
@RequestMapping("/")
public String index(Model model) {
Map<String, Object> dashboardMap = xxlJobService.dashboardInfo();
model.addAllAttributes(dashboardMap);
Map<String, Object> dashboardMap = xxlJobService.dashboardInfo();
model.addAllAttributes(dashboardMap);
return "index";
}
return "index";
}
@RequestMapping("/chartInfo")
@ResponseBody
public ReturnT<Map<String, Object>> chartInfo(Date startDate, Date endDate) {
@ResponseBody
public ReturnT<Map<String, Object>> chartInfo(Date startDate, Date endDate) {
ReturnT<Map<String, Object>> chartInfo = xxlJobService.chartInfo(startDate, endDate);
return chartInfo;
}
@RequestMapping("/toLogin")
@PermissionLimit(limit=false)
public ModelAndView toLogin(HttpServletRequest request, HttpServletResponse response,ModelAndView modelAndView) {
if (loginService.ifLogin(request, response) != null) {
modelAndView.setView(new RedirectView("/",true,false));
return modelAndView;
}
return new ModelAndView("login");
}
@RequestMapping(value="login", method=RequestMethod.POST)
@ResponseBody
@PermissionLimit(limit=false)
public ReturnT<String> loginDo(HttpServletRequest request, HttpServletResponse response, String userName, String password, String ifRemember){
boolean ifRem = (ifRemember!=null && ifRemember.trim().length()>0 && "on".equals(ifRemember))?true:false;
return loginService.login(request, response, userName, password, ifRem);
}
@RequestMapping(value="logout", method=RequestMethod.POST)
@ResponseBody
@PermissionLimit(limit=false)
public ReturnT<String> logout(HttpServletRequest request, HttpServletResponse response){
return loginService.logout(request, response);
}
@RequestMapping("/help")
public String help() {
/*if (!PermissionInterceptor.ifLogin(request)) {
return "redirect:/toLogin";
}*/
@RequestMapping("/toLogin")
@PermissionLimit(limit = false)
public ModelAndView toLogin(HttpServletRequest request, HttpServletResponse response, ModelAndView modelAndView) {
if (loginService.ifLogin(request, response) != null) {
modelAndView.setView(new RedirectView("/", true, false));
return modelAndView;
}
return new ModelAndView("login");
}
return "help";
}
@RequestMapping(value = "login", method = RequestMethod.POST)
@ResponseBody
@PermissionLimit(limit = false)
public ReturnT<String> loginDo(HttpServletRequest request, HttpServletResponse response, String userName, String password, String ifRemember) {
boolean ifRem = (ifRemember != null && ifRemember.trim().length() > 0 && "on".equals(ifRemember)) ? true : false;
return loginService.login(request, response, userName, password, ifRem);
}
@RequestMapping(value = "logout", method = RequestMethod.POST)
@ResponseBody
@PermissionLimit(limit = false)
public ReturnT<String> logout(HttpServletRequest request, HttpServletResponse response) {
return loginService.logout(request, response);
}
@RequestMapping("/help")
public String help() {
/*if (!PermissionInterceptor.ifLogin(request)) {
return "redirect:/toLogin";
}*/
return "help";
}
@InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
}
@InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
}
}

View File

@ -37,19 +37,19 @@ public class JobApiController {
*/
@RequestMapping("/{uri}")
@ResponseBody
@PermissionLimit(limit=false)
@PermissionLimit(limit = false)
public ReturnT<String> api(HttpServletRequest request, @PathVariable("uri") String uri, @RequestBody(required = false) String data) {
// valid
if (!"POST".equalsIgnoreCase(request.getMethod())) {
return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, HttpMethod not support.");
}
if (uri==null || uri.trim().length()==0) {
if (uri == null || uri.trim().length() == 0) {
return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, uri-mapping empty.");
}
if (XxlJobAdminConfig.getAdminConfig().getAccessToken()!=null
&& XxlJobAdminConfig.getAdminConfig().getAccessToken().trim().length()>0
&& !XxlJobAdminConfig.getAdminConfig().getAccessToken().equals(request.getHeader(XxlJobRemotingUtil.XXL_JOB_ACCESS_TOKEN))) {
if (XxlJobAdminConfig.getAdminConfig().getAccessToken() != null
&& XxlJobAdminConfig.getAdminConfig().getAccessToken().trim().length() > 0
&& !XxlJobAdminConfig.getAdminConfig().getAccessToken().equals(request.getHeader(XxlJobRemotingUtil.XXL_JOB_ACCESS_TOKEN))) {
return new ReturnT<String>(ReturnT.FAIL_CODE, "The access token is wrong.");
}
@ -64,7 +64,7 @@ public class JobApiController {
RegistryParam registryParam = GsonTool.fromJson(data, RegistryParam.class);
return adminBiz.registryRemove(registryParam);
} else {
return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, uri-mapping("+ uri +") not found.");
return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, uri-mapping(" + uri + ") not found.");
}
}

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