169 Commits

Author SHA1 Message Date
6f48fc3c58 若依 3.8.3 2022-06-27 08:23:47 +08:00
8558954da7 !516 修复缓存列表页面变量名错误导致错误
Merge pull request !516 from zbk/N/A
2022-06-27 00:10:17 +00:00
zbk
2ae41df23b 修复缓存列表页面变量名错误导致错误 2022-06-26 12:51:55 +00:00
47b8daf69c 字典类型删除多余的mapper注解 2022-06-26 13:10:44 +08:00
ef31a0de42 升级fastjson到最新版2.0.8 2022-06-26 10:37:45 +08:00
8c956d681b 默认不启用压缩文件缓存防止node_modules过大 2022-06-26 08:53:56 +08:00
89eb44afbc 优化字典数据回显样式下拉框显示值 2022-06-26 08:53:15 +08:00
9d7e32fb07 新增缓存列表菜单功能 2022-06-25 09:39:39 +08:00
abb88d622a 调整响应成功状态码与全局保持一致 2022-06-24 09:22:05 +08:00
1ccdd75019 !515 调整响应成功状态码为200,与全局保持一致
Merge pull request !515 from 武玉航/master
2022-06-24 01:16:59 +00:00
aaedafff52 调整响应成功状态码为200,与全局保持一致 2022-06-23 14:42:10 +08:00
3ccf5c0e50 新增内容编码/解码方便插件集成使用 2022-06-22 17:57:33 +08:00
db5fea922f 升级fastjson到最新版2.0.7 2022-06-15 17:08:29 +08:00
0214d93299 删除多余的salt字段 2022-06-15 17:08:06 +08:00
1124a203cc 升级druid到最新版本1.2.11 2022-06-14 21:29:06 +08:00
e8fbf5fdbd reset babel 2022-06-14 21:26:14 +08:00
8fd4ae1282 优化druid开启wall过滤器出现的异常问题 2022-06-13 21:43:31 +08:00
eab1b450d5 优化代码 2022-06-13 21:43:11 +08:00
98fc30786e !504 update 优化新增用户与角色信息、用户与岗位信息逻辑
Merge pull request !504 from 疯狂的狮子Li/N/A
2022-06-13 13:26:04 +00:00
a46c4bf04e update 优化新增用户与角色信息、用户与岗位信息逻辑 2022-06-08 13:53:08 +00:00
b97a662f2e 新增Anonymous匿名访问不鉴权注解 2022-05-28 09:34:05 +08:00
9639c096ba 用户列表查询不显示密码字段 2022-05-27 17:50:49 +08:00
e4af41e89a !497 增加对空字符串参数的过滤
Merge pull request !497 from root/master
2022-05-27 08:53:42 +00:00
52e1717014 增加对空字符串参数的过滤 2022-05-27 12:06:27 +08:00
8a2e3d13f2 表单构建按钮不显示正则校验 2022-05-27 09:18:26 +08:00
a29a0648ad 升级spring-boot到最新版本2.5.14 2022-05-27 08:37:34 +08:00
63d471ec94 修复字典导出序列化报错问题 2022-05-27 08:37:14 +08:00
9fa3eac3aa 升级fastjson到最新版2.0.4 2022-05-26 09:02:32 +08:00
e320c50e49 !492 fastjson 版本升级
Merge pull request !492 from abbfun/N/A
2022-05-24 01:54:24 +00:00
524ad4e6dd fastjson 版本升级
fastjson <= 1.2.80 存在反序列化任意代码执行漏洞
2022-05-23 07:36:18 +00:00
77fffda10e 添加新群号:139821253 2022-05-23 09:38:52 +08:00
da0309eb09 用户头像上传限制只能为图片格式 2022-05-22 18:21:26 +08:00
6805a96e53 接口使用泛型使其看到响应属性字段 2022-05-20 16:25:51 +08:00
a92667c000 新增获取配置文件中的属性值方法 2022-05-20 16:23:52 +08:00
4a0619cadb 优化switch case条件 2022-05-20 16:23:36 +08:00
a7e16d582d !488 修复操作日志列表查询业务类型时的bug
Merge pull request !488 from 也曾为你、像超人/N/A
2022-05-20 07:56:27 +00:00
b5b8d941f3 update ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml.
问题:查业务类型为其他(businessType = 0)的数据时,会查到所有数据

原因:当参数为 Integer 类型 0 时,MyBatis 会把 0 当做空字符串处理
2022-05-17 02:08:37 +00:00
9c3b53b701 用户管理左侧树型组件增加选中高亮保持 2022-05-13 15:02:16 +08:00
5693bbe1f5 升级oshi到最新版本6.1.6 2022-05-11 09:58:25 +08:00
0055f479cb 修复字典数据显示不全问题(I55MR3) 2022-05-09 20:27:09 +08:00
1c41b701dd 优化excel创建表格样式 2022-05-09 17:37:33 +08:00
9476f7f616 升级spring-boot到最新版本2.5.13 2022-05-01 20:22:35 +08:00
cbe405f6ea ui code format 2022-05-01 20:22:25 +08:00
7414bc492e 修改代码生成树选择组件 2022-04-25 10:27:06 +08:00
6f14087a16 修改显示顺序orderNum类型为整型 2022-04-25 10:23:47 +08:00
328d4b916d Excel注解支持color字体颜色 2022-04-23 20:53:16 +08:00
b42a8176ca 设置分页参数默认值 2022-04-17 10:29:12 +08:00
2a9beec31d 检查定时任务bean所在包名是否为白名单配置 2022-04-16 22:06:25 +08:00
910fe6261b 新增获取不带后缀文件名称方法 2022-04-16 22:06:15 +08:00
0c820b96d8 !471 新增一个取文件名而不带后缀的整合方法,干净又卫生啊兄弟们
Merge pull request !471 from XCSDN/N/A
2022-04-16 13:53:10 +00:00
c3c49a05c2 新增一个取文件名而不带后缀的整合方法,干净又卫生啊兄弟们 2022-04-16 06:02:07 +00:00
68a616d7c7 升级element-ui到最新版本2.15.8 2022-04-15 09:32:21 +08:00
a0447de061 字典类型必须以字母开头,且只能为(小写字母,数字,下滑线) 2022-04-15 09:31:51 +08:00
46db06a22b !465 update ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java.
Merge pull request !465 from XCSDN/N/A
2022-04-15 01:17:21 +00:00
de5ae4a05e 添加页签openPage支持传递参数 2022-04-08 15:42:10 +08:00
c0d430f4e5 update ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java.
字典类型必须以字母开头,且字典类型只能由小写字母或加下划线还有数字组成
防止由于字典类型不符合前端开发规范而报错
2022-04-07 04:57:56 +00:00
d910888181 代码生成树表新增(展开/折叠) 2022-04-07 10:56:40 +08:00
db2dfee6ae 用户缓存信息添加部门ancestors祖级列表 2022-04-07 09:50:42 +08:00
d311d56bbf 修复Excel注解prompt/combo同时使用不生效问题 2022-04-03 18:28:30 +08:00
3bc5ef38d3 升级spring-boot到最新版本2.5.12 防止RCE漏洞 2022-04-02 10:16:09 +08:00
bac3b3a0dc 降级jsencrypt版本兼容IE浏览器 2022-04-02 10:15:25 +08:00
07fded4da9 update readme 2022-04-02 10:13:58 +08:00
a854e0ca8e 若依 3.8.2 2022-04-01 08:30:48 +08:00
de1766abde 新增清理分页的线程变量方法 2022-03-31 11:48:27 +08:00
01a566c794 升级spring-boot到最新版本2.5.11 2022-03-30 10:40:07 +08:00
5362a633e6 升级fastjson到最新版1.2.80 2022-03-30 10:39:47 +08:00
b2c3f45141 update registry source 2022-03-30 10:39:09 +08:00
d5f9b5b74a topNav自定义隐藏侧边栏路由 2022-03-30 10:38:51 +08:00
2043d1f439 优化IP地址获取到多个的问题 2022-03-27 14:36:48 +08:00
61034d4dde 优化导出excel单元格验证,包含变更为开头.防止正常内容被替换 2022-03-27 14:36:31 +08:00
6605bf35a8 reset pr 452 2022-03-26 17:28:58 +08:00
b2b93e5060 !457 修改RedisCache方法形参命名
Merge pull request !457 from lu_ming/master
2022-03-26 09:25:05 +00:00
098286fcaf 修改RedisCache方法形参命名 2022-03-25 18:50:51 +08:00
eaa12de740 添加新群号:167385320 2022-03-22 16:47:56 +08:00
857054179c 优化固定Header后顶部导航栏样式问题(I4XDN5) 2022-03-17 09:42:39 +08:00
0a3fcfd9f4 !453 update ruoyi-ui/src/store/modules/user.js.
Merge pull request !453 from guxin0123/N/A
2022-03-16 05:19:33 +00:00
0271aa5414 update ruoyi-ui/src/store/modules/user.js.
修复数据库用户表 头像列为 null 时不显示默认头像问题
2022-03-16 04:52:33 +00:00
a0364f0758 优化菜单名称过长悬停显示标题 2022-03-15 14:24:52 +08:00
ed693e89c9 !452 跨域问题
Merge pull request !452 from younger007/master
2022-03-15 06:23:38 +00:00
526957e0ac !447 优化:解决导出数据时,LocalDateTime类型数据导出没数据问题
Merge pull request !447 from 黄严/dev
2022-03-15 06:23:24 +00:00
420a43cdd5 update ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java.
和文件下载那边一样,存在跨域问题
2022-03-14 02:52:29 +00:00
5e8ccda522 日期转换错误,issue地址:https://gitee.com/y_project/RuoYi-Vue/issues/I4X0U7 2022-03-09 14:39:19 +08:00
62fc38078c 修复遗漏的拼写错误 2022-03-09 10:05:39 +08:00
bc4f844cd8 !445 文件上传兼容Weblogic环境
Merge pull request !445 from yaoozu/master
2022-03-09 02:03:50 +00:00
f15f8e3295 文件上传兼容Weblogic环境 2022-03-07 10:44:01 +08:00
6130bebbb3 开启TopNav没有子菜单情况隐藏侧边栏 2022-03-06 09:03:44 +08:00
9f944c043f !444 修改提示
Merge pull request !444 from SG/N/A
2022-03-05 14:11:22 +00:00
092b3214c5 !443 修复代码错误,其他文件也修改下
Merge pull request !443 from SG/N/A
2022-03-05 14:11:17 +00:00
SG
07dfef48be 修改提示 2022-03-05 12:28:44 +00:00
e9571fc2e2 fix 2022-03-05 05:06:39 +00:00
22f7ccc11d 修复导入Excel时字典字段类型为Long转义为空问题 2022-03-05 08:39:52 +08:00
SG
4bd5009ec1 修复代码错误,其他文件也修改下 2022-03-04 14:38:57 +00:00
cb8f5de5af 修复表单清除元素位置未垂直居中问题(I4V27B) 2022-03-04 19:24:28 +08:00
ac030b7275 优化Excel格式化不同类型的日期对象 2022-02-26 09:54:52 +08:00
9370747479 升级spring-boot到最新版本2.5.10 2022-02-26 09:48:17 +08:00
45efd9290e !438 fix: 服务监控中运行参数显示条件错误
Merge pull request !438 from fuzui/fix_args_show_condition
2022-02-26 01:06:48 +00:00
96edba7eec fix: 服务监控中运行参数显示条件错误 2022-02-26 03:20:50 +08:00
927b05713a 组件fileUpload支持多文件同时选择上传 2022-02-25 11:51:29 +08:00
8f23ff7274 !437 解决通用下载接口跨域问题
Merge pull request !437 from 兮陌/master
2022-02-25 03:49:36 +00:00
158e883e47 fix: 修复文件下载跨域问题 2022-02-25 10:40:29 +08:00
e62e8e372c 组件ImageUpload支持多图同时选择上传 2022-02-25 09:08:56 +08:00
bb65cd1976 代码生成子表支持日期/字典配置 2022-02-24 09:28:51 +08:00
1086c00929 !436 优化部门管理页面email字段的表单验证多余的单引号
Merge pull request !436 from lu_ming/master
2022-02-23 12:46:09 +00:00
9aaa9ce8aa 优化部门管理页面email字段的表单验证多余的单引号 2022-02-23 20:00:47 +08:00
cb5a6d29e2 页面若未匹配到字典标签则返回原字典值 2022-02-23 16:55:09 +08:00
4d8bd8805b 优化个人中心页面email字段的表单验证多余的单引号 2022-02-23 16:54:59 +08:00
c8c57b545a 优化菜单关键字导致的插件报错问题 2022-02-22 19:10:34 +08:00
d0f7a317e4 定时任务默认保存到内存中执行 2022-02-22 19:10:21 +08:00
aa9ed2e863 修复分页组件请求两次问题 2022-02-21 15:21:16 +08:00
54c6c4e547 服务监控新增运行参数信息显示 2022-02-20 16:06:33 +08:00
986b48cf36 升级pagehelper到最新版1.4.1 2022-02-20 16:05:04 +08:00
3bb9b03add 升级spring-boot-mybatis到最新版2.2.2 2022-02-20 16:04:40 +08:00
f05aa674ab 升级oshi到最新版本6.1.2 2022-02-20 16:04:25 +08:00
965bdc9986 !431 修改登录超时刷新页面跳转登录页面还提示重新登录问题
Merge pull request !431 from 也曾为你、像超人/master
2022-02-19 09:08:50 +00:00
e793138031 修改登录超时刷新页面跳转登录页面还提示重新登录问题 2022-02-17 17:16:11 +08:00
d734bfc34f 修复分页组件请求两次问题(I4SQOR) 2022-02-17 11:56:11 +08:00
84fe0737de update 更新uuid去除默认值 漏改 2022-02-16 08:53:11 +00:00
81630a096f 代码生成同步保留必填/类型选项 2022-02-13 21:06:28 +08:00
21780d8106 优化代码 2022-02-13 21:06:18 +08:00
b7b4364db2 代码生成编辑修改打开新页签 2022-02-12 13:14:09 +08:00
d9859de756 代码优化 2022-02-12 13:13:04 +08:00
5e6fd0d1e1 !429 修复自定义组件file-upload无法显示第一个文件,列表显示的文件比实际文件少一个的问题
Merge pull request !429 from hjk2008/master
2022-02-12 03:56:02 +00:00
a91d7cdd72 !428 删除方法无返回值时,方法注释上的@return,StringBuilder append() 改为链式调用
Merge pull request !428 from 我的世界有我/master
2022-02-12 03:55:12 +00:00
d00dc3b03a !426 修正单词拼写错误
Merge pull request !426 from 稚屿/master
2022-02-12 03:54:13 +00:00
f5c69bae30 !425 优化默认值的问题,Model中不建议有默认值的逻辑
Merge pull request !425 from Yancey/default_value_optimization
2022-02-12 03:53:29 +00:00
89fe17f419 !424 update .gitignore.
Merge pull request !424 from oo0oo/N/A
2022-02-12 03:53:06 +00:00
sam
c491257359 修复自定义组件file-upload无法显示第一个文件,列表显示的文件比实际文件少一个的问题 2022-02-12 08:46:12 +08:00
dd5e514d92 StringBuilder append方法改为链式调用 2022-02-11 10:06:07 +08:00
2532e40f9c 删除方法无返回值时,方法注释上的@return 2022-02-11 10:05:01 +08:00
50236ae4e5 修复Xss注解字段值为空时的异常问题 2022-02-10 17:17:51 +08:00
c99eb98001 代码优化 2022-02-09 09:10:50 +08:00
a29201a248 修正单词拼写错误 2022-02-09 08:46:54 +08:00
6f0c59d7be 优化默认值的问题,Model中不建议有默认值的逻辑。 2022-02-09 00:27:51 +08:00
a6ed5667ab update .gitignore.
添加JRebel工具rebel.xml文件规则至gitignore
2022-02-01 02:24:49 +00:00
612c4293d1 用户访问控制时校验数据权限,防止越权 2022-01-27 12:05:04 +08:00
8007b22b85 导出Excel时屏蔽公式,防止CSV注入风险 2022-01-27 12:04:40 +08:00
35664d818d update ry.bat 2022-01-27 12:04:21 +08:00
1fe08f49c7 升级spring-boot到最新版本2.5.9 2022-01-23 10:56:41 +08:00
48b007543a fix css class name 2022-01-22 14:05:44 +00:00
dccb3ac6c6 修复选项卡点击右键刷新丢失参数问题 2022-01-18 11:29:31 +08:00
89cd2106ed !416 update ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java.
Merge pull request !416 from SG/N/A
2022-01-18 03:25:31 +00:00
74f991b8c5 !414 优化任务队列满时任务拒绝策略
Merge pull request !414 from root/master
2022-01-18 03:20:23 +00:00
SG
a966b95a5b update ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java.
修正文字
2022-01-14 09:24:15 +00:00
15f05b602f fix ruoyi-vue3下点击编辑,取消修改报错问题 2022-01-14 16:26:03 +08:00
9e51d3f250 优化任务队列满时任务拒绝策略 2022-01-14 11:54:46 +08:00
d7ca248bc8 update copyright 2022 2022-01-14 11:47:25 +08:00
3980b2f2ff 定时任务屏蔽违规的字符 2022-01-14 11:47:14 +08:00
bed9fcea46 优化加载字典缓存数据 2022-01-14 11:46:51 +08:00
b1b82857ba 优化字段更新未同步 2022-01-14 11:46:05 +08:00
869dcf73f8 Vue3前端代码生成模板同步到最新 2022-01-11 17:20:50 +08:00
96a34d1ad7 !409 翻页组件多了一个 :p 导致生成代码无法翻页
Merge pull request !409 from guxin0123/master
2022-01-11 09:17:31 +00:00
766361ac83 update ruoyi-generator/src/main/resources/vm/vue/v3/index.vue.vm.
翻页组件多了一个 :p 导致生成代码无法翻页
2022-01-11 04:57:26 +00:00
9bd7509e87 添加新群号:264312783 2022-01-11 09:02:16 +08:00
9f7acd4cf9 优化部门修改缩放后出现的错位问题 2022-01-08 09:23:45 +08:00
eb11337f7d 添加遗漏的分页参数合理化属性 2022-01-07 13:09:58 +08:00
d2872539e3 修正文字错误 2022-01-07 13:08:51 +08:00
1a5b024df6 定时任务目标字符串验证包名白名单 2022-01-06 14:50:56 +08:00
578d65dfb4 定时任务目标字符串过滤特殊字符 2022-01-05 14:56:05 +08:00
db4c2d3dd5 代码生成列表图片支持预览 2022-01-04 20:27:08 +08:00
47842a1611 update donate 2022-01-04 20:26:49 +08:00
f4f4cd9b1f Create FUNDING.yml 2022-01-04 19:50:01 +08:00
b7452cc281 update README.md 2022-01-04 10:49:59 +08:00
8ba91fc9dd 优化查询用户详细信息 2022-01-04 09:10:49 +08:00
c8d9b3f8fc 前端支持设置是否需要防止数据重复提交 2022-01-02 10:37:09 +08:00
c9d19cbe56 空值不进行回显数据字典 2022-01-02 10:29:15 +08:00
10ae0bce65 用户修改减少一次角色列表关联查询 2022-01-01 09:50:35 +08:00
7bc15245aa 预览组件支持多图显示 2022-01-01 09:46:18 +08:00
cb6228800b 代码生成新增Java类型Boolean 2022-01-01 09:28:52 +08:00
6ef899d000 修复登录失效后多次请求提示多次弹窗问题 2021-12-31 10:03:54 +08:00
167 changed files with 4395 additions and 3277 deletions

1
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1 @@
custom: http://doc.ruoyi.vip/ruoyi-vue/other/donate.html

3
.gitignore vendored
View File

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

View File

@ -1,3 +1,14 @@
<p align="center">
<img alt="logo" src="https://oscimg.oschina.net/oscnet/up-d3d0a9303e11d522a06cd263f3079027715.png">
</p>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v3.8.3</h1>
<h4 align="center">基于SpringBoot+Vue前后端分离的Java快速开发框架</h4>
<p align="center">
<a href="https://gitee.com/y_project/RuoYi-Vue/stargazers"><img src="https://gitee.com/y_project/RuoYi-Vue/badge/star.svg?theme=dark"></a>
<a href="https://gitee.com/y_project/RuoYi-Vue"><img src="https://img.shields.io/badge/RuoYi-v3.8.3-brightgreen.svg"></a>
<a href="https://gitee.com/y_project/RuoYi-Vue/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a>
</p>
## 平台简介 ## 平台简介
若依是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。 若依是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。
@ -83,4 +94,4 @@
## 若依前后端分离交流群 ## 若依前后端分离交流群
QQ群 [![加入QQ群](https://img.shields.io/badge/已满-937441-blue.svg)](https://jq.qq.com/?_wv=1027&k=5bVB1og) [![加入QQ群](https://img.shields.io/badge/已满-887144332-blue.svg)](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [![加入QQ群](https://img.shields.io/badge/已满-180251782-blue.svg)](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [![加入QQ群](https://img.shields.io/badge/已满-104180207-blue.svg)](https://jq.qq.com/?_wv=1027&k=51G72yr) [![加入QQ群](https://img.shields.io/badge/已满-186866453-blue.svg)](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [![加入QQ群](https://img.shields.io/badge/已满-201396349-blue.svg)](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [![加入QQ群](https://img.shields.io/badge/已满-101456076-blue.svg)](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [![加入QQ群](https://img.shields.io/badge/101539465-blue.svg)](https://jq.qq.com/?_wv=1027&k=UKtX5jhs) 点击按钮入群。 QQ群 [![加入QQ群](https://img.shields.io/badge/已满-937441-blue.svg)](https://jq.qq.com/?_wv=1027&k=5bVB1og) [![加入QQ群](https://img.shields.io/badge/已满-887144332-blue.svg)](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [![加入QQ群](https://img.shields.io/badge/已满-180251782-blue.svg)](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [![加入QQ群](https://img.shields.io/badge/已满-104180207-blue.svg)](https://jq.qq.com/?_wv=1027&k=51G72yr) [![加入QQ群](https://img.shields.io/badge/已满-186866453-blue.svg)](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [![加入QQ群](https://img.shields.io/badge/已满-201396349-blue.svg)](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [![加入QQ群](https://img.shields.io/badge/已满-101456076-blue.svg)](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [![加入QQ群](https://img.shields.io/badge/已满-101539465-blue.svg)](https://jq.qq.com/?_wv=1027&k=UKtX5jhs) [![加入QQ群](https://img.shields.io/badge/已满-264312783-blue.svg)](https://jq.qq.com/?_wv=1027&k=EI9an8lJ) [![加入QQ群](https://img.shields.io/badge/已满-167385320-blue.svg)](https://jq.qq.com/?_wv=1027&k=SWCtLnMz) [![加入QQ群](https://img.shields.io/badge/139821253-blue.svg)](https://jq.qq.com/?_wv=1027&k=njiWDmkj) 点击按钮入群。

47
pom.xml
View File

@ -6,33 +6,31 @@
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<version>3.8.1</version> <version>3.8.3</version>
<name>ruoyi</name> <name>ruoyi</name>
<url>http://www.ruoyi.vip</url> <url>http://www.ruoyi.vip</url>
<description>若依管理系统</description> <description>若依管理系统</description>
<properties> <properties>
<ruoyi.version>3.8.1</ruoyi.version> <ruoyi.version>3.8.3</ruoyi.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version> <java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version> <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<druid.version>1.2.8</druid.version> <druid.version>1.2.11</druid.version>
<bitwalker.version>1.21</bitwalker.version> <bitwalker.version>1.21</bitwalker.version>
<swagger.version>3.0.0</swagger.version> <swagger.version>3.0.0</swagger.version>
<kaptcha.version>2.3.2</kaptcha.version> <kaptcha.version>2.3.2</kaptcha.version>
<mybatis-spring-boot.version>2.2.0</mybatis-spring-boot.version> <mybatis-spring-boot.version>2.2.2</mybatis-spring-boot.version>
<pagehelper.boot.version>1.4.0</pagehelper.boot.version> <pagehelper.boot.version>1.4.1</pagehelper.boot.version>
<fastjson.version>1.2.79</fastjson.version> <fastjson.version>2.0.8</fastjson.version>
<oshi.version>5.8.6</oshi.version> <oshi.version>6.1.6</oshi.version>
<jna.version>5.10.0</jna.version>
<commons.io.version>2.11.0</commons.io.version> <commons.io.version>2.11.0</commons.io.version>
<commons.fileupload.version>1.4</commons.fileupload.version> <commons.fileupload.version>1.4</commons.fileupload.version>
<commons.collections.version>3.2.2</commons.collections.version> <commons.collections.version>3.2.2</commons.collections.version>
<poi.version>4.1.2</poi.version> <poi.version>4.1.2</poi.version>
<velocity.version>2.3</velocity.version> <velocity.version>2.3</velocity.version>
<log4j2.version>2.17.1</log4j2.version>
<jwt.version>0.9.1</jwt.version> <jwt.version>0.9.1</jwt.version>
</properties> </properties>
@ -44,7 +42,7 @@
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId> <artifactId>spring-boot-dependencies</artifactId>
<version>2.5.8</version> <version>2.5.14</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
@ -84,18 +82,6 @@
<version>${oshi.version}</version> <version>${oshi.version}</version>
</dependency> </dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>${jna.version}</version>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
<version>${jna.version}</version>
</dependency>
<!-- Swagger3依赖 --> <!-- Swagger3依赖 -->
<dependency> <dependency>
<groupId>io.springfox</groupId> <groupId>io.springfox</groupId>
@ -146,24 +132,11 @@
<!-- 阿里JSON解析器 --> <!-- 阿里JSON解析器 -->
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson</artifactId> <artifactId>fastjson2</artifactId>
<version>${fastjson.version}</version> <version>${fastjson.version}</version>
</dependency> </dependency>
<!-- log4j日志组件 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>${log4j2.version}</version>
</dependency>
<!-- Token生成与解析--> <!-- Token生成与解析-->
<dependency> <dependency>
<groupId>io.jsonwebtoken</groupId> <groupId>io.jsonwebtoken</groupId>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>3.8.1</version> <version>3.8.3</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>

View File

@ -6,12 +6,13 @@ import java.util.concurrent.TimeUnit;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import com.ruoyi.common.config.RuoYiConfig;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.FastByteArrayOutputStream; import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.google.code.kaptcha.Producer; import com.google.code.kaptcha.Producer;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.core.redis.RedisCache;
@ -54,7 +55,7 @@ public class CaptchaController
// 保存验证码信息 // 保存验证码信息
String uuid = IdUtils.simpleUUID(); String uuid = IdUtils.simpleUUID();
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid; String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
String capStr = null, code = null; String capStr = null, code = null;
BufferedImage image = null; BufferedImage image = null;

View File

@ -1,5 +1,7 @@
package com.ruoyi.web.controller.common; package com.ruoyi.web.controller.common;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -8,6 +10,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.config.RuoYiConfig; import com.ruoyi.common.config.RuoYiConfig;
@ -24,6 +27,7 @@ import com.ruoyi.framework.config.ServerConfig;
* @author ruoyi * @author ruoyi
*/ */
@RestController @RestController
@RequestMapping("/common")
public class CommonController public class CommonController
{ {
private static final Logger log = LoggerFactory.getLogger(CommonController.class); private static final Logger log = LoggerFactory.getLogger(CommonController.class);
@ -31,13 +35,15 @@ public class CommonController
@Autowired @Autowired
private ServerConfig serverConfig; private ServerConfig serverConfig;
private static final String FILE_DELIMETER = ",";
/** /**
* 通用下载请求 * 通用下载请求
* *
* @param fileName 文件名称 * @param fileName 文件名称
* @param delete 是否删除 * @param delete 是否删除
*/ */
@GetMapping("common/download") @GetMapping("/download")
public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request) public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request)
{ {
try try
@ -64,9 +70,9 @@ public class CommonController
} }
/** /**
* 通用上传请求 * 通用上传请求(单个)
*/ */
@PostMapping("/common/upload") @PostMapping("/upload")
public AjaxResult uploadFile(MultipartFile file) throws Exception public AjaxResult uploadFile(MultipartFile file) throws Exception
{ {
try try
@ -77,8 +83,47 @@ public class CommonController
String fileName = FileUploadUtils.upload(filePath, file); String fileName = FileUploadUtils.upload(filePath, file);
String url = serverConfig.getUrl() + fileName; String url = serverConfig.getUrl() + fileName;
AjaxResult ajax = AjaxResult.success(); AjaxResult ajax = AjaxResult.success();
ajax.put("fileName", fileName);
ajax.put("url", url); ajax.put("url", url);
ajax.put("fileName", fileName);
ajax.put("newFileName", FileUtils.getName(fileName));
ajax.put("originalFilename", file.getOriginalFilename());
return ajax;
}
catch (Exception e)
{
return AjaxResult.error(e.getMessage());
}
}
/**
* 通用上传请求(多个)
*/
@PostMapping("/uploads")
public AjaxResult uploadFiles(List<MultipartFile> files) throws Exception
{
try
{
// 上传文件路径
String filePath = RuoYiConfig.getUploadPath();
List<String> urls = new ArrayList<String>();
List<String> fileNames = new ArrayList<String>();
List<String> newFileNames = new ArrayList<String>();
List<String> originalFilenames = new ArrayList<String>();
for (MultipartFile file : files)
{
// 上传并返回新文件名称
String fileName = FileUploadUtils.upload(filePath, file);
String url = serverConfig.getUrl() + fileName;
urls.add(url);
fileNames.add(fileName);
newFileNames.add(FileUtils.getName(fileName));
originalFilenames.add(file.getOriginalFilename());
}
AjaxResult ajax = AjaxResult.success();
ajax.put("urls", StringUtils.join(urls, FILE_DELIMETER));
ajax.put("fileNames", StringUtils.join(fileNames, FILE_DELIMETER));
ajax.put("newFileNames", StringUtils.join(newFileNames, FILE_DELIMETER));
ajax.put("originalFilenames", StringUtils.join(originalFilenames, FILE_DELIMETER));
return ajax; return ajax;
} }
catch (Exception e) catch (Exception e)
@ -90,7 +135,7 @@ public class CommonController
/** /**
* 本地资源通用下载 * 本地资源通用下载
*/ */
@GetMapping("/common/download/resource") @GetMapping("/download/resource")
public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response) public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response)
throws Exception throws Exception
{ {

View File

@ -1,19 +1,25 @@
package com.ruoyi.web.controller.monitor; package com.ruoyi.web.controller.monitor;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.SysCache;
/** /**
* 缓存监控 * 缓存监控
@ -27,6 +33,16 @@ public class CacheController
@Autowired @Autowired
private RedisTemplate<String, String> redisTemplate; private RedisTemplate<String, String> redisTemplate;
private final static List<SysCache> caches = new ArrayList<SysCache>();
{
caches.add(new SysCache(CacheConstants.LOGIN_TOKEN_KEY, "用户信息"));
caches.add(new SysCache(CacheConstants.SYS_CONFIG_KEY, "配置信息"));
caches.add(new SysCache(CacheConstants.SYS_DICT_KEY, "数据字典"));
caches.add(new SysCache(CacheConstants.CAPTCHA_CODE_KEY, "验证码"));
caches.add(new SysCache(CacheConstants.REPEAT_SUBMIT_KEY, "防重提交"));
caches.add(new SysCache(CacheConstants.RATE_LIMIT_KEY, "限流处理"));
}
@PreAuthorize("@ss.hasPermi('monitor:cache:list')") @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@GetMapping() @GetMapping()
public AjaxResult getInfo() throws Exception public AjaxResult getInfo() throws Exception
@ -50,4 +66,54 @@ public class CacheController
result.put("commandStats", pieList); result.put("commandStats", pieList);
return AjaxResult.success(result); return AjaxResult.success(result);
} }
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@GetMapping("/getNames")
public AjaxResult cache()
{
return AjaxResult.success(caches);
}
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@GetMapping("/getKeys/{cacheName}")
public AjaxResult getCacheKeys(@PathVariable String cacheName)
{
Set<String> cacheKyes = redisTemplate.keys(cacheName + "*");
return AjaxResult.success(cacheKyes);
}
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@GetMapping("/getValue/{cacheName}/{cacheKey}")
public AjaxResult getCacheValue(@PathVariable String cacheName, @PathVariable String cacheKey)
{
String cacheValue = redisTemplate.opsForValue().get(cacheKey);
SysCache sysCache = new SysCache(cacheName, cacheKey, cacheValue);
return AjaxResult.success(sysCache);
}
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@DeleteMapping("/clearCacheName/{cacheName}")
public AjaxResult clearCacheName(@PathVariable String cacheName)
{
Collection<String> cacheKeys = redisTemplate.keys(cacheName + "*");
redisTemplate.delete(cacheKeys);
return AjaxResult.success();
}
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@DeleteMapping("/clearCacheKey/{cacheKey}")
public AjaxResult clearCacheKey(@PathVariable String cacheKey)
{
redisTemplate.delete(cacheKey);
return AjaxResult.success();
}
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@DeleteMapping("/clearCacheAll")
public AjaxResult clearCacheAll()
{
Collection<String> cacheKeys = redisTemplate.keys("*");
redisTemplate.delete(cacheKeys);
return AjaxResult.success();
}
} }

View File

@ -12,7 +12,7 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.annotation.Log; import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.core.domain.model.LoginUser;
@ -42,7 +42,7 @@ public class SysUserOnlineController extends BaseController
@GetMapping("/list") @GetMapping("/list")
public TableDataInfo list(String ipaddr, String userName) public TableDataInfo list(String ipaddr, String userName)
{ {
Collection<String> keys = redisCache.keys(Constants.LOGIN_TOKEN_KEY + "*"); Collection<String> keys = redisCache.keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>(); List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>();
for (String key : keys) for (String key : keys)
{ {
@ -86,7 +86,7 @@ public class SysUserOnlineController extends BaseController
@DeleteMapping("/{tokenId}") @DeleteMapping("/{tokenId}")
public AjaxResult forceLogout(@PathVariable String tokenId) public AjaxResult forceLogout(@PathVariable String tokenId)
{ {
redisCache.deleteObject(Constants.LOGIN_TOKEN_KEY + tokenId); redisCache.deleteObject(CacheConstants.LOGIN_TOKEN_KEY + tokenId);
return AjaxResult.success(); return AjaxResult.success();
} }
} }

View File

@ -125,16 +125,17 @@ public class SysDeptController extends BaseController
@PutMapping @PutMapping
public AjaxResult edit(@Validated @RequestBody SysDept dept) public AjaxResult edit(@Validated @RequestBody SysDept dept)
{ {
Long deptId = dept.getDeptId();
deptService.checkDeptDataScope(deptId);
if (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept))) if (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept)))
{ {
return AjaxResult.error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在"); return AjaxResult.error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在");
} }
else if (dept.getParentId().equals(dept.getDeptId())) else if (dept.getParentId().equals(deptId))
{ {
return AjaxResult.error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己"); return AjaxResult.error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己");
} }
else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) && deptService.selectNormalChildrenDeptById(deptId) > 0)
&& deptService.selectNormalChildrenDeptById(dept.getDeptId()) > 0)
{ {
return AjaxResult.error("该部门包含未停用的子部门!"); return AjaxResult.error("该部门包含未停用的子部门!");
} }
@ -158,6 +159,7 @@ public class SysDeptController extends BaseController
{ {
return AjaxResult.error("部门存在用户,不允许删除"); return AjaxResult.error("部门存在用户,不允许删除");
} }
deptService.checkDeptDataScope(deptId);
return toAjax(deptService.deleteDeptById(deptId)); return toAjax(deptService.deleteDeptById(deptId));
} }
} }

View File

@ -1,6 +1,5 @@
package com.ruoyi.web.controller.system; package com.ruoyi.web.controller.system;
import java.io.IOException;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -21,6 +20,7 @@ import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUploadUtils; import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.common.utils.file.MimeTypeUtils;
import com.ruoyi.framework.web.service.TokenService; import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.service.ISysUserService; import com.ruoyi.system.service.ISysUserService;
@ -121,12 +121,12 @@ public class SysProfileController extends BaseController
*/ */
@Log(title = "用户头像", businessType = BusinessType.UPDATE) @Log(title = "用户头像", businessType = BusinessType.UPDATE)
@PostMapping("/avatar") @PostMapping("/avatar")
public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) throws IOException public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) throws Exception
{ {
if (!file.isEmpty()) if (!file.isEmpty())
{ {
LoginUser loginUser = getLoginUser(); LoginUser loginUser = getLoginUser();
String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file); String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION);
if (userService.updateUserAvatar(loginUser.getUsername(), avatar)) if (userService.updateUserAvatar(loginUser.getUsername(), avatar))
{ {
AjaxResult ajax = AjaxResult.success(); AjaxResult ajax = AjaxResult.success();

View File

@ -111,6 +111,7 @@ public class SysRoleController extends BaseController
public AjaxResult edit(@Validated @RequestBody SysRole role) public AjaxResult edit(@Validated @RequestBody SysRole role)
{ {
roleService.checkRoleAllowed(role); roleService.checkRoleAllowed(role);
roleService.checkRoleDataScope(role.getRoleId());
if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role))) if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role)))
{ {
return AjaxResult.error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在"); return AjaxResult.error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在");
@ -145,6 +146,7 @@ public class SysRoleController extends BaseController
public AjaxResult dataScope(@RequestBody SysRole role) public AjaxResult dataScope(@RequestBody SysRole role)
{ {
roleService.checkRoleAllowed(role); roleService.checkRoleAllowed(role);
roleService.checkRoleDataScope(role.getRoleId());
return toAjax(roleService.authDataScope(role)); return toAjax(roleService.authDataScope(role));
} }
@ -157,6 +159,7 @@ public class SysRoleController extends BaseController
public AjaxResult changeStatus(@RequestBody SysRole role) public AjaxResult changeStatus(@RequestBody SysRole role)
{ {
roleService.checkRoleAllowed(role); roleService.checkRoleAllowed(role);
roleService.checkRoleDataScope(role.getRoleId());
role.setUpdateBy(getUsername()); role.setUpdateBy(getUsername());
return toAjax(roleService.updateRoleStatus(role)); return toAjax(roleService.updateRoleStatus(role));
} }
@ -236,6 +239,7 @@ public class SysRoleController extends BaseController
@PutMapping("/authUser/selectAll") @PutMapping("/authUser/selectAll")
public AjaxResult selectAuthUserAll(Long roleId, Long[] userIds) public AjaxResult selectAuthUserAll(Long roleId, Long[] userIds)
{ {
roleService.checkRoleDataScope(roleId);
return toAjax(roleService.insertAuthUsers(roleId, userIds)); return toAjax(roleService.insertAuthUsers(roleId, userIds));
} }
} }

View File

@ -104,9 +104,10 @@ public class SysUserController extends BaseController
ajax.put("posts", postService.selectPostAll()); ajax.put("posts", postService.selectPostAll());
if (StringUtils.isNotNull(userId)) if (StringUtils.isNotNull(userId))
{ {
ajax.put(AjaxResult.DATA_TAG, userService.selectUserById(userId)); SysUser sysUser = userService.selectUserById(userId);
ajax.put(AjaxResult.DATA_TAG, sysUser);
ajax.put("postIds", postService.selectPostListByUserId(userId)); ajax.put("postIds", postService.selectPostListByUserId(userId));
ajax.put("roleIds", roleService.selectRoleListByUserId(userId)); ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList()));
} }
return ajax; return ajax;
} }
@ -147,6 +148,7 @@ public class SysUserController extends BaseController
public AjaxResult edit(@Validated @RequestBody SysUser user) public AjaxResult edit(@Validated @RequestBody SysUser user)
{ {
userService.checkUserAllowed(user); userService.checkUserAllowed(user);
userService.checkUserDataScope(user.getUserId());
if (StringUtils.isNotEmpty(user.getPhonenumber()) if (StringUtils.isNotEmpty(user.getPhonenumber())
&& UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
{ {
@ -185,6 +187,7 @@ public class SysUserController extends BaseController
public AjaxResult resetPwd(@RequestBody SysUser user) public AjaxResult resetPwd(@RequestBody SysUser user)
{ {
userService.checkUserAllowed(user); userService.checkUserAllowed(user);
userService.checkUserDataScope(user.getUserId());
user.setPassword(SecurityUtils.encryptPassword(user.getPassword())); user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
user.setUpdateBy(getUsername()); user.setUpdateBy(getUsername());
return toAjax(userService.resetPwd(user)); return toAjax(userService.resetPwd(user));
@ -199,6 +202,7 @@ public class SysUserController extends BaseController
public AjaxResult changeStatus(@RequestBody SysUser user) public AjaxResult changeStatus(@RequestBody SysUser user)
{ {
userService.checkUserAllowed(user); userService.checkUserAllowed(user);
userService.checkUserDataScope(user.getUserId());
user.setUpdateBy(getUsername()); user.setUpdateBy(getUsername());
return toAjax(userService.updateUserStatus(user)); return toAjax(userService.updateUserStatus(user));
} }
@ -226,6 +230,7 @@ public class SysUserController extends BaseController
@PutMapping("/authRole") @PutMapping("/authRole")
public AjaxResult insertAuthRole(Long userId, Long[] roleIds) public AjaxResult insertAuthRole(Long userId, Long[] roleIds)
{ {
userService.checkUserDataScope(userId);
userService.insertUserAuth(userId, roleIds); userService.insertUserAuth(userId, roleIds);
return success(); return success();
} }

View File

@ -13,7 +13,7 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParam;
@ -40,24 +40,24 @@ public class TestController extends BaseController
@ApiOperation("获取用户列表") @ApiOperation("获取用户列表")
@GetMapping("/list") @GetMapping("/list")
public AjaxResult userList() public R<List<UserEntity>> userList()
{ {
List<UserEntity> userList = new ArrayList<UserEntity>(users.values()); List<UserEntity> userList = new ArrayList<UserEntity>(users.values());
return AjaxResult.success(userList); return R.ok(userList);
} }
@ApiOperation("获取用户详细") @ApiOperation("获取用户详细")
@ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class) @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class)
@GetMapping("/{userId}") @GetMapping("/{userId}")
public AjaxResult getUser(@PathVariable Integer userId) public R<UserEntity> getUser(@PathVariable Integer userId)
{ {
if (!users.isEmpty() && users.containsKey(userId)) if (!users.isEmpty() && users.containsKey(userId))
{ {
return AjaxResult.success(users.get(userId)); return R.ok(users.get(userId));
} }
else else
{ {
return error("用户不存在"); return R.fail("用户不存在");
} }
} }
@ -69,44 +69,46 @@ public class TestController extends BaseController
@ApiImplicitParam(name = "mobile", value = "用户手机", dataType = "String", dataTypeClass = String.class) @ApiImplicitParam(name = "mobile", value = "用户手机", dataType = "String", dataTypeClass = String.class)
}) })
@PostMapping("/save") @PostMapping("/save")
public AjaxResult save(UserEntity user) public R<String> save(UserEntity user)
{ {
if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId())) if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
{ {
return error("用户ID不能为空"); return R.fail("用户ID不能为空");
} }
return AjaxResult.success(users.put(user.getUserId(), user)); users.put(user.getUserId(), user);
return R.ok();
} }
@ApiOperation("更新用户") @ApiOperation("更新用户")
@PutMapping("/update") @PutMapping("/update")
public AjaxResult update(@RequestBody UserEntity user) public R<String> update(@RequestBody UserEntity user)
{ {
if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId())) if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
{ {
return error("用户ID不能为空"); return R.fail("用户ID不能为空");
} }
if (users.isEmpty() || !users.containsKey(user.getUserId())) if (users.isEmpty() || !users.containsKey(user.getUserId()))
{ {
return error("用户不存在"); return R.fail("用户不存在");
} }
users.remove(user.getUserId()); users.remove(user.getUserId());
return AjaxResult.success(users.put(user.getUserId(), user)); users.put(user.getUserId(), user);
return R.ok();
} }
@ApiOperation("删除用户信息") @ApiOperation("删除用户信息")
@ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class) @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class)
@DeleteMapping("/{userId}") @DeleteMapping("/{userId}")
public AjaxResult delete(@PathVariable Integer userId) public R<String> delete(@PathVariable Integer userId)
{ {
if (!users.isEmpty() && users.containsKey(userId)) if (!users.isEmpty() && users.containsKey(userId))
{ {
users.remove(userId); users.remove(userId);
return success(); return R.ok();
} }
else else
{ {
return error("用户不存在"); return R.fail("用户不存在");
} }
} }
} }

View File

@ -3,9 +3,9 @@ ruoyi:
# 名称 # 名称
name: RuoYi name: RuoYi
# 版本 # 版本
version: 3.8.1 version: 3.8.3
# 版权年份 # 版权年份
copyrightYear: 2021 copyrightYear: 2022
# 实例演示开关 # 实例演示开关
demoEnabled: true demoEnabled: true
# 文件路径 示例( Windows配置D:/ruoyi/uploadPathLinux配置 /home/ruoyi/uploadPath # 文件路径 示例( Windows配置D:/ruoyi/uploadPathLinux配置 /home/ruoyi/uploadPath

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>3.8.1</version> <version>3.8.3</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@ -61,8 +61,8 @@
<!-- 阿里JSON解析器 --> <!-- 阿里JSON解析器 -->
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson</artifactId> <artifactId>fastjson2</artifactId>
</dependency> </dependency>
<!-- io常用工具类 --> <!-- io常用工具类 -->

View File

@ -0,0 +1,19 @@
package com.ruoyi.common.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 匿名访问不鉴权注解
*
* @author ruoyi
*/
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Anonymous
{
}

View File

@ -5,6 +5,8 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import java.math.BigDecimal; import java.math.BigDecimal;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import com.ruoyi.common.utils.poi.ExcelHandlerAdapter; import com.ruoyi.common.utils.poi.ExcelHandlerAdapter;
/** /**
@ -56,11 +58,6 @@ public @interface Excel
*/ */
public int roundingMode() default BigDecimal.ROUND_HALF_EVEN; public int roundingMode() default BigDecimal.ROUND_HALF_EVEN;
/**
* 导出类型0数字 1字符串
*/
public ColumnType cellType() default ColumnType.STRING;
/** /**
* 导出时在excel中每个列的高度 单位为字符 * 导出时在excel中每个列的高度 单位为字符
*/ */
@ -107,9 +104,19 @@ public @interface Excel
public boolean isStatistics() default false; public boolean isStatistics() default false;
/** /**
* 导出字段对齐方式0默认1靠左2居中3靠右 * 导出类型0数字 1字符串
*/ */
public Align align() default Align.AUTO; public ColumnType cellType() default ColumnType.STRING;
/**
* 导出字体颜色
*/
public IndexedColors color() default IndexedColors.BLACK;
/**
* 导出字段对齐方式
*/
public HorizontalAlignment align() default HorizontalAlignment.CENTER;
/** /**
* 自定义数据处理器 * 自定义数据处理器

View File

@ -5,7 +5,7 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.enums.LimitType; import com.ruoyi.common.enums.LimitType;
/** /**
@ -21,7 +21,7 @@ public @interface RateLimiter
/** /**
* 限流key * 限流key
*/ */
public String key() default Constants.RATE_LIMIT_KEY; public String key() default CacheConstants.RATE_LIMIT_KEY;
/** /**
* 限流时间,单位秒 * 限流时间,单位秒

View File

@ -0,0 +1,39 @@
package com.ruoyi.common.constant;
/**
* 缓存的key 常量
*
* @author ruoyi
*/
public class CacheConstants
{
/**
* 登录用户 redis key
*/
public static final String LOGIN_TOKEN_KEY = "login_tokens:";
/**
* 验证码 redis key
*/
public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
/**
* 参数管理 cache key
*/
public static final String SYS_CONFIG_KEY = "sys_config:";
/**
* 字典管理 cache key
*/
public static final String SYS_DICT_KEY = "sys_dict:";
/**
* 防重提交 redis key
*/
public static final String REPEAT_SUBMIT_KEY = "repeat_submit:";
/**
* 限流 redis key
*/
public static final String RATE_LIMIT_KEY = "rate_limit:";
}

View File

@ -59,26 +59,6 @@ public class Constants
*/ */
public static final String LOGIN_FAIL = "Error"; 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:";
/** /**
* 验证码有效期(分钟) * 验证码有效期(分钟)
*/ */
@ -124,16 +104,6 @@ public class Constants
*/ */
public static final String JWT_AUTHORITIES = "authorities"; 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:";
/** /**
* 资源映射路径 前缀 * 资源映射路径 前缀
*/ */
@ -142,16 +112,26 @@ public class Constants
/** /**
* RMI 远程方法调用 * RMI 远程方法调用
*/ */
public static final String LOOKUP_RMI = "rmi://"; public static final String LOOKUP_RMI = "rmi:";
/** /**
* LDAP 远程方法调用 * LDAP 远程方法调用
*/ */
public static final String LOOKUP_LDAP = "ldap://"; public static final String LOOKUP_LDAP = "ldap:";
/**
* LDAPS 远程方法调用
*/
public static final String LOOKUP_LDAPS = "ldaps:";
/**
* 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)
*/
public static final String[] JOB_WHITELIST_STR = { "com.ruoyi" };
/** /**
* 定时任务违规的字符 * 定时任务违规的字符
*/ */
public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml", public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
"org.springframework.jndi" }; "org.springframework", "org.apache", "com.ruoyi.common.utils.file" };
} }

View File

@ -109,6 +109,9 @@ public class GenConstants
/** 模糊查询 */ /** 模糊查询 */
public static final String QUERY_LIKE = "LIKE"; public static final String QUERY_LIKE = "LIKE";
/** 相等查询 */
public static final String QUERY_EQ = "EQ";
/** 需要 */ /** 需要 */
public static final String REQUIRE = "1"; public static final String REQUIRE = "1";
} }

View File

@ -68,6 +68,14 @@ public class BaseController
} }
} }
/**
* 清理分页的线程变量
*/
protected void clearPage()
{
PageUtils.clearPage();
}
/** /**
* 响应请求分页数据 * 响应请求分页数据
*/ */

View File

@ -0,0 +1,105 @@
package com.ruoyi.common.core.domain;
import java.io.Serializable;
import com.ruoyi.common.constant.HttpStatus;
/**
* 响应信息主体
*
* @author ruoyi
*/
public class R<T> implements Serializable
{
private static final long serialVersionUID = 1L;
/** 成功 */
public static final int SUCCESS = HttpStatus.SUCCESS;
/** 失败 */
public static final int FAIL = HttpStatus.ERROR;
private int code;
private String msg;
private T data;
public static <T> R<T> ok()
{
return restResult(null, SUCCESS, "操作成功");
}
public static <T> R<T> ok(T data)
{
return restResult(data, SUCCESS, "操作成功");
}
public static <T> R<T> ok(T data, String msg)
{
return restResult(data, SUCCESS, msg);
}
public static <T> R<T> fail()
{
return restResult(null, FAIL, "操作失败");
}
public static <T> R<T> fail(String msg)
{
return restResult(null, FAIL, msg);
}
public static <T> R<T> fail(T data)
{
return restResult(data, FAIL, "操作失败");
}
public static <T> R<T> fail(T data, String msg)
{
return restResult(data, FAIL, msg);
}
public static <T> R<T> fail(int code, String msg)
{
return restResult(null, code, msg);
}
private static <T> R<T> restResult(T data, int code, String msg)
{
R<T> apiResult = new R<>();
apiResult.setCode(code);
apiResult.setData(data);
apiResult.setMsg(msg);
return apiResult;
}
public int getCode()
{
return code;
}
public void setCode(int code)
{
this.code = code;
}
public String getMsg()
{
return msg;
}
public void setMsg(String msg)
{
this.msg = msg;
}
public T getData()
{
return data;
}
public void setData(T data)
{
this.data = data;
}
}

View File

@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.validation.constraints.Email; import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size; import javax.validation.constraints.Size;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
@ -31,7 +32,7 @@ public class SysDept extends BaseEntity
private String deptName; private String deptName;
/** 显示顺序 */ /** 显示顺序 */
private String orderNum; private Integer orderNum;
/** 负责人 */ /** 负责人 */
private String leader; private String leader;
@ -96,13 +97,13 @@ public class SysDept extends BaseEntity
this.deptName = deptName; this.deptName = deptName;
} }
@NotBlank(message = "显示顺序不能为空") @NotNull(message = "显示顺序不能为空")
public String getOrderNum() public Integer getOrderNum()
{ {
return orderNum; return orderNum;
} }
public void setOrderNum(String orderNum) public void setOrderNum(Integer orderNum)
{ {
this.orderNum = orderNum; this.orderNum = orderNum;
} }

View File

@ -1,6 +1,7 @@
package com.ruoyi.common.core.domain.entity; package com.ruoyi.common.core.domain.entity;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size; import javax.validation.constraints.Size;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
@ -57,6 +58,7 @@ public class SysDictType extends BaseEntity
@NotBlank(message = "字典类型不能为空") @NotBlank(message = "字典类型不能为空")
@Size(min = 0, max = 100, message = "字典类型类型长度不能超过100个字符") @Size(min = 0, max = 100, message = "字典类型类型长度不能超过100个字符")
@Pattern(regexp = "^[a-z][a-z0-9_]*$", message = "字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)")
public String getDictType() public String getDictType()
{ {
return dictType; return dictType;

View File

@ -3,6 +3,7 @@ package com.ruoyi.common.core.domain.entity;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size; import javax.validation.constraints.Size;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
@ -30,7 +31,7 @@ public class SysMenu extends BaseEntity
private Long parentId; private Long parentId;
/** 显示顺序 */ /** 显示顺序 */
private String orderNum; private Integer orderNum;
/** 路由地址 */ /** 路由地址 */
private String path; private String path;
@ -107,13 +108,13 @@ public class SysMenu extends BaseEntity
this.parentId = parentId; this.parentId = parentId;
} }
@NotBlank(message = "显示顺序不能为空") @NotNull(message = "显示顺序不能为空")
public String getOrderNum() public Integer getOrderNum()
{ {
return orderNum; return orderNum;
} }
public void setOrderNum(String orderNum) public void setOrderNum(Integer orderNum)
{ {
this.orderNum = orderNum; this.orderNum = orderNum;
} }

View File

@ -5,8 +5,6 @@ import java.util.List;
import javax.validation.constraints.*; import javax.validation.constraints.*;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.ruoyi.common.annotation.Excel; import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.annotation.Excel.ColumnType; import com.ruoyi.common.annotation.Excel.ColumnType;
import com.ruoyi.common.annotation.Excel.Type; import com.ruoyi.common.annotation.Excel.Type;
@ -57,9 +55,6 @@ public class SysUser extends BaseEntity
/** 密码 */ /** 密码 */
private String password; private String password;
/** 盐加密 */
private String salt;
/** 帐号状态0正常 1停用 */ /** 帐号状态0正常 1停用 */
@Excel(name = "帐号状态", readConverterExp = "0=正常,1=停用") @Excel(name = "帐号状态", readConverterExp = "0=正常,1=停用")
private String status; private String status;
@ -202,8 +197,6 @@ public class SysUser extends BaseEntity
this.avatar = avatar; this.avatar = avatar;
} }
@JsonIgnore
@JsonProperty
public String getPassword() public String getPassword()
{ {
return password; return password;
@ -214,16 +207,6 @@ public class SysUser extends BaseEntity
this.password = password; this.password = password;
} }
public String getSalt()
{
return salt;
}
public void setSalt(String salt)
{
this.salt = salt;
}
public String getStatus() public String getStatus()
{ {
return status; return status;
@ -326,7 +309,6 @@ public class SysUser extends BaseEntity
.append("sex", getSex()) .append("sex", getSex())
.append("avatar", getAvatar()) .append("avatar", getAvatar())
.append("password", getPassword()) .append("password", getPassword())
.append("salt", getSalt())
.append("status", getStatus()) .append("status", getStatus())
.append("delFlag", getDelFlag()) .append("delFlag", getDelFlag())
.append("loginIp", getLoginIp()) .append("loginIp", getLoginIp())

View File

@ -25,7 +25,7 @@ public class LoginBody
/** /**
* 唯一标识 * 唯一标识
*/ */
private String uuid = ""; private String uuid;
public String getUsername() public String getUsername()
{ {

View File

@ -4,7 +4,7 @@ import java.util.Collection;
import java.util.Set; import java.util.Set;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import com.alibaba.fastjson.annotation.JSONField; import com.alibaba.fastjson2.annotation.JSONField;
import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.domain.entity.SysUser;
/** /**

View File

@ -1,5 +1,6 @@
package com.ruoyi.common.core.page; package com.ruoyi.common.core.page;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.utils.ServletUtils; import com.ruoyi.common.utils.ServletUtils;
/** /**
@ -40,8 +41,8 @@ public class TableSupport
public static PageDomain getPageDomain() public static PageDomain getPageDomain()
{ {
PageDomain pageDomain = new PageDomain(); PageDomain pageDomain = new PageDomain();
pageDomain.setPageNum(ServletUtils.getParameterToInt(PAGE_NUM)); pageDomain.setPageNum(Convert.toInt(ServletUtils.getParameter(PAGE_NUM), 1));
pageDomain.setPageSize(ServletUtils.getParameterToInt(PAGE_SIZE)); pageDomain.setPageSize(Convert.toInt(ServletUtils.getParameter(PAGE_SIZE), 10));
pageDomain.setOrderByColumn(ServletUtils.getParameter(ORDER_BY_COLUMN)); pageDomain.setOrderByColumn(ServletUtils.getParameter(ORDER_BY_COLUMN));
pageDomain.setIsAsc(ServletUtils.getParameter(IS_ASC)); pageDomain.setIsAsc(ServletUtils.getParameter(IS_ASC));
pageDomain.setReasonable(ServletUtils.getParameterToBool(REASONABLE)); pageDomain.setReasonable(ServletUtils.getParameterToBool(REASONABLE));

View File

@ -213,12 +213,12 @@ public class RedisCache
* 删除Hash中的数据 * 删除Hash中的数据
* *
* @param key * @param key
* @param mapkey * @param hKey
*/ */
public void delCacheMapValue(final String key, final String hkey) public void delCacheMapValue(final String key, final String hKey)
{ {
HashOperations hashOperations = redisTemplate.opsForHash(); HashOperations hashOperations = redisTemplate.opsForHash();
hashOperations.delete(key, hkey); hashOperations.delete(key, hKey);
} }
/** /**

View File

@ -562,17 +562,12 @@ public class Convert
switch (valueStr) switch (valueStr)
{ {
case "true": case "true":
return true;
case "false":
return false;
case "yes": case "yes":
return true;
case "ok": case "ok":
return true;
case "no":
return false;
case "1": case "1":
return true; return true;
case "false":
case "no":
case "0": case "0":
return false; return false;
default: default:

View File

@ -18,7 +18,7 @@ public class InvalidExtensionException extends FileUploadException
public InvalidExtensionException(String[] allowedExtension, String extension, String filename) public InvalidExtensionException(String[] allowedExtension, String extension, String filename)
{ {
super("filename : [" + filename + "], extension : [" + extension + "], allowed extension : [" + Arrays.toString(allowedExtension) + "]"); super("文件[" + filename + "]后缀[" + extension + "]不正确,请上传" + Arrays.toString(allowedExtension) + "格式");
this.allowedExtension = allowedExtension; this.allowedExtension = allowedExtension;
this.extension = extension; this.extension = extension;
this.filename = filename; this.filename = filename;

View File

@ -3,6 +3,11 @@ package com.ruoyi.common.utils;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date; import java.util.Date;
import org.apache.commons.lang3.time.DateFormatUtils; import org.apache.commons.lang3.time.DateFormatUtils;
@ -131,6 +136,14 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
return new Date(time); return new Date(time);
} }
/**
* 计算相差天数
*/
public static int differentDaysByMillisecond(Date date1, Date date2)
{
return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
}
/** /**
* 计算两个时间差 * 计算两个时间差
*/ */
@ -152,4 +165,23 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
// long sec = diff % nd % nh % nm / ns; // long sec = diff % nd % nh % nm / ns;
return day + "" + hour + "小时" + min + "分钟"; return day + "" + hour + "小时" + min + "分钟";
} }
/**
* 增加 LocalDateTime ==> Date
*/
public static Date toDate(LocalDateTime temporalAccessor)
{
ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());
return Date.from(zdt.toInstant());
}
/**
* 增加 LocalDate ==> Date
*/
public static Date toDate(LocalDate temporalAccessor)
{
LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));
ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
return Date.from(zdt.toInstant());
}
} }

View File

@ -2,7 +2,8 @@ package com.ruoyi.common.utils;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import com.ruoyi.common.constant.Constants; import com.alibaba.fastjson2.JSONArray;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.domain.entity.SysDictData; import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.spring.SpringUtils; import com.ruoyi.common.utils.spring.SpringUtils;
@ -38,11 +39,10 @@ public class DictUtils
*/ */
public static List<SysDictData> getDictCache(String key) public static List<SysDictData> getDictCache(String key)
{ {
Object cacheObj = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key)); JSONArray arrayCache = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key));
if (StringUtils.isNotNull(cacheObj)) if (StringUtils.isNotNull(arrayCache))
{ {
List<SysDictData> dictDatas = StringUtils.cast(cacheObj); return arrayCache.toList(SysDictData.class);
return dictDatas;
} }
return null; return null;
} }
@ -84,7 +84,9 @@ public class DictUtils
StringBuilder propertyString = new StringBuilder(); StringBuilder propertyString = new StringBuilder();
List<SysDictData> datas = getDictCache(dictType); List<SysDictData> datas = getDictCache(dictType);
if (StringUtils.containsAny(separator, dictValue) && StringUtils.isNotEmpty(datas)) if (StringUtils.isNotNull(datas))
{
if (StringUtils.containsAny(separator, dictValue))
{ {
for (SysDictData dict : datas) for (SysDictData dict : datas)
{ {
@ -92,7 +94,7 @@ public class DictUtils
{ {
if (value.equals(dict.getDictValue())) if (value.equals(dict.getDictValue()))
{ {
propertyString.append(dict.getDictLabel() + separator); propertyString.append(dict.getDictLabel()).append(separator);
break; break;
} }
} }
@ -108,6 +110,7 @@ public class DictUtils
} }
} }
} }
}
return StringUtils.stripEnd(propertyString.toString(), separator); return StringUtils.stripEnd(propertyString.toString(), separator);
} }
@ -132,7 +135,7 @@ public class DictUtils
{ {
if (label.equals(dict.getDictLabel())) if (label.equals(dict.getDictLabel()))
{ {
propertyString.append(dict.getDictValue() + separator); propertyString.append(dict.getDictValue()).append(separator);
break; break;
} }
} }
@ -166,7 +169,7 @@ public class DictUtils
*/ */
public static void clearDictCache() public static void clearDictCache()
{ {
Collection<String> keys = SpringUtils.getBean(RedisCache.class).keys(Constants.SYS_DICT_KEY + "*"); Collection<String> keys = SpringUtils.getBean(RedisCache.class).keys(CacheConstants.SYS_DICT_KEY + "*");
SpringUtils.getBean(RedisCache.class).deleteObject(keys); SpringUtils.getBean(RedisCache.class).deleteObject(keys);
} }
@ -178,6 +181,6 @@ public class DictUtils
*/ */
public static String getCacheKey(String configKey) public static String getCacheKey(String configKey)
{ {
return Constants.SYS_DICT_KEY + configKey; return CacheConstants.SYS_DICT_KEY + configKey;
} }
} }

View File

@ -18,8 +18,7 @@ public class ExceptionUtil
{ {
StringWriter sw = new StringWriter(); StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw, true)); e.printStackTrace(new PrintWriter(sw, true));
String str = sw.toString(); return sw.toString();
return str;
} }
public static String getRootErrorMessage(Exception e) public static String getRootErrorMessage(Exception e)

View File

@ -20,10 +20,16 @@ public class PageUtils extends PageHelper
PageDomain pageDomain = TableSupport.buildPageRequest(); PageDomain pageDomain = TableSupport.buildPageRequest();
Integer pageNum = pageDomain.getPageNum(); Integer pageNum = pageDomain.getPageNum();
Integer pageSize = pageDomain.getPageSize(); Integer pageSize = pageDomain.getPageSize();
if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize))
{
String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy()); String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
PageHelper.startPage(pageNum, pageSize, orderBy); Boolean reasonable = pageDomain.getReasonable();
} PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);
}
/**
* 清理分页的线程变量
*/
public static void clearPage()
{
PageHelper.clearPage();
} }
} }

View File

@ -1,12 +1,16 @@
package com.ruoyi.common.utils; package com.ruoyi.common.utils;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;
import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.request.ServletRequestAttributes;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.text.Convert; import com.ruoyi.common.core.text.Convert;
/** /**
@ -99,9 +103,8 @@ public class ServletUtils
* *
* @param response 渲染对象 * @param response 渲染对象
* @param string 待渲染的字符串 * @param string 待渲染的字符串
* @return null
*/ */
public static String renderString(HttpServletResponse response, String string) public static void renderString(HttpServletResponse response, String string)
{ {
try try
{ {
@ -114,7 +117,6 @@ public class ServletUtils
{ {
e.printStackTrace(); e.printStackTrace();
} }
return null;
} }
/** /**
@ -125,13 +127,13 @@ public class ServletUtils
public static boolean isAjaxRequest(HttpServletRequest request) public static boolean isAjaxRequest(HttpServletRequest request)
{ {
String accept = request.getHeader("accept"); String accept = request.getHeader("accept");
if (accept != null && accept.indexOf("application/json") != -1) if (accept != null && accept.contains("application/json"))
{ {
return true; return true;
} }
String xRequestedWith = request.getHeader("X-Requested-With"); String xRequestedWith = request.getHeader("X-Requested-With");
if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1) if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest"))
{ {
return true; return true;
} }
@ -143,10 +145,42 @@ public class ServletUtils
} }
String ajax = request.getParameter("__ajax"); String ajax = request.getParameter("__ajax");
if (StringUtils.inStringIgnoreCase(ajax, "json", "xml")) return StringUtils.inStringIgnoreCase(ajax, "json", "xml");
}
/**
* 内容编码
*
* @param str 内容
* @return 编码后的内容
*/
public static String urlEncode(String str)
{ {
return true; try
{
return URLEncoder.encode(str, Constants.UTF8);
}
catch (UnsupportedEncodingException e)
{
return StringUtils.EMPTY;
}
}
/**
* 内容解码
*
* @param str 内容
* @return 解码后的内容
*/
public static String urlDecode(String str)
{
try
{
return URLDecoder.decode(str, Constants.UTF8);
}
catch (UnsupportedEncodingException e)
{
return StringUtils.EMPTY;
} }
return false;
} }
} }

View File

@ -531,4 +531,53 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
{ {
return (T) obj; return (T) obj;
} }
/**
* 数字左边补齐0使之达到指定长度。注意如果数字转换为字符串后长度大于size则只保留 最后size个字符。
*
* @param num 数字对象
* @param size 字符串指定长度
* @return 返回数字的字符串格式,该字符串为指定长度。
*/
public static final String padl(final Number num, final int size)
{
return padl(num.toString(), size, '0');
}
/**
* 字符串左补齐。如果原始字符串s长度大于size则只保留最后size个字符。
*
* @param s 原始字符串
* @param size 字符串指定长度
* @param c 用于补齐的字符
* @return 返回指定长度的字符串,由原字符串左补齐或截取得到。
*/
public static final String padl(final String s, final int size, final char c)
{
final StringBuilder sb = new StringBuilder(size);
if (s != null)
{
final int len = s.length();
if (s.length() <= size)
{
for (int i = size - len; i > 0; i--)
{
sb.append(c);
}
sb.append(s);
}
else
{
return s.substring(len - size, len);
}
}
else
{
for (int i = size; i > 0; i--)
{
sb.append(c);
}
}
return sb.toString();
}
} }

View File

@ -1,228 +0,0 @@
package com.ruoyi.common.utils;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Random;
import javax.imageio.ImageIO;
/**
* 验证码工具类
*
* @author ruoyi
*/
public class VerifyCodeUtils
{
// 使用到Algerian字体系统里没有的话需要安装字体字体只显示大写去掉了1,0,i,o几个容易混淆的字符
public static final String VERIFY_CODES = "123456789ABCDEFGHJKLMNPQRSTUVWXYZ";
private static Random random = new SecureRandom();
/**
* 使用系统默认字符源生成验证码
*
* @param verifySize 验证码长度
* @return
*/
public static String generateVerifyCode(int verifySize)
{
return generateVerifyCode(verifySize, VERIFY_CODES);
}
/**
* 使用指定源生成验证码
*
* @param verifySize 验证码长度
* @param sources 验证码字符源
* @return
*/
public static String generateVerifyCode(int verifySize, String sources)
{
if (sources == null || sources.length() == 0)
{
sources = VERIFY_CODES;
}
int codesLen = sources.length();
Random rand = new Random(System.currentTimeMillis());
StringBuilder verifyCode = new StringBuilder(verifySize);
for (int i = 0; i < verifySize; i++)
{
verifyCode.append(sources.charAt(rand.nextInt(codesLen - 1)));
}
return verifyCode.toString();
}
/**
* 输出指定验证码图片流
*
* @param w
* @param h
* @param os
* @param code
* @throws IOException
*/
public static void outputImage(int w, int h, OutputStream os, String code) throws IOException
{
int verifySize = code.length();
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Random rand = new Random();
Graphics2D g2 = image.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Color[] colors = new Color[5];
Color[] colorSpaces = new Color[] { Color.WHITE, Color.CYAN, Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA,
Color.ORANGE, Color.PINK, Color.YELLOW };
float[] fractions = new float[colors.length];
for (int i = 0; i < colors.length; i++)
{
colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)];
fractions[i] = rand.nextFloat();
}
Arrays.sort(fractions);
g2.setColor(Color.GRAY);// 设置边框色
g2.fillRect(0, 0, w, h);
Color c = getRandColor(200, 250);
g2.setColor(c);// 设置背景色
g2.fillRect(0, 2, w, h - 4);
// 绘制干扰线
Random random = new Random();
g2.setColor(getRandColor(160, 200));// 设置线条的颜色
for (int i = 0; i < 20; i++)
{
int x = random.nextInt(w - 1);
int y = random.nextInt(h - 1);
int xl = random.nextInt(6) + 1;
int yl = random.nextInt(12) + 1;
g2.drawLine(x, y, x + xl + 40, y + yl + 20);
}
// 添加噪点
float yawpRate = 0.05f;// 噪声率
int area = (int) (yawpRate * w * h);
for (int i = 0; i < area; i++)
{
int x = random.nextInt(w);
int y = random.nextInt(h);
int rgb = getRandomIntColor();
image.setRGB(x, y, rgb);
}
shear(g2, w, h, c);// 使图片扭曲
g2.setColor(getRandColor(100, 160));
int fontSize = h - 4;
Font font = new Font("Algerian", Font.ITALIC, fontSize);
g2.setFont(font);
char[] chars = code.toCharArray();
for (int i = 0; i < verifySize; i++)
{
AffineTransform affine = new AffineTransform();
affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1),
(w / verifySize) * i + fontSize / 2, h / 2);
g2.setTransform(affine);
g2.drawChars(chars, i, 1, ((w - 10) / verifySize) * i + 5, h / 2 + fontSize / 2 - 10);
}
g2.dispose();
ImageIO.write(image, "jpg", os);
}
private static Color getRandColor(int fc, int bc)
{
if (fc > 255) {
fc = 255;
}
if (bc > 255) {
bc = 255;
}
int r = fc + random.nextInt(bc - fc);
int g = fc + random.nextInt(bc - fc);
int b = fc + random.nextInt(bc - fc);
return new Color(r, g, b);
}
private static int getRandomIntColor()
{
int[] rgb = getRandomRgb();
int color = 0;
for (int c : rgb)
{
color = color << 8;
color = color | c;
}
return color;
}
private static int[] getRandomRgb()
{
int[] rgb = new int[3];
for (int i = 0; i < 3; i++)
{
rgb[i] = random.nextInt(255);
}
return rgb;
}
private static void shear(Graphics g, int w1, int h1, Color color)
{
shearX(g, w1, h1, color);
shearY(g, w1, h1, color);
}
private static void shearX(Graphics g, int w1, int h1, Color color)
{
int period = random.nextInt(2);
boolean borderGap = true;
int frames = 1;
int phase = random.nextInt(2);
for (int i = 0; i < h1; i++)
{
double d = (double) (period >> 1)
* Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames);
g.copyArea(0, i, w1, 1, (int) d, 0);
if (borderGap)
{
g.setColor(color);
g.drawLine((int) d, i, 0, i);
g.drawLine((int) d + w1, i, w1, i);
}
}
}
private static void shearY(Graphics g, int w1, int h1, Color color)
{
int period = random.nextInt(40) + 10; // 50;
boolean borderGap = true;
int frames = 20;
int phase = 7;
for (int i = 0; i < w1; i++)
{
double d = (double) (period >> 1)
* Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames);
g.copyArea(i, 0, 1, h1, 0, (int) d);
if (borderGap)
{
g.setColor(color);
g.drawLine(i, (int) d, i, 0);
g.drawLine(i, (int) d + h1, i, h1);
}
}
}
}

View File

@ -2,6 +2,8 @@ package com.ruoyi.common.utils.file;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Paths;
import java.util.Objects;
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.config.RuoYiConfig; import com.ruoyi.common.config.RuoYiConfig;
@ -11,7 +13,7 @@ import com.ruoyi.common.exception.file.FileSizeLimitExceededException;
import com.ruoyi.common.exception.file.InvalidExtensionException; import com.ruoyi.common.exception.file.InvalidExtensionException;
import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.IdUtils; import com.ruoyi.common.utils.uuid.Seq;
/** /**
* 文件上传工具类 * 文件上传工具类
@ -100,7 +102,7 @@ public class FileUploadUtils
throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
InvalidExtensionException InvalidExtensionException
{ {
int fileNamelength = file.getOriginalFilename().length(); int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length();
if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH)
{ {
throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
@ -110,10 +112,9 @@ public class FileUploadUtils
String fileName = extractFilename(file); String fileName = extractFilename(file);
File desc = getAbsoluteFile(baseDir, fileName); String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
file.transferTo(desc); file.transferTo(Paths.get(absPath));
String pathFileName = getPathFileName(baseDir, fileName); return getPathFileName(baseDir, fileName);
return pathFileName;
} }
/** /**
@ -121,10 +122,8 @@ public class FileUploadUtils
*/ */
public static final String extractFilename(MultipartFile file) public static final String extractFilename(MultipartFile file)
{ {
String fileName = file.getOriginalFilename(); return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(),
String extension = getExtension(file); FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file));
fileName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension;
return fileName;
} }
public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException
@ -145,8 +144,7 @@ public class FileUploadUtils
{ {
int dirLastIndex = RuoYiConfig.getProfile().length() + 1; int dirLastIndex = RuoYiConfig.getProfile().length() + 1;
String currentDir = StringUtils.substring(uploadDir, dirLastIndex); String currentDir = StringUtils.substring(uploadDir, dirLastIndex);
String pathFileName = Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName; return Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName;
return pathFileName;
} }
/** /**
@ -161,7 +159,7 @@ public class FileUploadUtils
throws FileSizeLimitExceededException, InvalidExtensionException throws FileSizeLimitExceededException, InvalidExtensionException
{ {
long size = file.getSize(); long size = file.getSize();
if (DEFAULT_MAX_SIZE != -1 && size > DEFAULT_MAX_SIZE) if (size > DEFAULT_MAX_SIZE)
{ {
throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024); throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
} }
@ -195,7 +193,6 @@ public class FileUploadUtils
throw new InvalidExtensionException(allowedExtension, extension, fileName); throw new InvalidExtensionException(allowedExtension, extension, fileName);
} }
} }
} }
/** /**
@ -228,7 +225,7 @@ public class FileUploadUtils
String extension = FilenameUtils.getExtension(file.getOriginalFilename()); String extension = FilenameUtils.getExtension(file.getOriginalFilename());
if (StringUtils.isEmpty(extension)) if (StringUtils.isEmpty(extension))
{ {
extension = MimeTypeUtils.getExtension(file.getContentType()); extension = MimeTypeUtils.getExtension(Objects.requireNonNull(file.getContentType()));
} }
return extension; return extension;
} }

View File

@ -17,6 +17,7 @@ import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.IdUtils; import com.ruoyi.common.utils.uuid.IdUtils;
import org.apache.commons.io.FilenameUtils;
/** /**
* 文件处理工具类 * 文件处理工具类
@ -196,7 +197,6 @@ public class FileUtils
* *
* @param response 响应对象 * @param response 响应对象
* @param realFileName 真实文件名 * @param realFileName 真实文件名
* @return
*/ */
public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException
{ {
@ -210,7 +210,6 @@ public class FileUtils
.append("utf-8''") .append("utf-8''")
.append(percentEncodedFileName); .append(percentEncodedFileName);
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename"); response.addHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename");
response.setHeader("Content-disposition", contentDispositionValue.toString()); response.setHeader("Content-disposition", contentDispositionValue.toString());
response.setHeader("download-filename", percentEncodedFileName); response.setHeader("download-filename", percentEncodedFileName);
@ -256,4 +255,39 @@ public class FileUtils
} }
return strFileExtendName; return strFileExtendName;
} }
/**
* 获取文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi.png
*
* @param fileName 路径名称
* @return 没有文件路径的名称
*/
public static String getName(String fileName)
{
if (fileName == null)
{
return null;
}
int lastUnixPos = fileName.lastIndexOf('/');
int lastWindowsPos = fileName.lastIndexOf('\\');
int index = Math.max(lastUnixPos, lastWindowsPos);
return fileName.substring(index + 1);
}
/**
* 获取不带后缀文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi
*
* @param fileName 路径名称
* @return 没有文件路径和后缀的名称
*/
public static String getNameNotSuffix(String fileName)
{
if (fileName == null)
{
return null;
}
String baseName = FilenameUtils.getBaseName(fileName);
return baseName;
}
} }

View File

@ -1,7 +1,6 @@
package com.ruoyi.common.utils.file; package com.ruoyi.common.utils.file;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL; import java.net.URL;
@ -59,13 +58,12 @@ public class ImageUtils
/** /**
* 读取文件为字节数据 * 读取文件为字节数据
* *
* @param key 地址 * @param url 地址
* @return 字节数据 * @return 字节数据
*/ */
public static byte[] readFile(String url) public static byte[] readFile(String url)
{ {
InputStream in = null; InputStream in = null;
ByteArrayOutputStream baos = null;
try try
{ {
if (url.startsWith("http")) if (url.startsWith("http"))
@ -95,7 +93,6 @@ public class ImageUtils
finally finally
{ {
IOUtils.closeQuietly(in); IOUtils.closeQuietly(in);
IOUtils.closeQuietly(baos);
} }
} }
} }

View File

@ -4,7 +4,7 @@ import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.charset.Charset; import java.nio.charset.StandardCharsets;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -25,7 +25,7 @@ public class HttpHelper
BufferedReader reader = null; BufferedReader reader = null;
try (InputStream inputStream = request.getInputStream()) try (InputStream inputStream = request.getInputStream())
{ {
reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8"))); reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
String line = ""; String line = "";
while ((line = reader.readLine()) != null) while ((line = reader.readLine()) != null)
{ {

View File

@ -9,6 +9,7 @@ import java.net.ConnectException;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
import java.net.URL; import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.HttpsURLConnection;
@ -130,9 +131,8 @@ public class HttpUtils
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
try try
{ {
String urlNameString = url; log.info("sendPost - {}", url);
log.info("sendPost - {}", urlNameString); URL realUrl = new URL(url);
URL realUrl = new URL(urlNameString);
URLConnection conn = realUrl.openConnection(); URLConnection conn = realUrl.openConnection();
conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("connection", "Keep-Alive");
@ -144,7 +144,7 @@ public class HttpUtils
out = new PrintWriter(conn.getOutputStream()); out = new PrintWriter(conn.getOutputStream());
out.print(param); out.print(param);
out.flush(); out.flush();
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8")); in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
String line; String line;
while ((line = in.readLine()) != null) while ((line = in.readLine()) != null)
{ {
@ -218,7 +218,7 @@ public class HttpUtils
{ {
if (ret != null && !"".equals(ret.trim())) if (ret != null && !"".equals(ret.trim()))
{ {
result.append(new String(ret.getBytes("ISO-8859-1"), "utf-8")); result.append(new String(ret.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8));
} }
} }
log.info("recv - {}", result); log.info("recv - {}", result);

View File

@ -2,7 +2,8 @@ package com.ruoyi.common.utils.ip;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.config.RuoYiConfig; import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
@ -25,7 +26,6 @@ public class AddressUtils
public static String getRealAddressByIP(String ip) public static String getRealAddressByIP(String ip)
{ {
String address = UNKNOWN;
// 内网不查询 // 内网不查询
if (IpUtils.internalIp(ip)) if (IpUtils.internalIp(ip))
{ {
@ -41,7 +41,7 @@ public class AddressUtils
log.error("获取地理位置异常 {}", ip); log.error("获取地理位置异常 {}", ip);
return UNKNOWN; return UNKNOWN;
} }
JSONObject obj = JSONObject.parseObject(rspStr); JSONObject obj = JSON.parseObject(rspStr);
String region = obj.getString("pro"); String region = obj.getString("pro");
String city = obj.getString("city"); String city = obj.getString("city");
return String.format("%s %s", region, city); return String.format("%s %s", region, city);
@ -51,6 +51,6 @@ public class AddressUtils
log.error("获取地理位置异常 {}", ip); log.error("获取地理位置异常 {}", ip);
} }
} }
return address; return UNKNOWN;
} }
} }

View File

@ -4,7 +4,6 @@ import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.html.EscapeUtil;
/** /**
* 获取IP方法 * 获取IP方法
@ -13,6 +12,12 @@ import com.ruoyi.common.utils.html.EscapeUtil;
*/ */
public class IpUtils public class IpUtils
{ {
/**
* 获取客户端IP
*
* @param request 请求对象
* @return IP地址
*/
public static String getIpAddr(HttpServletRequest request) public static String getIpAddr(HttpServletRequest request)
{ {
if (request == null) if (request == null)
@ -41,15 +46,28 @@ public class IpUtils
{ {
ip = request.getRemoteAddr(); ip = request.getRemoteAddr();
} }
return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : EscapeUtil.clean(ip);
return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip);
} }
/**
* 检查是否为内部IP地址
*
* @param ip IP地址
* @return 结果
*/
public static boolean internalIp(String ip) public static boolean internalIp(String ip)
{ {
byte[] addr = textToNumericFormatV4(ip); byte[] addr = textToNumericFormatV4(ip);
return internalIp(addr) || "127.0.0.1".equals(ip); return internalIp(addr) || "127.0.0.1".equals(ip);
} }
/**
* 检查是否为内部IP地址
*
* @param addr byte地址
* @return 结果
*/
private static boolean internalIp(byte[] addr) private static boolean internalIp(byte[] addr)
{ {
if (StringUtils.isNull(addr) || addr.length < 2) if (StringUtils.isNull(addr) || addr.length < 2)
@ -110,7 +128,8 @@ public class IpUtils
{ {
case 1: case 1:
l = Long.parseLong(elements[0]); l = Long.parseLong(elements[0]);
if ((l < 0L) || (l > 4294967295L)) { if ((l < 0L) || (l > 4294967295L))
{
return null; return null;
} }
bytes[0] = (byte) (int) (l >> 24 & 0xFF); bytes[0] = (byte) (int) (l >> 24 & 0xFF);
@ -120,12 +139,14 @@ public class IpUtils
break; break;
case 2: case 2:
l = Integer.parseInt(elements[0]); l = Integer.parseInt(elements[0]);
if ((l < 0L) || (l > 255L)) { if ((l < 0L) || (l > 255L))
{
return null; return null;
} }
bytes[0] = (byte) (int) (l & 0xFF); bytes[0] = (byte) (int) (l & 0xFF);
l = Integer.parseInt(elements[1]); l = Integer.parseInt(elements[1]);
if ((l < 0L) || (l > 16777215L)) { if ((l < 0L) || (l > 16777215L))
{
return null; return null;
} }
bytes[1] = (byte) (int) (l >> 16 & 0xFF); bytes[1] = (byte) (int) (l >> 16 & 0xFF);
@ -136,13 +157,15 @@ public class IpUtils
for (i = 0; i < 2; ++i) for (i = 0; i < 2; ++i)
{ {
l = Integer.parseInt(elements[i]); l = Integer.parseInt(elements[i]);
if ((l < 0L) || (l > 255L)) { if ((l < 0L) || (l > 255L))
{
return null; return null;
} }
bytes[i] = (byte) (int) (l & 0xFF); bytes[i] = (byte) (int) (l & 0xFF);
} }
l = Integer.parseInt(elements[2]); l = Integer.parseInt(elements[2]);
if ((l < 0L) || (l > 65535L)) { if ((l < 0L) || (l > 65535L))
{
return null; return null;
} }
bytes[2] = (byte) (int) (l >> 8 & 0xFF); bytes[2] = (byte) (int) (l >> 8 & 0xFF);
@ -152,7 +175,8 @@ public class IpUtils
for (i = 0; i < 4; ++i) for (i = 0; i < 4; ++i)
{ {
l = Integer.parseInt(elements[i]); l = Integer.parseInt(elements[i]);
if ((l < 0L) || (l > 255L)) { if ((l < 0L) || (l > 255L))
{
return null; return null;
} }
bytes[i] = (byte) (int) (l & 0xFF); bytes[i] = (byte) (int) (l & 0xFF);
@ -169,6 +193,11 @@ public class IpUtils
return bytes; return bytes;
} }
/**
* 获取IP地址
*
* @return 本地IP地址
*/
public static String getHostIp() public static String getHostIp()
{ {
try try
@ -181,6 +210,11 @@ public class IpUtils
return "127.0.0.1"; return "127.0.0.1";
} }
/**
* 获取主机名
*
* @return 本地主机名
*/
public static String getHostName() public static String getHostName()
{ {
try try
@ -192,4 +226,39 @@ public class IpUtils
} }
return "未知"; return "未知";
} }
/**
* 从多级反向代理中获得第一个非unknown IP地址
*
* @param ip 获得的IP地址
* @return 第一个非unknown IP地址
*/
public static String getMultistageReverseProxyIp(String ip)
{
// 多级反向代理检测
if (ip != null && ip.indexOf(",") > 0)
{
final String[] ips = ip.trim().split(",");
for (String subIp : ips)
{
if (false == isUnknown(subIp))
{
ip = subIp;
break;
}
}
}
return ip;
}
/**
* 检测给定字符串是否为未知多用于检测HTTP请求相关
*
* @param checkString 被检测的字符串
* @return 是否未知
*/
public static boolean isUnknown(String checkString)
{
return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString);
}
} }

View File

@ -9,6 +9,8 @@ import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
@ -20,6 +22,7 @@ import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.RegExUtils;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor; import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFPicture; import org.apache.poi.hssf.usermodel.HSSFPicture;
import org.apache.poi.hssf.usermodel.HSSFPictureData; import org.apache.poi.hssf.usermodel.HSSFPictureData;
@ -86,6 +89,10 @@ public class ExcelUtil<T>
{ {
private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class); private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);
public static final String FORMULA_REGEX_STR = "=|-|\\+|@";
public static final String[] FORMULA_STR = { "=", "-", "+", "@" };
/** /**
* Excel sheet最大行数默认65536 * Excel sheet最大行数默认65536
*/ */
@ -312,7 +319,7 @@ public class ExcelUtil<T>
String dateFormat = field.getAnnotation(Excel.class).dateFormat(); String dateFormat = field.getAnnotation(Excel.class).dateFormat();
if (StringUtils.isNotEmpty(dateFormat)) if (StringUtils.isNotEmpty(dateFormat))
{ {
val = DateUtils.parseDateToStr(dateFormat, (Date) val); val = parseDateToStr(dateFormat, val);
} }
else else
{ {
@ -324,7 +331,7 @@ public class ExcelUtil<T>
{ {
val = Convert.toInt(val); val = Convert.toInt(val);
} }
else if (Long.TYPE == fieldType || Long.class == fieldType) else if ((Long.TYPE == fieldType || Long.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val)))
{ {
val = Convert.toLong(val); val = Convert.toLong(val);
} }
@ -429,7 +436,6 @@ public class ExcelUtil<T>
* @param list 导出数据集合 * @param list 导出数据集合
* @param sheetName 工作表的名称 * @param sheetName 工作表的名称
* @return 结果 * @return 结果
* @throws IOException
*/ */
public void exportExcel(HttpServletResponse response, List<T> list, String sheetName) public void exportExcel(HttpServletResponse response, List<T> list, String sheetName)
{ {
@ -444,7 +450,6 @@ public class ExcelUtil<T>
* @param sheetName 工作表的名称 * @param sheetName 工作表的名称
* @param title 标题 * @param title 标题
* @return 结果 * @return 结果
* @throws IOException
*/ */
public void exportExcel(HttpServletResponse response, List<T> list, String sheetName, String title) public void exportExcel(HttpServletResponse response, List<T> list, String sheetName, String title)
{ {
@ -667,21 +672,46 @@ public class ExcelUtil<T>
style.setFont(totalFont); style.setFont(totalFont);
styles.put("total", style); styles.put("total", style);
style = wb.createCellStyle(); styles.putAll(annotationStyles(wb));
style.cloneStyleFrom(styles.get("data"));
style.setAlignment(HorizontalAlignment.LEFT);
styles.put("data1", style);
style = wb.createCellStyle(); return styles;
style.cloneStyleFrom(styles.get("data")); }
style.setAlignment(HorizontalAlignment.CENTER);
styles.put("data2", style);
/**
* 根据Excel注解创建表格样式
*
* @param wb 工作薄对象
* @return 自定义样式列表
*/
private Map<String, CellStyle> annotationStyles(Workbook wb)
{
Map<String, CellStyle> styles = new HashMap<String, CellStyle>();
for (Object[] os : fields)
{
Excel excel = (Excel) os[1];
String key = "data_" + excel.align() + "_" + excel.color();
if (!styles.containsKey(key))
{
CellStyle style = wb.createCellStyle();
style = wb.createCellStyle(); style = wb.createCellStyle();
style.cloneStyleFrom(styles.get("data")); style.setAlignment(excel.align());
style.setAlignment(HorizontalAlignment.RIGHT); style.setVerticalAlignment(VerticalAlignment.CENTER);
styles.put("data3", style); style.setBorderRight(BorderStyle.THIN);
style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setBorderLeft(BorderStyle.THIN);
style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setBorderTop(BorderStyle.THIN);
style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setBorderBottom(BorderStyle.THIN);
style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
Font dataFont = wb.createFont();
dataFont.setFontName("Arial");
dataFont.setFontHeightInPoints((short) 10);
dataFont.setColor(excel.color().index);
style.setFont(dataFont);
styles.put(key, style);
}
}
return styles; return styles;
} }
@ -710,7 +740,13 @@ public class ExcelUtil<T>
{ {
if (ColumnType.STRING == attr.cellType()) if (ColumnType.STRING == attr.cellType())
{ {
cell.setCellValue(StringUtils.isNull(value) ? attr.defaultValue() : value + attr.suffix()); String cellValue = Convert.toStr(value);
// 对于任何以表达式触发字符 =-+@开头的单元格直接使用tab字符作为前缀防止CSV注入。
if (StringUtils.startsWithAny(cellValue, FORMULA_STR))
{
cellValue = RegExUtils.replaceFirst(cellValue, FORMULA_REGEX_STR, "\t$0");
}
cell.setCellValue(StringUtils.isNull(cellValue) ? attr.defaultValue() : cellValue + attr.suffix());
} }
else if (ColumnType.NUMERIC == attr.cellType()) else if (ColumnType.NUMERIC == attr.cellType())
{ {
@ -775,17 +811,10 @@ public class ExcelUtil<T>
// 设置列宽 // 设置列宽
sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256)); sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256));
} }
// 如果设置了提示信息则鼠标放上去提示. if (StringUtils.isNotEmpty(attr.prompt()) || attr.combo().length > 0)
if (StringUtils.isNotEmpty(attr.prompt()))
{ {
// 这里默认设了2-101列提示. // 提示信息或只能选择不能输入的列内容.
setXSSFPrompt(sheet, "", attr.prompt(), 1, 100, column, column); setPromptOrValidation(sheet, attr.combo(), attr.prompt(), 1, 100, column, column);
}
// 如果设置了combo属性则本列只能选择不能输入
if (attr.combo().length > 0)
{
// 这里默认设了2-101列只能选择不能输入.
setXSSFValidation(sheet, attr.combo(), 1, 100, column, column);
} }
} }
@ -804,8 +833,7 @@ public class ExcelUtil<T>
{ {
// 创建cell // 创建cell
cell = row.createCell(column); cell = row.createCell(column);
int align = attr.align().value(); cell.setCellStyle(styles.get("data_" + attr.align() + "_" + attr.color()));
cell.setCellStyle(styles.get("data" + (align >= 1 && align <= 3 ? align : "")));
// 用于读取对象中的属性 // 用于读取对象中的属性
Object value = getTargetValue(vo, field, attr); Object value = getTargetValue(vo, field, attr);
@ -815,7 +843,7 @@ public class ExcelUtil<T>
String dictType = attr.dictType(); String dictType = attr.dictType();
if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value)) if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value))
{ {
cell.setCellValue(DateUtils.parseDateToStr(dateFormat, (Date) value)); cell.setCellValue(parseDateToStr(dateFormat, value));
} }
else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value)) else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value))
{ {
@ -849,48 +877,29 @@ public class ExcelUtil<T>
} }
/** /**
* 设置 POI XSSFSheet 单元格提示 * 设置 POI XSSFSheet 单元格提示或选择框
* *
* @param sheet 表单 * @param sheet 表单
* @param promptTitle 提示标题 * @param textlist 下拉框显示的内容
* @param promptContent 提示内容 * @param promptContent 提示内容
* @param firstRow 开始行 * @param firstRow 开始行
* @param endRow 结束行 * @param endRow 结束行
* @param firstCol 开始列 * @param firstCol 开始列
* @param endCol 结束列 * @param endCol 结束列
*/ */
public void setXSSFPrompt(Sheet sheet, String promptTitle, String promptContent, int firstRow, int endRow, public void setPromptOrValidation(Sheet sheet, String[] textlist, String promptContent, int firstRow, int endRow,
int firstCol, int endCol) int firstCol, int endCol)
{ {
DataValidationHelper helper = sheet.getDataValidationHelper(); DataValidationHelper helper = sheet.getDataValidationHelper();
DataValidationConstraint constraint = helper.createCustomConstraint("DD1"); DataValidationConstraint constraint = textlist.length > 0 ? helper.createExplicitListConstraint(textlist) : helper.createCustomConstraint("DD1");
CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
DataValidation dataValidation = helper.createValidation(constraint, regions); DataValidation dataValidation = helper.createValidation(constraint, regions);
dataValidation.createPromptBox(promptTitle, promptContent); if (StringUtils.isNotEmpty(promptContent))
dataValidation.setShowPromptBox(true);
sheet.addValidationData(dataValidation);
}
/**
* 设置某些列的值只能输入预制的数据,显示下拉框.
*
* @param sheet 要设置的sheet.
* @param textlist 下拉框显示的内容
* @param firstRow 开始行
* @param endRow 结束行
* @param firstCol 开始列
* @param endCol 结束列
* @return 设置好的sheet.
*/
public void setXSSFValidation(Sheet sheet, String[] textlist, int firstRow, int endRow, int firstCol, int endCol)
{ {
DataValidationHelper helper = sheet.getDataValidationHelper(); // 如果设置了提示信息则鼠标放上去提示
// 加载下拉列表内容 dataValidation.createPromptBox("", promptContent);
DataValidationConstraint constraint = helper.createExplicitListConstraint(textlist); dataValidation.setShowPromptBox(true);
// 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列 }
CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
// 数据有效性对象
DataValidation dataValidation = helper.createValidation(constraint, regions);
// 处理Excel兼容性问题 // 处理Excel兼容性问题
if (dataValidation instanceof XSSFDataValidation) if (dataValidation instanceof XSSFDataValidation)
{ {
@ -901,7 +910,6 @@ public class ExcelUtil<T>
{ {
dataValidation.setSuppressDropDownArrow(false); dataValidation.setSuppressDropDownArrow(false);
} }
sheet.addValidationData(dataValidation); sheet.addValidationData(dataValidation);
} }
@ -1113,7 +1121,7 @@ public class ExcelUtil<T>
if (StringUtils.isNotEmpty(excel.targetAttr())) if (StringUtils.isNotEmpty(excel.targetAttr()))
{ {
String target = excel.targetAttr(); String target = excel.targetAttr();
if (target.indexOf(".") > -1) if (target.contains("."))
{ {
String[] targets = target.split("[.]"); String[] targets = target.split("[.]");
for (String name : targets) for (String name : targets)
@ -1208,7 +1216,7 @@ public class ExcelUtil<T>
for (Object[] os : this.fields) for (Object[] os : this.fields)
{ {
Excel excel = (Excel) os[1]; Excel excel = (Excel) os[1];
maxHeight = maxHeight > excel.height() ? maxHeight : excel.height(); maxHeight = Math.max(maxHeight, excel.height());
} }
return (short) (maxHeight * 20); return (short) (maxHeight * 20);
} }
@ -1388,4 +1396,37 @@ public class ExcelUtil<T>
} }
return sheetIndexPicMap; return sheetIndexPicMap;
} }
/**
* 格式化不同类型的日期对象
*
* @param dateFormat 日期格式
* @param val 被格式化的日期对象
* @return 格式化后的日期字符
*/
public String parseDateToStr(String dateFormat, Object val)
{
if (val == null)
{
return "";
}
String str;
if (val instanceof Date)
{
str = DateUtils.parseDateToStr(dateFormat, (Date) val);
}
else if (val instanceof LocalDateTime)
{
str = DateUtils.parseDateToStr(dateFormat, DateUtils.toDate((LocalDateTime) val));
}
else if (val instanceof LocalDate)
{
str = DateUtils.parseDateToStr(dateFormat, DateUtils.toDate((LocalDate) val));
}
else
{
str = val.toString();
}
return str;
}
} }

View File

@ -1,5 +1,6 @@
package com.ruoyi.common.utils.sign; package com.ruoyi.common.utils.sign;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest; import java.security.MessageDigest;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -55,7 +56,7 @@ public class Md5Utils
{ {
try try
{ {
return new String(toHex(md5(s)).getBytes("UTF-8"), "UTF-8"); return new String(toHex(md5(s)).getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -143,4 +143,16 @@ public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationC
final String[] activeProfiles = getActiveProfiles(); final String[] activeProfiles = getActiveProfiles();
return StringUtils.isNotEmpty(activeProfiles) ? activeProfiles[0] : null; return StringUtils.isNotEmpty(activeProfiles) ? activeProfiles[0] : null;
} }
/**
* 获取配置文件中的值
*
* @param key 配置文件的key
* @return 当前的配置文件的值
*
*/
public static String getRequiredProperty(String key)
{
return applicationContext.getEnvironment().getRequiredProperty(key);
}
} }

View File

@ -50,9 +50,9 @@ public class SqlUtil
return; return;
} }
String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|"); String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|");
for (int i = 0; i < sqlKeywords.length; i++) for (String sqlKeyword : sqlKeywords)
{ {
if (StringUtils.indexOfIgnoreCase(value, sqlKeywords[i]) > -1) if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1)
{ {
throw new UtilException("参数存在SQL注入风险"); throw new UtilException("参数存在SQL注入风险");
} }

View File

@ -0,0 +1,86 @@
package com.ruoyi.common.utils.uuid;
import java.util.concurrent.atomic.AtomicInteger;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
/**
* @author ruoyi 序列生成类
*/
public class Seq
{
// 通用序列类型
public static final String commSeqType = "COMMON";
// 上传序列类型
public static final String uploadSeqType = "UPLOAD";
// 通用接口序列数
private static AtomicInteger commSeq = new AtomicInteger(1);
// 上传接口序列数
private static AtomicInteger uploadSeq = new AtomicInteger(1);
// 机器标识
private static String machineCode = "A";
/**
* 获取通用序列号
*
* @return 序列值
*/
public static String getId()
{
return getId(commSeqType);
}
/**
* 默认16位序列号 yyMMddHHmmss + 一位机器标识 + 3长度循环递增字符串
*
* @return 序列值
*/
public static String getId(String type)
{
AtomicInteger atomicInt = commSeq;
if (uploadSeqType.equals(type))
{
atomicInt = uploadSeq;
}
return getId(atomicInt, 3);
}
/**
* 通用接口序列号 yyMMddHHmmss + 一位机器标识 + length长度循环递增字符串
*
* @param atomicInt 序列数
* @param length 数值长度
* @return 序列值
*/
public static String getId(AtomicInteger atomicInt, int length)
{
String result = DateUtils.dateTimeNow();
result += machineCode;
result += getSeq(atomicInt, length);
return result;
}
/**
* 序列循环递增字符串[1, 10 的 (length)幂次方), 用0左补齐length位数
*
* @return 序列值
*/
private synchronized static String getSeq(AtomicInteger atomicInt, int length)
{
// 先取值再+1
int value = atomicInt.getAndIncrement();
// 如果更新后值>=10 的 (length)幂次方则重置为1
int maxSeq = (int) Math.pow(10, length);
if (atomicInt.get() >= maxSeq)
{
atomicInt.set(1);
}
// 转字符串用0左补齐
return StringUtils.padl(value, length);
}
}

View File

@ -1,5 +1,6 @@
package com.ruoyi.common.xss; package com.ruoyi.common.xss;
import com.ruoyi.common.utils.StringUtils;
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext; import javax.validation.ConstraintValidatorContext;
import java.util.regex.Matcher; import java.util.regex.Matcher;
@ -12,15 +13,19 @@ import java.util.regex.Pattern;
*/ */
public class XssValidator implements ConstraintValidator<Xss, String> public class XssValidator implements ConstraintValidator<Xss, String>
{ {
private final String HTML_PATTERN = "<(\\S*?)[^>]*>.*?|<.*? />"; private static final String HTML_PATTERN = "<(\\S*?)[^>]*>.*?|<.*? />";
@Override @Override
public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext)
{ {
if (StringUtils.isBlank(value))
{
return true;
}
return !containsHtml(value); return !containsHtml(value);
} }
public boolean containsHtml(String value) public static boolean containsHtml(String value)
{ {
Pattern pattern = Pattern.compile(HTML_PATTERN); Pattern pattern = Pattern.compile(HTML_PATTERN);
Matcher matcher = pattern.matcher(value); Matcher matcher = pattern.matcher(value);

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>3.8.1</version> <version>3.8.3</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -118,7 +118,7 @@ public class DataScopeAspect
else else
{ {
// 数据权限为仅本人且没有userAlias别名不查询任何数据 // 数据权限为仅本人且没有userAlias别名不查询任何数据
sqlString.append(" OR 1=0 "); sqlString.append(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias));
} }
} }
} }

View File

@ -14,7 +14,7 @@ import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult; import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.HandlerMapping;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.annotation.Log; import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.BusinessStatus; import com.ruoyi.common.enums.BusinessStatus;
@ -65,7 +65,6 @@ public class LogAspect
{ {
try try
{ {
// 获取当前的用户 // 获取当前的用户
LoginUser loginUser = SecurityUtils.getLoginUser(); LoginUser loginUser = SecurityUtils.getLoginUser();

View File

@ -1,15 +1,11 @@
package com.ruoyi.framework.config; package com.ruoyi.framework.config;
import com.alibaba.fastjson.JSON; import java.nio.charset.Charset;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException; import org.springframework.data.redis.serializer.SerializationException;
import com.alibaba.fastjson.parser.ParserConfig; import com.alibaba.fastjson2.JSON;
import org.springframework.util.Assert; import com.alibaba.fastjson2.JSONReader;
import java.nio.charset.Charset; import com.alibaba.fastjson2.JSONWriter;
/** /**
* Redis使用FastJson序列化 * Redis使用FastJson序列化
@ -18,18 +14,10 @@ import java.nio.charset.Charset;
*/ */
public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
{ {
@SuppressWarnings("unused")
private ObjectMapper objectMapper = new ObjectMapper();
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
private Class<T> clazz; private Class<T> clazz;
static
{
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
}
public FastJson2JsonRedisSerializer(Class<T> clazz) public FastJson2JsonRedisSerializer(Class<T> clazz)
{ {
super(); super();
@ -43,7 +31,7 @@ public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
{ {
return new byte[0]; return new byte[0];
} }
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET); return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName).getBytes(DEFAULT_CHARSET);
} }
@Override @Override
@ -55,17 +43,6 @@ public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
} }
String str = new String(bytes, DEFAULT_CHARSET); String str = new String(bytes, DEFAULT_CHARSET);
return JSON.parseObject(str, clazz); return JSON.parseObject(str, clazz, JSONReader.Feature.SupportAutoType);
}
public void setObjectMapper(ObjectMapper objectMapper)
{
Assert.notNull(objectMapper, "'objectMapper' must not be null");
this.objectMapper = objectMapper;
}
protected JavaType getJavaType(Class<?> clazz)
{
return TypeFactory.defaultInstance().constructType(clazz);
} }
} }

View File

@ -8,11 +8,6 @@ import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
/** /**
* redis配置 * redis配置
@ -32,11 +27,6 @@ public class RedisConfig extends CachingConfigurerSupport
FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class); FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
serializer.setObjectMapper(mapper);
// 使用StringRedisSerializer来序列化和反序列化redis的key值 // 使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer()); template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(serializer); template.setValueSerializer(serializer);

View File

@ -8,12 +8,14 @@ import org.springframework.security.config.annotation.authentication.builders.Au
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter; import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.filter.CorsFilter; import org.springframework.web.filter.CorsFilter;
import com.ruoyi.framework.config.properties.PermitAllUrlProperties;
import com.ruoyi.framework.security.filter.JwtAuthenticationTokenFilter; import com.ruoyi.framework.security.filter.JwtAuthenticationTokenFilter;
import com.ruoyi.framework.security.handle.AuthenticationEntryPointImpl; import com.ruoyi.framework.security.handle.AuthenticationEntryPointImpl;
import com.ruoyi.framework.security.handle.LogoutSuccessHandlerImpl; import com.ruoyi.framework.security.handle.LogoutSuccessHandlerImpl;
@ -56,6 +58,12 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
@Autowired @Autowired
private CorsFilter corsFilter; private CorsFilter corsFilter;
/**
* 允许匿名访问的地址
*/
@Autowired
private PermitAllUrlProperties permitAllUrl;
/** /**
* 解决 无法直接注入 AuthenticationManager * 解决 无法直接注入 AuthenticationManager
* *
@ -87,6 +95,10 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
@Override @Override
protected void configure(HttpSecurity httpSecurity) throws Exception protected void configure(HttpSecurity httpSecurity) throws Exception
{ {
// 注解标记允许匿名访问的url
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = httpSecurity.authorizeRequests();
permitAllUrl.getUrls().forEach(url -> registry.antMatchers(url).permitAll());
httpSecurity httpSecurity
// CSRF禁用因为不使用session // CSRF禁用因为不使用session
.csrf().disable() .csrf().disable()
@ -98,24 +110,14 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
.authorizeRequests() .authorizeRequests()
// 对于登录login 注册register 验证码captchaImage 允许匿名访问 // 对于登录login 注册register 验证码captchaImage 允许匿名访问
.antMatchers("/login", "/register", "/captchaImage").anonymous() .antMatchers("/login", "/register", "/captchaImage").anonymous()
.antMatchers( // 静态资源,可匿名访问
HttpMethod.GET, .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
"/", .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
"/*.html",
"/**/*.html",
"/**/*.css",
"/**/*.js",
"/profile/**"
).permitAll()
.antMatchers("/swagger-ui.html").anonymous()
.antMatchers("/swagger-resources/**").anonymous()
.antMatchers("/webjars/**").anonymous()
.antMatchers("/*/api-docs").anonymous()
.antMatchers("/druid/**").anonymous()
// 除上面外的所有请求全部需要鉴权认证 // 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated() .anyRequest().authenticated()
.and() .and()
.headers().frameOptions().disable(); .headers().frameOptions().disable();
// 添加Logout filter
httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler); httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);
// 添加JWT filter // 添加JWT filter
httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);

View File

@ -1,13 +1,13 @@
package com.ruoyi.framework.config; package com.ruoyi.framework.config;
import java.util.concurrent.ScheduledExecutorService; import com.ruoyi.common.utils.Threads;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import com.ruoyi.common.utils.Threads; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
/** /**
* 线程池配置 * 线程池配置
@ -49,7 +49,8 @@ public class ThreadPoolConfig
protected ScheduledExecutorService scheduledExecutorService() protected ScheduledExecutorService scheduledExecutorService()
{ {
return new ScheduledThreadPoolExecutor(corePoolSize, return new ScheduledThreadPoolExecutor(corePoolSize,
new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build()) new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(),
new ThreadPoolExecutor.CallerRunsPolicy())
{ {
@Override @Override
protected void afterExecute(Runnable r, Throwable t) protected void afterExecute(Runnable r, Throwable t)

View File

@ -0,0 +1,72 @@
package com.ruoyi.framework.config.properties;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern;
import org.apache.commons.lang3.RegExUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import com.ruoyi.common.annotation.Anonymous;
/**
* 设置Anonymous注解允许匿名访问的url
*
* @author ruoyi
*/
@Configuration
public class PermitAllUrlProperties implements InitializingBean, ApplicationContextAware
{
private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}");
private ApplicationContext applicationContext;
private List<String> urls = new ArrayList<>();
public String ASTERISK = "*";
@Override
public void afterPropertiesSet()
{
RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();
map.keySet().forEach(info -> {
HandlerMethod handlerMethod = map.get(info);
// 获取方法上边的注解 替代path variable 为 *
Anonymous method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Anonymous.class);
Optional.ofNullable(method).ifPresent(anonymous -> info.getPatternsCondition().getPatterns()
.forEach(url -> urls.add(RegExUtils.replaceAll(url, PATTERN, ASTERISK))));
// 获取类上边的注解, 替代path variable 为 *
Anonymous controller = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), Anonymous.class);
Optional.ofNullable(controller).ifPresent(anonymous -> info.getPatternsCondition().getPatterns()
.forEach(url -> urls.add(RegExUtils.replaceAll(url, PATTERN, ASTERISK))));
});
}
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException
{
this.applicationContext = context;
}
public List<String> getUrls()
{
return urls;
}
public void setUrls(List<String> urls)
{
this.urls = urls;
}
}

View File

@ -6,7 +6,7 @@ import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod; import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.HandlerInterceptor;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.annotation.RepeatSubmit; import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.ServletUtils; import com.ruoyi.common.utils.ServletUtils;
@ -32,7 +32,7 @@ public abstract class RepeatSubmitInterceptor implements HandlerInterceptor
if (this.isRepeatSubmit(request, annotation)) if (this.isRepeatSubmit(request, annotation))
{ {
AjaxResult ajaxResult = AjaxResult.error(annotation.message()); AjaxResult ajaxResult = AjaxResult.error(annotation.message());
ServletUtils.renderString(response, JSONObject.toJSONString(ajaxResult)); ServletUtils.renderString(response, JSON.toJSONString(ajaxResult));
return false; return false;
} }
} }

View File

@ -7,9 +7,9 @@ import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.annotation.RepeatSubmit; import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.filter.RepeatedlyRequestWrapper; import com.ruoyi.common.filter.RepeatedlyRequestWrapper;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
@ -50,7 +50,7 @@ public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
// body参数为空获取Parameter的数据 // body参数为空获取Parameter的数据
if (StringUtils.isEmpty(nowParams)) if (StringUtils.isEmpty(nowParams))
{ {
nowParams = JSONObject.toJSONString(request.getParameterMap()); nowParams = JSON.toJSONString(request.getParameterMap());
} }
Map<String, Object> nowDataMap = new HashMap<String, Object>(); Map<String, Object> nowDataMap = new HashMap<String, Object>();
nowDataMap.put(REPEAT_PARAMS, nowParams); nowDataMap.put(REPEAT_PARAMS, nowParams);
@ -63,7 +63,7 @@ public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
String submitKey = StringUtils.trimToEmpty(request.getHeader(header)); String submitKey = StringUtils.trimToEmpty(request.getHeader(header));
// 唯一标识指定key + url + 消息头) // 唯一标识指定key + url + 消息头)
String cacheRepeatKey = Constants.REPEAT_SUBMIT_KEY + url + submitKey; String cacheRepeatKey = CacheConstants.REPEAT_SUBMIT_KEY + url + submitKey;
Object sessionObj = redisCache.getCacheObject(cacheRepeatKey); Object sessionObj = redisCache.getCacheObject(cacheRepeatKey);
if (sessionObj != null) if (sessionObj != null)

View File

@ -7,7 +7,7 @@ import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.constant.HttpStatus; import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.ServletUtils; import com.ruoyi.common.utils.ServletUtils;

View File

@ -8,7 +8,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.HttpStatus; import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.AjaxResult;

View File

@ -119,4 +119,12 @@ public class Jvm
{ {
return DateUtils.getDatePoor(DateUtils.getNowDate(), DateUtils.getServerStartDate()); return DateUtils.getDatePoor(DateUtils.getNowDate(), DateUtils.getServerStartDate());
} }
/**
* 运行参数
*/
public String getInputArgs()
{
return ManagementFactory.getRuntimeMXBean().getInputArguments().toString();
}
} }

View File

@ -7,6 +7,7 @@ import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.core.domain.model.LoginUser;
@ -18,6 +19,7 @@ import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.MessageUtils; import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.ServletUtils; import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ip.IpUtils; import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.framework.manager.AsyncManager; import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.framework.manager.factory.AsyncFactory; import com.ruoyi.framework.manager.factory.AsyncFactory;
@ -102,7 +104,7 @@ public class SysLoginService
*/ */
public void validateCaptcha(String username, String code, String uuid) public void validateCaptcha(String username, String code, String uuid)
{ {
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid; String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
String captcha = redisCache.getCacheObject(verifyKey); String captcha = redisCache.getCacheObject(verifyKey);
redisCache.deleteObject(verifyKey); redisCache.deleteObject(verifyKey);
if (captcha == null) if (captcha == null)

View File

@ -2,6 +2,7 @@ package com.ruoyi.framework.web.service;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.domain.entity.SysUser;
@ -100,7 +101,7 @@ public class SysRegisterService
*/ */
public void validateCaptcha(String username, String code, String uuid) public void validateCaptcha(String username, String code, String uuid)
{ {
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid; String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
String captcha = redisCache.getCacheObject(verifyKey); String captcha = redisCache.getCacheObject(verifyKey);
redisCache.deleteObject(verifyKey); redisCache.deleteObject(verifyKey);
if (captcha == null) if (captcha == null)

View File

@ -7,6 +7,7 @@ import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.core.redis.RedisCache;
@ -220,6 +221,6 @@ public class TokenService
private String getTokenKey(String uuid) private String getTokenKey(String uuid)
{ {
return Constants.LOGIN_TOKEN_KEY + uuid; return CacheConstants.LOGIN_TOKEN_KEY + uuid;
} }
} }

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>3.8.1</version> <version>3.8.3</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -59,12 +59,12 @@ public class GenController extends BaseController
* 修改代码生成业务 * 修改代码生成业务
*/ */
@PreAuthorize("@ss.hasPermi('tool:gen:query')") @PreAuthorize("@ss.hasPermi('tool:gen:query')")
@GetMapping(value = "/{talbleId}") @GetMapping(value = "/{tableId}")
public AjaxResult getInfo(@PathVariable Long talbleId) public AjaxResult getInfo(@PathVariable Long tableId)
{ {
GenTable table = genTableService.selectGenTableById(talbleId); GenTable table = genTableService.selectGenTableById(tableId);
List<GenTable> tables = genTableService.selectGenTableAll(); List<GenTable> tables = genTableService.selectGenTableAll();
List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(talbleId); List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(tableId);
Map<String, Object> map = new HashMap<String, Object>(); Map<String, Object> map = new HashMap<String, Object>();
map.put("info", table); map.put("info", table);
map.put("rows", list); map.put("rows", list);
@ -88,7 +88,7 @@ public class GenController extends BaseController
* 查询数据表字段列表 * 查询数据表字段列表
*/ */
@PreAuthorize("@ss.hasPermi('tool:gen:list')") @PreAuthorize("@ss.hasPermi('tool:gen:list')")
@GetMapping(value = "/column/{talbleId}") @GetMapping(value = "/column/{tableId}")
public TableDataInfo columnList(Long tableId) public TableDataInfo columnList(Long tableId)
{ {
TableDataInfo dataInfo = new TableDataInfo(); TableDataInfo dataInfo = new TableDataInfo();

View File

@ -7,6 +7,7 @@ import java.io.StringWriter;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
@ -20,8 +21,8 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.GenConstants; import com.ruoyi.common.constant.GenConstants;
import com.ruoyi.common.core.text.CharsetKit; import com.ruoyi.common.core.text.CharsetKit;
@ -286,7 +287,7 @@ public class GenTableServiceImpl implements IGenTableService
{ {
GenTable table = genTableMapper.selectGenTableByName(tableName); GenTable table = genTableMapper.selectGenTableByName(tableName);
List<GenTableColumn> tableColumns = table.getColumns(); List<GenTableColumn> tableColumns = table.getColumns();
List<String> tableColumnNames = tableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList()); Map<String, GenTableColumn> tableColumnMap = tableColumns.stream().collect(Collectors.toMap(GenTableColumn::getColumnName, Function.identity()));
List<GenTableColumn> dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName); List<GenTableColumn> dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
if (StringUtils.isEmpty(dbTableColumns)) if (StringUtils.isEmpty(dbTableColumns))
@ -296,9 +297,29 @@ public class GenTableServiceImpl implements IGenTableService
List<String> dbTableColumnNames = dbTableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList()); List<String> dbTableColumnNames = dbTableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList());
dbTableColumns.forEach(column -> { dbTableColumns.forEach(column -> {
if (!tableColumnNames.contains(column.getColumnName()))
{
GenUtils.initColumnField(column, table); GenUtils.initColumnField(column, table);
if (tableColumnMap.containsKey(column.getColumnName()))
{
GenTableColumn prevColumn = tableColumnMap.get(column.getColumnName());
column.setColumnId(prevColumn.getColumnId());
if (column.isList())
{
// 如果是列表,继续保留查询方式/字典类型选项
column.setDictType(prevColumn.getDictType());
column.setQueryType(prevColumn.getQueryType());
}
if (StringUtils.isNotEmpty(prevColumn.getIsRequired()) && !column.isPk()
&& (column.isInsert() || column.isEdit())
&& ((column.isUsableColumn()) || (!column.isSuperColumn())))
{
// 如果是(新增/修改&非主键/非忽略及父属性),继续保留必填/显示类型选项
column.setIsRequired(prevColumn.getIsRequired());
column.setHtmlType(prevColumn.getHtmlType());
}
genTableColumnMapper.updateGenTableColumn(column);
}
else
{
genTableColumnMapper.insertGenTableColumn(column); genTableColumnMapper.insertGenTableColumn(column);
} }
}); });
@ -380,7 +401,7 @@ public class GenTableServiceImpl implements IGenTableService
if (GenConstants.TPL_TREE.equals(genTable.getTplCategory())) if (GenConstants.TPL_TREE.equals(genTable.getTplCategory()))
{ {
String options = JSON.toJSONString(genTable.getParams()); String options = JSON.toJSONString(genTable.getParams());
JSONObject paramsObj = JSONObject.parseObject(options); JSONObject paramsObj = JSON.parseObject(options);
if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_CODE))) if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_CODE)))
{ {
throw new ServiceException("树编码字段不能为空"); throw new ServiceException("树编码字段不能为空");
@ -464,7 +485,7 @@ public class GenTableServiceImpl implements IGenTableService
*/ */
public void setTableFromOptions(GenTable genTable) public void setTableFromOptions(GenTable genTable)
{ {
JSONObject paramsObj = JSONObject.parseObject(genTable.getOptions()); JSONObject paramsObj = JSON.parseObject(genTable.getOptions());
if (StringUtils.isNotNull(paramsObj)) if (StringUtils.isNotNull(paramsObj))
{ {
String treeCode = paramsObj.getString(GenConstants.TREE_CODE); String treeCode = paramsObj.getString(GenConstants.TREE_CODE);

View File

@ -42,6 +42,7 @@ public class GenUtils
column.setJavaField(StringUtils.toCamelCase(columnName)); column.setJavaField(StringUtils.toCamelCase(columnName));
// 设置默认类型 // 设置默认类型
column.setJavaType(GenConstants.TYPE_STRING); column.setJavaType(GenConstants.TYPE_STRING);
column.setQueryType(GenConstants.QUERY_EQ);
if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType) || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType)) if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType) || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType))
{ {
@ -151,8 +152,7 @@ public class GenUtils
{ {
int lastIndex = packageName.lastIndexOf("."); int lastIndex = packageName.lastIndexOf(".");
int nameLength = packageName.length(); int nameLength = packageName.length();
String moduleName = StringUtils.substring(packageName, lastIndex + 1, nameLength); return StringUtils.substring(packageName, lastIndex + 1, nameLength);
return moduleName;
} }
/** /**
@ -165,8 +165,7 @@ public class GenUtils
{ {
int lastIndex = tableName.lastIndexOf("_"); int lastIndex = tableName.lastIndexOf("_");
int nameLength = tableName.length(); int nameLength = tableName.length();
String businessName = StringUtils.substring(tableName, lastIndex + 1, nameLength); return StringUtils.substring(tableName, lastIndex + 1, nameLength);
return businessName;
} }
/** /**

View File

@ -5,7 +5,8 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import org.apache.velocity.VelocityContext; import org.apache.velocity.VelocityContext;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.constant.GenConstants; import com.ruoyi.common.constant.GenConstants;
import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
@ -75,7 +76,7 @@ public class VelocityUtils
public static void setMenuVelocityContext(VelocityContext context, GenTable genTable) public static void setMenuVelocityContext(VelocityContext context, GenTable genTable)
{ {
String options = genTable.getOptions(); String options = genTable.getOptions();
JSONObject paramsObj = JSONObject.parseObject(options); JSONObject paramsObj = JSON.parseObject(options);
String parentMenuId = getParentMenuId(paramsObj); String parentMenuId = getParentMenuId(paramsObj);
context.put("parentMenuId", parentMenuId); context.put("parentMenuId", parentMenuId);
} }
@ -83,7 +84,7 @@ public class VelocityUtils
public static void setTreeVelocityContext(VelocityContext context, GenTable genTable) public static void setTreeVelocityContext(VelocityContext context, GenTable genTable)
{ {
String options = genTable.getOptions(); String options = genTable.getOptions();
JSONObject paramsObj = JSONObject.parseObject(options); JSONObject paramsObj = JSON.parseObject(options);
String treeCode = getTreecode(paramsObj); String treeCode = getTreecode(paramsObj);
String treeParentCode = getTreeParentCode(paramsObj); String treeParentCode = getTreeParentCode(paramsObj);
String treeName = getTreeName(paramsObj); String treeName = getTreeName(paramsObj);
@ -228,8 +229,7 @@ public class VelocityUtils
public static String getPackagePrefix(String packageName) public static String getPackagePrefix(String packageName)
{ {
int lastIndex = packageName.lastIndexOf("."); int lastIndex = packageName.lastIndexOf(".");
String basePackage = StringUtils.substring(packageName, 0, lastIndex); return StringUtils.substring(packageName, 0, lastIndex);
return basePackage;
} }
/** /**
@ -272,6 +272,23 @@ public class VelocityUtils
{ {
List<GenTableColumn> columns = genTable.getColumns(); List<GenTableColumn> columns = genTable.getColumns();
Set<String> dicts = new HashSet<String>(); Set<String> dicts = new HashSet<String>();
addDicts(dicts, columns);
if (StringUtils.isNotNull(genTable.getSubTable()))
{
List<GenTableColumn> subColumns = genTable.getSubTable().getColumns();
addDicts(dicts, subColumns);
}
return StringUtils.join(dicts, ", ");
}
/**
* 添加字典列表
*
* @param dicts 字典列表
* @param columns 列集合
*/
public static void addDicts(Set<String> dicts, List<GenTableColumn> columns)
{
for (GenTableColumn column : columns) for (GenTableColumn column : columns)
{ {
if (!column.isSuperColumn() && StringUtils.isNotEmpty(column.getDictType()) && StringUtils.equalsAny( if (!column.isSuperColumn() && StringUtils.isNotEmpty(column.getDictType()) && StringUtils.equalsAny(
@ -281,7 +298,6 @@ public class VelocityUtils
dicts.add("'" + column.getDictType() + "'"); dicts.add("'" + column.getDictType() + "'");
} }
} }
return StringUtils.join(dicts, ", ");
} }
/** /**
@ -366,7 +382,7 @@ public class VelocityUtils
public static int getExpandColumn(GenTable genTable) public static int getExpandColumn(GenTable genTable)
{ {
String options = genTable.getOptions(); String options = genTable.getOptions();
JSONObject paramsObj = JSONObject.parseObject(options); JSONObject paramsObj = JSON.parseObject(options);
String treeName = paramsObj.getString(GenConstants.TREE_NAME); String treeName = paramsObj.getString(GenConstants.TREE_NAME);
int num = 0; int num = 0;
for (GenTableColumn column : genTable.getColumns()) for (GenTableColumn column : genTable.getColumns())

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px"> <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
#foreach($column in $columns) #foreach($column in $columns)
#if($column.query) #if($column.query)
#set($dictType=$column.dictType) #set($dictType=$column.dictType)
@ -17,13 +17,12 @@
v-model="queryParams.${column.javaField}" v-model="queryParams.${column.javaField}"
placeholder="请输入${comment}" placeholder="请输入${comment}"
clearable clearable
size="small"
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType) #elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small"> <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
<el-option <el-option
v-for="dict in dict.type.${dictType}" v-for="dict in dict.type.${dictType}"
:key="dict.value" :key="dict.value"
@ -34,13 +33,13 @@
</el-form-item> </el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType) #elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small"> <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
<el-option label="请选择字典生成" value="" /> <el-option label="请选择字典生成" value="" />
</el-select> </el-select>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN") #elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-date-picker clearable size="small" <el-date-picker clearable
v-model="queryParams.${column.javaField}" v-model="queryParams.${column.javaField}"
type="date" type="date"
value-format="yyyy-MM-dd" value-format="yyyy-MM-dd"
@ -51,7 +50,6 @@
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<el-date-picker <el-date-picker
v-model="daterange${AttrName}" v-model="daterange${AttrName}"
size="small"
style="width: 240px" style="width: 240px"
value-format="yyyy-MM-dd" value-format="yyyy-MM-dd"
type="daterange" type="daterange"
@ -80,14 +78,24 @@
v-hasPermi="['${moduleName}:${businessName}:add']" v-hasPermi="['${moduleName}:${businessName}:add']"
>新增</el-button> >新增</el-button>
</el-col> </el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="el-icon-sort"
size="mini"
@click="toggleExpandAll"
>展开/折叠</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row> </el-row>
<el-table <el-table
v-if="refreshTable"
v-loading="loading" v-loading="loading"
:data="${businessName}List" :data="${businessName}List"
row-key="${treeCode}" row-key="${treeCode}"
default-expand-all :default-expand-all="isExpandAll"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}" :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
> >
#foreach($column in $columns) #foreach($column in $columns)
@ -105,6 +113,12 @@
<span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span> <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
</template> </template>
</el-table-column> </el-table-column>
#elseif($column.list && $column.htmlType == "imageUpload")
<el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
<template slot-scope="scope">
<image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
</template>
</el-table-column>
#elseif($column.list && "" != $column.dictType) #elseif($column.list && "" != $column.dictType)
<el-table-column label="${comment}" align="center" prop="${javaField}"> <el-table-column label="${comment}" align="center" prop="${javaField}">
<template slot-scope="scope"> <template slot-scope="scope">
@ -174,11 +188,11 @@
</el-form-item> </el-form-item>
#elseif($column.htmlType == "imageUpload") #elseif($column.htmlType == "imageUpload")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<imageUpload v-model="form.${field}"/> <image-upload v-model="form.${field}"/>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "fileUpload") #elseif($column.htmlType == "fileUpload")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<fileUpload v-model="form.${field}"/> <file-upload v-model="form.${field}"/>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "editor") #elseif($column.htmlType == "editor")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
@ -238,7 +252,7 @@
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime") #elseif($column.htmlType == "datetime")
<el-form-item label="${comment}" prop="${field}"> <el-form-item label="${comment}" prop="${field}">
<el-date-picker clearable size="small" <el-date-picker clearable
v-model="form.${field}" v-model="form.${field}"
type="date" type="date"
value-format="yyyy-MM-dd" value-format="yyyy-MM-dd"
@ -289,6 +303,10 @@ export default {
title: "", title: "",
// 是否显示弹出层 // 是否显示弹出层
open: false, open: false,
// 是否展开,默认全部展开
isExpandAll: true,
// 重新渲染表格状态
refreshTable: true,
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") #if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
@ -419,6 +437,14 @@ export default {
this.open = true; this.open = true;
this.title = "添加${functionName}"; this.title = "添加${functionName}";
}, },
/** 展开/折叠操作 */
toggleExpandAll() {
this.refreshTable = false;
this.isExpandAll = !this.isExpandAll;
this.$nextTick(() => {
this.refreshTable = true;
});
},
/** 修改按钮操作 */ /** 修改按钮操作 */
handleUpdate(row) { handleUpdate(row) {
this.reset(); this.reset();

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px"> <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
#foreach($column in $columns) #foreach($column in $columns)
#if($column.query) #if($column.query)
#set($dictType=$column.dictType) #set($dictType=$column.dictType)
@ -17,13 +17,12 @@
v-model="queryParams.${column.javaField}" v-model="queryParams.${column.javaField}"
placeholder="请输入${comment}" placeholder="请输入${comment}"
clearable clearable
size="small"
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType) #elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small"> <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
<el-option <el-option
v-for="dict in dict.type.${dictType}" v-for="dict in dict.type.${dictType}"
:key="dict.value" :key="dict.value"
@ -34,24 +33,23 @@
</el-form-item> </el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType) #elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small"> <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
<el-option label="请选择字典生成" value="" /> <el-option label="请选择字典生成" value="" />
</el-select> </el-select>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN") #elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-date-picker clearable size="small" <el-date-picker clearable
v-model="queryParams.${column.javaField}" v-model="queryParams.${column.javaField}"
type="date" type="date"
value-format="yyyy-MM-dd" value-format="yyyy-MM-dd"
placeholder="选择${comment}"> placeholder="选择${comment}">
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN") #elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<el-date-picker <el-date-picker
v-model="daterange${AttrName}" v-model="daterange${AttrName}"
size="small"
style="width: 240px" style="width: 240px"
value-format="yyyy-MM-dd" value-format="yyyy-MM-dd"
type="daterange" type="daterange"
@ -133,6 +131,12 @@
<span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span> <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
</template> </template>
</el-table-column> </el-table-column>
#elseif($column.list && $column.htmlType == "imageUpload")
<el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
<template slot-scope="scope">
<image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
</template>
</el-table-column>
#elseif($column.list && "" != $column.dictType) #elseif($column.list && "" != $column.dictType)
<el-table-column label="${comment}" align="center" prop="${javaField}"> <el-table-column label="${comment}" align="center" prop="${javaField}">
<template slot-scope="scope"> <template slot-scope="scope">
@ -195,11 +199,11 @@
</el-form-item> </el-form-item>
#elseif($column.htmlType == "imageUpload") #elseif($column.htmlType == "imageUpload")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<imageUpload v-model="form.${field}"/> <image-upload v-model="form.${field}"/>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "fileUpload") #elseif($column.htmlType == "fileUpload")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<fileUpload v-model="form.${field}"/> <file-upload v-model="form.${field}"/>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "editor") #elseif($column.htmlType == "editor")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
@ -259,11 +263,11 @@
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime") #elseif($column.htmlType == "datetime")
<el-form-item label="${comment}" prop="${field}"> <el-form-item label="${comment}" prop="${field}">
<el-date-picker clearable size="small" <el-date-picker clearable
v-model="form.${field}" v-model="form.${field}"
type="date" type="date"
value-format="yyyy-MM-dd" value-format="yyyy-MM-dd"
placeholder="选择${comment}"> placeholder="选择${comment}">
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "textarea") #elseif($column.htmlType == "textarea")
@ -296,12 +300,39 @@
#set($comment=$column.columnComment) #set($comment=$column.columnComment)
#end #end
#if($column.pk || $javaField == ${subTableFkclassName}) #if($column.pk || $javaField == ${subTableFkclassName})
#elseif($column.list && "" != $javaField) #elseif($column.list && $column.htmlType == "input")
<el-table-column label="$comment" prop="${javaField}"> <el-table-column label="$comment" prop="${javaField}" width="150">
<template slot-scope="scope"> <template slot-scope="scope">
<el-input v-model="scope.row.$javaField" placeholder="请输入$comment" /> <el-input v-model="scope.row.$javaField" placeholder="请输入$comment" />
</template> </template>
</el-table-column> </el-table-column>
#elseif($column.list && $column.htmlType == "datetime")
<el-table-column label="$comment" prop="${javaField}" width="240">
<template slot-scope="scope">
<el-date-picker clearable v-model="scope.row.$javaField" type="date" value-format="yyyy-MM-dd" placeholder="请选择$comment" />
</template>
</el-table-column>
#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" != $column.dictType)
<el-table-column label="$comment" prop="${javaField}" width="150">
<template slot-scope="scope">
<el-select v-model="scope.row.$javaField" placeholder="请选择$comment">
<el-option
v-for="dict in dict.type.$column.dictType"
:key="dict.value"
:label="dict.label"
:value="dict.value"
></el-option>
</el-select>
</template>
</el-table-column>
#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" == $column.dictType)
<el-table-column label="$comment" prop="${javaField}" width="150">
<template slot-scope="scope">
<el-select v-model="scope.row.$javaField" placeholder="请选择$comment">
<el-option label="请选择字典生成" value="" />
</el-select>
</template>
</el-table-column>
#end #end
#end #end
</el-table> </el-table>

View File

@ -17,13 +17,12 @@
v-model="queryParams.${column.javaField}" v-model="queryParams.${column.javaField}"
placeholder="请输入${comment}" placeholder="请输入${comment}"
clearable clearable
size="small"
@keyup.enter="handleQuery" @keyup.enter="handleQuery"
/> />
</el-form-item> </el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType) #elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small"> <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
<el-option <el-option
v-for="dict in ${dictType}" v-for="dict in ${dictType}"
:key="dict.value" :key="dict.value"
@ -34,13 +33,13 @@
</el-form-item> </el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType) #elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small"> <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
<el-option label="请选择字典生成" value="" /> <el-option label="请选择字典生成" value="" />
</el-select> </el-select>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN") #elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-date-picker clearable size="small" <el-date-picker clearable
v-model="queryParams.${column.javaField}" v-model="queryParams.${column.javaField}"
type="date" type="date"
value-format="YYYY-MM-DD" value-format="YYYY-MM-DD"
@ -48,11 +47,9 @@
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN") #elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
<el-form-item label="${comment}"> <el-form-item label="${comment}" style="width: 308px">
<el-date-picker <el-date-picker
v-model="daterange${AttrName}" v-model="daterange${AttrName}"
size="small"
style="width: 240px"
value-format="YYYY-MM-DD" value-format="YYYY-MM-DD"
type="daterange" type="daterange"
range-separator="-" range-separator="-"
@ -64,8 +61,8 @@
#end #end
#end #end
<el-form-item> <el-form-item>
<el-button type="primary" icon="Search" size="mini" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" size="mini" @click="resetQuery">重置</el-button> <el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -75,19 +72,27 @@
type="primary" type="primary"
plain plain
icon="Plus" icon="Plus"
size="mini"
@click="handleAdd" @click="handleAdd"
v-hasPermi="['${moduleName}:${businessName}:add']" v-hasPermi="['${moduleName}:${businessName}:add']"
>新增</el-button> >新增</el-button>
</el-col> </el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="Sort"
@click="toggleExpandAll"
>展开/折叠</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row> </el-row>
<el-table <el-table
v-if="refreshTable"
v-loading="loading" v-loading="loading"
:data="${businessName}List" :data="${businessName}List"
row-key="${treeCode}" row-key="${treeCode}"
default-expand-all :default-expand-all="isExpandAll"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}" :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
> >
#foreach($column in $columns) #foreach($column in $columns)
@ -105,6 +110,12 @@
<span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span> <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
</template> </template>
</el-table-column> </el-table-column>
#elseif($column.list && $column.htmlType == "imageUpload")
<el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
<template #default="scope">
<image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
</template>
</el-table-column>
#elseif($column.list && "" != $column.dictType) #elseif($column.list && "" != $column.dictType)
<el-table-column label="${comment}" align="center" prop="${javaField}"> <el-table-column label="${comment}" align="center" prop="${javaField}">
<template #default="scope"> <template #default="scope">
@ -126,21 +137,18 @@
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope"> <template #default="scope">
<el-button <el-button
size="mini"
type="text" type="text"
icon="Edit" icon="Edit"
@click="handleUpdate(scope.row)" @click="handleUpdate(scope.row)"
v-hasPermi="['${moduleName}:${businessName}:edit']" v-hasPermi="['${moduleName}:${businessName}:edit']"
>修改</el-button> >修改</el-button>
<el-button <el-button
size="mini"
type="text" type="text"
icon="Plus" icon="Plus"
@click="handleAdd(scope.row)" @click="handleAdd(scope.row)"
v-hasPermi="['${moduleName}:${businessName}:add']" v-hasPermi="['${moduleName}:${businessName}:add']"
>新增</el-button> >新增</el-button>
<el-button <el-button
size="mini"
type="text" type="text"
icon="Delete" icon="Delete"
@click="handleDelete(scope.row)" @click="handleDelete(scope.row)"
@ -166,11 +174,13 @@
#set($dictType=$column.dictType) #set($dictType=$column.dictType)
#if("" != $treeParentCode && $column.javaField == $treeParentCode) #if("" != $treeParentCode && $column.javaField == $treeParentCode)
<el-form-item label="${comment}" prop="${treeParentCode}"> <el-form-item label="${comment}" prop="${treeParentCode}">
<tree-select <el-tree-select
v-model:value="form.${treeParentCode}" v-model="form.${treeParentCode}"
:options="${businessName}Options" :data="${businessName}Options"
:objMap="{ value: '${treeCode}', label: '${treeName}', children: 'children' }" :props="{ value: '${treeCode}', label: '${treeName}', children: 'children' }"
value-key="${treeCode}"
placeholder="请选择${comment}" placeholder="请选择${comment}"
check-strictly
/> />
</el-form-item> </el-form-item>
#elseif($column.htmlType == "input") #elseif($column.htmlType == "input")
@ -179,11 +189,11 @@
</el-form-item> </el-form-item>
#elseif($column.htmlType == "imageUpload") #elseif($column.htmlType == "imageUpload")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<imageUpload v-model="form.${field}"/> <image-upload v-model="form.${field}"/>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "fileUpload") #elseif($column.htmlType == "fileUpload")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<fileUpload v-model="form.${field}"/> <file-upload v-model="form.${field}"/>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "editor") #elseif($column.htmlType == "editor")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
@ -243,7 +253,7 @@
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime") #elseif($column.htmlType == "datetime")
<el-form-item label="${comment}" prop="${field}"> <el-form-item label="${comment}" prop="${field}">
<el-date-picker clearable size="small" <el-date-picker clearable
v-model="form.${field}" v-model="form.${field}"
type="date" type="date"
value-format="YYYY-MM-DD" value-format="YYYY-MM-DD"
@ -284,6 +294,8 @@ const open = ref(false);
const loading = ref(true); const loading = ref(true);
const showSearch = ref(true); const showSearch = ref(true);
const title = ref(""); const title = ref("");
const isExpandAll = ref(true);
const refreshTable = ref(true);
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") #if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
@ -344,8 +356,8 @@ function getList() {
} }
/** 查询${functionName}下拉树结构 */ /** 查询${functionName}下拉树结构 */
async function getTreeselect() { function getTreeselect() {
await list${BusinessName}().then(response => { list${BusinessName}().then(response => {
${businessName}Options.value = []; ${businessName}Options.value = [];
const data = { ${treeCode}: 0, ${treeName}: '顶级节点', children: [] }; const data = { ${treeCode}: 0, ${treeName}: '顶级节点', children: [] };
data.children = proxy.handleTree(response.data, "${treeCode}", "${treeParentCode}"); data.children = proxy.handleTree(response.data, "${treeCode}", "${treeParentCode}");
@ -394,9 +406,9 @@ function resetQuery() {
} }
/** 新增按钮操作 */ /** 新增按钮操作 */
async function handleAdd(row) { function handleAdd(row) {
reset(); reset();
await getTreeselect(); getTreeselect();
if (row != null && row.${treeCode}) { if (row != null && row.${treeCode}) {
form.value.${treeParentCode} = row.${treeCode}; form.value.${treeParentCode} = row.${treeCode};
} else { } else {
@ -406,6 +418,15 @@ async function handleAdd(row) {
title.value = "添加${functionName}"; title.value = "添加${functionName}";
} }
/** 展开/折叠操作 */
function toggleExpandAll() {
refreshTable.value = false;
isExpandAll.value = !isExpandAll.value;
nextTick(() => {
refreshTable.value = true;
});
}
/** 修改按钮操作 */ /** 修改按钮操作 */
async function handleUpdate(row) { async function handleUpdate(row) {
reset(); reset();

View File

@ -17,13 +17,12 @@
v-model="queryParams.${column.javaField}" v-model="queryParams.${column.javaField}"
placeholder="请输入${comment}" placeholder="请输入${comment}"
clearable clearable
size="small"
@keyup.enter="handleQuery" @keyup.enter="handleQuery"
/> />
</el-form-item> </el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType) #elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small"> <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
<el-option <el-option
v-for="dict in ${dictType}" v-for="dict in ${dictType}"
:key="dict.value" :key="dict.value"
@ -34,25 +33,23 @@
</el-form-item> </el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType) #elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small"> <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
<el-option label="请选择字典生成" value="" /> <el-option label="请选择字典生成" value="" />
</el-select> </el-select>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN") #elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-date-picker clearable size="small" <el-date-picker clearable
v-model="queryParams.${column.javaField}" v-model="queryParams.${column.javaField}"
type="date" type="date"
value-format="YYYY-MM-DD" value-format="YYYY-MM-DD"
placeholder="选择${comment}"> placeholder="选择${comment}">
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN") #elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
<el-form-item label="${comment}"> <el-form-item label="${comment}" style="width: 308px">
<el-date-picker <el-date-picker
v-model="daterange${AttrName}" v-model="daterange${AttrName}"
size="small"
style="width: 240px"
value-format="YYYY-MM-DD" value-format="YYYY-MM-DD"
type="daterange" type="daterange"
range-separator="-" range-separator="-"
@ -64,8 +61,8 @@
#end #end
#end #end
<el-form-item> <el-form-item>
<el-button type="primary" icon="Search" size="mini" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" size="mini" @click="resetQuery">重置</el-button> <el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -75,7 +72,6 @@
type="primary" type="primary"
plain plain
icon="Plus" icon="Plus"
size="mini"
@click="handleAdd" @click="handleAdd"
v-hasPermi="['${moduleName}:${businessName}:add']" v-hasPermi="['${moduleName}:${businessName}:add']"
>新增</el-button> >新增</el-button>
@ -85,7 +81,6 @@
type="success" type="success"
plain plain
icon="Edit" icon="Edit"
size="mini"
:disabled="single" :disabled="single"
@click="handleUpdate" @click="handleUpdate"
v-hasPermi="['${moduleName}:${businessName}:edit']" v-hasPermi="['${moduleName}:${businessName}:edit']"
@ -96,7 +91,6 @@
type="danger" type="danger"
plain plain
icon="Delete" icon="Delete"
size="mini"
:disabled="multiple" :disabled="multiple"
@click="handleDelete" @click="handleDelete"
v-hasPermi="['${moduleName}:${businessName}:remove']" v-hasPermi="['${moduleName}:${businessName}:remove']"
@ -107,7 +101,6 @@
type="warning" type="warning"
plain plain
icon="Download" icon="Download"
size="mini"
@click="handleExport" @click="handleExport"
v-hasPermi="['${moduleName}:${businessName}:export']" v-hasPermi="['${moduleName}:${businessName}:export']"
>导出</el-button> >导出</el-button>
@ -133,6 +126,12 @@
<span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span> <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
</template> </template>
</el-table-column> </el-table-column>
#elseif($column.list && $column.htmlType == "imageUpload")
<el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
<template #default="scope">
<image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
</template>
</el-table-column>
#elseif($column.list && "" != $column.dictType) #elseif($column.list && "" != $column.dictType)
<el-table-column label="${comment}" align="center" prop="${javaField}"> <el-table-column label="${comment}" align="center" prop="${javaField}">
<template #default="scope"> <template #default="scope">
@ -150,14 +149,12 @@
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope"> <template #default="scope">
<el-button <el-button
size="mini"
type="text" type="text"
icon="Edit" icon="Edit"
@click="handleUpdate(scope.row)" @click="handleUpdate(scope.row)"
v-hasPermi="['${moduleName}:${businessName}:edit']" v-hasPermi="['${moduleName}:${businessName}:edit']"
>修改</el-button> >修改</el-button>
<el-button <el-button
size="mini"
type="text" type="text"
icon="Delete" icon="Delete"
@click="handleDelete(scope.row)" @click="handleDelete(scope.row)"
@ -170,8 +167,8 @@
<pagination <pagination
v-show="total>0" v-show="total>0"
:total="total" :total="total"
v-model:p:page="queryParams.pageNum" v-model:page="queryParams.pageNum"
v-model:p:limit="queryParams.pageSize" v-model:limit="queryParams.pageSize"
@pagination="getList" @pagination="getList"
/> />
@ -195,11 +192,11 @@
</el-form-item> </el-form-item>
#elseif($column.htmlType == "imageUpload") #elseif($column.htmlType == "imageUpload")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<imageUpload v-model="form.${field}"/> <image-upload v-model="form.${field}"/>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "fileUpload") #elseif($column.htmlType == "fileUpload")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<fileUpload v-model="form.${field}"/> <file-upload v-model="form.${field}"/>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "editor") #elseif($column.htmlType == "editor")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
@ -259,11 +256,11 @@
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime") #elseif($column.htmlType == "datetime")
<el-form-item label="${comment}" prop="${field}"> <el-form-item label="${comment}" prop="${field}">
<el-date-picker clearable size="small" <el-date-picker clearable
v-model="form.${field}" v-model="form.${field}"
type="date" type="date"
value-format="YYYY-MM-DD" value-format="YYYY-MM-DD"
placeholder="选择${comment}"> placeholder="选择${comment}">
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "textarea") #elseif($column.htmlType == "textarea")
@ -278,10 +275,10 @@
<el-divider content-position="center">${subTable.functionName}信息</el-divider> <el-divider content-position="center">${subTable.functionName}信息</el-divider>
<el-row :gutter="10" class="mb8"> <el-row :gutter="10" class="mb8">
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="primary" icon="Plus" size="mini" @click="handleAdd${subClassName}">添加</el-button> <el-button type="primary" icon="Plus" @click="handleAdd${subClassName}">添加</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="danger" icon="Delete" size="mini" @click="handleDelete${subClassName}">删除</el-button> <el-button type="danger" icon="Delete" @click="handleDelete${subClassName}">删除</el-button>
</el-col> </el-col>
</el-row> </el-row>
<el-table :data="${subclassName}List" :row-class-name="row${subClassName}Index" @selection-change="handle${subClassName}SelectionChange" ref="${subclassName}"> <el-table :data="${subclassName}List" :row-class-name="row${subClassName}Index" @selection-change="handle${subClassName}SelectionChange" ref="${subclassName}">
@ -296,12 +293,44 @@
#set($comment=$column.columnComment) #set($comment=$column.columnComment)
#end #end
#if($column.pk || $javaField == ${subTableFkclassName}) #if($column.pk || $javaField == ${subTableFkclassName})
#elseif($column.list && "" != $javaField) #elseif($column.list && $column.htmlType == "input")
<el-table-column label="$comment" prop="${javaField}"> <el-table-column label="$comment" prop="${javaField}" width="150">
<template #default="scope"> <template #default="scope">
<el-input v-model="scope.row.$javaField" placeholder="请输入$comment" /> <el-input v-model="scope.row.$javaField" placeholder="请输入$comment" />
</template> </template>
</el-table-column> </el-table-column>
#elseif($column.list && $column.htmlType == "datetime")
<el-table-column label="$comment" prop="${javaField}" width="240">
<template #default="scope">
<el-date-picker clearable
v-model="scope.row.$javaField"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择$comment">
</el-date-picker>
</template>
</el-table-column>
#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" != $column.dictType)
<el-table-column label="$comment" prop="${javaField}" width="150">
<template #default="scope">
<el-select v-model="scope.row.$javaField" placeholder="请选择$comment">
<el-option
v-for="dict in $column.dictType"
:key="dict.value"
:label="dict.label"
:value="dict.value"
></el-option>
</el-select>
</template>
</el-table-column>
#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" == $column.dictType)
<el-table-column label="$comment" prop="${javaField}" width="150">
<template #default="scope">
<el-select v-model="scope.row.$javaField" placeholder="请选择$comment">
<el-option label="请选择字典生成" value="" />
</el-select>
</template>
</el-table-column>
#end #end
#end #end
</el-table> </el-table>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>3.8.1</version> <version>3.8.3</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -1,57 +1,57 @@
package com.ruoyi.quartz.config; //package com.ruoyi.quartz.config;
//
import org.springframework.context.annotation.Bean; //import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; //import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean; //import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import javax.sql.DataSource; //import javax.sql.DataSource;
import java.util.Properties; //import java.util.Properties;
//
/** ///**
* 定时任务配置单机部署建议删除此类和qrtz数据库表默认走内存会最高效 // * 定时任务配置单机部署建议删除此类和qrtz数据库表默认走内存会最高效
* // *
* @author ruoyi // * @author ruoyi
*/ // */
@Configuration //@Configuration
public class ScheduleConfig //public class ScheduleConfig
{ //{
@Bean // @Bean
public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) // public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource)
{ // {
SchedulerFactoryBean factory = new SchedulerFactoryBean(); // SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setDataSource(dataSource); // factory.setDataSource(dataSource);
//
// quartz参数 // // quartz参数
Properties prop = new Properties(); // Properties prop = new Properties();
prop.put("org.quartz.scheduler.instanceName", "RuoyiScheduler"); // prop.put("org.quartz.scheduler.instanceName", "RuoyiScheduler");
prop.put("org.quartz.scheduler.instanceId", "AUTO"); // prop.put("org.quartz.scheduler.instanceId", "AUTO");
// 线程池配置 // // 线程池配置
prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool"); // prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
prop.put("org.quartz.threadPool.threadCount", "20"); // prop.put("org.quartz.threadPool.threadCount", "20");
prop.put("org.quartz.threadPool.threadPriority", "5"); // prop.put("org.quartz.threadPool.threadPriority", "5");
// JobStore配置 // // JobStore配置
prop.put("org.quartz.jobStore.class", "org.springframework.scheduling.quartz.LocalDataSourceJobStore"); // prop.put("org.quartz.jobStore.class", "org.springframework.scheduling.quartz.LocalDataSourceJobStore");
// 集群配置 // // 集群配置
prop.put("org.quartz.jobStore.isClustered", "true"); // prop.put("org.quartz.jobStore.isClustered", "true");
prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000"); // prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000");
prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1"); // prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1");
prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true"); // prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true");
//
// sqlserver 启用 // // sqlserver 启用
// prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?"); // // prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?");
prop.put("org.quartz.jobStore.misfireThreshold", "12000"); // prop.put("org.quartz.jobStore.misfireThreshold", "12000");
prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_"); // prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
factory.setQuartzProperties(prop); // factory.setQuartzProperties(prop);
//
factory.setSchedulerName("RuoyiScheduler"); // factory.setSchedulerName("RuoyiScheduler");
// 延时启动 // // 延时启动
factory.setStartupDelay(1); // factory.setStartupDelay(1);
factory.setApplicationContextSchedulerContextKey("applicationContextKey"); // factory.setApplicationContextSchedulerContextKey("applicationContextKey");
// 可选QuartzScheduler // // 可选QuartzScheduler
// 启动时更新己存在的Job这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了 // // 启动时更新己存在的Job这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了
factory.setOverwriteExistingJobs(true); // factory.setOverwriteExistingJobs(true);
// 设置自动启动默认为true // // 设置自动启动默认为true
factory.setAutoStartup(true); // factory.setAutoStartup(true);
//
return factory; // return factory;
} // }
} //}

View File

@ -25,6 +25,7 @@ import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.quartz.domain.SysJob; import com.ruoyi.quartz.domain.SysJob;
import com.ruoyi.quartz.service.ISysJobService; import com.ruoyi.quartz.service.ISysJobService;
import com.ruoyi.quartz.util.CronUtils; import com.ruoyi.quartz.util.CronUtils;
import com.ruoyi.quartz.util.ScheduleUtils;
/** /**
* 调度任务信息操作处理 * 调度任务信息操作处理
@ -87,20 +88,24 @@ public class SysJobController extends BaseController
} }
else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI)) else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))
{ {
return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi://'调用"); return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用");
} }
else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_LDAP)) else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS }))
{ {
return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap://'调用"); return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap(s)'调用");
} }
else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS })) else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
{ {
return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)//'调用"); return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用");
} }
else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR)) else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR))
{ {
return error("新增任务'" + job.getJobName() + "'失败,目标字符串存在违规"); return error("新增任务'" + job.getJobName() + "'失败,目标字符串存在违规");
} }
else if (!ScheduleUtils.whiteList(job.getInvokeTarget()))
{
return error("新增任务'" + job.getJobName() + "'失败,目标字符串不在白名单内");
}
job.setCreateBy(getUsername()); job.setCreateBy(getUsername());
return toAjax(jobService.insertJob(job)); return toAjax(jobService.insertJob(job));
} }
@ -119,20 +124,24 @@ public class SysJobController extends BaseController
} }
else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI)) else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))
{ {
return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi://'调用"); return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用");
} }
else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_LDAP)) else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS }))
{ {
return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap://'调用"); return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap(s)'调用");
} }
else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS })) else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
{ {
return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)//'调用"); return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用");
} }
else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR)) else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR))
{ {
return error("修改任务'" + job.getJobName() + "'失败,目标字符串存在违规"); return error("修改任务'" + job.getJobName() + "'失败,目标字符串存在违规");
} }
else if (!ScheduleUtils.whiteList(job.getInvokeTarget()))
{
return error("修改任务'" + job.getJobName() + "'失败,目标字符串不在白名单内");
}
job.setUpdateBy(getUsername()); job.setUpdateBy(getUsername());
return toAjax(jobService.updateJob(job)); return toAjax(jobService.updateJob(job));
} }

View File

@ -10,9 +10,12 @@ import org.quartz.Scheduler;
import org.quartz.SchedulerException; import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder; import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey; import org.quartz.TriggerKey;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.ScheduleConstants; import com.ruoyi.common.constant.ScheduleConstants;
import com.ruoyi.common.exception.job.TaskException; import com.ruoyi.common.exception.job.TaskException;
import com.ruoyi.common.exception.job.TaskException.Code; import com.ruoyi.common.exception.job.TaskException.Code;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.quartz.domain.SysJob; import com.ruoyi.quartz.domain.SysJob;
/** /**
@ -110,4 +113,22 @@ public class ScheduleUtils
+ "' cannot be used in cron schedule tasks", Code.CONFIG_ERROR); + "' cannot be used in cron schedule tasks", Code.CONFIG_ERROR);
} }
} }
/**
* 检查包名是否为白名单配置
*
* @param invokeTarget 目标字符串
* @return 结果
*/
public static boolean whiteList(String invokeTarget)
{
String packageName = StringUtils.substringBefore(invokeTarget, "(");
int count = StringUtils.countMatches(packageName, ".");
if (count > 1)
{
return StringUtils.containsAnyIgnoreCase(invokeTarget, Constants.JOB_WHITELIST_STR);
}
Object obj = SpringUtils.getBean(StringUtils.split(invokeTarget, ".")[0]);
return StringUtils.containsAnyIgnoreCase(obj.getClass().getPackage().getName(), Constants.JOB_WHITELIST_STR);
}
} }

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>3.8.1</version> <version>3.8.3</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -0,0 +1,81 @@
package com.ruoyi.system.domain;
import com.ruoyi.common.utils.StringUtils;
/**
* 缓存信息
*
* @author ruoyi
*/
public class SysCache
{
/** 缓存名称 */
private String cacheName = "";
/** 缓存键名 */
private String cacheKey = "";
/** 缓存内容 */
private String cacheValue = "";
/** 备注 */
private String remark = "";
public SysCache()
{
}
public SysCache(String cacheName, String remark)
{
this.cacheName = cacheName;
this.remark = remark;
}
public SysCache(String cacheName, String cacheKey, String cacheValue)
{
this.cacheName = StringUtils.replace(cacheName, ":", "");
this.cacheKey = StringUtils.replace(cacheKey, cacheName, "");
this.cacheValue = cacheValue;
}
public String getCacheName()
{
return cacheName;
}
public void setCacheName(String cacheName)
{
this.cacheName = cacheName;
}
public String getCacheKey()
{
return cacheKey;
}
public void setCacheKey(String cacheKey)
{
this.cacheKey = cacheKey;
}
public String getCacheValue()
{
return cacheValue;
}
public void setCacheValue(String cacheValue)
{
this.cacheValue = cacheValue;
}
public String getRemark()
{
return remark;
}
public void setRemark(String remark)
{
this.remark = remark;
}
}

View File

@ -1,7 +1,6 @@
package com.ruoyi.system.mapper; package com.ruoyi.system.mapper;
import java.util.List; import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import com.ruoyi.common.core.domain.entity.SysDictType; import com.ruoyi.common.core.domain.entity.SysDictType;
/** /**
@ -9,7 +8,6 @@ import com.ruoyi.common.core.domain.entity.SysDictType;
* *
* @author ruoyi * @author ruoyi
*/ */
@Mapper
public interface SysDictTypeMapper public interface SysDictTypeMapper
{ {
/** /**

View File

@ -20,7 +20,7 @@ public interface SysUserMapper
public List<SysUser> selectUserList(SysUser sysUser); public List<SysUser> selectUserList(SysUser sysUser);
/** /**
* 根据条件分页查询已配用户角色列表 * 根据条件分页查询已配用户角色列表
* *
* @param user 用户信息 * @param user 用户信息
* @return 用户信息集合信息 * @return 用户信息集合信息

View File

@ -61,7 +61,6 @@ public interface ISysConfigService
* 批量删除参数信息 * 批量删除参数信息
* *
* @param configIds 需要删除的参数ID * @param configIds 需要删除的参数ID
* @return 结果
*/ */
public void deleteConfigByIds(Long[] configIds); public void deleteConfigByIds(Long[] configIds);

View File

@ -39,7 +39,6 @@ public interface ISysDictDataService
* 批量删除字典数据信息 * 批量删除字典数据信息
* *
* @param dictCodes 需要删除的字典数据ID * @param dictCodes 需要删除的字典数据ID
* @return 结果
*/ */
public void deleteDictDataByIds(Long[] dictCodes); public void deleteDictDataByIds(Long[] dictCodes);

View File

@ -54,7 +54,6 @@ public interface ISysDictTypeService
* 批量删除字典信息 * 批量删除字典信息
* *
* @param dictIds 需要删除的字典ID * @param dictIds 需要删除的字典ID
* @return 结果
*/ */
public void deleteDictTypeByIds(Long[] dictIds); public void deleteDictTypeByIds(Long[] dictIds);

View File

@ -29,7 +29,7 @@ public interface ISysLogininforService
* 批量删除系统登录日志 * 批量删除系统登录日志
* *
* @param infoIds 需要删除的登录日志ID * @param infoIds 需要删除的登录日志ID
* @return * @return 结果
*/ */
public int deleteLogininforByIds(Long[] infoIds); public int deleteLogininforByIds(Long[] infoIds);

View File

@ -78,7 +78,6 @@ public interface ISysPostService
* *
* @param postIds 需要删除的岗位ID * @param postIds 需要删除的岗位ID
* @return 结果 * @return 结果
* @throws Exception 异常
*/ */
public int deletePostByIds(Long[] postIds); public int deletePostByIds(Long[] postIds);

View File

@ -1,7 +1,12 @@
package com.ruoyi.system.service.impl; package com.ruoyi.system.service.impl;
import java.util.Collection;
import java.util.List;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.common.annotation.DataSource; import com.ruoyi.common.annotation.DataSource;
import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.core.text.Convert; import com.ruoyi.common.core.text.Convert;
@ -11,11 +16,6 @@ import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.SysConfig; import com.ruoyi.system.domain.SysConfig;
import com.ruoyi.system.mapper.SysConfigMapper; import com.ruoyi.system.mapper.SysConfigMapper;
import com.ruoyi.system.service.ISysConfigService; import com.ruoyi.system.service.ISysConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.Collection;
import java.util.List;
/** /**
* 参数配置 服务层实现 * 参数配置 服务层实现
@ -146,7 +146,6 @@ public class SysConfigServiceImpl implements ISysConfigService
* 批量删除参数信息 * 批量删除参数信息
* *
* @param configIds 需要删除的参数ID * @param configIds 需要删除的参数ID
* @return 结果
*/ */
@Override @Override
public void deleteConfigByIds(Long[] configIds) public void deleteConfigByIds(Long[] configIds)
@ -182,7 +181,7 @@ public class SysConfigServiceImpl implements ISysConfigService
@Override @Override
public void clearConfigCache() public void clearConfigCache()
{ {
Collection<String> keys = redisCache.keys(Constants.SYS_CONFIG_KEY + "*"); Collection<String> keys = redisCache.keys(CacheConstants.SYS_CONFIG_KEY + "*");
redisCache.deleteObject(keys); redisCache.deleteObject(keys);
} }
@ -222,6 +221,6 @@ public class SysConfigServiceImpl implements ISysConfigService
*/ */
private String getCacheKey(String configKey) private String getCacheKey(String configKey)
{ {
return Constants.SYS_CONFIG_KEY + configKey; return CacheConstants.SYS_CONFIG_KEY + configKey;
} }
} }

View File

@ -63,9 +63,8 @@ public class SysDeptServiceImpl implements ISysDeptService
{ {
tempList.add(dept.getDeptId()); tempList.add(dept.getDeptId());
} }
for (Iterator<SysDept> iterator = depts.iterator(); iterator.hasNext();) for (SysDept dept : depts)
{ {
SysDept dept = (SysDept) iterator.next();
// 如果是顶级节点, 遍历该父节点的所有子节点 // 如果是顶级节点, 遍历该父节点的所有子节点
if (!tempList.contains(dept.getParentId())) if (!tempList.contains(dept.getParentId()))
{ {

View File

@ -60,7 +60,6 @@ public class SysDictDataServiceImpl implements ISysDictDataService
* 批量删除字典数据信息 * 批量删除字典数据信息
* *
* @param dictCodes 需要删除的字典数据ID * @param dictCodes 需要删除的字典数据ID
* @return 结果
*/ */
@Override @Override
public void deleteDictDataByIds(Long[] dictCodes) public void deleteDictDataByIds(Long[] dictCodes)

View File

@ -1,5 +1,13 @@
package com.ruoyi.system.service.impl; package com.ruoyi.system.service.impl;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.entity.SysDictData; import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.domain.entity.SysDictType; import com.ruoyi.common.core.domain.entity.SysDictType;
@ -9,11 +17,6 @@ import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.mapper.SysDictDataMapper; import com.ruoyi.system.mapper.SysDictDataMapper;
import com.ruoyi.system.mapper.SysDictTypeMapper; import com.ruoyi.system.mapper.SysDictTypeMapper;
import com.ruoyi.system.service.ISysDictTypeService; import com.ruoyi.system.service.ISysDictTypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.PostConstruct;
import java.util.List;
/** /**
* 字典 业务层处理 * 字典 业务层处理
@ -112,7 +115,6 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService
* 批量删除字典类型信息 * 批量删除字典类型信息
* *
* @param dictIds 需要删除的字典ID * @param dictIds 需要删除的字典ID
* @return 结果
*/ */
@Override @Override
public void deleteDictTypeByIds(Long[] dictIds) public void deleteDictTypeByIds(Long[] dictIds)
@ -135,11 +137,12 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService
@Override @Override
public void loadingDictCache() public void loadingDictCache()
{ {
List<SysDictType> dictTypeList = dictTypeMapper.selectDictTypeAll(); SysDictData dictData = new SysDictData();
for (SysDictType dictType : dictTypeList) dictData.setStatus("0");
Map<String, List<SysDictData>> dictDataMap = dictDataMapper.selectDictDataList(dictData).stream().collect(Collectors.groupingBy(SysDictData::getDictType));
for (Map.Entry<String, List<SysDictData>> entry : dictDataMap.entrySet())
{ {
List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(dictType.getDictType()); DictUtils.setDictCache(entry.getKey(), entry.getValue().stream().sorted(Comparator.comparing(SysDictData::getDictSort)).collect(Collectors.toList()));
DictUtils.setDictCache(dictType.getDictType(), dictDatas);
} }
} }

View File

@ -46,7 +46,7 @@ public class SysLogininforServiceImpl implements ISysLogininforService
* 批量删除系统登录日志 * 批量删除系统登录日志
* *
* @param infoIds 需要删除的登录日志ID * @param infoIds 需要删除的登录日志ID
* @return * @return 结果
*/ */
@Override @Override
public int deleteLogininforByIds(Long[] infoIds) public int deleteLogininforByIds(Long[] infoIds)

View File

@ -176,7 +176,7 @@ public class SysMenuServiceImpl implements ISysMenuService
else if (menu.getParentId().intValue() == 0 && isInnerLink(menu)) else if (menu.getParentId().intValue() == 0 && isInnerLink(menu))
{ {
router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon())); router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon()));
router.setPath("/inner"); router.setPath("/");
List<RouterVo> childrenList = new ArrayList<RouterVo>(); List<RouterVo> childrenList = new ArrayList<RouterVo>();
RouterVo children = new RouterVo(); RouterVo children = new RouterVo();
String routerPath = innerLinkReplaceEach(menu.getPath()); String routerPath = innerLinkReplaceEach(menu.getPath());
@ -259,7 +259,7 @@ public class SysMenuServiceImpl implements ISysMenuService
public boolean hasChildByMenuId(Long menuId) public boolean hasChildByMenuId(Long menuId)
{ {
int result = menuMapper.hasChildByMenuId(menuId); int result = menuMapper.hasChildByMenuId(menuId);
return result > 0 ? true : false; return result > 0;
} }
/** /**
@ -272,7 +272,7 @@ public class SysMenuServiceImpl implements ISysMenuService
public boolean checkMenuExistRole(Long menuId) public boolean checkMenuExistRole(Long menuId)
{ {
int result = roleMenuMapper.checkMenuExistRole(menuId); int result = roleMenuMapper.checkMenuExistRole(menuId);
return result > 0 ? true : false; return result > 0;
} }
/** /**
@ -498,7 +498,7 @@ public class SysMenuServiceImpl implements ISysMenuService
*/ */
private boolean hasChild(List<SysMenu> list, SysMenu t) private boolean hasChild(List<SysMenu> list, SysMenu t)
{ {
return getChildList(list, t).size() > 0 ? true : false; return getChildList(list, t).size() > 0;
} }
/** /**

View File

@ -137,7 +137,6 @@ public class SysPostServiceImpl implements ISysPostService
* *
* @param postIds 需要删除的岗位ID * @param postIds 需要删除的岗位ID
* @return 结果 * @return 结果
* @throws Exception 异常
*/ */
@Override @Override
public int deletePostByIds(Long[] postIds) public int deletePostByIds(Long[] postIds)

View File

@ -361,6 +361,7 @@ public class SysRoleServiceImpl implements ISysRoleService
for (Long roleId : roleIds) for (Long roleId : roleIds)
{ {
checkRoleAllowed(new SysRole(roleId)); checkRoleAllowed(new SysRole(roleId));
checkRoleDataScope(roleId);
SysRole role = selectRoleById(roleId); SysRole role = selectRoleById(roleId);
if (countUserRoleByRoleId(roleId) > 0) if (countUserRoleByRoleId(roleId) > 0)
{ {
@ -403,7 +404,7 @@ public class SysRoleServiceImpl implements ISysRoleService
* 批量选择授权用户角色 * 批量选择授权用户角色
* *
* @param roleId 角色ID * @param roleId 角色ID
* @param userIds 需要删除的用户数据ID * @param userIds 需要授权的用户数据ID
* @return 结果 * @return 结果
*/ */
@Override @Override

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