202 Commits

Author SHA1 Message Date
c3a727b2fd 若依 3.8.5 2023-01-01 09:09:25 +08:00
19eaad0129 v3最新版本不需要render-after-expand 2022-12-23 16:08:23 +08:00
565cbb8c7a 升级pagehelper到最新版1.4.6 2022-12-13 19:42:39 +08:00
b2cf949956 修改参数键名时移除前缓存配置 2022-12-13 19:40:48 +08:00
3fec133c69 升级oshi到最新版本6.4.0 2022-12-13 19:39:36 +08:00
c9de6fcd82 优化代码 2022-12-13 19:39:19 +08:00
22ee2c2e94 删除fuse无效选项maxPatternLength 2022-12-08 10:21:48 +08:00
f11db02ff8 修复代码生成图片/文件/单选时选择必填无法校验问题(I64IO2) 2022-12-08 10:19:38 +08:00
d5f5c5d066 升级fastjson到最新版2.0.20 2022-12-08 10:13:39 +08:00
4536906b21 修复Vue3树形下拉不能默认选中(I64ESN) 2022-12-07 20:24:08 +08:00
9748e10339 升级druid到最新版本1.2.15 2022-12-07 11:41:44 +08:00
b08a6ce3f6 升级kaptcha到最新版2.3.3 2022-12-07 10:45:50 +08:00
3039b745a9 升级echarts到最新版本5.4.0 2022-12-07 10:12:15 +08:00
39298d803c 添加新群号:170801498 2022-12-03 12:50:26 +08:00
09bb3e15c6 定时任务违规的字符 2022-12-03 12:48:51 +08:00
3b8a68c4cf 升级oshi到最新版本6.3.2 2022-12-03 12:43:37 +08:00
9aae863ce3 优化弹窗内容过多展示不全问题(I645RU) 2022-12-03 12:42:50 +08:00
963247df43 !627 update ruoyi-ui/src/plugins/download.js.
Merge pull request !627 from Zeno/N/A
2022-12-01 08:21:29 +00:00
7d874e31cf update ruoyi-ui/src/plugins/download.js.
修复文件名包含特殊字符(+、-、*...)的文件无法下载问题

Signed-off-by: Zeno <15270656234@163.com>
2022-11-28 10:29:38 +00:00
1bb6342bcb 修复Log注解GET请求记录不到参数问题 2022-11-22 10:41:40 +08:00
27acbe5b73 修复某些特性的环境生成代码变乱码TXT文件问题 2022-11-22 09:23:17 +08:00
6474a17100 消除Vue3控制台出现的警告信息 2022-11-21 19:10:25 +08:00
142f6ad6a0 兼容Excel下拉框内容过多无法显示的问题(I5XB6I) 2022-11-21 12:20:36 +08:00
b4bdd4f306 开启TopNav没有子菜单隐藏侧边栏 2022-11-17 14:27:30 +08:00
74ba681fee 修复回显数据字典数组异常问题(I60UYQ) 2022-11-15 14:11:52 +08:00
8f2b3ac465 !611 修复调度日志点击多次数据不变化的问题
Merge pull request !611 from 也曾为你像超人/N/A
2022-11-15 06:09:02 +00:00
7eee3b9f02 升级druid到最新版本1.2.14 2022-11-14 11:17:04 +08:00
27e34c2f0a 忽略不必要的属性数据返回 2022-11-12 11:26:48 +08:00
836180fe0e 优化导出对象的子列表为空会出现[]问题 2022-11-11 11:31:27 +08:00
06fbda5324 修复sheet超出最大行数异常问题 2022-11-07 11:20:02 +08:00
bf313b17da !612 根据调度编号获取详细信息参数名改正
Merge pull request !612 from Rain/N/A
2022-10-31 05:51:48 +00:00
a8b9485a29 根据调度编号获取详细信息参数名改正
Signed-off-by: Rain <938448486@qq.com>
2022-10-31 05:51:08 +00:00
101e15d83f 修复调度日志点击多次数据不变化的问题
Signed-off-by: 也曾为你像超人 <1553592282@qq.com>
2022-10-31 05:45:21 +00:00
ebb9f15a75 新增返回警告消息提示 2022-10-30 12:02:06 +08:00
cd137bd9fc 升级fastjson到最新版2.0.16 2022-10-30 09:58:12 +08:00
07bde5f88a !610 pagehelper-boot更新1.4.5
Merge pull request !610 from abbfun/N/A
2022-10-30 01:57:27 +00:00
6fffa02acf pagehelper-boot更新1.4.5
Signed-off-by: abbfun <819589789@qq.com>
2022-10-29 14:45:55 +00:00
dc48f9858b 修复table中更多按钮切换主题色未生效修复问题 2022-10-28 20:59:42 +08:00
a6b2ac5dcd 升级oshi到最新版本6.3.0 2022-10-28 19:57:35 +08:00
c0685b7f7f !608 编辑头像时生成为透明png图片
Merge pull request !608 from BlossomWave/N/A
2022-10-28 11:48:22 +00:00
fb2d616c57 !609 优化代码
Merge pull request !609 from lihy2021/N/A
2022-10-28 11:44:27 +00:00
6ff6853082 !606 重置时取消部门选中
Merge pull request !606 from 也曾为你像超人/N/A
2022-10-28 11:42:26 +00:00
f8014ae969 !602 去除某些svg图标的fill="#bfbfbf"属性,避免菜单激活无法修改其填充颜色
Merge pull request !602 from 清溪先生/master
2022-10-28 11:39:13 +00:00
1de2b7a57e 优化代码 2022-10-27 01:25:39 +00:00
f01aa37394 update ruoyi-ui/src/views/system/user/profile/userAvatar.vue.
默认修改头像时如果上传的图片为png透明图片,生成的头像透明部分会变成黑色,修改了生成头像为png格式。可正常显示图片透明部分。

Signed-off-by: BlossomWave <316975215@qq.com>
2022-10-24 08:25:33 +00:00
4517dea98d 重置时取消部门选中
Signed-off-by: 也曾为你、像超人 <1553592282@qq.com>
2022-10-21 23:24:35 +00:00
e21396870f 修正菜单状态注释信息 2022-10-21 11:56:15 +08:00
b67f6a0fec !604 修复小屏幕上修改头像界面布局错位的问题
Merge pull request !604 from 也曾为你、像超人/master
2022-10-21 03:50:16 +00:00
42d8104505 !603 update ruoyi-ui/src/views/system/user/index.vue.
Merge pull request !603 from kknd97/N/A
2022-10-21 03:46:49 +00:00
f40a0eab23 !601 swagger-ui静态资源缓存
Merge pull request !601 from abbfun/N/A
2022-10-21 03:41:22 +00:00
b6153d1aef 修正选择按钮宽度 2022-10-21 11:21:59 +08:00
a2c585daa4 !605 升级fastjson到最新版2.0.15
Merge pull request !605 from Rain/N/A
2022-10-21 03:11:58 +00:00
5a60bf0b0a 升级fastjson到最新版2.0.15
Signed-off-by: Rain <938448486@qq.com>
2022-10-21 03:01:54 +00:00
9dcddc7876 修复小屏幕上修改头像界面布局错位的问题 2022-10-20 19:18:10 +08:00
b970185536 update ruoyi-ui/src/views/system/user/index.vue.
handleUpdate(row)方法中:this.form = response.data;语句
会导致【this.form.postIds = response.postIds;】和【this.form.roleIds = response.roleIds;】失效。
导致用户编辑对话框中,角色和部门多选框无法正常修改。
建议使用以下语句修改:
this.$set(this.form, "postIds", response.postIds);
this.$set(this.form, "roleIds", response.roleIds);

Signed-off-by: kknd97 <liujingwei@ln.chinamobile.com>
2022-10-20 06:27:02 +00:00
a64a029323 去除某些svg图标的fill="#bfbfbf"属性,避免菜单激活无法修改其填充颜色。
Signed-off-by: 清溪先生 <usfree2021@163.com>
2022-10-19 22:11:14 +08:00
78f4d1c85b swagger-ui静态资源缓存
Signed-off-by: abbfun <819589789@qq.com>
2022-10-19 09:07:35 +00:00
bf83fe568b 修复主题颜色在Drawer组件不会加载问题(I5VCF0) 2022-10-19 10:54:01 +08:00
6505432bf4 修复文件上传组件格式验证问题(I5V32H) 2022-10-12 19:33:58 +08:00
a32a931d24 升级core-js到最新版本3.25.3 2022-10-10 09:22:47 +08:00
4d72fb4289 R isError and isSuccess static 2022-10-10 09:22:37 +08:00
186c04d90a !595 解决导出时包含空子列表数据异常的问题
Merge pull request !595 from 也曾为你、像超人/N/A
2022-10-10 01:20:41 +00:00
c542b7ac32 解决导出时包含空子列表数据异常的问题
Signed-off-by: 也曾为你、像超人 <1553592282@qq.com>
2022-09-30 23:06:10 +00:00
3607e008a3 优化限流打印日志KEY(I5SQ09) 2022-09-28 19:32:55 +08:00
5b8edbf381 修复代码生成勾选属性无效问题 2022-09-28 19:31:52 +08:00
03f7bc0f3f 导入更新用户数据前校验数据权限 2022-09-28 19:26:16 +08:00
e95a1245c5 若依 3.8.4 2022-09-26 08:29:03 +08:00
d7441edae7 升级core-js到最新版本3.25.2 2022-09-22 11:13:49 +08:00
5053361a7f 升级fastjson到最新版2.0.14 2022-09-22 11:13:32 +08:00
acbdd6365a !581 优化日志操作中重置按钮时重复查询的问题
Merge pull request !581 from 也曾为你、像超人/N/A
2022-09-19 06:41:36 +00:00
e781f88eca 优化日志操作中重置按钮时重复查询的问题
Signed-off-by: 也曾为你、像超人 <1553592282@qq.com>
2022-09-19 06:30:47 +00:00
86d16d070d 通用下载方法新增config配置选项(I5PNXE) 2022-09-19 13:09:21 +08:00
854b405d89 修改用户登录账号重复验证 2022-09-18 11:26:03 +08:00
c3faa1a925 升级element-ui到最新版本2.15.10 2022-09-15 08:48:43 +08:00
37d6cc8146 优化代码生成同步后值NULL问题(I5OJDW) 2022-09-13 08:23:30 +08:00
2293822dc2 优化没有权限的用户编辑部门缺少数据(I5OF3O) 2022-09-12 17:22:23 +08:00
f5bec70911 R add isError and isSuccess method 2022-09-12 17:22:07 +08:00
87c53a049b !574 修复 issue#I5Q2ZO
Merge pull request !574 from 捏造的信仰/fix-I5Q2ZO
2022-09-09 01:45:12 +00:00
5bcd2825b6 !568 style重复赋值
Merge pull request !568 from coverme/N/A
2022-09-09 01:25:22 +00:00
036144b9ea 插入 SysOperLog 时,限制 operUrl 属性的长度
Signed-off-by: 捏造的信仰 <yiding.he@gmail.com>
2022-09-07 03:00:51 +00:00
42d602b7a8 添加新群号:160110482 2022-08-28 20:09:25 +08:00
d4b800036c style重复赋值
Signed-off-by: 胡亚飞 <huyafeily@aliyun.com>
2022-08-26 16:26:09 +00:00
2f380f0c41 !564 修复执行任务时,若方法入口在任务的父类,则无法执行的问题
Merge pull request !564 from 捏造的信仰/fix-issue-I5NNXI
2022-08-26 00:42:03 +00:00
39efed1710 修复多文件上传报错出现的异常问题 2022-08-24 11:18:52 +08:00
9a895763d5 优化页面内嵌iframe切换tab不刷新数据 2022-08-23 20:59:26 +08:00
7347cbaedf 优化页面内嵌iframe切换tab不刷新数据 2022-08-23 17:29:09 +08:00
a78b5b7b2a 修复执行任务时,若方法入口在任务的父类,则无法执行的问题
实际项目开发中,可能会为所有定时任务类建一个共同的父类,任务的执行入口在父类定义,以便管理。此时使用 `getDeclaredMethod()` 是无法从子类找到要执行的方法的,而是要换用 `getMethod()` 方法。

Signed-off-by: 捏造的信仰 <yiding.he@gmail.com>
2022-08-23 05:36:29 +00:00
99d1760b98 优化代码 2022-08-22 15:27:58 +08:00
4d71cfa90a !562 修复菜单管理已知问题
Merge pull request !562 from 稚屿/N/A
2022-08-22 06:20:18 +00:00
e02f692359 修复菜单管理已知问题
问题描述:在菜单管理下,类型为菜单或者按钮的条目下点击修改按钮。
情况1,如果是类型为菜单,第一次点击修改按钮正常,则第二次点击另一个条目后面的修改按钮时报错!
情况2,如果是类型为按钮,第一次点击修改时正常,当点击取消按钮关闭弹窗时,浏览器报错!

报错代码:this.resetForm("form")

修复方案:添加遗漏的表单 prop 属性

Signed-off-by: 稚屿 <1491182878@qq.com>
2022-08-22 06:19:08 +00:00
77ec8d1c9a 修复代码生成权限父编号错误(I5NATP) 2022-08-22 12:21:07 +08:00
66ce21ec29 升级fastjson到最新版2.0.12 2022-08-22 12:04:01 +08:00
27e0937235 支持多权限字符匹配角色数据权限 2022-08-22 12:03:51 +08:00
aadb7a41cb 优化Context信息,防止泄漏问题 2022-08-22 10:24:20 +08:00
9b3767a954 优化多角色数据权限匹配规则 2022-08-21 22:53:57 +08:00
851dc54b49 修复图片预览组件src属性为null值控制台报错问题(I5KBAS) 2022-08-15 12:07:24 +08:00
cf2c4e02c6 字典管理操作类型新增其他 2022-08-14 09:40:36 +08:00
88b5715eae 升级oshi到最新版本6.2.2 2022-08-12 12:17:48 +08:00
5b05d4a123 个人中心修改密码去除多余的user传递 2022-08-12 12:17:28 +08:00
893ef39401 防止用户个人信息修改部门 2022-08-12 12:16:30 +08:00
890ad682d7 优化修改资料头像被覆盖的问题(I5LK04) 2022-08-11 13:22:55 +08:00
b9f45057b8 操作日志记录支持排除敏感属性字段 2022-08-10 18:01:02 +08:00
89008c28df 升级fastjson到最新版2.0.11 2022-08-10 14:03:35 +08:00
af7d0a3409 优化导出对象的子列表判断条件 2022-08-10 13:59:57 +08:00
1cd2eef899 优化excel/scale属性导出单元格数值类型 2022-08-09 08:02:24 +08:00
8c7b93ec4f !547 fix: 账户解锁接口去掉多余的 /
Merge pull request !547 from iacker/N/A
2022-08-08 23:44:57 +00:00
3f7bf545b5 fix: 账户解锁接口去掉多余的 / 2022-08-08 13:55:08 +00:00
cbedec7ca6 登录日志新增解锁账户功能 2022-08-08 09:23:52 +08:00
fb1bac2114 新增删除Hash中的某条数据 2022-08-07 19:31:04 +08:00
d0f399a66a 优化xss过滤后格式出现的异常 2022-08-07 19:30:54 +08:00
e73dbd470a Excel注解支持导出对象的子列表方法 2022-08-07 18:33:04 +08:00
e0cd5381e2 数据逻辑删除不进行唯一验证 2022-08-03 16:48:55 +08:00
aee5d417ed 支持配置密码最大错误次数/锁定时间 2022-07-30 14:01:38 +08:00
250c5ba226 优化任务过期不执行调度 2022-07-29 20:28:59 +08:00
b91c848962 !538 优化表格上右侧工具条(搜索按钮显隐&右侧样式凸出)
Merge pull request !538 from abbfun/N/A
2022-07-29 12:28:38 +00:00
d4475d0e8d 优化表格上右侧工具条(搜索按钮显隐&右侧样式凸出)
无搜索条件时可通过search隐藏搜索按钮,工具条组右侧样式超出5px(相对于底部表格),其父节点gutter代码生成默认10,此处也默认10,使工具组样式左右一致
2022-07-27 09:05:31 +00:00
aff54ab5fe 自定义数据权限不排除重复 2022-07-26 20:02:17 +08:00
06177addf5 添加新群号:104748341 2022-07-25 18:45:51 +08:00
9f3b91fe57 !535 所有的覆写方法,必须加@Override注解
Merge pull request !535 from 天才的逻辑/master
2022-07-25 10:32:48 +00:00
80d25863db !536 防止主键字段名与'row'或'ids'一致导致报错的问题。
Merge pull request !536 from 张政/N/A
2022-07-25 10:32:42 +00:00
cf8a7f8678 防止主键字段名与'row'或'ids'一致导致报错的问题。 2022-07-23 08:29:52 +00:00
86fc709b03 升级pagehelper到最新版1.4.3 2022-07-22 14:54:38 +08:00
b8b58cb202 所有的覆写方法,必须加@Override注解 2022-07-22 10:57:00 +08:00
96970ff951 所有的覆写方法,必须加@Override注解 2022-07-22 10:35:31 +08:00
7cc9d17424 支持自定义隐藏Excel属性列 2022-07-21 13:52:05 +08:00
bc8b5f1079 优化布局设置使用el-drawer抽屉显示 2022-07-21 08:50:48 +08:00
5ec5e1a65d 优化字典数据使用store存取 2022-07-20 19:38:16 +08:00
1f0e742710 Excel注解支持backgroundColor属性设置背景色 2022-07-20 09:39:58 +08:00
28b9fbb4d2 优化多个相同角色数据导致权限SQL重复问题 2022-07-19 15:55:03 +08:00
2c79dc906e 升级oshi到最新版本6.2.1 2022-07-14 19:49:32 +08:00
1852017ecc 修改验证码开关变量名 2022-07-14 19:49:00 +08:00
424d11896a !531 去除生成验证码多余的逻辑判断
Merge pull request !531 from 稚屿/N/A
2022-07-14 09:28:46 +00:00
edefee46b2 去除生成验证码多余的逻辑判断 2022-07-13 01:00:44 +00:00
c7c3da2038 升级fastjson到最新版2.0.9 2022-07-12 18:07:05 +08:00
eb9f3d3772 修改验证码开关变量名 2022-07-12 18:04:49 +08:00
1a61790407 !523 修改错误的变量名
Merge pull request !523 from SG/N/A
2022-07-12 10:02:50 +00:00
fe98fba5b5 !527 调增数组格式声明,random随机转换修正
Merge pull request !527 from 靖少毅/jsy20220705
2022-07-12 10:01:56 +00:00
4eb8809a8a 调增数组格式声明,random随机转换修正 2022-07-05 16:43:55 +08:00
0a893d196e update 优化魔法值 2022-07-05 02:06:31 +00:00
SG
ec45cf04af 修改错误的变量名 2022-07-01 13:56:44 +00:00
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
192 changed files with 4145 additions and 2322 deletions

View File

@ -1,11 +1,11 @@
<p align="center"> <p align="center">
<img alt="logo" src="https://oscimg.oschina.net/oscnet/up-d3d0a9303e11d522a06cd263f3079027715.png"> <img alt="logo" src="https://oscimg.oschina.net/oscnet/up-d3d0a9303e11d522a06cd263f3079027715.png">
</p> </p>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v3.8.1</h1> <h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v3.8.5</h1>
<h4 align="center">基于SpringBoot+Vue前后端分离的Java快速开发框架</h4> <h4 align="center">基于SpringBoot+Vue前后端分离的Java快速开发框架</h4>
<p align="center"> <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/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.1-brightgreen.svg"></a> <a href="https://gitee.com/y_project/RuoYi-Vue"><img src="https://img.shields.io/badge/RuoYi-v3.8.5-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> <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> </p>
@ -94,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群](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群 [![加入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/已满-104748341-blue.svg)](https://jq.qq.com/?_wv=1027&k=96Dkdq0k) [![加入QQ群](https://img.shields.io/badge/已满-160110482-blue.svg)](https://jq.qq.com/?_wv=1027&k=0fsNiYZt) [![加入QQ群](https://img.shields.io/badge/170801498-blue.svg)](https://jq.qq.com/?_wv=1027&k=7xw4xUG1) 点击按钮入群。

43
pom.xml
View File

@ -6,27 +6,25 @@
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<version>3.8.2</version> <version>3.8.5</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.2</ruoyi.version> <ruoyi.version>3.8.5</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.15</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.3</kaptcha.version>
<mybatis-spring-boot.version>2.2.2</mybatis-spring-boot.version> <pagehelper.boot.version>1.4.6</pagehelper.boot.version>
<pagehelper.boot.version>1.4.1</pagehelper.boot.version> <fastjson.version>2.0.20</fastjson.version>
<fastjson.version>1.2.80</fastjson.version> <oshi.version>6.4.0</oshi.version>
<oshi.version>6.1.2</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>
@ -43,7 +41,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.11</version> <version>2.5.14</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
@ -62,13 +60,6 @@
<version>${bitwalker.version}</version> <version>${bitwalker.version}</version>
</dependency> </dependency>
<!-- SpringBoot集成mybatis框架 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring-boot.version}</version>
</dependency>
<!-- pagehelper 分页插件 --> <!-- pagehelper 分页插件 -->
<dependency> <dependency>
<groupId>com.github.pagehelper</groupId> <groupId>com.github.pagehelper</groupId>
@ -83,18 +74,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>
@ -145,8 +124,8 @@
<!-- 阿里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>
@ -159,7 +138,7 @@
<!-- 验证码 --> <!-- 验证码 -->
<dependency> <dependency>
<groupId>com.github.penggle</groupId> <groupId>pro.fessional</groupId>
<artifactId>kaptcha</artifactId> <artifactId>kaptcha</artifactId>
<version>${kaptcha.version}</version> <version>${kaptcha.version}</version>
</dependency> </dependency>

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.2</version> <version>3.8.5</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;
@ -45,16 +46,16 @@ public class CaptchaController
public AjaxResult getCode(HttpServletResponse response) throws IOException public AjaxResult getCode(HttpServletResponse response) throws IOException
{ {
AjaxResult ajax = AjaxResult.success(); AjaxResult ajax = AjaxResult.success();
boolean captchaOnOff = configService.selectCaptchaOnOff(); boolean captchaEnabled = configService.selectCaptchaEnabled();
ajax.put("captchaOnOff", captchaOnOff); ajax.put("captchaEnabled", captchaEnabled);
if (!captchaOnOff) if (!captchaEnabled)
{ {
return ajax; return ajax;
} }
// 保存验证码信息 // 保存验证码信息
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,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,17 @@ 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, "限流处理"));
caches.add(new SysCache(CacheConstants.PWD_ERR_CNT_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 +67,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> cacheKeys = redisTemplate.keys(cacheName + "*");
return AjaxResult.success(cacheKeys);
}
@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

@ -16,6 +16,7 @@ import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.service.SysPasswordService;
import com.ruoyi.system.domain.SysLogininfor; import com.ruoyi.system.domain.SysLogininfor;
import com.ruoyi.system.service.ISysLogininforService; import com.ruoyi.system.service.ISysLogininforService;
@ -31,6 +32,9 @@ public class SysLogininforController extends BaseController
@Autowired @Autowired
private ISysLogininforService logininforService; private ISysLogininforService logininforService;
@Autowired
private SysPasswordService passwordService;
@PreAuthorize("@ss.hasPermi('monitor:logininfor:list')") @PreAuthorize("@ss.hasPermi('monitor:logininfor:list')")
@GetMapping("/list") @GetMapping("/list")
public TableDataInfo list(SysLogininfor logininfor) public TableDataInfo list(SysLogininfor logininfor)
@ -64,6 +68,15 @@ public class SysLogininforController extends BaseController
public AjaxResult clean() public AjaxResult clean()
{ {
logininforService.cleanLogininfor(); logininforService.cleanLogininfor();
return AjaxResult.success(); return success();
}
@PreAuthorize("@ss.hasPermi('monitor:logininfor:unlock')")
@Log(title = "账户解锁", businessType = BusinessType.OTHER)
@GetMapping("/unlock/{userName}")
public AjaxResult unlock(@PathVariable("userName") String userName)
{
passwordService.clearLoginRecordCache(userName);
return success();
} }
} }

View File

@ -64,6 +64,6 @@ public class SysOperlogController extends BaseController
public AjaxResult clean() public AjaxResult clean()
{ {
operLogService.cleanOperLog(); operLogService.cleanOperLog();
return AjaxResult.success(); return 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 success();
} }
} }

View File

@ -64,7 +64,7 @@ public class SysConfigController extends BaseController
@GetMapping(value = "/{configId}") @GetMapping(value = "/{configId}")
public AjaxResult getInfo(@PathVariable Long configId) public AjaxResult getInfo(@PathVariable Long configId)
{ {
return AjaxResult.success(configService.selectConfigById(configId)); return success(configService.selectConfigById(configId));
} }
/** /**
@ -73,7 +73,7 @@ public class SysConfigController extends BaseController
@GetMapping(value = "/configKey/{configKey}") @GetMapping(value = "/configKey/{configKey}")
public AjaxResult getConfigKey(@PathVariable String configKey) public AjaxResult getConfigKey(@PathVariable String configKey)
{ {
return AjaxResult.success(configService.selectConfigByKey(configKey)); return success(configService.selectConfigByKey(configKey));
} }
/** /**
@ -86,7 +86,7 @@ public class SysConfigController extends BaseController
{ {
if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config))) if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config)))
{ {
return AjaxResult.error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在"); return error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在");
} }
config.setCreateBy(getUsername()); config.setCreateBy(getUsername());
return toAjax(configService.insertConfig(config)); return toAjax(configService.insertConfig(config));
@ -102,7 +102,7 @@ public class SysConfigController extends BaseController
{ {
if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config))) if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config)))
{ {
return AjaxResult.error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在"); return error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在");
} }
config.setUpdateBy(getUsername()); config.setUpdateBy(getUsername());
return toAjax(configService.updateConfig(config)); return toAjax(configService.updateConfig(config));
@ -129,6 +129,6 @@ public class SysConfigController extends BaseController
public AjaxResult refreshCache() public AjaxResult refreshCache()
{ {
configService.resetConfigCache(); configService.resetConfigCache();
return AjaxResult.success(); return success();
} }
} }

View File

@ -1,6 +1,5 @@
package com.ruoyi.web.controller.system; package com.ruoyi.web.controller.system;
import java.util.Iterator;
import java.util.List; import java.util.List;
import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -43,7 +42,7 @@ public class SysDeptController extends BaseController
public AjaxResult list(SysDept dept) public AjaxResult list(SysDept dept)
{ {
List<SysDept> depts = deptService.selectDeptList(dept); List<SysDept> depts = deptService.selectDeptList(dept);
return AjaxResult.success(depts); return success(depts);
} }
/** /**
@ -54,17 +53,8 @@ public class SysDeptController extends BaseController
public AjaxResult excludeChild(@PathVariable(value = "deptId", required = false) Long deptId) public AjaxResult excludeChild(@PathVariable(value = "deptId", required = false) Long deptId)
{ {
List<SysDept> depts = deptService.selectDeptList(new SysDept()); List<SysDept> depts = deptService.selectDeptList(new SysDept());
Iterator<SysDept> it = depts.iterator(); depts.removeIf(d -> d.getDeptId().intValue() == deptId || ArrayUtils.contains(StringUtils.split(d.getAncestors(), ","), deptId + ""));
while (it.hasNext()) return success(depts);
{
SysDept d = (SysDept) it.next();
if (d.getDeptId().intValue() == deptId
|| ArrayUtils.contains(StringUtils.split(d.getAncestors(), ","), deptId + ""))
{
it.remove();
}
}
return AjaxResult.success(depts);
} }
/** /**
@ -75,30 +65,7 @@ public class SysDeptController extends BaseController
public AjaxResult getInfo(@PathVariable Long deptId) public AjaxResult getInfo(@PathVariable Long deptId)
{ {
deptService.checkDeptDataScope(deptId); deptService.checkDeptDataScope(deptId);
return AjaxResult.success(deptService.selectDeptById(deptId)); return success(deptService.selectDeptById(deptId));
}
/**
* 获取部门下拉树列表
*/
@GetMapping("/treeselect")
public AjaxResult treeselect(SysDept dept)
{
List<SysDept> depts = deptService.selectDeptList(dept);
return AjaxResult.success(deptService.buildDeptTreeSelect(depts));
}
/**
* 加载对应角色部门列表树
*/
@GetMapping(value = "/roleDeptTreeselect/{roleId}")
public AjaxResult roleDeptTreeselect(@PathVariable("roleId") Long roleId)
{
List<SysDept> depts = deptService.selectDeptList(new SysDept());
AjaxResult ajax = AjaxResult.success();
ajax.put("checkedKeys", deptService.selectDeptListByRoleId(roleId));
ajax.put("depts", deptService.buildDeptTreeSelect(depts));
return ajax;
} }
/** /**
@ -111,7 +78,7 @@ public class SysDeptController extends BaseController
{ {
if (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept))) if (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept)))
{ {
return AjaxResult.error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在"); return error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在");
} }
dept.setCreateBy(getUsername()); dept.setCreateBy(getUsername());
return toAjax(deptService.insertDept(dept)); return toAjax(deptService.insertDept(dept));
@ -129,15 +96,15 @@ public class SysDeptController extends BaseController
deptService.checkDeptDataScope(deptId); 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 error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在");
} }
else if (dept.getParentId().equals(deptId)) else if (dept.getParentId().equals(deptId))
{ {
return AjaxResult.error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己"); return error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己");
} }
else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) && deptService.selectNormalChildrenDeptById(deptId) > 0) else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) && deptService.selectNormalChildrenDeptById(deptId) > 0)
{ {
return AjaxResult.error("该部门包含未停用的子部门!"); return error("该部门包含未停用的子部门!");
} }
dept.setUpdateBy(getUsername()); dept.setUpdateBy(getUsername());
return toAjax(deptService.updateDept(dept)); return toAjax(deptService.updateDept(dept));
@ -153,11 +120,11 @@ public class SysDeptController extends BaseController
{ {
if (deptService.hasChildByDeptId(deptId)) if (deptService.hasChildByDeptId(deptId))
{ {
return AjaxResult.error("存在下级部门,不允许删除"); return warn("存在下级部门,不允许删除");
} }
if (deptService.checkDeptExistUser(deptId)) if (deptService.checkDeptExistUser(deptId))
{ {
return AjaxResult.error("部门存在用户,不允许删除"); return warn("部门存在用户,不允许删除");
} }
deptService.checkDeptDataScope(deptId); deptService.checkDeptDataScope(deptId);
return toAjax(deptService.deleteDeptById(deptId)); return toAjax(deptService.deleteDeptById(deptId));

View File

@ -66,7 +66,7 @@ public class SysDictDataController extends BaseController
@GetMapping(value = "/{dictCode}") @GetMapping(value = "/{dictCode}")
public AjaxResult getInfo(@PathVariable Long dictCode) public AjaxResult getInfo(@PathVariable Long dictCode)
{ {
return AjaxResult.success(dictDataService.selectDictDataById(dictCode)); return success(dictDataService.selectDictDataById(dictCode));
} }
/** /**
@ -80,7 +80,7 @@ public class SysDictDataController extends BaseController
{ {
data = new ArrayList<SysDictData>(); data = new ArrayList<SysDictData>();
} }
return AjaxResult.success(data); return success(data);
} }
/** /**

View File

@ -61,7 +61,7 @@ public class SysDictTypeController extends BaseController
@GetMapping(value = "/{dictId}") @GetMapping(value = "/{dictId}")
public AjaxResult getInfo(@PathVariable Long dictId) public AjaxResult getInfo(@PathVariable Long dictId)
{ {
return AjaxResult.success(dictTypeService.selectDictTypeById(dictId)); return success(dictTypeService.selectDictTypeById(dictId));
} }
/** /**
@ -74,7 +74,7 @@ public class SysDictTypeController extends BaseController
{ {
if (UserConstants.NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict))) if (UserConstants.NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict)))
{ {
return AjaxResult.error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在"); return error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在");
} }
dict.setCreateBy(getUsername()); dict.setCreateBy(getUsername());
return toAjax(dictTypeService.insertDictType(dict)); return toAjax(dictTypeService.insertDictType(dict));
@ -90,7 +90,7 @@ public class SysDictTypeController extends BaseController
{ {
if (UserConstants.NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict))) if (UserConstants.NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict)))
{ {
return AjaxResult.error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在"); return error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在");
} }
dict.setUpdateBy(getUsername()); dict.setUpdateBy(getUsername());
return toAjax(dictTypeService.updateDictType(dict)); return toAjax(dictTypeService.updateDictType(dict));
@ -117,7 +117,7 @@ public class SysDictTypeController extends BaseController
public AjaxResult refreshCache() public AjaxResult refreshCache()
{ {
dictTypeService.resetDictCache(); dictTypeService.resetDictCache();
return AjaxResult.success(); return success();
} }
/** /**
@ -127,6 +127,6 @@ public class SysDictTypeController extends BaseController
public AjaxResult optionselect() public AjaxResult optionselect()
{ {
List<SysDictType> dictTypes = dictTypeService.selectDictTypeAll(); List<SysDictType> dictTypes = dictTypeService.selectDictTypeAll();
return AjaxResult.success(dictTypes); return success(dictTypes);
} }
} }

View File

@ -41,7 +41,7 @@ public class SysMenuController extends BaseController
public AjaxResult list(SysMenu menu) public AjaxResult list(SysMenu menu)
{ {
List<SysMenu> menus = menuService.selectMenuList(menu, getUserId()); List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
return AjaxResult.success(menus); return success(menus);
} }
/** /**
@ -51,7 +51,7 @@ public class SysMenuController extends BaseController
@GetMapping(value = "/{menuId}") @GetMapping(value = "/{menuId}")
public AjaxResult getInfo(@PathVariable Long menuId) public AjaxResult getInfo(@PathVariable Long menuId)
{ {
return AjaxResult.success(menuService.selectMenuById(menuId)); return success(menuService.selectMenuById(menuId));
} }
/** /**
@ -61,7 +61,7 @@ public class SysMenuController extends BaseController
public AjaxResult treeselect(SysMenu menu) public AjaxResult treeselect(SysMenu menu)
{ {
List<SysMenu> menus = menuService.selectMenuList(menu, getUserId()); List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
return AjaxResult.success(menuService.buildMenuTreeSelect(menus)); return success(menuService.buildMenuTreeSelect(menus));
} }
/** /**
@ -87,11 +87,11 @@ public class SysMenuController extends BaseController
{ {
if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu))) if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu)))
{ {
return AjaxResult.error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); return error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
} }
else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
{ {
return AjaxResult.error("新增菜单'" + menu.getMenuName() + "'失败地址必须以http(s)://开头"); return error("新增菜单'" + menu.getMenuName() + "'失败地址必须以http(s)://开头");
} }
menu.setCreateBy(getUsername()); menu.setCreateBy(getUsername());
return toAjax(menuService.insertMenu(menu)); return toAjax(menuService.insertMenu(menu));
@ -107,15 +107,15 @@ public class SysMenuController extends BaseController
{ {
if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu))) if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu)))
{ {
return AjaxResult.error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); return error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
} }
else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
{ {
return AjaxResult.error("修改菜单'" + menu.getMenuName() + "'失败地址必须以http(s)://开头"); return error("修改菜单'" + menu.getMenuName() + "'失败地址必须以http(s)://开头");
} }
else if (menu.getMenuId().equals(menu.getParentId())) else if (menu.getMenuId().equals(menu.getParentId()))
{ {
return AjaxResult.error("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己"); return error("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己");
} }
menu.setUpdateBy(getUsername()); menu.setUpdateBy(getUsername());
return toAjax(menuService.updateMenu(menu)); return toAjax(menuService.updateMenu(menu));
@ -131,11 +131,11 @@ public class SysMenuController extends BaseController
{ {
if (menuService.hasChildByMenuId(menuId)) if (menuService.hasChildByMenuId(menuId))
{ {
return AjaxResult.error("存在子菜单,不允许删除"); return warn("存在子菜单,不允许删除");
} }
if (menuService.checkMenuExistRole(menuId)) if (menuService.checkMenuExistRole(menuId))
{ {
return AjaxResult.error("菜单已分配,不允许删除"); return warn("菜单已分配,不允许删除");
} }
return toAjax(menuService.deleteMenuById(menuId)); return toAjax(menuService.deleteMenuById(menuId));
} }

View File

@ -51,7 +51,7 @@ public class SysNoticeController extends BaseController
@GetMapping(value = "/{noticeId}") @GetMapping(value = "/{noticeId}")
public AjaxResult getInfo(@PathVariable Long noticeId) public AjaxResult getInfo(@PathVariable Long noticeId)
{ {
return AjaxResult.success(noticeService.selectNoticeById(noticeId)); return success(noticeService.selectNoticeById(noticeId));
} }
/** /**

View File

@ -64,7 +64,7 @@ public class SysPostController extends BaseController
@GetMapping(value = "/{postId}") @GetMapping(value = "/{postId}")
public AjaxResult getInfo(@PathVariable Long postId) public AjaxResult getInfo(@PathVariable Long postId)
{ {
return AjaxResult.success(postService.selectPostById(postId)); return success(postService.selectPostById(postId));
} }
/** /**
@ -77,11 +77,11 @@ public class SysPostController extends BaseController
{ {
if (UserConstants.NOT_UNIQUE.equals(postService.checkPostNameUnique(post))) if (UserConstants.NOT_UNIQUE.equals(postService.checkPostNameUnique(post)))
{ {
return AjaxResult.error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在"); return error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在");
} }
else if (UserConstants.NOT_UNIQUE.equals(postService.checkPostCodeUnique(post))) else if (UserConstants.NOT_UNIQUE.equals(postService.checkPostCodeUnique(post)))
{ {
return AjaxResult.error("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在"); return error("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在");
} }
post.setCreateBy(getUsername()); post.setCreateBy(getUsername());
return toAjax(postService.insertPost(post)); return toAjax(postService.insertPost(post));
@ -97,11 +97,11 @@ public class SysPostController extends BaseController
{ {
if (UserConstants.NOT_UNIQUE.equals(postService.checkPostNameUnique(post))) if (UserConstants.NOT_UNIQUE.equals(postService.checkPostNameUnique(post)))
{ {
return AjaxResult.error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在"); return error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在");
} }
else if (UserConstants.NOT_UNIQUE.equals(postService.checkPostCodeUnique(post))) else if (UserConstants.NOT_UNIQUE.equals(postService.checkPostCodeUnique(post)))
{ {
return AjaxResult.error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在"); return error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在");
} }
post.setUpdateBy(getUsername()); post.setUpdateBy(getUsername());
return toAjax(postService.updatePost(post)); return toAjax(postService.updatePost(post));
@ -125,6 +125,6 @@ public class SysPostController extends BaseController
public AjaxResult optionselect() public AjaxResult optionselect()
{ {
List<SysPost> posts = postService.selectPostAll(); List<SysPost> posts = postService.selectPostAll();
return AjaxResult.success(posts); return success(posts);
} }
} }

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;
@ -66,15 +66,17 @@ public class SysProfileController extends BaseController
if (StringUtils.isNotEmpty(user.getPhonenumber()) if (StringUtils.isNotEmpty(user.getPhonenumber())
&& UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
{ {
return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
} }
if (StringUtils.isNotEmpty(user.getEmail()) if (StringUtils.isNotEmpty(user.getEmail())
&& UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user))) && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
{ {
return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
} }
user.setUserId(sysUser.getUserId()); user.setUserId(sysUser.getUserId());
user.setPassword(null); user.setPassword(null);
user.setAvatar(null);
user.setDeptId(null);
if (userService.updateUserProfile(user) > 0) if (userService.updateUserProfile(user) > 0)
{ {
// 更新缓存用户信息 // 更新缓存用户信息
@ -83,9 +85,9 @@ public class SysProfileController extends BaseController
sysUser.setEmail(user.getEmail()); sysUser.setEmail(user.getEmail());
sysUser.setSex(user.getSex()); sysUser.setSex(user.getSex());
tokenService.setLoginUser(loginUser); tokenService.setLoginUser(loginUser);
return AjaxResult.success(); return success();
} }
return AjaxResult.error("修改个人信息异常,请联系管理员"); return error("修改个人信息异常,请联系管理员");
} }
/** /**
@ -100,20 +102,20 @@ public class SysProfileController extends BaseController
String password = loginUser.getPassword(); String password = loginUser.getPassword();
if (!SecurityUtils.matchesPassword(oldPassword, password)) if (!SecurityUtils.matchesPassword(oldPassword, password))
{ {
return AjaxResult.error("修改密码失败,旧密码错误"); return error("修改密码失败,旧密码错误");
} }
if (SecurityUtils.matchesPassword(newPassword, password)) if (SecurityUtils.matchesPassword(newPassword, password))
{ {
return AjaxResult.error("新密码不能与旧密码相同"); return error("新密码不能与旧密码相同");
} }
if (userService.resetUserPwd(userName, SecurityUtils.encryptPassword(newPassword)) > 0) if (userService.resetUserPwd(userName, SecurityUtils.encryptPassword(newPassword)) > 0)
{ {
// 更新缓存用户密码 // 更新缓存用户密码
loginUser.getUser().setPassword(SecurityUtils.encryptPassword(newPassword)); loginUser.getUser().setPassword(SecurityUtils.encryptPassword(newPassword));
tokenService.setLoginUser(loginUser); tokenService.setLoginUser(loginUser);
return AjaxResult.success(); return success();
} }
return AjaxResult.error("修改密码异常,请联系管理员"); return error("修改密码异常,请联系管理员");
} }
/** /**
@ -121,12 +123,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();
@ -137,6 +139,6 @@ public class SysProfileController extends BaseController
return ajax; return ajax;
} }
} }
return AjaxResult.error("上传图片异常,请联系管理员"); return error("上传图片异常,请联系管理员");
} }
} }

View File

@ -17,6 +17,7 @@ import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.constant.UserConstants;
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.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysRole; import com.ruoyi.common.core.domain.entity.SysRole;
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;
@ -27,6 +28,7 @@ import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.service.SysPermissionService; import com.ruoyi.framework.web.service.SysPermissionService;
import com.ruoyi.framework.web.service.TokenService; import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.domain.SysUserRole; import com.ruoyi.system.domain.SysUserRole;
import com.ruoyi.system.service.ISysDeptService;
import com.ruoyi.system.service.ISysRoleService; import com.ruoyi.system.service.ISysRoleService;
import com.ruoyi.system.service.ISysUserService; import com.ruoyi.system.service.ISysUserService;
@ -44,13 +46,16 @@ public class SysRoleController extends BaseController
@Autowired @Autowired
private TokenService tokenService; private TokenService tokenService;
@Autowired @Autowired
private SysPermissionService permissionService; private SysPermissionService permissionService;
@Autowired @Autowired
private ISysUserService userService; private ISysUserService userService;
@Autowired
private ISysDeptService deptService;
@PreAuthorize("@ss.hasPermi('system:role:list')") @PreAuthorize("@ss.hasPermi('system:role:list')")
@GetMapping("/list") @GetMapping("/list")
public TableDataInfo list(SysRole role) public TableDataInfo list(SysRole role)
@ -78,7 +83,7 @@ public class SysRoleController extends BaseController
public AjaxResult getInfo(@PathVariable Long roleId) public AjaxResult getInfo(@PathVariable Long roleId)
{ {
roleService.checkRoleDataScope(roleId); roleService.checkRoleDataScope(roleId);
return AjaxResult.success(roleService.selectRoleById(roleId)); return success(roleService.selectRoleById(roleId));
} }
/** /**
@ -91,11 +96,11 @@ public class SysRoleController extends BaseController
{ {
if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role))) if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role)))
{ {
return AjaxResult.error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在"); return error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在");
} }
else if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role))) else if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role)))
{ {
return AjaxResult.error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在"); return error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在");
} }
role.setCreateBy(getUsername()); role.setCreateBy(getUsername());
return toAjax(roleService.insertRole(role)); return toAjax(roleService.insertRole(role));
@ -114,11 +119,11 @@ public class SysRoleController extends BaseController
roleService.checkRoleDataScope(role.getRoleId()); 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 error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在");
} }
else if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role))) else if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role)))
{ {
return AjaxResult.error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在"); return error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在");
} }
role.setUpdateBy(getUsername()); role.setUpdateBy(getUsername());
@ -132,9 +137,9 @@ public class SysRoleController extends BaseController
loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getUserName())); loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getUserName()));
tokenService.setLoginUser(loginUser); tokenService.setLoginUser(loginUser);
} }
return AjaxResult.success(); return success();
} }
return AjaxResult.error("修改角色'" + role.getRoleName() + "'失败,请联系管理员"); return error("修改角色'" + role.getRoleName() + "'失败,请联系管理员");
} }
/** /**
@ -182,7 +187,7 @@ public class SysRoleController extends BaseController
@GetMapping("/optionselect") @GetMapping("/optionselect")
public AjaxResult optionselect() public AjaxResult optionselect()
{ {
return AjaxResult.success(roleService.selectRoleAll()); return success(roleService.selectRoleAll());
} }
/** /**
@ -242,4 +247,17 @@ public class SysRoleController extends BaseController
roleService.checkRoleDataScope(roleId); roleService.checkRoleDataScope(roleId);
return toAjax(roleService.insertAuthUsers(roleId, userIds)); return toAjax(roleService.insertAuthUsers(roleId, userIds));
} }
/**
* 获取对应角色部门树列表
*/
@PreAuthorize("@ss.hasPermi('system:role:query')")
@GetMapping(value = "/deptTree/{roleId}")
public AjaxResult deptTree(@PathVariable("roleId") Long roleId)
{
AjaxResult ajax = AjaxResult.success();
ajax.put("checkedKeys", deptService.selectDeptListByRoleId(roleId));
ajax.put("depts", deptService.selectDeptTreeList(new SysDept()));
return ajax;
}
} }

View File

@ -20,6 +20,7 @@ import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.constant.UserConstants;
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.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysRole; import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.core.page.TableDataInfo;
@ -27,6 +28,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.poi.ExcelUtil; import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.system.service.ISysDeptService;
import com.ruoyi.system.service.ISysPostService; import com.ruoyi.system.service.ISysPostService;
import com.ruoyi.system.service.ISysRoleService; import com.ruoyi.system.service.ISysRoleService;
import com.ruoyi.system.service.ISysUserService; import com.ruoyi.system.service.ISysUserService;
@ -46,6 +48,9 @@ public class SysUserController extends BaseController
@Autowired @Autowired
private ISysRoleService roleService; private ISysRoleService roleService;
@Autowired
private ISysDeptService deptService;
@Autowired @Autowired
private ISysPostService postService; private ISysPostService postService;
@ -80,7 +85,7 @@ public class SysUserController extends BaseController
List<SysUser> userList = util.importExcel(file.getInputStream()); List<SysUser> userList = util.importExcel(file.getInputStream());
String operName = getUsername(); String operName = getUsername();
String message = userService.importUser(userList, updateSupport, operName); String message = userService.importUser(userList, updateSupport, operName);
return AjaxResult.success(message); return success(message);
} }
@PostMapping("/importTemplate") @PostMapping("/importTemplate")
@ -120,19 +125,19 @@ public class SysUserController extends BaseController
@PostMapping @PostMapping
public AjaxResult add(@Validated @RequestBody SysUser user) public AjaxResult add(@Validated @RequestBody SysUser user)
{ {
if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user.getUserName()))) if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user)))
{ {
return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,登录账号已存在"); return error("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
} }
else if (StringUtils.isNotEmpty(user.getPhonenumber()) else if (StringUtils.isNotEmpty(user.getPhonenumber())
&& UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
{ {
return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,手机号码已存在"); return error("新增用户'" + user.getUserName() + "'失败,手机号码已存在");
} }
else if (StringUtils.isNotEmpty(user.getEmail()) else if (StringUtils.isNotEmpty(user.getEmail())
&& UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user))) && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
{ {
return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在"); return error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在");
} }
user.setCreateBy(getUsername()); user.setCreateBy(getUsername());
user.setPassword(SecurityUtils.encryptPassword(user.getPassword())); user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
@ -149,15 +154,19 @@ public class SysUserController extends BaseController
{ {
userService.checkUserAllowed(user); userService.checkUserAllowed(user);
userService.checkUserDataScope(user.getUserId()); userService.checkUserDataScope(user.getUserId());
if (StringUtils.isNotEmpty(user.getPhonenumber()) if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user)))
{
return error("修改用户'" + user.getUserName() + "'失败,登录账号已存在");
}
else if (StringUtils.isNotEmpty(user.getPhonenumber())
&& UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
{ {
return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
} }
else if (StringUtils.isNotEmpty(user.getEmail()) else if (StringUtils.isNotEmpty(user.getEmail())
&& UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user))) && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
{ {
return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
} }
user.setUpdateBy(getUsername()); user.setUpdateBy(getUsername());
return toAjax(userService.updateUser(user)); return toAjax(userService.updateUser(user));
@ -234,4 +243,14 @@ public class SysUserController extends BaseController
userService.insertUserAuth(userId, roleIds); userService.insertUserAuth(userId, roleIds);
return success(); return success();
} }
/**
* 获取部门树列表
*/
@PreAuthorize("@ss.hasPermi('system:user:list')")
@GetMapping("/deptTree")
public AjaxResult deptTree(SysDept dept)
{
return success(deptService.selectDeptTreeList(dept));
}
} }

View File

@ -1,24 +0,0 @@
package com.ruoyi.web.controller.tool;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.ruoyi.common.core.controller.BaseController;
/**
* swagger 接口
*
* @author ruoyi
*/
@Controller
@RequestMapping("/tool/swagger")
public class SwaggerController extends BaseController
{
@PreAuthorize("@ss.hasPermi('tool:swagger:view')")
@GetMapping()
public String index()
{
return redirect("/swagger-ui.html");
}
}

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.2 version: 3.8.5
# 版权年份 # 版权年份
copyrightYear: 2022 copyrightYear: 2023
# 实例演示开关 # 实例演示开关
demoEnabled: true demoEnabled: true
# 文件路径 示例( Windows配置D:/ruoyi/uploadPathLinux配置 /home/ruoyi/uploadPath # 文件路径 示例( Windows配置D:/ruoyi/uploadPathLinux配置 /home/ruoyi/uploadPath
@ -39,6 +39,14 @@ logging:
com.ruoyi: debug com.ruoyi: debug
org.springframework: warn org.springframework: warn
# 用户配置
user:
password:
# 密码最大错误次数
maxRetryCount: 5
# 密码锁定时间默认10分钟
lockTime: 10
# Spring配置 # Spring配置
spring: spring:
# 资源信息 # 资源信息

View File

@ -5,7 +5,7 @@ user.jcaptcha.expire=验证码已失效
user.not.exists=用户不存在/密码错误 user.not.exists=用户不存在/密码错误
user.password.not.match=用户不存在/密码错误 user.password.not.match=用户不存在/密码错误
user.password.retry.limit.count=密码输入错误{0}次 user.password.retry.limit.count=密码输入错误{0}次
user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定10分钟 user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟
user.password.delete=对不起,您的账号已被删除 user.password.delete=对不起,您的账号已被删除
user.blocked=用户已封禁,请联系管理员 user.blocked=用户已封禁,请联系管理员
role.blocked=角色已封禁,请联系管理员 role.blocked=角色已封禁,请联系管理员

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.2</version> <version>3.8.5</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@ -58,11 +58,18 @@
<groupId>com.fasterxml.jackson.core</groupId> <groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId> <artifactId>jackson-databind</artifactId>
</dependency> </dependency>
<!-- 动态数据源 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<!-- 阿里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

@ -25,4 +25,9 @@ public @interface DataScope
* 用户表的别名 * 用户表的别名
*/ */
public String userAlias() default ""; public String userAlias() default "";
/**
* 权限字符(用于多个角色匹配符合要求的权限)默认根据权限注解@ss获取多个权限用逗号分隔开来
*/
public String permission() default "";
} }

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中每个列的高度 单位为字符
*/ */
@ -91,6 +88,11 @@ public @interface Excel
*/ */
public String[] combo() default {}; public String[] combo() default {};
/**
* 是否需要纵向合并单元格,应对需求:含有list集合单元格)
*/
public boolean needMerge() default false;
/** /**
* 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写. * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
*/ */
@ -107,9 +109,34 @@ public @interface Excel
public boolean isStatistics() default false; public boolean isStatistics() default false;
/** /**
* 导出字段对齐方式0默认1靠左2居中3靠右 * 导出类型0数字 1字符串 2图片
*/ */
public Align align() default Align.AUTO; public ColumnType cellType() default ColumnType.STRING;
/**
* 导出列头背景色
*/
public IndexedColors headerBackgroundColor() default IndexedColors.GREY_50_PERCENT;
/**
* 导出列头字体颜色
*/
public IndexedColors headerColor() default IndexedColors.WHITE;
/**
* 导出单元格背景色
*/
public IndexedColors backgroundColor() default IndexedColors.WHITE;
/**
* 导出单元格字体颜色
*/
public IndexedColors color() default IndexedColors.BLACK;
/**
* 导出字段对齐方式
*/
public HorizontalAlignment align() default HorizontalAlignment.CENTER;
/** /**
* 自定义数据处理器 * 自定义数据处理器
@ -121,22 +148,6 @@ public @interface Excel
*/ */
public String[] args() default {}; public String[] args() default {};
public enum Align
{
AUTO(0), LEFT(1), CENTER(2), RIGHT(3);
private final int value;
Align(int value)
{
this.value = value;
}
public int value()
{
return this.value;
}
}
/** /**
* 字段类型0导出导入1仅导出2仅导入 * 字段类型0导出导入1仅导出2仅导入
*/ */

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,44 @@
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:";
/**
* 登录账户密码错误次数 redis key
*/
public static final String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
}

View File

@ -19,6 +19,11 @@ public class Constants
*/ */
public static final String GBK = "GBK"; public static final String GBK = "GBK";
/**
* www主域
*/
public static final String WWW = "www.";
/** /**
* http请求 * http请求
*/ */
@ -58,27 +63,7 @@ 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 +109,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:";
/** /**
* 资源映射路径 前缀 * 资源映射路径 前缀
*/ */
@ -163,5 +138,5 @@ public class Constants
* 定时任务违规的字符 * 定时任务违规的字符
*/ */
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", "org.apache", "com.ruoyi.common.utils.file" }; "org.springframework", "org.apache", "com.ruoyi.common.utils.file", "com.ruoyi.common.config" };
} }

View File

@ -86,4 +86,9 @@ public class HttpStatus
* 接口未实现 * 接口未实现
*/ */
public static final int NOT_IMPLEMENTED = 501; public static final int NOT_IMPLEMENTED = 501;
/**
* 系统警告消息
*/
public static final int WARN = 601;
} }

View File

@ -113,6 +113,14 @@ public class BaseController
{ {
return AjaxResult.success(message); return AjaxResult.success(message);
} }
/**
* 返回成功消息
*/
public AjaxResult success(Object data)
{
return AjaxResult.success(data);
}
/** /**
* 返回失败消息 * 返回失败消息
@ -122,6 +130,14 @@ public class BaseController
return AjaxResult.error(message); return AjaxResult.error(message);
} }
/**
* 返回警告消息
*/
public AjaxResult warn(String message)
{
return AjaxResult.warn(message);
}
/** /**
* 响应返回结果 * 响应返回结果
* *

View File

@ -101,10 +101,33 @@ public class AjaxResult extends HashMap<String, Object>
return new AjaxResult(HttpStatus.SUCCESS, msg, data); return new AjaxResult(HttpStatus.SUCCESS, msg, data);
} }
/**
* 返回警告消息
*
* @param msg 返回内容
* @return 警告消息
*/
public static AjaxResult warn(String msg)
{
return AjaxResult.warn(msg, null);
}
/**
* 返回警告消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 警告消息
*/
public static AjaxResult warn(String msg, Object data)
{
return new AjaxResult(HttpStatus.WARN, msg, data);
}
/** /**
* 返回错误消息 * 返回错误消息
* *
* @return * @return 错误消息
*/ */
public static AjaxResult error() public static AjaxResult error()
{ {
@ -115,7 +138,7 @@ public class AjaxResult extends HashMap<String, Object>
* 返回错误消息 * 返回错误消息
* *
* @param msg 返回内容 * @param msg 返回内容
* @return 警告消息 * @return 错误消息
*/ */
public static AjaxResult error(String msg) public static AjaxResult error(String msg)
{ {
@ -127,7 +150,7 @@ public class AjaxResult extends HashMap<String, Object>
* *
* @param msg 返回内容 * @param msg 返回内容
* @param data 数据对象 * @param data 数据对象
* @return 警告消息 * @return 错误消息
*/ */
public static AjaxResult error(String msg, Object data) public static AjaxResult error(String msg, Object data)
{ {
@ -139,7 +162,7 @@ public class AjaxResult extends HashMap<String, Object>
* *
* @param code 状态码 * @param code 状态码
* @param msg 返回内容 * @param msg 返回内容
* @return 警告消息 * @return 错误消息
*/ */
public static AjaxResult error(int code, String msg) public static AjaxResult error(int code, String msg)
{ {

View File

@ -5,6 +5,8 @@ import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
/** /**
* Entity基类 * Entity基类
@ -16,6 +18,7 @@ public class BaseEntity implements Serializable
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** 搜索值 */ /** 搜索值 */
@JsonIgnore
private String searchValue; private String searchValue;
/** 创建者 */ /** 创建者 */
@ -36,6 +39,7 @@ public class BaseEntity implements Serializable
private String remark; private String remark;
/** 请求参数 */ /** 请求参数 */
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private Map<String, Object> params; private Map<String, Object> params;
public String getSearchValue() public String getSearchValue()

View File

@ -0,0 +1,115 @@
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;
}
public static <T> Boolean isError(R<T> ret)
{
return !isSuccess(ret);
}
public static <T> Boolean isSuccess(R<T> ret)
{
return R.SUCCESS == ret.getCode();
}
}

View File

@ -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

@ -131,7 +131,7 @@ public class SysDictData extends BaseEntity
public boolean getDefault() public boolean getDefault()
{ {
return UserConstants.YES.equals(this.isDefault) ? true : false; return UserConstants.YES.equals(this.isDefault);
} }
public String getIsDefault() public String getIsDefault()

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

@ -54,7 +54,7 @@ public class SysMenu extends BaseEntity
/** 显示状态0显示 1隐藏 */ /** 显示状态0显示 1隐藏 */
private String visible; private String visible;
/** 菜单状态0显示 1隐藏 */ /** 菜单状态0正常 1停用 */
private String status; private String status;
/** 权限字符串 */ /** 权限字符串 */

View File

@ -1,6 +1,8 @@
package com.ruoyi.common.core.domain.entity; package com.ruoyi.common.core.domain.entity;
import java.util.Set;
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 +33,7 @@ public class SysRole extends BaseEntity
/** 角色排序 */ /** 角色排序 */
@Excel(name = "角色排序") @Excel(name = "角色排序")
private String roleSort; private Integer roleSort;
/** 数据范围1所有数据权限2自定义数据权限3本部门数据权限4本部门及以下数据权限5仅本人数据权限 */ /** 数据范围1所有数据权限2自定义数据权限3本部门数据权限4本部门及以下数据权限5仅本人数据权限 */
@Excel(name = "数据范围", readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限") @Excel(name = "数据范围", readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限")
@ -59,6 +61,9 @@ public class SysRole extends BaseEntity
/** 部门组(数据权限) */ /** 部门组(数据权限) */
private Long[] deptIds; private Long[] deptIds;
/** 角色菜单权限 */
private Set<String> permissions;
public SysRole() public SysRole()
{ {
@ -113,13 +118,13 @@ public class SysRole extends BaseEntity
this.roleKey = roleKey; this.roleKey = roleKey;
} }
@NotBlank(message = "显示顺序不能为空") @NotNull(message = "显示顺序不能为空")
public String getRoleSort() public Integer getRoleSort()
{ {
return roleSort; return roleSort;
} }
public void setRoleSort(String roleSort) public void setRoleSort(Integer roleSort)
{ {
this.roleSort = roleSort; this.roleSort = roleSort;
} }
@ -203,7 +208,17 @@ public class SysRole extends BaseEntity
{ {
this.deptIds = deptIds; this.deptIds = deptIds;
} }
public Set<String> getPermissions()
{
return permissions;
}
public void setPermissions(Set<String> permissions)
{
this.permissions = permissions;
}
@Override @Override
public String toString() { public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)

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

@ -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

@ -74,6 +74,28 @@ public class RedisCache
return redisTemplate.expire(key, timeout, unit); return redisTemplate.expire(key, timeout, unit);
} }
/**
* 获取有效时间
*
* @param key Redis键
* @return 有效时间
*/
public long getExpire(final String key)
{
return redisTemplate.getExpire(key);
}
/**
* 判断 key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
public Boolean hasKey(String key)
{
return redisTemplate.hasKey(key);
}
/** /**
* 获得缓存的基本对象。 * 获得缓存的基本对象。
* *
@ -102,9 +124,9 @@ public class RedisCache
* @param collection 多个对象 * @param collection 多个对象
* @return * @return
*/ */
public long deleteObject(final Collection collection) public boolean deleteObject(final Collection collection)
{ {
return redisTemplate.delete(collection); return redisTemplate.delete(collection) > 0;
} }
/** /**
@ -209,18 +231,6 @@ public class RedisCache
return opsForHash.get(key, hKey); return opsForHash.get(key, hKey);
} }
/**
* 删除Hash中的数据
*
* @param key
* @param hKey
*/
public void delCacheMapValue(final String key, final String hKey)
{
HashOperations hashOperations = redisTemplate.opsForHash();
hashOperations.delete(key, hKey);
}
/** /**
* 获取多个Hash中的数据 * 获取多个Hash中的数据
* *
@ -233,6 +243,18 @@ public class RedisCache
return redisTemplate.opsForHash().multiGet(key, hKeys); return redisTemplate.opsForHash().multiGet(key, hKeys);
} }
/**
* 删除Hash中的某条数据
*
* @param key Redis键
* @param hKey Hash键
* @return 是否成功
*/
public boolean deleteCacheMapValue(final String key, final String hKey)
{
return redisTemplate.opsForHash().delete(key, hKey) > 0;
}
/** /**
* 获得缓存的基本对象列表 * 获得缓存的基本对象列表
* *

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:
@ -718,7 +713,7 @@ public class Convert
} }
if (value instanceof Double) if (value instanceof Double)
{ {
return new BigDecimal((Double) value); return BigDecimal.valueOf((Double) value);
} }
if (value instanceof Integer) if (value instanceof Integer)
{ {
@ -899,7 +894,7 @@ public class Convert
*/ */
public static String toSBC(String input, Set<Character> notConvertSet) public static String toSBC(String input, Set<Character> notConvertSet)
{ {
char c[] = input.toCharArray(); char[] c = input.toCharArray();
for (int i = 0; i < c.length; i++) for (int i = 0; i < c.length; i++)
{ {
if (null != notConvertSet && notConvertSet.contains(c[i])) if (null != notConvertSet && notConvertSet.contains(c[i]))
@ -941,7 +936,7 @@ public class Convert
*/ */
public static String toDBC(String text, Set<Character> notConvertSet) public static String toDBC(String text, Set<Character> notConvertSet)
{ {
char c[] = text.toCharArray(); char[] c = text.toCharArray();
for (int i = 0; i < c.length; i++) for (int i = 0; i < c.length; i++)
{ {
if (null != notConvertSet && notConvertSet.contains(c[i])) if (null != notConvertSet && notConvertSet.contains(c[i]))

View File

@ -7,7 +7,6 @@ package com.ruoyi.common.exception;
*/ */
public class GlobalException extends RuntimeException public class GlobalException extends RuntimeException
{ {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
@ -45,6 +44,7 @@ public class GlobalException extends RuntimeException
return this; return this;
} }
@Override
public String getMessage() public String getMessage()
{ {
return message; return message;

View File

@ -49,6 +49,7 @@ public final class ServiceException extends RuntimeException
return detailMessage; return detailMessage;
} }
@Override
public String getMessage() public String getMessage()
{ {
return message; return message;

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

@ -0,0 +1,16 @@
package com.ruoyi.common.exception.user;
/**
* 用户错误最大次数异常类
*
* @author ruoyi
*/
public class UserPasswordRetryLimitExceedException extends UserException
{
private static final long serialVersionUID = 1L;
public UserPasswordRetryLimitExceedException(int retryLimitCount, int lockTime)
{
super("user.password.retry.limit.exceed", new Object[] { retryLimitCount, lockTime });
}
}

View File

@ -0,0 +1,24 @@
package com.ruoyi.common.filter;
import com.alibaba.fastjson2.filter.SimplePropertyPreFilter;
/**
* 排除JSON敏感属性
*
* @author ruoyi
*/
public class PropertyPreExcludeFilter extends SimplePropertyPreFilter
{
public PropertyPreExcludeFilter()
{
}
public PropertyPreExcludeFilter addExcludes(String... filters)
{
for (int i = 0; i < filters.length; i++)
{
this.getExcludes().add(filters[i]);
}
return this;
}
}

View File

@ -10,6 +10,7 @@ import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletRequestWrapper;
import com.ruoyi.common.utils.http.HttpHelper; import com.ruoyi.common.utils.http.HttpHelper;
import com.ruoyi.common.constant.Constants;
/** /**
* 构建可重复读取inputStream的request * 构建可重复读取inputStream的request
@ -23,10 +24,10 @@ public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper
public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException
{ {
super(request); super(request);
request.setCharacterEncoding("UTF-8"); request.setCharacterEncoding(Constants.UTF8);
response.setCharacterEncoding("UTF-8"); response.setCharacterEncoding(Constants.UTF8);
body = HttpHelper.getBodyString(request).getBytes("UTF-8"); body = HttpHelper.getBodyString(request).getBytes(Constants.UTF8);
} }
@Override @Override

View File

@ -12,6 +12,7 @@ import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.enums.HttpMethod;
/** /**
* 防止XSS攻击的过滤器 * 防止XSS攻击的过滤器
@ -59,7 +60,7 @@ public class XssFilter implements Filter
String url = request.getServletPath(); String url = request.getServletPath();
String method = request.getMethod(); String method = request.getMethod();
// GET DELETE 不过滤 // GET DELETE 不过滤
if (method == null || method.matches("GET") || method.matches("DELETE")) if (method == null || HttpMethod.GET.matches(method) || HttpMethod.DELETE.matches(method))
{ {
return true; return true;
} }

View File

@ -34,13 +34,13 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper
if (values != null) if (values != null)
{ {
int length = values.length; int length = values.length;
String[] escapseValues = new String[length]; String[] escapesValues = new String[length];
for (int i = 0; i < length; i++) for (int i = 0; i < length; i++)
{ {
// 防xss攻击和过滤前后空格 // 防xss攻击和过滤前后空格
escapseValues[i] = EscapeUtil.clean(values[i]).trim(); escapesValues[i] = EscapeUtil.clean(values[i]).trim();
} }
return escapseValues; return escapesValues;
} }
return super.getParameterValues(name); return super.getParameterValues(name);
} }

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,10 +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))
{ {
return StringUtils.cast(cacheObj); return arrayCache.toList(SysDictData.class);
} }
return null; return null;
} }
@ -83,27 +84,30 @@ 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))
{ {
for (SysDictData dict : datas) if (StringUtils.containsAny(separator, dictValue))
{ {
for (String value : dictValue.split(separator)) for (SysDictData dict : datas)
{ {
if (value.equals(dict.getDictValue())) for (String value : dictValue.split(separator))
{ {
propertyString.append(dict.getDictLabel()).append(separator); if (value.equals(dict.getDictValue()))
break; {
propertyString.append(dict.getDictLabel()).append(separator);
break;
}
} }
} }
} }
} else
else
{
for (SysDictData dict : datas)
{ {
if (dictValue.equals(dict.getDictValue())) for (SysDictData dict : datas)
{ {
return dict.getDictLabel(); if (dictValue.equals(dict.getDictValue()))
{
return dict.getDictLabel();
}
} }
} }
} }
@ -165,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);
} }
@ -177,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

@ -20,12 +20,9 @@ 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());
{ Boolean reasonable = pageDomain.getReasonable();
String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy()); PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);
Boolean reasonable = pageDomain.getReasonable();
PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);
}
} }
/** /**

View File

@ -1,12 +1,20 @@
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 java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletRequest;
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;
/** /**
@ -64,6 +72,34 @@ public class ServletUtils
return Convert.toBool(getRequest().getParameter(name), defaultValue); return Convert.toBool(getRequest().getParameter(name), defaultValue);
} }
/**
* 获得所有请求参数
*
* @param request 请求对象{@link ServletRequest}
* @return Map
*/
public static Map<String, String[]> getParams(ServletRequest request)
{
final Map<String, String[]> map = request.getParameterMap();
return Collections.unmodifiableMap(map);
}
/**
* 获得所有请求参数
*
* @param request 请求对象{@link ServletRequest}
* @return Map
*/
public static Map<String, String> getParamMap(ServletRequest request)
{
Map<String, String> params = new HashMap<>();
for (Map.Entry<String, String[]> entry : getParams(request).entrySet())
{
params.put(entry.getKey(), StringUtils.join(entry.getValue(), ","));
}
return params;
}
/** /**
* 获取request * 获取request
*/ */
@ -143,4 +179,40 @@ public class ServletUtils
String ajax = request.getParameter("__ajax"); String ajax = request.getParameter("__ajax");
return StringUtils.inStringIgnoreCase(ajax, "json", "xml"); return StringUtils.inStringIgnoreCase(ajax, "json", "xml");
} }
/**
* 内容编码
*
* @param str 内容
* @return 编码后的内容
*/
public static String urlEncode(String str)
{
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;
}
}
} }

View File

@ -324,6 +324,32 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
return list; return list;
} }
/**
* 判断给定的set列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value
*
* @param set 给定的集合
* @param array 给定的数组
* @return boolean 结果
*/
public static boolean containsAny(Collection<String> collection, String... array)
{
if (isEmpty(collection) || isEmpty(array))
{
return false;
}
else
{
for (String str : array)
{
if (collection.contains(str))
{
return true;
}
}
return false;
}
}
/** /**
* 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写 * 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写
* *

View File

@ -193,7 +193,6 @@ public class FileUploadUtils
throw new InvalidExtensionException(allowedExtension, extension, fileName); throw new InvalidExtensionException(allowedExtension, extension, fileName);
} }
} }
} }
/** /**

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;
/** /**
* 文件处理工具类 * 文件处理工具类
@ -115,8 +116,7 @@ public class FileUtils
// 路径为文件且不为空则进行删除 // 路径为文件且不为空则进行删除
if (file.isFile() && file.exists()) if (file.isFile() && file.exists())
{ {
file.delete(); flag = file.delete();
flag = true;
} }
return flag; return flag;
} }
@ -256,7 +256,7 @@ public class FileUtils
} }
/** /**
* 获取名称 * 获取文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi.png
* *
* @param fileName 路径名称 * @param fileName 路径名称
* @return 没有文件路径的名称 * @return 没有文件路径的名称
@ -272,4 +272,20 @@ public class FileUtils
int index = Math.max(lastUnixPos, lastWindowsPos); int index = Math.max(lastUnixPos, lastWindowsPos);
return fileName.substring(index + 1); 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

@ -387,7 +387,7 @@ public final class HTMLFilter
{ {
paramValue = processParamProtocol(paramValue); paramValue = processParamProtocol(paramValue);
} }
params.append(' ').append(paramName).append("=\\\"").append(paramValue).append("\""); params.append(' ').append(paramName).append("=\\\"").append(paramValue).append("\\\"");
} }
} }

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;
@ -40,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);

View File

@ -7,12 +7,14 @@ import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator; import java.util.Comparator;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
@ -22,7 +24,9 @@ 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.ArrayUtils;
import org.apache.commons.lang3.RegExUtils; import org.apache.commons.lang3.RegExUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
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;
@ -44,6 +48,7 @@ import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font; import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment; import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors; import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Name;
import org.apache.poi.ss.usermodel.PictureData; import org.apache.poi.ss.usermodel.PictureData;
import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Sheet;
@ -148,6 +153,26 @@ public class ExcelUtil<T>
*/ */
private short maxHeight; private short maxHeight;
/**
* 合并后最后行数
*/
private int subMergedLastRowNum = 0;
/**
* 合并后开始行数
*/
private int subMergedFirstRowNum = 1;
/**
* 对象的子列表方法
*/
private Method subMethod;
/**
* 对象的子列表属性
*/
private List<Field> subFields;
/** /**
* 统计列表 * 统计列表
*/ */
@ -163,11 +188,27 @@ public class ExcelUtil<T>
*/ */
public Class<T> clazz; public Class<T> clazz;
/**
* 需要排除列属性
*/
public String[] excludeFields;
public ExcelUtil(Class<T> clazz) public ExcelUtil(Class<T> clazz)
{ {
this.clazz = clazz; this.clazz = clazz;
} }
/**
* 隐藏Excel中列属性
*
* @param fields 列属性名 示例[单个"name"/多个"id","name"]
* @throws Exception
*/
public void hideColumn(String... fields)
{
this.excludeFields = fields;
}
public void init(List<T> list, String sheetName, String title, Type type) public void init(List<T> list, String sheetName, String title, Type type)
{ {
if (list == null) if (list == null)
@ -181,6 +222,7 @@ public class ExcelUtil<T>
createExcelField(); createExcelField();
createWorkbook(); createWorkbook();
createTitle(); createTitle();
createSubHead();
} }
/** /**
@ -190,13 +232,48 @@ public class ExcelUtil<T>
{ {
if (StringUtils.isNotEmpty(title)) if (StringUtils.isNotEmpty(title))
{ {
subMergedFirstRowNum++;
subMergedLastRowNum++;
int titleLastCol = this.fields.size() - 1;
if (isSubList())
{
titleLastCol = titleLastCol + subFields.size() - 1;
}
Row titleRow = sheet.createRow(rownum == 0 ? rownum++ : 0); Row titleRow = sheet.createRow(rownum == 0 ? rownum++ : 0);
titleRow.setHeightInPoints(30); titleRow.setHeightInPoints(30);
Cell titleCell = titleRow.createCell(0); Cell titleCell = titleRow.createCell(0);
titleCell.setCellStyle(styles.get("title")); titleCell.setCellStyle(styles.get("title"));
titleCell.setCellValue(title); titleCell.setCellValue(title);
sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), titleRow.getRowNum(), sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), titleRow.getRowNum(), titleLastCol));
this.fields.size() - 1)); }
}
/**
* 创建对象的子列表名称
*/
public void createSubHead()
{
if (isSubList())
{
subMergedFirstRowNum++;
subMergedLastRowNum++;
Row subRow = sheet.createRow(rownum);
int excelNum = 0;
for (Object[] objects : fields)
{
Excel attr = (Excel) objects[1];
Cell headCell1 = subRow.createCell(excelNum);
headCell1.setCellValue(attr.name());
headCell1.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
excelNum++;
}
int headFirstRow = excelNum - 1;
int headLastRow = headFirstRow + subFields.size() - 1;
if (headLastRow > headFirstRow)
{
sheet.addMergedRegion(new CellRangeAddress(rownum, rownum, headFirstRow, headLastRow));
}
rownum++;
} }
} }
@ -576,8 +653,20 @@ public class ExcelUtil<T>
// 写入各个字段的列头名称 // 写入各个字段的列头名称
for (Object[] os : fields) for (Object[] os : fields)
{ {
Field field = (Field) os[0];
Excel excel = (Excel) os[1]; Excel excel = (Excel) os[1];
this.createCell(excel, row, column++); if (Collection.class.isAssignableFrom(field.getType()))
{
for (Field subField : subFields)
{
Excel subExcel = subField.getAnnotation(Excel.class);
this.createHeadCell(subExcel, row, column++);
}
}
else
{
this.createHeadCell(excel, row, column++);
}
} }
if (Type.EXPORT.equals(type)) if (Type.EXPORT.equals(type))
{ {
@ -593,21 +682,67 @@ public class ExcelUtil<T>
* @param index 序号 * @param index 序号
* @param row 单元格行 * @param row 单元格行
*/ */
@SuppressWarnings("unchecked")
public void fillExcelData(int index, Row row) public void fillExcelData(int index, Row row)
{ {
int startNo = index * sheetSize; int startNo = index * sheetSize;
int endNo = Math.min(startNo + sheetSize, list.size()); int endNo = Math.min(startNo + sheetSize, list.size());
int rowNo = (1 + rownum) - startNo;
for (int i = startNo; i < endNo; i++) for (int i = startNo; i < endNo; i++)
{ {
row = sheet.createRow(i + 1 + rownum - startNo); rowNo = isSubList() ? (i > 1 ? rowNo + 1 : rowNo + i) : i + 1 + rownum - startNo;
row = sheet.createRow(rowNo);
// 得到导出对象. // 得到导出对象.
T vo = (T) list.get(i); T vo = (T) list.get(i);
Collection<?> subList = null;
if (isSubList())
{
if (isSubListValue(vo))
{
subList = getListCellValue(vo);
subMergedLastRowNum = subMergedLastRowNum + subList.size();
}
else
{
subMergedFirstRowNum++;
subMergedLastRowNum++;
}
}
int column = 0; int column = 0;
for (Object[] os : fields) for (Object[] os : fields)
{ {
Field field = (Field) os[0]; Field field = (Field) os[0];
Excel excel = (Excel) os[1]; Excel excel = (Excel) os[1];
this.addCell(excel, row, vo, field, column++); if (Collection.class.isAssignableFrom(field.getType()) && StringUtils.isNotNull(subList))
{
boolean subFirst = false;
for (Object obj : subList)
{
if (subFirst)
{
rowNo++;
row = sheet.createRow(rowNo);
}
List<Field> subFields = FieldUtils.getFieldsListWithAnnotation(obj.getClass(), Excel.class);
int subIndex = 0;
for (Field subField : subFields)
{
if (subField.isAnnotationPresent(Excel.class))
{
subField.setAccessible(true);
Excel attr = subField.getAnnotation(Excel.class);
this.addCell(attr, row, (T) obj, subField, column + subIndex);
}
subIndex++;
}
subFirst = true;
}
this.subMergedFirstRowNum = this.subMergedFirstRowNum + subList.size();
}
else
{
this.addCell(excel, row, vo, field, column++);
}
} }
} }
} }
@ -649,20 +784,6 @@ public class ExcelUtil<T>
style.setFont(dataFont); style.setFont(dataFont);
styles.put("data", style); styles.put("data", style);
style = wb.createCellStyle();
style.cloneStyleFrom(styles.get("data"));
style.setAlignment(HorizontalAlignment.CENTER);
style.setVerticalAlignment(VerticalAlignment.CENTER);
style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
Font headerFont = wb.createFont();
headerFont.setFontName("Arial");
headerFont.setFontHeightInPoints((short) 10);
headerFont.setBold(true);
headerFont.setColor(IndexedColors.WHITE.getIndex());
style.setFont(headerFont);
styles.put("header", style);
style = wb.createCellStyle(); style = wb.createCellStyle();
style.setAlignment(HorizontalAlignment.CENTER); style.setAlignment(HorizontalAlignment.CENTER);
style.setVerticalAlignment(VerticalAlignment.CENTER); style.setVerticalAlignment(VerticalAlignment.CENTER);
@ -672,35 +793,105 @@ public class ExcelUtil<T>
style.setFont(totalFont); style.setFont(totalFont);
styles.put("total", style); styles.put("total", style);
style = wb.createCellStyle(); styles.putAll(annotationHeaderStyles(wb, styles));
style.cloneStyleFrom(styles.get("data"));
style.setAlignment(HorizontalAlignment.LEFT);
styles.put("data1", style);
style = wb.createCellStyle(); styles.putAll(annotationDataStyles(wb));
style.cloneStyleFrom(styles.get("data"));
style.setAlignment(HorizontalAlignment.CENTER);
styles.put("data2", style);
style = wb.createCellStyle(); return styles;
style.cloneStyleFrom(styles.get("data")); }
style.setAlignment(HorizontalAlignment.RIGHT);
styles.put("data3", style);
/**
* 根据Excel注解创建表格头样式
*
* @param wb 工作薄对象
* @return 自定义样式列表
*/
private Map<String, CellStyle> annotationHeaderStyles(Workbook wb, Map<String, CellStyle> styles)
{
Map<String, CellStyle> headerStyles = new HashMap<String, CellStyle>();
for (Object[] os : fields)
{
Excel excel = (Excel) os[1];
String key = StringUtils.format("header_{}_{}", excel.headerColor(), excel.headerBackgroundColor());
if (!headerStyles.containsKey(key))
{
CellStyle style = wb.createCellStyle();
style.cloneStyleFrom(styles.get("data"));
style.setAlignment(HorizontalAlignment.CENTER);
style.setVerticalAlignment(VerticalAlignment.CENTER);
style.setFillForegroundColor(excel.headerBackgroundColor().index);
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
Font headerFont = wb.createFont();
headerFont.setFontName("Arial");
headerFont.setFontHeightInPoints((short) 10);
headerFont.setBold(true);
headerFont.setColor(excel.headerColor().index);
style.setFont(headerFont);
headerStyles.put(key, style);
}
}
return headerStyles;
}
/**
* 根据Excel注解创建表格列样式
*
* @param wb 工作薄对象
* @return 自定义样式列表
*/
private Map<String, CellStyle> annotationDataStyles(Workbook wb)
{
Map<String, CellStyle> styles = new HashMap<String, CellStyle>();
for (Object[] os : fields)
{
Excel excel = (Excel) os[1];
String key = StringUtils.format("data_{}_{}_{}", excel.align(), excel.color(), excel.backgroundColor());
if (!styles.containsKey(key))
{
CellStyle style = wb.createCellStyle();
style.setAlignment(excel.align());
style.setVerticalAlignment(VerticalAlignment.CENTER);
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());
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
style.setFillForegroundColor(excel.backgroundColor().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;
} }
/** /**
* 创建单元格 * 创建单元格
*/ */
public Cell createCell(Excel attr, Row row, int column) public Cell createHeadCell(Excel attr, Row row, int column)
{ {
// 创建列 // 创建列
Cell cell = row.createCell(column); Cell cell = row.createCell(column);
// 写入列信息 // 写入列信息
cell.setCellValue(attr.name()); cell.setCellValue(attr.name());
setDataValidation(attr, row, column); setDataValidation(attr, row, column);
cell.setCellStyle(styles.get("header")); cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
if (isSubList())
{
// 填充默认样式,防止合并单元格样式失效
sheet.setDefaultColumnStyle(column, styles.get(StringUtils.format("data_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor())));
if (attr.needMerge())
{
sheet.addMergedRegion(new CellRangeAddress(rownum - 1, rownum, column, column));
}
}
return cell; return cell;
} }
@ -721,6 +912,10 @@ public class ExcelUtil<T>
{ {
cellValue = RegExUtils.replaceFirst(cellValue, FORMULA_REGEX_STR, "\t$0"); cellValue = RegExUtils.replaceFirst(cellValue, FORMULA_REGEX_STR, "\t$0");
} }
if (value instanceof Collection && StringUtils.equals("[]", cellValue))
{
cellValue = StringUtils.EMPTY;
}
cell.setCellValue(StringUtils.isNull(cellValue) ? attr.defaultValue() : cellValue + attr.suffix()); cell.setCellValue(StringUtils.isNull(cellValue) ? attr.defaultValue() : cellValue + attr.suffix());
} }
else if (ColumnType.NUMERIC == attr.cellType()) else if (ColumnType.NUMERIC == attr.cellType())
@ -786,17 +981,18 @@ 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列提示. if (attr.combo().length > 15 || StringUtils.join(attr.combo()).length() > 255)
setXSSFPrompt(sheet, "", attr.prompt(), 1, 100, column, column); {
} // 如果下拉数大于15或字符串长度大于255则使用一个新sheet存储避免生成的模板下拉值获取不到
// 如果设置了combo属性则本列只能选择不能输入 setXSSFValidationWithHidden(sheet, attr.combo(), attr.prompt(), 1, 100, column, column);
if (attr.combo().length > 0) }
{ else
// 这里默认设了2-101列只能选择不能输入. {
setXSSFValidation(sheet, attr.combo(), 1, 100, column, column); // 提示信息或只能选择不能输入的列内容.
setPromptOrValidation(sheet, attr.combo(), attr.prompt(), 1, 100, column, column);
}
} }
} }
@ -815,8 +1011,12 @@ public class ExcelUtil<T>
{ {
// 创建cell // 创建cell
cell = row.createCell(column); cell = row.createCell(column);
int align = attr.align().value(); if (isSubListValue(vo) && getListCellValue(vo).size() > 1 && attr.needMerge())
cell.setCellStyle(styles.get("data" + (align >= 1 && align <= 3 ? align : ""))); {
CellRangeAddress cellAddress = new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column);
sheet.addMergedRegion(cellAddress);
}
cell.setCellStyle(styles.get(StringUtils.format("data_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor())));
// 用于读取对象中的属性 // 用于读取对象中的属性
Object value = getTargetValue(vo, field, attr); Object value = getTargetValue(vo, field, attr);
@ -838,7 +1038,7 @@ public class ExcelUtil<T>
} }
else if (value instanceof BigDecimal && -1 != attr.scale()) else if (value instanceof BigDecimal && -1 != attr.scale())
{ {
cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).toString()); cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).doubleValue());
} }
else if (!attr.handler().equals(ExcelHandlerAdapter.class)) else if (!attr.handler().equals(ExcelHandlerAdapter.class))
{ {
@ -860,48 +1060,78 @@ 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); {
// 如果设置了提示信息则鼠标放上去提示
dataValidation.createPromptBox("", promptContent);
dataValidation.setShowPromptBox(true);
}
// 处理Excel兼容性问题
if (dataValidation instanceof XSSFDataValidation)
{
dataValidation.setSuppressDropDownArrow(true);
dataValidation.setShowErrorBox(true);
}
else
{
dataValidation.setSuppressDropDownArrow(false);
}
sheet.addValidationData(dataValidation); sheet.addValidationData(dataValidation);
} }
/** /**
* 设置某些列的值只能输入预制的数据,显示下拉框. * 设置某些列的值只能输入预制的数据,显示下拉框(兼容超出一定数量的下拉框).
* *
* @param sheet 要设置的sheet. * @param sheet 要设置的sheet.
* @param textlist 下拉框显示的内容 * @param textlist 下拉框显示的内容
* @param promptContent 提示内容
* @param firstRow 开始行 * @param firstRow 开始行
* @param endRow 结束行 * @param endRow 结束行
* @param firstCol 开始列 * @param firstCol 开始列
* @param endCol 结束列 * @param endCol 结束列
* @return 设置好的sheet.
*/ */
public void setXSSFValidation(Sheet sheet, String[] textlist, int firstRow, int endRow, int firstCol, int endCol) public void setXSSFValidationWithHidden(Sheet sheet, String[] textlist, String promptContent, int firstRow, int endRow, int firstCol, int endCol)
{ {
String hideSheetName = "combo_" + firstCol + "_" + endCol;
Sheet hideSheet = wb.createSheet(hideSheetName); // 用于存储 下拉菜单数据
for (int i = 0; i < textlist.length; i++)
{
hideSheet.createRow(i).createCell(0).setCellValue(textlist[i]);
}
// 创建名称,可被其他单元格引用
Name name = wb.createName();
name.setNameName(hideSheetName + "_data");
name.setRefersToFormula(hideSheetName + "!$A$1:$A$" + textlist.length);
DataValidationHelper helper = sheet.getDataValidationHelper(); DataValidationHelper helper = sheet.getDataValidationHelper();
// 加载下拉列表内容 // 加载下拉列表内容
DataValidationConstraint constraint = helper.createExplicitListConstraint(textlist); DataValidationConstraint constraint = helper.createFormulaListConstraint(hideSheetName + "_data");
// 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列 // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列
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);
if (StringUtils.isNotEmpty(promptContent))
{
// 如果设置了提示信息则鼠标放上去提示
dataValidation.createPromptBox("", promptContent);
dataValidation.setShowPromptBox(true);
}
// 处理Excel兼容性问题 // 处理Excel兼容性问题
if (dataValidation instanceof XSSFDataValidation) if (dataValidation instanceof XSSFDataValidation)
{ {
@ -914,6 +1144,8 @@ public class ExcelUtil<T>
} }
sheet.addValidationData(dataValidation); sheet.addValidationData(dataValidation);
// 设置hiddenSheet隐藏
wb.setSheetHidden(wb.getSheetIndex(hideSheet), true);
} }
/** /**
@ -931,7 +1163,7 @@ public class ExcelUtil<T>
for (String item : convertSource) for (String item : convertSource)
{ {
String[] itemArray = item.split("="); String[] itemArray = item.split("=");
if (StringUtils.containsAny(separator, propertyValue)) if (StringUtils.containsAny(propertyValue, separator))
{ {
for (String value : propertyValue.split(separator)) for (String value : propertyValue.split(separator))
{ {
@ -968,7 +1200,7 @@ public class ExcelUtil<T>
for (String item : convertSource) for (String item : convertSource)
{ {
String[] itemArray = item.split("="); String[] itemArray = item.split("=");
if (StringUtils.containsAny(separator, propertyValue)) if (StringUtils.containsAny(propertyValue, separator))
{ {
for (String value : propertyValue.split(separator)) for (String value : propertyValue.split(separator))
{ {
@ -1181,29 +1413,39 @@ public class ExcelUtil<T>
tempFields.addAll(Arrays.asList(clazz.getDeclaredFields())); tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
for (Field field : tempFields) for (Field field : tempFields)
{ {
// 单注解 if (!ArrayUtils.contains(this.excludeFields, field.getName()))
if (field.isAnnotationPresent(Excel.class))
{ {
Excel attr = field.getAnnotation(Excel.class); // 单注解
if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) if (field.isAnnotationPresent(Excel.class))
{
field.setAccessible(true);
fields.add(new Object[] { field, attr });
}
}
// 多注解
if (field.isAnnotationPresent(Excels.class))
{
Excels attrs = field.getAnnotation(Excels.class);
Excel[] excels = attrs.value();
for (Excel attr : excels)
{ {
Excel attr = field.getAnnotation(Excel.class);
if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
{ {
field.setAccessible(true); field.setAccessible(true);
fields.add(new Object[] { field, attr }); fields.add(new Object[] { field, attr });
} }
if (Collection.class.isAssignableFrom(field.getType()))
{
subMethod = getSubMethod(field.getName(), clazz);
ParameterizedType pt = (ParameterizedType) field.getGenericType();
Class<?> subClass = (Class<?>) pt.getActualTypeArguments()[0];
this.subFields = FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class);
}
}
// 多注解
if (field.isAnnotationPresent(Excels.class))
{
Excels attrs = field.getAnnotation(Excels.class);
Excel[] excels = attrs.value();
for (Excel attr : excels)
{
if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
{
field.setAccessible(true);
fields.add(new Object[] { field, attr });
}
}
} }
} }
} }
@ -1432,4 +1674,61 @@ public class ExcelUtil<T>
} }
return str; return str;
} }
/**
* 是否有对象的子列表
*/
public boolean isSubList()
{
return StringUtils.isNotNull(subFields) && subFields.size() > 0;
}
/**
* 是否有对象的子列表,集合不为空
*/
public boolean isSubListValue(T vo)
{
return StringUtils.isNotNull(subFields) && subFields.size() > 0 && StringUtils.isNotNull(getListCellValue(vo)) && getListCellValue(vo).size() > 0;
}
/**
* 获取集合的值
*/
public Collection<?> getListCellValue(Object obj)
{
Object value;
try
{
value = subMethod.invoke(obj, new Object[] {});
}
catch (Exception e)
{
return new ArrayList<Object>();
}
return (Collection<?>) value;
}
/**
* 获取对象的子列表方法
*
* @param name 名称
* @param pojoClass 类对象
* @return 子列表方法
*/
public Method getSubMethod(String name, Class<?> pojoClass)
{
StringBuffer getMethodName = new StringBuffer("get");
getMethodName.append(name.substring(0, 1).toUpperCase());
getMethodName.append(name.substring(1));
Method method = null;
try
{
method = pojoClass.getMethod(getMethodName.toString(), new Class[] {});
}
catch (Exception e)
{
log.error("获取对象异常{}", e.getMessage());
}
return method;
}
} }

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

@ -13,7 +13,7 @@ public class SqlUtil
/** /**
* 定义常用的 sql关键字 * 定义常用的 sql关键字
*/ */
public static String SQL_REGEX = "select |insert |delete |update |drop |count |exec |chr |mid |master |truncate |char |and |declare "; public static String SQL_REGEX = "and |extractvalue|updatexml|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |+|user()";
/** /**
* 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序) * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序)

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.2</version> <version>3.8.5</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@ -37,7 +37,7 @@
<!-- 验证码 --> <!-- 验证码 -->
<dependency> <dependency>
<groupId>com.github.penggle</groupId> <groupId>pro.fessional</groupId>
<artifactId>kaptcha</artifactId> <artifactId>kaptcha</artifactId>
<exclusions> <exclusions>
<exclusion> <exclusion>

View File

@ -1,5 +1,7 @@
package com.ruoyi.framework.aspectj; package com.ruoyi.framework.aspectj;
import java.util.ArrayList;
import java.util.List;
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Before;
@ -9,8 +11,10 @@ import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.core.domain.entity.SysRole; import com.ruoyi.common.core.domain.entity.SysRole;
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;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.security.context.PermissionContextHolder;
/** /**
* 数据过滤处理 * 数据过滤处理
@ -68,8 +72,9 @@ public class DataScopeAspect
// 如果是超级管理员,则不过滤数据 // 如果是超级管理员,则不过滤数据
if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin()) if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin())
{ {
String permission = StringUtils.defaultIfEmpty(controllerDataScope.permission(), PermissionContextHolder.getContext());
dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(), dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(),
controllerDataScope.userAlias()); controllerDataScope.userAlias(), permission);
} }
} }
} }
@ -79,15 +84,27 @@ public class DataScopeAspect
* *
* @param joinPoint 切点 * @param joinPoint 切点
* @param user 用户 * @param user 用户
* @param userAlias 别名 * @param deptAlias 部门别名
* @param userAlias 用户别名
* @param permission 权限字符
*/ */
public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias) public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias, String permission)
{ {
StringBuilder sqlString = new StringBuilder(); StringBuilder sqlString = new StringBuilder();
List<String> conditions = new ArrayList<String>();
for (SysRole role : user.getRoles()) for (SysRole role : user.getRoles())
{ {
String dataScope = role.getDataScope(); String dataScope = role.getDataScope();
if (!DATA_SCOPE_CUSTOM.equals(dataScope) && conditions.contains(dataScope))
{
continue;
}
if (StringUtils.isNotEmpty(permission) && StringUtils.isNotEmpty(role.getPermissions())
&& !StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission)))
{
continue;
}
if (DATA_SCOPE_ALL.equals(dataScope)) if (DATA_SCOPE_ALL.equals(dataScope))
{ {
sqlString = new StringBuilder(); sqlString = new StringBuilder();
@ -118,9 +135,10 @@ public class DataScopeAspect
else else
{ {
// 数据权限为仅本人且没有userAlias别名不查询任何数据 // 数据权限为仅本人且没有userAlias别名不查询任何数据
sqlString.append(" OR 1=0 "); sqlString.append(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias));
} }
} }
conditions.add(dataScope);
} }
if (StringUtils.isNotBlank(sqlString.toString())) if (StringUtils.isNotBlank(sqlString.toString()))

View File

@ -13,16 +13,16 @@ import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component; 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 com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson.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;
import com.ruoyi.common.enums.HttpMethod; import com.ruoyi.common.enums.HttpMethod;
import com.ruoyi.common.filter.PropertyPreExcludeFilter;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServletUtils; import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ip.IpUtils; import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.common.utils.SecurityUtils;
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;
import com.ruoyi.system.domain.SysOperLog; import com.ruoyi.system.domain.SysOperLog;
@ -38,6 +38,9 @@ public class LogAspect
{ {
private static final Logger log = LoggerFactory.getLogger(LogAspect.class); private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
/** 排除敏感属性字段 */
public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" };
/** /**
* 处理完请求后执行 * 处理完请求后执行
* *
@ -74,7 +77,7 @@ public class LogAspect
// 请求的地址 // 请求的地址
String ip = IpUtils.getIpAddr(ServletUtils.getRequest()); String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
operLog.setOperIp(ip); operLog.setOperIp(ip);
operLog.setOperUrl(ServletUtils.getRequest().getRequestURI()); operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255));
if (loginUser != null) if (loginUser != null)
{ {
operLog.setOperName(loginUser.getUsername()); operLog.setOperName(loginUser.getUsername());
@ -99,7 +102,6 @@ public class LogAspect
catch (Exception exp) catch (Exception exp)
{ {
// 记录本地异常日志 // 记录本地异常日志
log.error("==前置通知异常==");
log.error("异常信息:{}", exp.getMessage()); log.error("异常信息:{}", exp.getMessage());
exp.printStackTrace(); exp.printStackTrace();
} }
@ -149,8 +151,8 @@ public class LogAspect
} }
else else
{ {
Map<?, ?> paramsMap = (Map<?, ?>) ServletUtils.getRequest().getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE); Map<?, ?> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest());
operLog.setOperParam(StringUtils.substring(paramsMap.toString(), 0, 2000)); operLog.setOperParam(StringUtils.substring(JSON.toJSONString(paramsMap, excludePropertyPreFilter()), 0, 2000));
} }
} }
@ -168,7 +170,7 @@ public class LogAspect
{ {
try try
{ {
Object jsonObj = JSON.toJSON(o); String jsonObj = JSON.toJSONString(o, excludePropertyPreFilter());
params += jsonObj.toString() + " "; params += jsonObj.toString() + " ";
} }
catch (Exception e) catch (Exception e)
@ -180,6 +182,14 @@ public class LogAspect
return params.trim(); return params.trim();
} }
/**
* 忽略敏感属性
*/
public PropertyPreExcludeFilter excludePropertyPreFilter()
{
return new PropertyPreExcludeFilter().addExcludes(EXCLUDE_PROPERTIES);
}
/** /**
* 判断是否需要过滤的对象。 * 判断是否需要过滤的对象。
* *

View File

@ -50,7 +50,6 @@ public class RateLimiterAspect
@Before("@annotation(rateLimiter)") @Before("@annotation(rateLimiter)")
public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable
{ {
String key = rateLimiter.key();
int time = rateLimiter.time(); int time = rateLimiter.time();
int count = rateLimiter.count(); int count = rateLimiter.count();
@ -63,7 +62,7 @@ public class RateLimiterAspect
{ {
throw new ServiceException("访问过于频繁,请稍候再试"); throw new ServiceException("访问过于频繁,请稍候再试");
} }
log.info("限制请求'{}',当前请求'{}',缓存key'{}'", count, number.intValue(), key); log.info("限制请求'{}',当前请求'{}',缓存key'{}'", count, number.intValue(), combineKey);
} }
catch (ServiceException e) catch (ServiceException e)
{ {

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

@ -5,7 +5,7 @@ import com.google.code.kaptcha.text.impl.DefaultTextCreator;
/** /**
* 验证码文本生成器 * 验证码文本生成器
* *
* @author ruoyi * @author ruoyi
*/ */
public class KaptchaTextCreator extends DefaultTextCreator public class KaptchaTextCreator extends DefaultTextCreator
@ -20,7 +20,7 @@ public class KaptchaTextCreator extends DefaultTextCreator
int x = random.nextInt(10); int x = random.nextInt(10);
int y = random.nextInt(10); int y = random.nextInt(10);
StringBuilder suChinese = new StringBuilder(); StringBuilder suChinese = new StringBuilder();
int randomoperands = (int) Math.round(Math.random() * 2); int randomoperands = random.nextInt(3);
if (randomoperands == 0) if (randomoperands == 0)
{ {
result = x * y; result = x * y;
@ -30,7 +30,7 @@ public class KaptchaTextCreator extends DefaultTextCreator
} }
else if (randomoperands == 1) else if (randomoperands == 1)
{ {
if (!(x == 0) && y % x == 0) if ((x != 0) && y % x == 0)
{ {
result = y / x; result = y / x;
suChinese.append(CNUMBERS[y]); suChinese.append(CNUMBERS[y]);
@ -45,7 +45,7 @@ public class KaptchaTextCreator extends DefaultTextCreator
suChinese.append(CNUMBERS[y]); suChinese.append(CNUMBERS[y]);
} }
} }
else if (randomoperands == 2) else
{ {
if (x >= y) if (x >= y)
{ {
@ -62,13 +62,6 @@ public class KaptchaTextCreator extends DefaultTextCreator
suChinese.append(CNUMBERS[x]); suChinese.append(CNUMBERS[x]);
} }
} }
else
{
result = x + y;
suChinese.append(CNUMBERS[x]);
suChinese.append("+");
suChinese.append(CNUMBERS[y]);
}
suChinese.append("=?@" + result); suChinese.append("=?@" + result);
return suChinese.toString(); return suChinese.toString();
} }

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

@ -1,8 +1,10 @@
package com.ruoyi.framework.config; package com.ruoyi.framework.config;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
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.http.CacheControl;
import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter; import org.springframework.web.filter.CorsFilter;
@ -33,7 +35,8 @@ public class ResourcesConfig implements WebMvcConfigurer
/** swagger配置 */ /** swagger配置 */
registry.addResourceHandler("/swagger-ui/**") registry.addResourceHandler("/swagger-ui/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/"); .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/")
.setCacheControl(CacheControl.maxAge(5, TimeUnit.HOURS).cachePublic());;
} }
/** /**

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;
@ -55,7 +57,13 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
*/ */
@Autowired @Autowired
private CorsFilter corsFilter; private CorsFilter corsFilter;
/**
* 允许匿名访问的地址
*/
@Autowired
private PermitAllUrlProperties permitAllUrl;
/** /**
* 解决 无法直接注入 AuthenticationManager * 解决 无法直接注入 AuthenticationManager
* *
@ -87,9 +95,15 @@ 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()
// 禁用HTTP响应标头
.headers().cacheControl().disable().and()
// 认证失败处理类 // 认证失败处理类
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and() .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
// 基于token所以不需要session // 基于token所以不需要session
@ -97,25 +111,15 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
// 过滤请求 // 过滤请求
.authorizeRequests() .authorizeRequests()
// 对于登录login 注册register 验证码captchaImage 允许匿名访问 // 对于登录login 注册register 验证码captchaImage 允许匿名访问
.antMatchers("/login", "/register", "/captchaImage").anonymous() .antMatchers("/login", "/register", "/captchaImage").permitAll()
.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

@ -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

@ -0,0 +1,28 @@
package com.ruoyi.framework.security.context;
import org.springframework.security.core.Authentication;
/**
* 身份验证信息
*
* @author ruoyi
*/
public class AuthenticationContextHolder
{
private static final ThreadLocal<Authentication> contextHolder = new ThreadLocal<>();
public static Authentication getContext()
{
return contextHolder.get();
}
public static void setContext(Authentication context)
{
contextHolder.set(context);
}
public static void clearContext()
{
contextHolder.remove();
}
}

View File

@ -0,0 +1,27 @@
package com.ruoyi.framework.security.context;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import com.ruoyi.common.core.text.Convert;
/**
* 权限信息
*
* @author ruoyi
*/
public class PermissionContextHolder
{
private static final String PERMISSION_CONTEXT_ATTRIBUTES = "PERMISSION_CONTEXT";
public static void setContext(String permission)
{
RequestContextHolder.currentRequestAttributes().setAttribute(PERMISSION_CONTEXT_ATTRIBUTES, permission,
RequestAttributes.SCOPE_REQUEST);
}
public static String getContext()
{
return Convert.toStr(RequestContextHolder.currentRequestAttributes().getAttribute(PERMISSION_CONTEXT_ATTRIBUTES,
RequestAttributes.SCOPE_REQUEST));
}
}

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,9 +8,8 @@ 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.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;
import com.ruoyi.common.utils.ServletUtils; import com.ruoyi.common.utils.ServletUtils;
@ -48,6 +47,6 @@ public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler
// 记录用户退出日志 // 记录用户退出日志
AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, "退出成功")); AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, "退出成功"));
} }
ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(HttpStatus.SUCCESS, "退出成功"))); ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.success("退出成功")));
} }
} }

View File

@ -7,6 +7,7 @@ import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.core.domain.model.LoginUser;
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.framework.security.context.PermissionContextHolder;
/** /**
* RuoYi首创 自定义权限实现ss取自SpringSecurity首字母 * RuoYi首创 自定义权限实现ss取自SpringSecurity首字母
@ -43,6 +44,7 @@ public class PermissionService
{ {
return false; return false;
} }
PermissionContextHolder.setContext(permission);
return hasPermissions(loginUser.getPermissions(), permission); return hasPermissions(loginUser.getPermissions(), permission);
} }
@ -74,6 +76,7 @@ public class PermissionService
{ {
return false; return false;
} }
PermissionContextHolder.setContext(permissions);
Set<String> authorities = loginUser.getPermissions(); Set<String> authorities = loginUser.getPermissions();
for (String permission : permissions.split(PERMISSION_DELIMETER)) for (String permission : permissions.split(PERMISSION_DELIMETER))
{ {

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;
@ -17,11 +18,12 @@ import com.ruoyi.common.exception.user.CaptchaExpireException;
import com.ruoyi.common.exception.user.UserPasswordNotMatchException; 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.StringUtils;
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;
import com.ruoyi.framework.security.context.AuthenticationContextHolder;
import com.ruoyi.system.service.ISysConfigService; import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysUserService; import com.ruoyi.system.service.ISysUserService;
@ -59,9 +61,9 @@ public class SysLoginService
*/ */
public String login(String username, String password, String code, String uuid) public String login(String username, String password, String code, String uuid)
{ {
boolean captchaOnOff = configService.selectCaptchaOnOff(); boolean captchaEnabled = configService.selectCaptchaEnabled();
// 验证码开关 // 验证码开关
if (captchaOnOff) if (captchaEnabled)
{ {
validateCaptcha(username, code, uuid); validateCaptcha(username, code, uuid);
} }
@ -69,9 +71,10 @@ public class SysLoginService
Authentication authentication = null; Authentication authentication = null;
try try
{ {
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
AuthenticationContextHolder.setContext(authenticationToken);
// 该方法会去调用UserDetailsServiceImpl.loadUserByUsername // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
authentication = authenticationManager authentication = authenticationManager.authenticate(authenticationToken);
.authenticate(new UsernamePasswordAuthenticationToken(username, password));
} }
catch (Exception e) catch (Exception e)
{ {
@ -86,6 +89,10 @@ public class SysLoginService
throw new ServiceException(e.getMessage()); throw new ServiceException(e.getMessage());
} }
} }
finally
{
AuthenticationContextHolder.clearContext();
}
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"))); AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
LoginUser loginUser = (LoginUser) authentication.getPrincipal(); LoginUser loginUser = (LoginUser) authentication.getPrincipal();
recordLoginInfo(loginUser.getUserId()); recordLoginInfo(loginUser.getUserId());
@ -103,7 +110,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 + StringUtils.nvl(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

@ -0,0 +1,94 @@
package com.ruoyi.framework.web.service;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
import com.ruoyi.common.exception.user.UserPasswordRetryLimitExceedException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.framework.manager.factory.AsyncFactory;
import com.ruoyi.framework.security.context.AuthenticationContextHolder;
/**
* 登录密码方法
*
* @author ruoyi
*/
@Component
public class SysPasswordService
{
@Autowired
private RedisCache redisCache;
@Value(value = "${user.password.maxRetryCount}")
private int maxRetryCount;
@Value(value = "${user.password.lockTime}")
private int lockTime;
/**
* 登录账户密码错误次数缓存键名
*
* @param username 用户名
* @return 缓存键key
*/
private String getCacheKey(String username)
{
return CacheConstants.PWD_ERR_CNT_KEY + username;
}
public void validate(SysUser user)
{
Authentication usernamePasswordAuthenticationToken = AuthenticationContextHolder.getContext();
String username = usernamePasswordAuthenticationToken.getName();
String password = usernamePasswordAuthenticationToken.getCredentials().toString();
Integer retryCount = redisCache.getCacheObject(getCacheKey(username));
if (retryCount == null)
{
retryCount = 0;
}
if (retryCount >= Integer.valueOf(maxRetryCount).intValue())
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL,
MessageUtils.message("user.password.retry.limit.exceed", maxRetryCount, lockTime)));
throw new UserPasswordRetryLimitExceedException(maxRetryCount, lockTime);
}
if (!matches(user, password))
{
retryCount = retryCount + 1;
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL,
MessageUtils.message("user.password.retry.limit.count", retryCount)));
redisCache.setCacheObject(getCacheKey(username), retryCount, lockTime, TimeUnit.MINUTES);
throw new UserPasswordNotMatchException();
}
else
{
clearLoginRecordCache(username);
}
}
public boolean matches(SysUser user, String rawPassword)
{
return SecurityUtils.matchesPassword(rawPassword, user.getPassword());
}
public void clearLoginRecordCache(String loginName)
{
if (redisCache.hasKey(getCacheKey(loginName)))
{
redisCache.deleteObject(getCacheKey(loginName));
}
}
}

View File

@ -1,9 +1,11 @@
package com.ruoyi.framework.web.service; package com.ruoyi.framework.web.service;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
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.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.system.service.ISysMenuService; import com.ruoyi.system.service.ISysMenuService;
import com.ruoyi.system.service.ISysRoleService; import com.ruoyi.system.service.ISysRoleService;
@ -59,7 +61,21 @@ public class SysPermissionService
} }
else else
{ {
perms.addAll(menuService.selectMenuPermsByUserId(user.getUserId())); List<SysRole> roles = user.getRoles();
if (!roles.isEmpty() && roles.size() > 1)
{
// 多角色设置permissions属性以便数据权限匹配权限
for (SysRole role : roles)
{
Set<String> rolePerms = menuService.selectMenuPermsByRoleId(role.getRoleId());
role.setPermissions(rolePerms);
perms.addAll(rolePerms);
}
}
else
{
perms.addAll(menuService.selectMenuPermsByUserId(user.getUserId()));
}
} }
return perms; return perms;
} }

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;
@ -40,10 +41,12 @@ public class SysRegisterService
public String register(RegisterBody registerBody) public String register(RegisterBody registerBody)
{ {
String msg = "", username = registerBody.getUsername(), password = registerBody.getPassword(); String msg = "", username = registerBody.getUsername(), password = registerBody.getPassword();
SysUser sysUser = new SysUser();
sysUser.setUserName(username);
boolean captchaOnOff = configService.selectCaptchaOnOff();
// 验证码开关 // 验证码开关
if (captchaOnOff) boolean captchaEnabled = configService.selectCaptchaEnabled();
if (captchaEnabled)
{ {
validateCaptcha(username, registerBody.getCode(), registerBody.getUuid()); validateCaptcha(username, registerBody.getCode(), registerBody.getUuid());
} }
@ -66,16 +69,14 @@ public class SysRegisterService
{ {
msg = "密码长度必须在5到20个字符之间"; msg = "密码长度必须在5到20个字符之间";
} }
else if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(username))) else if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(sysUser)))
{ {
msg = "保存用户'" + username + "'失败,注册账号已存在"; msg = "保存用户'" + username + "'失败,注册账号已存在";
} }
else else
{ {
SysUser sysUser = new SysUser();
sysUser.setUserName(username);
sysUser.setNickName(username); sysUser.setNickName(username);
sysUser.setPassword(SecurityUtils.encryptPassword(registerBody.getPassword())); sysUser.setPassword(SecurityUtils.encryptPassword(password));
boolean regFlag = userService.registerUser(sysUser); boolean regFlag = userService.registerUser(sysUser);
if (!regFlag) if (!regFlag)
{ {
@ -83,8 +84,7 @@ public class SysRegisterService
} }
else else
{ {
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.REGISTER, AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.REGISTER, MessageUtils.message("user.register.success")));
MessageUtils.message("user.register.success")));
} }
} }
return msg; return msg;
@ -100,7 +100,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 + StringUtils.nvl(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

@ -26,6 +26,9 @@ public class UserDetailsServiceImpl implements UserDetailsService
@Autowired @Autowired
private ISysUserService userService; private ISysUserService userService;
@Autowired
private SysPasswordService passwordService;
@Autowired @Autowired
private SysPermissionService permissionService; private SysPermissionService permissionService;
@ -50,6 +53,8 @@ public class UserDetailsServiceImpl implements UserDetailsService
throw new ServiceException("对不起,您的账号:" + username + " 已停用"); throw new ServiceException("对不起,您的账号:" + username + " 已停用");
} }
passwordService.validate(user);
return createLoginUser(user); return createLoginUser(user);
} }

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.2</version> <version>3.8.5</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -69,7 +69,7 @@ public class GenController extends BaseController
map.put("info", table); map.put("info", table);
map.put("rows", list); map.put("rows", list);
map.put("tables", tables); map.put("tables", tables);
return AjaxResult.success(map); return success(map);
} }
/** /**
@ -110,7 +110,7 @@ public class GenController extends BaseController
// 查询表信息 // 查询表信息
List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames); List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames);
genTableService.importGenTable(tableList); genTableService.importGenTable(tableList);
return AjaxResult.success(); return success();
} }
/** /**
@ -123,7 +123,7 @@ public class GenController extends BaseController
{ {
genTableService.validateEdit(genTable); genTableService.validateEdit(genTable);
genTableService.updateGenTable(genTable); genTableService.updateGenTable(genTable);
return AjaxResult.success(); return success();
} }
/** /**
@ -135,7 +135,7 @@ public class GenController extends BaseController
public AjaxResult remove(@PathVariable Long[] tableIds) public AjaxResult remove(@PathVariable Long[] tableIds)
{ {
genTableService.deleteGenTableByIds(tableIds); genTableService.deleteGenTableByIds(tableIds);
return AjaxResult.success(); return success();
} }
/** /**
@ -146,7 +146,7 @@ public class GenController extends BaseController
public AjaxResult preview(@PathVariable("tableId") Long tableId) throws IOException public AjaxResult preview(@PathVariable("tableId") Long tableId) throws IOException
{ {
Map<String, String> dataMap = genTableService.previewCode(tableId); Map<String, String> dataMap = genTableService.previewCode(tableId);
return AjaxResult.success(dataMap); return success(dataMap);
} }
/** /**
@ -170,7 +170,7 @@ public class GenController extends BaseController
public AjaxResult genCode(@PathVariable("tableName") String tableName) public AjaxResult genCode(@PathVariable("tableName") String tableName)
{ {
genTableService.generatorCode(tableName); genTableService.generatorCode(tableName);
return AjaxResult.success(); return success();
} }
/** /**
@ -182,7 +182,7 @@ public class GenController extends BaseController
public AjaxResult synchDb(@PathVariable("tableName") String tableName) public AjaxResult synchDb(@PathVariable("tableName") String tableName)
{ {
genTableService.synchDb(tableName); genTableService.synchDb(tableName);
return AjaxResult.success(); return success();
} }
/** /**

View File

@ -21,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;
@ -401,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("树编码字段不能为空");
@ -485,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

@ -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);
@ -381,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

@ -92,19 +92,19 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<update id="updateGenTableColumn" parameterType="GenTableColumn"> <update id="updateGenTableColumn" parameterType="GenTableColumn">
update gen_table_column update gen_table_column
<set> <set>
column_comment = #{columnComment}, <if test="columnComment != null">column_comment = #{columnComment},</if>
java_type = #{javaType}, <if test="javaType != null">java_type = #{javaType},</if>
java_field = #{javaField}, <if test="javaField != null">java_field = #{javaField},</if>
is_insert = #{isInsert}, <if test="isInsert != null">is_insert = #{isInsert},</if>
is_edit = #{isEdit}, <if test="isEdit != null">is_edit = #{isEdit},</if>
is_list = #{isList}, <if test="isList != null">is_list = #{isList},</if>
is_query = #{isQuery}, <if test="isQuery != null">is_query = #{isQuery},</if>
is_required = #{isRequired}, <if test="isRequired != null">is_required = #{isRequired},</if>
query_type = #{queryType}, <if test="queryType != null">query_type = #{queryType},</if>
html_type = #{htmlType}, <if test="htmlType != null">html_type = #{htmlType},</if>
dict_type = #{dictType}, <if test="dictType != null">dict_type = #{dictType},</if>
sort = #{sort}, <if test="sort != null">sort = #{sort},</if>
update_by = #{updateBy}, <if test="updateBy != null">update_by = #{updateBy},</if>
update_time = sysdate() update_time = sysdate()
</set> </set>
where column_id = #{columnId} where column_id = #{columnId}

View File

@ -53,7 +53,7 @@ public class ${ClassName}Controller extends BaseController
public AjaxResult list(${ClassName} ${className}) public AjaxResult list(${ClassName} ${className})
{ {
List<${ClassName}> list = ${className}Service.select${ClassName}List(${className}); List<${ClassName}> list = ${className}Service.select${ClassName}List(${className});
return AjaxResult.success(list); return success(list);
} }
#end #end
@ -77,7 +77,7 @@ public class ${ClassName}Controller extends BaseController
@GetMapping(value = "/{${pkColumn.javaField}}") @GetMapping(value = "/{${pkColumn.javaField}}")
public AjaxResult getInfo(@PathVariable("${pkColumn.javaField}") ${pkColumn.javaType} ${pkColumn.javaField}) public AjaxResult getInfo(@PathVariable("${pkColumn.javaField}") ${pkColumn.javaType} ${pkColumn.javaField})
{ {
return AjaxResult.success(${className}Service.select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField})); return success(${className}Service.select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField}));
} }
/** /**

View File

@ -78,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)
@ -177,11 +187,11 @@
<el-input v-model="form.${field}" placeholder="请输入${comment}" /> <el-input v-model="form.${field}" placeholder="请输入${comment}" />
</el-form-item> </el-form-item>
#elseif($column.htmlType == "imageUpload") #elseif($column.htmlType == "imageUpload")
<el-form-item label="${comment}"> <el-form-item label="${comment}" prop="${field}">
<image-upload 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}" prop="${field}">
<file-upload v-model="form.${field}"/> <file-upload v-model="form.${field}"/>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "editor") #elseif($column.htmlType == "editor")
@ -195,8 +205,11 @@
v-for="dict in dict.type.${dictType}" v-for="dict in dict.type.${dictType}"
:key="dict.value" :key="dict.value"
:label="dict.label" :label="dict.label"
#if($column.javaType == "Integer" || $column.javaType == "Long"):value="parseInt(dict.value)"#else:value="dict.value"#end #if($column.javaType == "Integer" || $column.javaType == "Long")
:value="parseInt(dict.value)"
#else
:value="dict.value"
#end
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
@ -207,7 +220,7 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "checkbox" && "" != $dictType) #elseif($column.htmlType == "checkbox" && "" != $dictType)
<el-form-item label="${comment}"> <el-form-item label="${comment}" prop="${field}">
<el-checkbox-group v-model="form.${field}"> <el-checkbox-group v-model="form.${field}">
<el-checkbox <el-checkbox
v-for="dict in dict.type.${dictType}" v-for="dict in dict.type.${dictType}"
@ -218,24 +231,27 @@
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "checkbox" && $dictType) #elseif($column.htmlType == "checkbox" && $dictType)
<el-form-item label="${comment}"> <el-form-item label="${comment}" prop="${field}">
<el-checkbox-group v-model="form.${field}"> <el-checkbox-group v-model="form.${field}">
<el-checkbox>请选择字典生成</el-checkbox> <el-checkbox>请选择字典生成</el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "radio" && "" != $dictType) #elseif($column.htmlType == "radio" && "" != $dictType)
<el-form-item label="${comment}"> <el-form-item label="${comment}" prop="${field}">
<el-radio-group v-model="form.${field}"> <el-radio-group v-model="form.${field}">
<el-radio <el-radio
v-for="dict in dict.type.${dictType}" v-for="dict in dict.type.${dictType}"
:key="dict.value" :key="dict.value"
#if($column.javaType == "Integer" || $column.javaType == "Long"):label="parseInt(dict.value)"#else:label="dict.value"#end #if($column.javaType == "Integer" || $column.javaType == "Long")
:label="parseInt(dict.value)"
#else
:label="dict.value"
#end
>{{dict.label}}</el-radio> >{{dict.label}}</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "radio" && $dictType) #elseif($column.htmlType == "radio" && $dictType)
<el-form-item label="${comment}"> <el-form-item label="${comment}" prop="${field}">
<el-radio-group v-model="form.${field}"> <el-radio-group v-model="form.${field}">
<el-radio label="1">请选择字典生成</el-radio> <el-radio label="1">请选择字典生成</el-radio>
</el-radio-group> </el-radio-group>
@ -293,6 +309,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)})
@ -321,7 +341,7 @@ export default {
#set($comment=$column.columnComment) #set($comment=$column.columnComment)
#end #end
$column.javaField: [ $column.javaField: [
{ required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select")"change"#else"blur"#end } { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio")"change"#else"blur"#end }
]#if($foreach.count != $columns.size()),#end ]#if($foreach.count != $columns.size()),#end
#end #end
#end #end
@ -384,10 +404,7 @@ export default {
reset() { reset() {
this.form = { this.form = {
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "radio") #if($column.htmlType == "checkbox")
$column.javaField: #if($column.javaType == "Integer" || $column.javaType == "Long")0#else"0"#end#if($foreach.count != $columns.size()),#end
#elseif($column.htmlType == "checkbox")
$column.javaField: []#if($foreach.count != $columns.size()),#end $column.javaField: []#if($foreach.count != $columns.size()),#end
#else #else
$column.javaField: null#if($foreach.count != $columns.size()),#end $column.javaField: null#if($foreach.count != $columns.size()),#end
@ -423,6 +440,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

@ -198,11 +198,11 @@
<el-input v-model="form.${field}" placeholder="请输入${comment}" /> <el-input v-model="form.${field}" placeholder="请输入${comment}" />
</el-form-item> </el-form-item>
#elseif($column.htmlType == "imageUpload") #elseif($column.htmlType == "imageUpload")
<el-form-item label="${comment}"> <el-form-item label="${comment}" prop="${field}">
<image-upload 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}" prop="${field}">
<file-upload v-model="form.${field}"/> <file-upload v-model="form.${field}"/>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "editor") #elseif($column.htmlType == "editor")
@ -216,8 +216,11 @@
v-for="dict in dict.type.${dictType}" v-for="dict in dict.type.${dictType}"
:key="dict.value" :key="dict.value"
:label="dict.label" :label="dict.label"
#if($column.javaType == "Integer" || $column.javaType == "Long"):value="parseInt(dict.value)"#else:value="dict.value"#end #if($column.javaType == "Integer" || $column.javaType == "Long")
:value="parseInt(dict.value)"
#else
:value="dict.value"
#end
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
@ -228,7 +231,7 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "checkbox" && "" != $dictType) #elseif($column.htmlType == "checkbox" && "" != $dictType)
<el-form-item label="${comment}"> <el-form-item label="${comment}" prop="${field}">
<el-checkbox-group v-model="form.${field}"> <el-checkbox-group v-model="form.${field}">
<el-checkbox <el-checkbox
v-for="dict in dict.type.${dictType}" v-for="dict in dict.type.${dictType}"
@ -239,24 +242,27 @@
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "checkbox" && $dictType) #elseif($column.htmlType == "checkbox" && $dictType)
<el-form-item label="${comment}"> <el-form-item label="${comment}" prop="${field}">
<el-checkbox-group v-model="form.${field}"> <el-checkbox-group v-model="form.${field}">
<el-checkbox>请选择字典生成</el-checkbox> <el-checkbox>请选择字典生成</el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "radio" && "" != $dictType) #elseif($column.htmlType == "radio" && "" != $dictType)
<el-form-item label="${comment}"> <el-form-item label="${comment}" prop="${field}">
<el-radio-group v-model="form.${field}"> <el-radio-group v-model="form.${field}">
<el-radio <el-radio
v-for="dict in dict.type.${dictType}" v-for="dict in dict.type.${dictType}"
:key="dict.value" :key="dict.value"
#if($column.javaType == "Integer" || $column.javaType == "Long"):label="parseInt(dict.value)"#else:label="dict.value"#end #if($column.javaType == "Integer" || $column.javaType == "Long")
:label="parseInt(dict.value)"
#else
:label="dict.value"
#end
>{{dict.label}}</el-radio> >{{dict.label}}</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "radio" && $dictType) #elseif($column.htmlType == "radio" && $dictType)
<el-form-item label="${comment}"> <el-form-item label="${comment}" prop="${field}">
<el-radio-group v-model="form.${field}"> <el-radio-group v-model="form.${field}">
<el-radio label="1">请选择字典生成</el-radio> <el-radio label="1">请选择字典生成</el-radio>
</el-radio-group> </el-radio-group>
@ -412,7 +418,7 @@ export default {
#set($comment=$column.columnComment) #set($comment=$column.columnComment)
#end #end
$column.javaField: [ $column.javaField: [
{ required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select")"change"#else"blur"#end } { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio")"change"#else"blur"#end }
]#if($foreach.count != $columns.size()),#end ]#if($foreach.count != $columns.size()),#end
#end #end
#end #end
@ -456,9 +462,7 @@ export default {
reset() { reset() {
this.form = { this.form = {
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "radio") #if($column.htmlType == "checkbox")
$column.javaField: #if($column.javaType == "Integer" || $column.javaType == "Long")0#else"0"#end#if($foreach.count != $columns.size()),#end
#elseif($column.htmlType == "checkbox")
$column.javaField: []#if($foreach.count != $columns.size()),#end $column.javaField: []#if($foreach.count != $columns.size()),#end
#else #else
$column.javaField: null#if($foreach.count != $columns.size()),#end $column.javaField: null#if($foreach.count != $columns.size()),#end

View File

@ -76,14 +76,23 @@
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)
@ -127,24 +136,9 @@
#end #end
<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 link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['${moduleName}:${businessName}:edit']">修改</el-button>
type="text" <el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['${moduleName}:${businessName}:add']">新增</el-button>
icon="Edit" <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['${moduleName}:${businessName}:remove']">删除</el-button>
@click="handleUpdate(scope.row)"
v-hasPermi="['${moduleName}:${businessName}:edit']"
>修改</el-button>
<el-button
type="text"
icon="Plus"
@click="handleAdd(scope.row)"
v-hasPermi="['${moduleName}:${businessName}:add']"
>新增</el-button>
<el-button
type="text"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['${moduleName}:${businessName}:remove']"
>删除</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -165,11 +159,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")
@ -177,11 +173,11 @@
<el-input v-model="form.${field}" placeholder="请输入${comment}" /> <el-input v-model="form.${field}" placeholder="请输入${comment}" />
</el-form-item> </el-form-item>
#elseif($column.htmlType == "imageUpload") #elseif($column.htmlType == "imageUpload")
<el-form-item label="${comment}"> <el-form-item label="${comment}" prop="${field}">
<image-upload 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}" prop="${field}">
<file-upload v-model="form.${field}"/> <file-upload v-model="form.${field}"/>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "editor") #elseif($column.htmlType == "editor")
@ -195,8 +191,11 @@
v-for="dict in ${dictType}" v-for="dict in ${dictType}"
:key="dict.value" :key="dict.value"
:label="dict.label" :label="dict.label"
#if($column.javaType == "Integer" || $column.javaType == "Long"):value="parseInt(dict.value)"#else:value="dict.value"#end #if($column.javaType == "Integer" || $column.javaType == "Long")
:value="parseInt(dict.value)"
#else
:value="dict.value"
#end
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
@ -207,7 +206,7 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "checkbox" && "" != $dictType) #elseif($column.htmlType == "checkbox" && "" != $dictType)
<el-form-item label="${comment}"> <el-form-item label="${comment}" prop="${field}">
<el-checkbox-group v-model="form.${field}"> <el-checkbox-group v-model="form.${field}">
<el-checkbox <el-checkbox
v-for="dict in ${dictType}" v-for="dict in ${dictType}"
@ -218,24 +217,27 @@
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "checkbox" && $dictType) #elseif($column.htmlType == "checkbox" && $dictType)
<el-form-item label="${comment}"> <el-form-item label="${comment}" prop="${field}">
<el-checkbox-group v-model="form.${field}"> <el-checkbox-group v-model="form.${field}">
<el-checkbox>请选择字典生成</el-checkbox> <el-checkbox>请选择字典生成</el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "radio" && "" != $dictType) #elseif($column.htmlType == "radio" && "" != $dictType)
<el-form-item label="${comment}"> <el-form-item label="${comment}" prop="${field}">
<el-radio-group v-model="form.${field}"> <el-radio-group v-model="form.${field}">
<el-radio <el-radio
v-for="dict in ${dictType}" v-for="dict in ${dictType}"
:key="dict.value" :key="dict.value"
#if($column.javaType == "Integer" || $column.javaType == "Long"):label="parseInt(dict.value)"#else:label="dict.value"#end #if($column.javaType == "Integer" || $column.javaType == "Long")
:label="parseInt(dict.value)"
#else
:label="dict.value"
#end
>{{dict.label}}</el-radio> >{{dict.label}}</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "radio" && $dictType) #elseif($column.htmlType == "radio" && $dictType)
<el-form-item label="${comment}"> <el-form-item label="${comment}" prop="${field}">
<el-radio-group v-model="form.${field}"> <el-radio-group v-model="form.${field}">
<el-radio label="1">请选择字典生成</el-radio> <el-radio label="1">请选择字典生成</el-radio>
</el-radio-group> </el-radio-group>
@ -283,6 +285,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)})
@ -309,7 +313,7 @@ const data = reactive({
#set($comment=$column.columnComment) #set($comment=$column.columnComment)
#end #end
$column.javaField: [ $column.javaField: [
{ required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select")"change"#else"blur"#end } { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio")"change"#else"blur"#end }
]#if($foreach.count != $columns.size()),#end ]#if($foreach.count != $columns.size()),#end
#end #end
#end #end
@ -343,8 +347,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}");
@ -362,10 +366,7 @@ function cancel() {
function reset() { function reset() {
form.value = { form.value = {
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "radio") #if($column.htmlType == "checkbox")
$column.javaField: #if($column.javaType == "Integer" || $column.javaType == "Long")0#else"0"#end#if($foreach.count != $columns.size()),#end
#elseif($column.htmlType == "checkbox")
$column.javaField: []#if($foreach.count != $columns.size()),#end $column.javaField: []#if($foreach.count != $columns.size()),#end
#else #else
$column.javaField: null#if($foreach.count != $columns.size()),#end $column.javaField: null#if($foreach.count != $columns.size()),#end
@ -393,9 +394,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 {
@ -405,6 +406,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

@ -148,18 +148,8 @@
#end #end
<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 link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['${moduleName}:${businessName}:edit']">修改</el-button>
type="text" <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['${moduleName}:${businessName}:remove']">删除</el-button>
icon="Edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['${moduleName}:${businessName}:edit']"
>修改</el-button>
<el-button
type="text"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['${moduleName}:${businessName}:remove']"
>删除</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -191,11 +181,11 @@
<el-input v-model="form.${field}" placeholder="请输入${comment}" /> <el-input v-model="form.${field}" placeholder="请输入${comment}" />
</el-form-item> </el-form-item>
#elseif($column.htmlType == "imageUpload") #elseif($column.htmlType == "imageUpload")
<el-form-item label="${comment}"> <el-form-item label="${comment}" prop="${field}">
<image-upload 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}" prop="${field}">
<file-upload v-model="form.${field}"/> <file-upload v-model="form.${field}"/>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "editor") #elseif($column.htmlType == "editor")
@ -209,8 +199,11 @@
v-for="dict in ${dictType}" v-for="dict in ${dictType}"
:key="dict.value" :key="dict.value"
:label="dict.label" :label="dict.label"
#if($column.javaType == "Integer" || $column.javaType == "Long"):value="parseInt(dict.value)"#else:value="dict.value"#end #if($column.javaType == "Integer" || $column.javaType == "Long")
:value="parseInt(dict.value)"
#else
:value="dict.value"
#end
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
@ -221,7 +214,7 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "checkbox" && "" != $dictType) #elseif($column.htmlType == "checkbox" && "" != $dictType)
<el-form-item label="${comment}"> <el-form-item label="${comment}" prop="${field}">
<el-checkbox-group v-model="form.${field}"> <el-checkbox-group v-model="form.${field}">
<el-checkbox <el-checkbox
v-for="dict in ${dictType}" v-for="dict in ${dictType}"
@ -232,24 +225,27 @@
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "checkbox" && $dictType) #elseif($column.htmlType == "checkbox" && $dictType)
<el-form-item label="${comment}"> <el-form-item label="${comment}" prop="${field}">
<el-checkbox-group v-model="form.${field}"> <el-checkbox-group v-model="form.${field}">
<el-checkbox>请选择字典生成</el-checkbox> <el-checkbox>请选择字典生成</el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "radio" && "" != $dictType) #elseif($column.htmlType == "radio" && "" != $dictType)
<el-form-item label="${comment}"> <el-form-item label="${comment}" prop="${field}">
<el-radio-group v-model="form.${field}"> <el-radio-group v-model="form.${field}">
<el-radio <el-radio
v-for="dict in ${dictType}" v-for="dict in ${dictType}"
:key="dict.value" :key="dict.value"
#if($column.javaType == "Integer" || $column.javaType == "Long"):label="parseInt(dict.value)"#else:label="dict.value"#end #if($column.javaType == "Integer" || $column.javaType == "Long")
:label="parseInt(dict.value)"
#else
:label="dict.value"
#end
>{{dict.label}}</el-radio> >{{dict.label}}</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "radio" && $dictType) #elseif($column.htmlType == "radio" && $dictType)
<el-form-item label="${comment}"> <el-form-item label="${comment}" prop="${field}">
<el-radio-group v-model="form.${field}"> <el-radio-group v-model="form.${field}">
<el-radio label="1">请选择字典生成</el-radio> <el-radio label="1">请选择字典生成</el-radio>
</el-radio-group> </el-radio-group>
@ -398,7 +394,7 @@ const data = reactive({
#set($comment=$column.columnComment) #set($comment=$column.columnComment)
#end #end
$column.javaField: [ $column.javaField: [
{ required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select")"change"#else"blur"#end } { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio")"change"#else"blur"#end }
]#if($foreach.count != $columns.size()),#end ]#if($foreach.count != $columns.size()),#end
#end #end
#end #end
@ -442,9 +438,7 @@ function cancel() {
function reset() { function reset() {
form.value = { form.value = {
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "radio") #if($column.htmlType == "checkbox")
$column.javaField: #if($column.javaType == "Integer" || $column.javaType == "Long")0#else"0"#end#if($foreach.count != $columns.size()),#end
#elseif($column.htmlType == "checkbox")
$column.javaField: []#if($foreach.count != $columns.size()),#end $column.javaField: []#if($foreach.count != $columns.size()),#end
#else #else
$column.javaField: null#if($foreach.count != $columns.size()),#end $column.javaField: null#if($foreach.count != $columns.size()),#end
@ -492,8 +486,8 @@ function handleAdd() {
/** 修改按钮操作 */ /** 修改按钮操作 */
function handleUpdate(row) { function handleUpdate(row) {
reset(); reset();
const ${pkColumn.javaField} = row.${pkColumn.javaField} || ids.value const _${pkColumn.javaField} = row.${pkColumn.javaField} || ids.value
get${BusinessName}(${pkColumn.javaField}).then(response => { get${BusinessName}(_${pkColumn.javaField}).then(response => {
form.value = response.data; form.value = response.data;
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "checkbox") #if($column.htmlType == "checkbox")
@ -539,9 +533,9 @@ function submitForm() {
/** 删除按钮操作 */ /** 删除按钮操作 */
function handleDelete(row) { function handleDelete(row) {
const ${pkColumn.javaField}s = row.${pkColumn.javaField} || ids.value; const _${pkColumn.javaField}s = row.${pkColumn.javaField} || ids.value;
proxy.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + ${pkColumn.javaField}s + '"的数据项?').then(function() { proxy.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + _${pkColumn.javaField}s + '"的数据项?').then(function() {
return del${BusinessName}(${pkColumn.javaField}s); return del${BusinessName}(_${pkColumn.javaField}s);
}).then(() => { }).then(() => {
getList(); getList();
proxy.#[[$modal]]#.msgSuccess("删除成功"); proxy.#[[$modal]]#.msgSuccess("删除成功");

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.2</version> <version>3.8.5</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -71,7 +71,7 @@ public class SysJobController extends BaseController
@GetMapping(value = "/{jobId}") @GetMapping(value = "/{jobId}")
public AjaxResult getInfo(@PathVariable("jobId") Long jobId) public AjaxResult getInfo(@PathVariable("jobId") Long jobId)
{ {
return AjaxResult.success(jobService.selectJobById(jobId)); return success(jobService.selectJobById(jobId));
} }
/** /**
@ -167,8 +167,8 @@ public class SysJobController extends BaseController
@PutMapping("/run") @PutMapping("/run")
public AjaxResult run(@RequestBody SysJob job) throws SchedulerException public AjaxResult run(@RequestBody SysJob job) throws SchedulerException
{ {
jobService.run(job); boolean result = jobService.run(job);
return AjaxResult.success(); return result ? success() : error("任务不存在或已过期!");
} }
/** /**
@ -180,6 +180,6 @@ public class SysJobController extends BaseController
public AjaxResult remove(@PathVariable Long[] jobIds) throws SchedulerException, TaskException public AjaxResult remove(@PathVariable Long[] jobIds) throws SchedulerException, TaskException
{ {
jobService.deleteJobByIds(jobIds); jobService.deleteJobByIds(jobIds);
return AjaxResult.success(); return success();
} }
} }

View File

@ -60,10 +60,10 @@ public class SysJobLogController extends BaseController
* 根据调度编号获取详细信息 * 根据调度编号获取详细信息
*/ */
@PreAuthorize("@ss.hasPermi('monitor:job:query')") @PreAuthorize("@ss.hasPermi('monitor:job:query')")
@GetMapping(value = "/{configId}") @GetMapping(value = "/{jobLogId}")
public AjaxResult getInfo(@PathVariable Long jobLogId) public AjaxResult getInfo(@PathVariable Long jobLogId)
{ {
return AjaxResult.success(jobLogService.selectJobLogById(jobLogId)); return success(jobLogService.selectJobLogById(jobLogId));
} }
@ -87,6 +87,6 @@ public class SysJobLogController extends BaseController
public AjaxResult clean() public AjaxResult clean()
{ {
jobLogService.cleanJobLog(); jobLogService.cleanJobLog();
return AjaxResult.success(); return success();
} }
} }

View File

@ -74,7 +74,7 @@ public interface ISysJobService
* @param job 调度信息 * @param job 调度信息
* @return 结果 * @return 结果
*/ */
public void run(SysJob job) throws SchedulerException; public boolean run(SysJob job) throws SchedulerException;
/** /**
* 新增任务 * 新增任务

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