mirror of
https://github.com/dromara/RuoYi-Vue-Plus.git
synced 2025-11-25 02:16:46 +08:00
Compare commits
145 Commits
v5.4.0
...
554152635d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
554152635d | ||
|
|
b379574637 | ||
|
|
6a556cc6ff | ||
|
|
a6950275ad | ||
|
|
58b1bf5c33 | ||
|
|
c85f693ca6 | ||
|
|
5f466fd0c4 | ||
|
|
127eaf936c | ||
|
|
fcd8556076 | ||
|
|
0512781513 | ||
|
|
2472359adb | ||
|
|
29d4bb4e59 | ||
|
|
cce95424ce | ||
|
|
8d7358e663 | ||
|
|
240f10ab45 | ||
|
|
48213bc9c9 | ||
|
|
3995d9699d | ||
|
|
ecd4e3eaf0 | ||
|
|
2e3a42c669 | ||
|
|
82997fc6cd | ||
|
|
0dce571270 | ||
|
|
9375578925 | ||
|
|
e19ccf5064 | ||
|
|
1cea7b72d7 | ||
|
|
5da9ddf5e3 | ||
|
|
93ee01c6b9 | ||
|
|
acd30fda3c | ||
|
|
3f62a76cc8 | ||
|
|
b0b4e573f6 | ||
|
|
de61899eed | ||
|
|
3a9bdb36f1 | ||
|
|
b815b8e574 | ||
|
|
45edee4e63 | ||
|
|
868bc492a2 | ||
|
|
90fef1bb17 | ||
|
|
d79b48ea99 | ||
|
|
f6993a1491 | ||
|
|
6b0b7382a6 | ||
|
|
c41add355f | ||
|
|
74e3d232f5 | ||
|
|
03fca40c7d | ||
|
|
b2ad257bd8 | ||
|
|
7e4f0d73f4 | ||
|
|
2ec802f17f | ||
|
|
e0ce662c28 | ||
|
|
3d9ed1b92f | ||
|
|
d4e6e70c43 | ||
|
|
2095a96e67 | ||
|
|
328b61b252 | ||
|
|
781463417c | ||
|
|
446a14b928 | ||
|
|
6c2518640b | ||
|
|
d8d138092f | ||
|
|
ec31b736c7 | ||
|
|
e7467b2c5c | ||
|
|
8050e2f1b1 | ||
|
|
7de4559b4a | ||
|
|
fc9c0d7657 | ||
|
|
ab3037dc4f | ||
|
|
8281b838b9 | ||
|
|
2bc7171abd | ||
|
|
4f99487d24 | ||
|
|
a7cddc8d40 | ||
|
|
f3c4c02d73 | ||
|
|
eb631360f4 | ||
|
|
a62bf04428 | ||
|
|
7147f81b42 | ||
|
|
c9098563ca | ||
|
|
d4a8c25eab | ||
|
|
0ddba506bf | ||
|
|
d02bea85cb | ||
|
|
d27c58bfe8 | ||
|
|
34bb51f5c0 | ||
|
|
64c37aaec6 | ||
|
|
3de036adde | ||
|
|
e0df8c15d8 | ||
|
|
176793e15b | ||
|
|
589ec1fdbc | ||
|
|
b421c8d017 | ||
|
|
e2200bac71 | ||
|
|
f8950d1e20 | ||
|
|
9dfe9f610d | ||
|
|
17610e8721 | ||
|
|
f29b787767 | ||
|
|
9775283a24 | ||
|
|
debc73d7d4 | ||
|
|
d501e82541 | ||
|
|
3002585e63 | ||
|
|
60aca2eef3 | ||
|
|
5baf342478 | ||
|
|
3f9919fbee | ||
|
|
682d8b0099 | ||
|
|
bbabffe191 | ||
|
|
6722f2eeed | ||
|
|
5a9728c868 | ||
|
|
eea96e87d9 | ||
|
|
e659740cb8 | ||
|
|
314909a536 | ||
|
|
8f5d60f543 | ||
|
|
1ad0d5387b | ||
|
|
770c3bd03e | ||
|
|
4b04a4bf09 | ||
|
|
1598447f6b | ||
|
|
a8a1db4463 | ||
|
|
4b47053dcf | ||
|
|
03054fc1e8 | ||
|
|
9dce540a09 | ||
|
|
534182deff | ||
|
|
4577c45110 | ||
|
|
0796791ec9 | ||
|
|
84baac0a4f | ||
|
|
74d257a610 | ||
|
|
cb8fa6ff9a | ||
|
|
c157012807 | ||
|
|
ffa01bdb3a | ||
|
|
3fa572f0a8 | ||
|
|
f868de1b7b | ||
|
|
fb785dc17f | ||
|
|
f3d475438f | ||
|
|
d7af327248 | ||
|
|
bd88e27c82 | ||
|
|
83b6addbba | ||
|
|
d51f3b9f4e | ||
|
|
9256432532 | ||
|
|
97d3a31aba | ||
|
|
d9cc85187a | ||
|
|
2ff2d89b2d | ||
|
|
be2e5059fd | ||
|
|
fad91f01ff | ||
|
|
8f95374cef | ||
|
|
7471fa7ee0 | ||
|
|
529f1e5dbb | ||
|
|
eff131a1ed | ||
|
|
60b0faa3c6 | ||
|
|
b2d694b90b | ||
|
|
fecc564099 | ||
|
|
297e920179 | ||
|
|
ea9379a52f | ||
|
|
0b0f2ee8ea | ||
|
|
6d2f104a43 | ||
|
|
2e50e30778 | ||
|
|
daf79683b3 | ||
|
|
5849ddc160 | ||
|
|
c88367939c | ||
|
|
a748d0d62c |
@@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="ruoyi-monitor-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
|
||||
<deployment type="dockerfile">
|
||||
<settings>
|
||||
<option name="imageTag" value="ruoyi/ruoyi-monitor-admin:5.4.0" />
|
||||
<option name="imageTag" value="ruoyi/ruoyi-monitor-admin:5.4.1" />
|
||||
<option name="buildOnly" value="true" />
|
||||
<option name="sourceFilePath" value="ruoyi-extend/ruoyi-monitor-admin/Dockerfile" />
|
||||
</settings>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="ruoyi-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
|
||||
<deployment type="dockerfile">
|
||||
<settings>
|
||||
<option name="imageTag" value="ruoyi/ruoyi-server:5.4.0" />
|
||||
<option name="imageTag" value="ruoyi/ruoyi-server:5.4.1" />
|
||||
<option name="buildOnly" value="true" />
|
||||
<option name="sourceFilePath" value="ruoyi-admin/Dockerfile" />
|
||||
</settings>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="ruoyi-snailjob-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
|
||||
<deployment type="dockerfile">
|
||||
<settings>
|
||||
<option name="imageTag" value="ruoyi/ruoyi-snailjob-server:5.4.0" />
|
||||
<option name="imageTag" value="ruoyi/ruoyi-snailjob-server:5.4.1" />
|
||||
<option name="buildOnly" value="true" />
|
||||
<option name="sourceFilePath" value="ruoyi-extend/ruoyi-snailjob-server/Dockerfile" />
|
||||
</settings>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
[](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/5.X/LICENSE)
|
||||
[](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
|
||||
<br>
|
||||
[](https://gitee.com/dromara/RuoYi-Vue-Plus)
|
||||
[](https://gitee.com/dromara/RuoYi-Vue-Plus)
|
||||
[]()
|
||||
[]()
|
||||
[]()
|
||||
@@ -27,7 +27,7 @@
|
||||
> 成员前端项目地址: 基于soybean [ruoyi-plus-soybean](https://gitee.com/xlsea/ruoyi-plus-soybean)<br>
|
||||
> 成员项目地址: 删除多租户与工作流 [RuoYi-Vue-Plus-Single](https://gitee.com/ColorDreams/RuoYi-Vue-Plus-Single)<br>
|
||||
|
||||
> 文档地址: [plus-doc](https://plus-doc.dromara.org) 文档在华为云上如果打不开大概率是DNS问题 可以尝试切换网络等方式(或者科学上网)
|
||||
> 文档地址: [plus-doc](https://plus-doc.dromara.org) 国内加速: [plus-doc.top](https://plus-doc.top)
|
||||
|
||||
## 赞助商
|
||||
|
||||
@@ -37,6 +37,8 @@ CCFlow 驰聘低代码-流程-表单 - https://gitee.com/opencc/RuoYi-JFlow <br>
|
||||
引迈信息 软件开发平台 - https://www.jnpfsoft.com/index.html?from=plus-doc <br>
|
||||
<font color="red">**启山商城系统 多租户商城源码可免费商用可二次开发 - https://www.73app.cn/** </font><br>
|
||||
Mall4J 高质量Java商城系统 - https://www.mall4j.com/cn/?statId=11 <br>
|
||||
aizuda flowlong 工作流 - https://gitee.com/aizuda/flowlong <br>
|
||||
|
||||
[如何成为赞助商 加群联系作者详谈](https://plus-doc.dromara.org/#/common/add_group)
|
||||
|
||||
# 本框架与RuoYi的功能差异
|
||||
|
||||
25
pom.xml
25
pom.xml
@@ -13,8 +13,8 @@
|
||||
<description>Dromara RuoYi-Vue-Plus多租户管理系统</description>
|
||||
|
||||
<properties>
|
||||
<revision>5.4.0</revision>
|
||||
<spring-boot.version>3.4.6</spring-boot.version>
|
||||
<revision>5.4.1</revision>
|
||||
<spring-boot.version>3.4.7</spring-boot.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>17</java.version>
|
||||
@@ -23,15 +23,15 @@
|
||||
<therapi-javadoc.version>0.15.0</therapi-javadoc.version>
|
||||
<fastexcel.version>1.2.0</fastexcel.version>
|
||||
<velocity.version>2.3</velocity.version>
|
||||
<satoken.version>1.42.0</satoken.version>
|
||||
<satoken.version>1.44.0</satoken.version>
|
||||
<mybatis-plus.version>3.5.12</mybatis-plus.version>
|
||||
<p6spy.version>3.9.1</p6spy.version>
|
||||
<hutool.version>5.8.35</hutool.version>
|
||||
<hutool.version>5.8.38</hutool.version>
|
||||
<spring-boot-admin.version>3.4.7</spring-boot-admin.version>
|
||||
<redisson.version>3.45.1</redisson.version>
|
||||
<redisson.version>3.50.0</redisson.version>
|
||||
<lock4j.version>2.2.7</lock4j.version>
|
||||
<dynamic-ds.version>4.3.1</dynamic-ds.version>
|
||||
<snailjob.version>1.5.0</snailjob.version>
|
||||
<snailjob.version>1.6.0</snailjob.version>
|
||||
<mapstruct-plus.version>1.4.8</mapstruct-plus.version>
|
||||
<mapstruct-plus.lombok.version>0.2.0</mapstruct-plus.lombok.version>
|
||||
<lombok.version>1.18.36</lombok.version>
|
||||
@@ -39,7 +39,6 @@
|
||||
<justauth.version>1.16.7</justauth.version>
|
||||
<!-- 离线IP地址定位库 -->
|
||||
<ip2region.version>2.7.0</ip2region.version>
|
||||
|
||||
<!-- OSS 配置 -->
|
||||
<aws.sdk.version>2.28.22</aws.sdk.version>
|
||||
<!-- SMS 配置 -->
|
||||
@@ -47,15 +46,15 @@
|
||||
<!-- 限制框架中的fastjson版本 -->
|
||||
<fastjson.version>1.2.83</fastjson.version>
|
||||
<!-- 面向运行时的D-ORM依赖 -->
|
||||
<anyline.version>8.7.2-20250101</anyline.version>
|
||||
<anyline.version>8.7.2-20250603</anyline.version>
|
||||
<!-- 工作流配置 -->
|
||||
<warm-flow.version>1.7.3</warm-flow.version>
|
||||
<warm-flow.version>1.7.4</warm-flow.version>
|
||||
|
||||
<!-- 插件版本 -->
|
||||
<maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
|
||||
<maven-war-plugin.version>3.2.2</maven-war-plugin.version>
|
||||
<maven-compiler-plugin.version>3.11.0</maven-compiler-plugin.version>
|
||||
<maven-surefire-plugin.version>3.1.2</maven-surefire-plugin.version>
|
||||
<maven-jar-plugin.version>3.4.2</maven-jar-plugin.version>
|
||||
<maven-war-plugin.version>3.4.0</maven-war-plugin.version>
|
||||
<maven-compiler-plugin.version>3.14.0</maven-compiler-plugin.version>
|
||||
<maven-surefire-plugin.version>3.5.3</maven-surefire-plugin.version>
|
||||
<flatten-maven-plugin.version>1.3.0</flatten-maven-plugin.version>
|
||||
<!-- 打包默认跳过测试 -->
|
||||
<skipTests>true</skipTests>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 贝尔实验室 Spring 官方推荐镜像 JDK下载地址 https://bell-sw.com/pages/downloads/
|
||||
FROM bellsoft/liberica-openjdk-debian:17.0.11-cds
|
||||
#FROM bellsoft/liberica-openjdk-debian:21.0.5-cds
|
||||
FROM bellsoft/liberica-openjdk-rocky:17.0.15-cds
|
||||
#FROM bellsoft/liberica-openjdk-rocky:21.0.7-cds
|
||||
#FROM findepi/graalvm:java17-native
|
||||
|
||||
LABEL maintainer="Lion Li"
|
||||
|
||||
@@ -21,6 +21,8 @@ import org.dromara.common.core.domain.model.SocialLoginBody;
|
||||
import org.dromara.common.core.utils.*;
|
||||
import org.dromara.common.encrypt.annotation.ApiEncrypt;
|
||||
import org.dromara.common.json.utils.JsonUtils;
|
||||
import org.dromara.common.ratelimiter.annotation.RateLimiter;
|
||||
import org.dromara.common.ratelimiter.enums.LimitType;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.common.social.config.properties.SocialLoginConfigProperties;
|
||||
import org.dromara.common.social.config.properties.SocialProperties;
|
||||
@@ -198,6 +200,7 @@ public class AuthController {
|
||||
*
|
||||
* @return 租户列表
|
||||
*/
|
||||
@RateLimiter(time = 60, count = 20, limitType = LimitType.IP)
|
||||
@GetMapping("/tenant/list")
|
||||
public R<LoginTenantVo> tenantList(HttpServletRequest request) throws Exception {
|
||||
// 返回对象
|
||||
|
||||
@@ -158,6 +158,6 @@ public class UserActionListener implements SaTokenListener {
|
||||
* 每次Token续期时触发
|
||||
*/
|
||||
@Override
|
||||
public void doRenewTimeout(String tokenValue, Object loginId, long timeout) {
|
||||
public void doRenewTimeout(String loginType, Object loginId, String tokenValue, long timeout) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,7 @@ package org.dromara.web.service.impl;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.hutool.http.Method;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
@@ -68,15 +65,6 @@ public class SocialAuthStrategy implements IAuthStrategy {
|
||||
throw new ServiceException(response.getMsg());
|
||||
}
|
||||
AuthUser authUserData = response.getData();
|
||||
if ("GITEE".equals(authUserData.getSource())) {
|
||||
// 如用户使用 gitee 登录顺手 star 给作者一点支持 拒绝白嫖
|
||||
HttpUtil.createRequest(Method.PUT, "https://gitee.com/api/v5/user/starred/dromara/RuoYi-Vue-Plus")
|
||||
.formStr(MapUtil.of("access_token", authUserData.getToken().getAccessToken()))
|
||||
.executeAsync();
|
||||
HttpUtil.createRequest(Method.PUT, "https://gitee.com/api/v5/user/starred/dromara/RuoYi-Cloud-Plus")
|
||||
.formStr(MapUtil.of("access_token", authUserData.getToken().getAccessToken()))
|
||||
.executeAsync();
|
||||
}
|
||||
|
||||
List<SysSocialVo> list = sysSocialService.selectByAuthId(authUserData.getSource() + authUserData.getUuid());
|
||||
if (CollUtil.isEmpty(list)) {
|
||||
|
||||
@@ -127,6 +127,7 @@ tenant:
|
||||
- sys_user_role
|
||||
- sys_client
|
||||
- sys_oss_config
|
||||
- flow_spel
|
||||
|
||||
# MyBatisPlus配置
|
||||
# https://baomidou.com/config/
|
||||
@@ -183,19 +184,12 @@ springdoc:
|
||||
# 描述
|
||||
description: '描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...'
|
||||
# 版本
|
||||
version: '版本号: ${ruoyi.version}'
|
||||
version: '版本号: ${project.version}'
|
||||
# 作者信息
|
||||
contact:
|
||||
name: Lion Li
|
||||
email: crazylionli@163.com
|
||||
url: https://gitee.com/dromara/RuoYi-Vue-Plus
|
||||
components:
|
||||
# 鉴权方式配置
|
||||
security-schemes:
|
||||
apiKey:
|
||||
type: APIKEY
|
||||
in: HEADER
|
||||
name: ${sa-token.token-name}
|
||||
#这里定义了两个分组,可定义多个,也可以不定义
|
||||
group-configs:
|
||||
- group: 1.演示模块
|
||||
@@ -213,7 +207,7 @@ springdoc:
|
||||
xss:
|
||||
# 过滤开关
|
||||
enabled: true
|
||||
# 排除链接(多个用逗号分隔)
|
||||
# 排除链接
|
||||
excludeUrls:
|
||||
- /system/notice
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ user.username.length.valid=账户长度必须在{min}到{max}个字符之间
|
||||
user.password.not.blank=用户密码不能为空
|
||||
user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间
|
||||
user.password.not.valid=* 5-50个字符
|
||||
user.password.format.valid=密码必须包含大写字母、小写字母、数字和特殊字符
|
||||
user.email.not.valid=邮箱格式错误
|
||||
user.email.not.blank=邮箱不能为空
|
||||
user.phonenumber.not.blank=用户手机号不能为空
|
||||
|
||||
@@ -17,6 +17,7 @@ user.username.length.valid=Account length must be between {min} and {max} charac
|
||||
user.password.not.blank=Password cannot be empty
|
||||
user.password.length.valid=Password length must be between {min} and {max} characters
|
||||
user.password.not.valid=* 5-50 characters
|
||||
user.password.format.valid=Password must contain uppercase, lowercase, digit, and special character
|
||||
user.email.not.valid=Mailbox format error
|
||||
user.email.not.blank=Mailbox cannot be blank
|
||||
user.phonenumber.not.blank=Phone number cannot be blank
|
||||
|
||||
@@ -17,6 +17,7 @@ user.username.length.valid=账户长度必须在{min}到{max}个字符之间
|
||||
user.password.not.blank=用户密码不能为空
|
||||
user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间
|
||||
user.password.not.valid=* 5-50个字符
|
||||
user.password.format.valid=密码必须包含大写字母、小写字母、数字和特殊字符
|
||||
user.email.not.valid=邮箱格式错误
|
||||
user.email.not.blank=邮箱不能为空
|
||||
user.phonenumber.not.blank=用户手机号不能为空
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
</description>
|
||||
|
||||
<properties>
|
||||
<revision>5.4.0</revision>
|
||||
<revision>5.4.1</revision>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
|
||||
@@ -77,4 +77,9 @@ public interface SystemConstants {
|
||||
*/
|
||||
String ROOT_DEPT_ANCESTORS = "0";
|
||||
|
||||
/**
|
||||
* 默认部门 ID
|
||||
*/
|
||||
Long DEFAULT_DEPT_ID = 100L;
|
||||
|
||||
}
|
||||
|
||||
@@ -52,14 +52,14 @@ public class TaskAssigneeDTO implements Serializable {
|
||||
*/
|
||||
public static <T> List<TaskHandler> convertToHandlerList(
|
||||
List<T> sourceList,
|
||||
Function<T, Long> storageId,
|
||||
Function<T, String> storageId,
|
||||
Function<T, String> handlerCode,
|
||||
Function<T, String> handlerName,
|
||||
Function<T, Long> groupName,
|
||||
Function<T, Date> createTimeMapper) {
|
||||
return sourceList.stream()
|
||||
.map(item -> new TaskHandler(
|
||||
String.valueOf(storageId.apply(item)),
|
||||
storageId.apply(item),
|
||||
handlerCode.apply(item),
|
||||
handlerName.apply(item),
|
||||
groupName != null ? String.valueOf(groupName.apply(item)) : null,
|
||||
|
||||
@@ -27,6 +27,11 @@ public class ProcessEvent implements Serializable {
|
||||
*/
|
||||
private String flowCode;
|
||||
|
||||
/**
|
||||
* 实例id
|
||||
*/
|
||||
private Long instanceId;
|
||||
|
||||
/**
|
||||
* 业务id
|
||||
*/
|
||||
|
||||
@@ -4,6 +4,7 @@ import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 流程任务监听
|
||||
@@ -46,6 +47,11 @@ public class ProcessTaskEvent implements Serializable {
|
||||
*/
|
||||
private Long taskId;
|
||||
|
||||
/**
|
||||
* 实例id
|
||||
*/
|
||||
private Long instanceId;
|
||||
|
||||
/**
|
||||
* 业务id
|
||||
*/
|
||||
@@ -56,4 +62,9 @@ public class ProcessTaskEvent implements Serializable {
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 办理参数
|
||||
*/
|
||||
private Map<String, Object> params;
|
||||
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ public class PasswordLoginBody extends LoginBody {
|
||||
*/
|
||||
@NotBlank(message = "{user.password.not.blank}")
|
||||
@Length(min = 5, max = 30, message = "{user.password.length.valid}")
|
||||
// @Pattern(regexp = RegexConstants.PASSWORD, message = "{user.password.format.valid}")
|
||||
private String password;
|
||||
|
||||
}
|
||||
|
||||
@@ -26,8 +26,12 @@ public class RegisterBody extends LoginBody {
|
||||
*/
|
||||
@NotBlank(message = "{user.password.not.blank}")
|
||||
@Length(min = 5, max = 30, message = "{user.password.length.valid}")
|
||||
// @Pattern(regexp = RegexConstants.PASSWORD, message = "{user.password.format.valid}")
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 用户类型
|
||||
*/
|
||||
private String userType;
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.dromara.common.core.service;
|
||||
import org.dromara.common.core.domain.dto.DeptDTO;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 通用 部门服务
|
||||
@@ -34,4 +35,12 @@ public interface DeptService {
|
||||
*/
|
||||
List<DeptDTO> selectDeptsByList();
|
||||
|
||||
/**
|
||||
* 根据部门 ID 列表查询部门名称映射关系
|
||||
*
|
||||
* @param deptIds 部门 ID 列表
|
||||
* @return Map,其中 key 为部门 ID,value 为对应的部门名称
|
||||
*/
|
||||
Map<Long, String> selectDeptNamesByIds(List<Long> deptIds);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package org.dromara.common.core.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 通用 岗位服务
|
||||
*
|
||||
@@ -7,4 +10,12 @@ package org.dromara.common.core.service;
|
||||
*/
|
||||
public interface PostService {
|
||||
|
||||
/**
|
||||
* 根据岗位 ID 列表查询岗位名称映射关系
|
||||
*
|
||||
* @param postIds 岗位 ID 列表
|
||||
* @return Map,其中 key 为岗位 ID,value 为对应的岗位名称
|
||||
*/
|
||||
Map<Long, String> selectPostNamesByIds(List<Long> postIds);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package org.dromara.common.core.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 通用 角色服务
|
||||
*
|
||||
@@ -7,4 +10,12 @@ package org.dromara.common.core.service;
|
||||
*/
|
||||
public interface RoleService {
|
||||
|
||||
/**
|
||||
* 根据角色 ID 列表查询角色名称映射关系
|
||||
*
|
||||
* @param roleIds 角色 ID 列表
|
||||
* @return Map,其中 key 为角色 ID,value 为对应的角色名称
|
||||
*/
|
||||
Map<Long, String> selectRoleNamesByIds(List<Long> roleIds);
|
||||
|
||||
}
|
||||
|
||||
@@ -100,28 +100,4 @@ public interface UserService {
|
||||
*/
|
||||
Map<Long, String> selectUserNamesByIds(List<Long> userIds);
|
||||
|
||||
/**
|
||||
* 根据角色 ID 列表查询角色名称映射关系
|
||||
*
|
||||
* @param roleIds 角色 ID 列表
|
||||
* @return Map,其中 key 为角色 ID,value 为对应的角色名称
|
||||
*/
|
||||
Map<Long, String> selectRoleNamesByIds(List<Long> roleIds);
|
||||
|
||||
/**
|
||||
* 根据部门 ID 列表查询部门名称映射关系
|
||||
*
|
||||
* @param deptIds 部门 ID 列表
|
||||
* @return Map,其中 key 为部门 ID,value 为对应的部门名称
|
||||
*/
|
||||
Map<Long, String> selectDeptNamesByIds(List<Long> deptIds);
|
||||
|
||||
/**
|
||||
* 根据岗位 ID 列表查询岗位名称映射关系
|
||||
*
|
||||
* @param postIds 岗位 ID 列表
|
||||
* @return Map,其中 key 为岗位 ID,value 为对应的岗位名称
|
||||
*/
|
||||
Map<Long, String> selectPostNamesByIds(List<Long> postIds);
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import lombok.NoArgsConstructor;
|
||||
import org.dromara.common.core.utils.reflect.ReflectUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@@ -60,6 +62,31 @@ public class TreeBuildUtils extends TreeUtil {
|
||||
return TreeUtil.build(list, parentId, DEFAULT_CONFIG, nodeParser);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建多根节点的树结构(支持多个顶级节点)
|
||||
*
|
||||
* @param list 原始数据列表
|
||||
* @param getId 获取节点 ID 的方法引用,例如:node -> node.getId()
|
||||
* @param getParentId 获取节点父级 ID 的方法引用,例如:node -> node.getParentId()
|
||||
* @param parser 树节点属性映射器,用于将原始节点 T 转为 Tree 节点
|
||||
* @param <T> 原始数据类型(如实体类、DTO 等)
|
||||
* @param <K> 节点 ID 类型(如 Long、String)
|
||||
* @return 构建完成的树形结构(可能包含多个顶级根节点)
|
||||
*/
|
||||
public static <T, K> List<Tree<K>> buildMultiRoot(List<T> list, Function<T, K> getId, Function<T, K> getParentId, NodeParser<T, K> parser) {
|
||||
if (CollUtil.isEmpty(list)) {
|
||||
return CollUtil.newArrayList();
|
||||
}
|
||||
|
||||
Set<K> rootParentIds = StreamUtils.toSet(list, getParentId);
|
||||
rootParentIds.removeAll(StreamUtils.toSet(list, getId));
|
||||
|
||||
// 构建每一个根 parentId 下的树,并合并成最终结果列表
|
||||
return rootParentIds.stream()
|
||||
.flatMap(rootParentId -> TreeUtil.build(list, rootParentId, parser).stream())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取节点列表中所有节点的叶子节点
|
||||
*
|
||||
|
||||
@@ -16,28 +16,55 @@ import org.dromara.common.core.utils.StringUtils;
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class AddressUtils {
|
||||
|
||||
// 未知IP
|
||||
public static final String UNKNOWN_IP = "XX XX";
|
||||
// 内网地址
|
||||
public static final String LOCAL_ADDRESS = "内网IP";
|
||||
// 未知地址
|
||||
public static final String UNKNOWN = "XX XX";
|
||||
public static final String UNKNOWN_ADDRESS = "未知";
|
||||
|
||||
public static String getRealAddressByIP(String ip) {
|
||||
// 处理空串并过滤HTML标签
|
||||
ip = HtmlUtil.cleanHtmlTag(StringUtils.blankToDefault(ip,""));
|
||||
boolean isIPv6 = NetUtils.isIPv6(ip);
|
||||
// 判断是否为IPv4或IPv6,如果不是则返回未知地址
|
||||
if (!NetUtils.isIPv4(ip) && !isIPv6) {
|
||||
return UNKNOWN;
|
||||
// 判断是否为IPv4
|
||||
if (NetUtils.isIPv4(ip)) {
|
||||
return resolverIPv4Region(ip);
|
||||
}
|
||||
// 判断是否为IPv6
|
||||
if (NetUtils.isIPv6(ip)) {
|
||||
return resolverIPv6Region(ip);
|
||||
}
|
||||
// 如果不是IPv4或IPv6,则返回未知IP
|
||||
return UNKNOWN_IP;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据IPv4地址查询IP归属行政区域
|
||||
* @param ip ipv4地址
|
||||
* @return 归属行政区域
|
||||
*/
|
||||
private static String resolverIPv4Region(String ip){
|
||||
// 内网不查询
|
||||
if (NetUtils.isInnerIPv6(ip) || NetUtils.isInnerIP(ip)) {
|
||||
return "内网IP";
|
||||
}
|
||||
// 不支持IPv6,不再进行没有必要的IP地址信息的解析,直接返回
|
||||
if (isIPv6) {
|
||||
log.warn("ip2region不支持IPV6地址解析:{}", ip);
|
||||
// 如有需要,可自行实现IPv6地址信息解析逻辑,并在这里返回
|
||||
return "未知";
|
||||
if (NetUtils.isInnerIP(ip)) {
|
||||
return LOCAL_ADDRESS;
|
||||
}
|
||||
return RegionUtils.getCityInfo(ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据IPv6地址查询IP归属行政区域
|
||||
* @param ip ipv6地址
|
||||
* @return 归属行政区域
|
||||
*/
|
||||
private static String resolverIPv6Region(String ip){
|
||||
// 内网不查询
|
||||
if (NetUtils.isInnerIPv6(ip)) {
|
||||
return LOCAL_ADDRESS;
|
||||
}
|
||||
log.warn("ip2region不支持IPV6地址解析:{}", ip);
|
||||
// 不支持IPv6,不再进行没有必要的IP地址信息的解析,直接返回
|
||||
// 如有需要,可自行实现IPv6地址信息解析逻辑,并在这里返回
|
||||
return UNKNOWN_ADDRESS;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ public class SpringDocConfig {
|
||||
openApi.externalDocs(properties.getExternalDocs());
|
||||
openApi.tags(properties.getTags());
|
||||
openApi.paths(properties.getPaths());
|
||||
if (properties.getComponents() != null) {
|
||||
openApi.components(properties.getComponents());
|
||||
Set<String> keySet = properties.getComponents().getSecuritySchemes().keySet();
|
||||
List<SecurityRequirement> list = new ArrayList<>();
|
||||
@@ -61,7 +62,7 @@ public class SpringDocConfig {
|
||||
keySet.forEach(securityRequirement::addList);
|
||||
list.add(securityRequirement);
|
||||
openApi.security(list);
|
||||
|
||||
}
|
||||
return openApi;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.ibatis.executor.parameter.ParameterHandler;
|
||||
import org.apache.ibatis.executor.resultset.ResultSetHandler;
|
||||
import org.apache.ibatis.plugin.*;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
@@ -39,12 +40,23 @@ public class MybatisDecryptInterceptor implements Interceptor {
|
||||
|
||||
@Override
|
||||
public Object intercept(Invocation invocation) throws Throwable {
|
||||
// 开始进行参数解密
|
||||
ResultSetHandler resultSetHandler = (ResultSetHandler) invocation.getTarget();
|
||||
Field parameterHandlerField = resultSetHandler.getClass().getDeclaredField("parameterHandler");
|
||||
parameterHandlerField.setAccessible(true);
|
||||
Object target = parameterHandlerField.get(resultSetHandler);
|
||||
if (target instanceof ParameterHandler parameterHandler) {
|
||||
Object parameterObject = parameterHandler.getParameterObject();
|
||||
if (ObjectUtil.isNotNull(parameterObject) && !(parameterObject instanceof String)) {
|
||||
this.decryptHandler(parameterObject);
|
||||
}
|
||||
}
|
||||
// 获取执行mysql执行结果
|
||||
Object result = invocation.proceed();
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
decryptHandler(result);
|
||||
this.decryptHandler(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,17 +6,13 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 批注
|
||||
* 批注 此注解仅用于单表头 不支持多层级表头
|
||||
* @author guzhouyanyu
|
||||
*/
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ExcelNotation {
|
||||
|
||||
/**
|
||||
* col index
|
||||
*/
|
||||
int index() default -1;
|
||||
/**
|
||||
* 批注内容
|
||||
*/
|
||||
|
||||
@@ -8,17 +8,13 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 是否必填
|
||||
* 是否必填 此注解仅用于单表头 不支持多层级表头
|
||||
* @author guzhouyanyu
|
||||
*/
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ExcelRequired {
|
||||
|
||||
/**
|
||||
* col index
|
||||
*/
|
||||
int index() default -1;
|
||||
/**
|
||||
* 字体颜色
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.dromara.common.excel.handler;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import cn.idev.excel.metadata.data.DataFormatData;
|
||||
import cn.idev.excel.metadata.data.WriteCellData;
|
||||
import cn.idev.excel.util.StyleUtil;
|
||||
@@ -13,7 +14,6 @@ import cn.idev.excel.write.metadata.style.WriteFont;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
|
||||
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
|
||||
import org.dromara.common.core.utils.reflect.ReflectUtils;
|
||||
import org.dromara.common.excel.annotation.ExcelNotation;
|
||||
import org.dromara.common.excel.annotation.ExcelRequired;
|
||||
|
||||
@@ -31,12 +31,12 @@ public class DataWriteHandler implements SheetWriteHandler, CellWriteHandler {
|
||||
/**
|
||||
* 批注
|
||||
*/
|
||||
private final Map<Integer, String> notationMap;
|
||||
private final Map<String, String> notationMap;
|
||||
|
||||
/**
|
||||
* 头列字体颜色
|
||||
*/
|
||||
private final Map<Integer, Short> headColumnMap;
|
||||
private final Map<String, Short> headColumnMap;
|
||||
|
||||
|
||||
public DataWriteHandler(Class<?> clazz) {
|
||||
@@ -49,15 +49,16 @@ public class DataWriteHandler implements SheetWriteHandler, CellWriteHandler {
|
||||
if (CollUtil.isEmpty(notationMap) && CollUtil.isEmpty(headColumnMap)) {
|
||||
return;
|
||||
}
|
||||
// 第一行
|
||||
WriteCellData<?> cellData = context.getFirstCellData();
|
||||
// 第一个格子
|
||||
WriteCellStyle writeCellStyle = cellData.getOrCreateStyle();
|
||||
|
||||
if (context.getHead()) {
|
||||
DataFormatData dataFormatData = new DataFormatData();
|
||||
// 单元格设置为文本格式
|
||||
dataFormatData.setIndex((short) 49);
|
||||
writeCellStyle.setDataFormatData(dataFormatData);
|
||||
|
||||
if (context.getHead()) {
|
||||
Cell cell = context.getCell();
|
||||
WriteSheetHolder writeSheetHolder = context.getWriteSheetHolder();
|
||||
Sheet sheet = writeSheetHolder.getSheet();
|
||||
@@ -67,17 +68,17 @@ public class DataWriteHandler implements SheetWriteHandler, CellWriteHandler {
|
||||
WriteFont headWriteFont = new WriteFont();
|
||||
// 加粗
|
||||
headWriteFont.setBold(true);
|
||||
if (CollUtil.isNotEmpty(headColumnMap) && headColumnMap.containsKey(cell.getColumnIndex())) {
|
||||
if (CollUtil.isNotEmpty(headColumnMap) && headColumnMap.containsKey(cell.getStringCellValue())) {
|
||||
// 设置字体颜色
|
||||
headWriteFont.setColor(headColumnMap.get(cell.getColumnIndex()));
|
||||
headWriteFont.setColor(headColumnMap.get(cell.getStringCellValue()));
|
||||
}
|
||||
writeCellStyle.setWriteFont(headWriteFont);
|
||||
CellStyle cellStyle = StyleUtil.buildCellStyle(workbook, null, writeCellStyle);
|
||||
cell.setCellStyle(cellStyle);
|
||||
|
||||
if (CollUtil.isNotEmpty(notationMap) && notationMap.containsKey(cell.getColumnIndex())) {
|
||||
if (CollUtil.isNotEmpty(notationMap) && notationMap.containsKey(cell.getStringCellValue())) {
|
||||
// 批注内容
|
||||
String notationContext = notationMap.get(cell.getColumnIndex());
|
||||
String notationContext = notationMap.get(cell.getStringCellValue());
|
||||
// 创建绘图对象
|
||||
Comment comment = drawing.createCellComment(new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), 0, (short) 5, 5));
|
||||
comment.setString(new XSSFRichTextString(notationContext));
|
||||
@@ -89,23 +90,16 @@ public class DataWriteHandler implements SheetWriteHandler, CellWriteHandler {
|
||||
/**
|
||||
* 获取必填列
|
||||
*/
|
||||
private static Map<Integer, Short> getRequiredMap(Class<?> clazz) {
|
||||
Map<Integer, Short> requiredMap = new HashMap<>();
|
||||
private static Map<String, Short> getRequiredMap(Class<?> clazz) {
|
||||
Map<String, Short> requiredMap = new HashMap<>();
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
// 检查 fields 数组是否为空
|
||||
if (fields.length == 0) {
|
||||
return requiredMap;
|
||||
}
|
||||
Field[] filteredFields = ReflectUtils.getFields(clazz, field -> !"serialVersionUID".equals(field.getName()));
|
||||
|
||||
for (int i = 0; i < filteredFields.length; i++) {
|
||||
Field field = filteredFields[i];
|
||||
for (Field field : fields) {
|
||||
if (!field.isAnnotationPresent(ExcelRequired.class)) {
|
||||
continue;
|
||||
}
|
||||
ExcelRequired excelRequired = field.getAnnotation(ExcelRequired.class);
|
||||
int columnIndex = excelRequired.index() == -1 ? i : excelRequired.index();
|
||||
requiredMap.put(columnIndex, excelRequired.fontColor().getIndex());
|
||||
ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
|
||||
requiredMap.put(excelProperty.value()[0], excelRequired.fontColor().getIndex());
|
||||
}
|
||||
return requiredMap;
|
||||
}
|
||||
@@ -113,22 +107,16 @@ public class DataWriteHandler implements SheetWriteHandler, CellWriteHandler {
|
||||
/**
|
||||
* 获取批注
|
||||
*/
|
||||
private static Map<Integer, String> getNotationMap(Class<?> clazz) {
|
||||
Map<Integer, String> notationMap = new HashMap<>();
|
||||
private static Map<String, String> getNotationMap(Class<?> clazz) {
|
||||
Map<String, String> notationMap = new HashMap<>();
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
// 检查 fields 数组是否为空
|
||||
if (fields.length == 0) {
|
||||
return notationMap;
|
||||
}
|
||||
Field[] filteredFields = ReflectUtils.getFields(clazz, field -> !"serialVersionUID".equals(field.getName()));
|
||||
for (int i = 0; i < filteredFields.length; i++) {
|
||||
Field field = filteredFields[i];
|
||||
for (Field field : fields) {
|
||||
if (!field.isAnnotationPresent(ExcelNotation.class)) {
|
||||
continue;
|
||||
}
|
||||
ExcelNotation excelNotation = field.getAnnotation(ExcelNotation.class);
|
||||
int columnIndex = excelNotation.index() == -1 ? i : excelNotation.index();
|
||||
notationMap.put(columnIndex, excelNotation.value());
|
||||
ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
|
||||
notationMap.put(excelProperty.value()[0], excelNotation.value());
|
||||
}
|
||||
return notationMap;
|
||||
}
|
||||
|
||||
@@ -27,9 +27,7 @@ import org.springframework.http.HttpMethod;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 操作日志记录处理
|
||||
@@ -176,15 +174,29 @@ public class LogAspect {
|
||||
if (ArrayUtil.isEmpty(paramsArray)) {
|
||||
return params.toString();
|
||||
}
|
||||
String[] exclude = ArrayUtil.addAll(excludeParamNames, EXCLUDE_PROPERTIES);
|
||||
for (Object o : paramsArray) {
|
||||
if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) {
|
||||
String str = JsonUtils.toJsonString(o);
|
||||
String str = "";
|
||||
if (o instanceof List<?> list) {
|
||||
List<Dict> list1 = new ArrayList<>();
|
||||
for (Object obj : list) {
|
||||
String str1 = JsonUtils.toJsonString(obj);
|
||||
Dict dict = JsonUtils.parseMap(str1);
|
||||
if (MapUtil.isNotEmpty(dict)) {
|
||||
MapUtil.removeAny(dict, exclude);
|
||||
list1.add(dict);
|
||||
}
|
||||
}
|
||||
str = JsonUtils.toJsonString(list1);
|
||||
} else {
|
||||
str = JsonUtils.toJsonString(o);
|
||||
Dict dict = JsonUtils.parseMap(str);
|
||||
if (MapUtil.isNotEmpty(dict)) {
|
||||
MapUtil.removeAny(dict, EXCLUDE_PROPERTIES);
|
||||
MapUtil.removeAny(dict, excludeParamNames);
|
||||
MapUtil.removeAny(dict, exclude);
|
||||
str = JsonUtils.toJsonString(dict);
|
||||
}
|
||||
}
|
||||
params.add(str);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package org.dromara.common.mybatis.aspect;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.dromara.common.mybatis.annotation.DataPermission;
|
||||
import org.dromara.common.mybatis.helper.DataPermissionHelper;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
/**
|
||||
* 数据权限注解Advice
|
||||
*
|
||||
* @author 秋辞未寒
|
||||
*/
|
||||
@Slf4j
|
||||
public class DataPermissionAdvice implements MethodInterceptor {
|
||||
|
||||
@Override
|
||||
public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||
Object target = invocation.getThis();
|
||||
Method method = invocation.getMethod();
|
||||
Object[] args = invocation.getArguments();
|
||||
// 设置权限注解
|
||||
DataPermissionHelper.setPermission(getDataPermissionAnnotation(target, method, args));
|
||||
try {
|
||||
// 执行代理方法
|
||||
return invocation.proceed();
|
||||
} finally {
|
||||
// 清除权限注解
|
||||
DataPermissionHelper.removePermission();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据权限注解
|
||||
*/
|
||||
private DataPermission getDataPermissionAnnotation(Object target, Method method,Object[] args){
|
||||
DataPermission dataPermission = method.getAnnotation(DataPermission.class);
|
||||
// 优先获取方法上的注解
|
||||
if (dataPermission != null) {
|
||||
return dataPermission;
|
||||
}
|
||||
// 方法上没有注解,则获取类上的注解
|
||||
Class<?> targetClass = target.getClass();
|
||||
// 如果是 JDK 动态代理,则获取真实的Class实例
|
||||
if (Proxy.isProxyClass(targetClass)) {
|
||||
targetClass = targetClass.getInterfaces()[0];
|
||||
}
|
||||
dataPermission = targetClass.getAnnotation(DataPermission.class);
|
||||
return dataPermission;
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package org.dromara.common.mybatis.aspect;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.AfterReturning;
|
||||
import org.aspectj.lang.annotation.AfterThrowing;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Before;
|
||||
import org.dromara.common.mybatis.annotation.DataPermission;
|
||||
import org.dromara.common.mybatis.helper.DataPermissionHelper;
|
||||
|
||||
/**
|
||||
* 数据权限处理
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Slf4j
|
||||
@Aspect
|
||||
public class DataPermissionAspect {
|
||||
|
||||
/**
|
||||
* 处理请求前执行
|
||||
*/
|
||||
@Before(value = "@annotation(dataPermission)")
|
||||
public void doBefore(JoinPoint joinPoint, DataPermission dataPermission) {
|
||||
DataPermissionHelper.setPermission(dataPermission);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理完请求后执行
|
||||
*
|
||||
* @param joinPoint 切点
|
||||
*/
|
||||
@AfterReturning(pointcut = "@annotation(dataPermission)")
|
||||
public void doAfterReturning(JoinPoint joinPoint, DataPermission dataPermission) {
|
||||
DataPermissionHelper.removePermission();
|
||||
}
|
||||
|
||||
/**
|
||||
* 拦截异常操作
|
||||
*
|
||||
* @param joinPoint 切点
|
||||
* @param e 异常
|
||||
*/
|
||||
@AfterThrowing(value = "@annotation(dataPermission)", throwing = "e")
|
||||
public void doAfterThrowing(JoinPoint joinPoint, DataPermission dataPermission, Exception e) {
|
||||
DataPermissionHelper.removePermission();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.dromara.common.mybatis.aspect;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.mybatis.annotation.DataPermission;
|
||||
import org.springframework.aop.support.StaticMethodMatcherPointcut;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
/**
|
||||
* 数据权限匹配切点
|
||||
*
|
||||
* @author 秋辞未寒
|
||||
*/
|
||||
@Slf4j
|
||||
@SuppressWarnings("all")
|
||||
public class DataPermissionPointcut extends StaticMethodMatcherPointcut {
|
||||
|
||||
@Override
|
||||
public boolean matches(Method method, Class<?> targetClass) {
|
||||
// 优先匹配方法
|
||||
// 数据权限注解不对继承生效,所以检查当前方法是否有注解即可,不再往上匹配父类或接口
|
||||
if (method.isAnnotationPresent(DataPermission.class)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// MyBatis 的 Mapper 就是通过 JDK 动态代理实现的,所以这里需要检查是否匹配 JDK 的动态代理
|
||||
Class<?> targetClassRef = targetClass;
|
||||
if (Proxy.isProxyClass(targetClassRef)) {
|
||||
// 数据权限注解不对继承生效,但由于 SpringIOC 容器拿到的实际上是 MyBatis 代理过后的 Mapper,而 targetClass.isAnnotationPresent 实际匹配的是 Proxy 类的注解,不会查找代理类。
|
||||
// 所以这里不能用 targetClass.isAnnotationPresent,只能用 AnnotatedElementUtils.hasAnnotation 或 targetClass.getInterfaces()[0].isAnnotationPresent 去做匹配,以检查被代理的 MapperClass 是否具有注解
|
||||
// 原理:JDK 动态代理本质上就是对接口进行实现然后对具体的接口实现做代理,所以直接通过接口可以拿到实际的 MapperClass
|
||||
targetClassRef = targetClass.getInterfaces()[0];
|
||||
|
||||
}
|
||||
return targetClassRef.isAnnotationPresent(DataPermission.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package org.dromara.common.mybatis.aspect;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.aop.support.AbstractPointcutAdvisor;
|
||||
|
||||
/**
|
||||
* 数据权限注解切面定义
|
||||
*
|
||||
* @author 秋辞未寒
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public class DataPermissionPointcutAdvisor extends AbstractPointcutAdvisor {
|
||||
|
||||
private final Advice advice;
|
||||
private final Pointcut pointcut;
|
||||
|
||||
public DataPermissionPointcutAdvisor() {
|
||||
this.advice = new DataPermissionAdvice();
|
||||
this.pointcut = new DataPermissionPointcut();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pointcut getPointcut() {
|
||||
return this.pointcut;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Advice getAdvice() {
|
||||
return this.advice;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,15 +11,17 @@ import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerIntercept
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
|
||||
import org.dromara.common.core.factory.YmlPropertySourceFactory;
|
||||
import org.dromara.common.core.utils.SpringUtils;
|
||||
import org.dromara.common.mybatis.aspect.DataPermissionAspect;
|
||||
import org.dromara.common.mybatis.aspect.DataPermissionPointcutAdvisor;
|
||||
import org.dromara.common.mybatis.handler.InjectionMetaObjectHandler;
|
||||
import org.dromara.common.mybatis.handler.MybatisExceptionHandler;
|
||||
import org.dromara.common.mybatis.handler.PlusPostInitTableInfoHandler;
|
||||
import org.dromara.common.mybatis.interceptor.PlusDataPermissionInterceptor;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
/**
|
||||
@@ -27,6 +29,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
@EnableTransactionManagement(proxyTargetClass = true)
|
||||
@MapperScan("${mybatis-plus.mapperPackage}")
|
||||
@PropertySource(value = "classpath:common-mybatis.yml", factory = YmlPropertySourceFactory.class)
|
||||
@@ -54,15 +57,16 @@ public class MybatisPlusConfig {
|
||||
* 数据权限拦截器
|
||||
*/
|
||||
public PlusDataPermissionInterceptor dataPermissionInterceptor() {
|
||||
return new PlusDataPermissionInterceptor(SpringUtils.getProperty("mybatis-plus.mapperPackage"));
|
||||
return new PlusDataPermissionInterceptor();
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据权限切面处理器
|
||||
*/
|
||||
@Bean
|
||||
public DataPermissionAspect dataPermissionAspect() {
|
||||
return new DataPermissionAspect();
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public DataPermissionPointcutAdvisor dataPermissionPointcutAdvisor() {
|
||||
return new DataPermissionPointcutAdvisor();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,6 +22,11 @@ import java.util.Date;
|
||||
@Slf4j
|
||||
public class InjectionMetaObjectHandler implements MetaObjectHandler {
|
||||
|
||||
/**
|
||||
* 如果用户不存在默认注入-1代表无用户
|
||||
*/
|
||||
private static final Long DEFAULT_USER_ID = -1L;
|
||||
|
||||
/**
|
||||
* 插入填充方法,用于在插入数据时自动填充实体对象中的创建时间、更新时间、创建人、更新人等信息
|
||||
*
|
||||
@@ -45,6 +50,11 @@ public class InjectionMetaObjectHandler implements MetaObjectHandler {
|
||||
baseEntity.setCreateBy(userId);
|
||||
baseEntity.setUpdateBy(userId);
|
||||
baseEntity.setCreateDept(ObjectUtils.notNull(baseEntity.getCreateDept(), loginUser.getDeptId()));
|
||||
} else {
|
||||
// 填充创建人、更新人和创建部门信息
|
||||
baseEntity.setCreateBy(DEFAULT_USER_ID);
|
||||
baseEntity.setUpdateBy(DEFAULT_USER_ID);
|
||||
baseEntity.setCreateDept(ObjectUtils.notNull(baseEntity.getCreateDept(), DEFAULT_USER_ID));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -74,6 +84,8 @@ public class InjectionMetaObjectHandler implements MetaObjectHandler {
|
||||
Long userId = LoginHelper.getUserId();
|
||||
if (ObjectUtil.isNotNull(userId)) {
|
||||
baseEntity.setUpdateBy(userId);
|
||||
} else {
|
||||
baseEntity.setUpdateBy(DEFAULT_USER_ID);
|
||||
}
|
||||
} else {
|
||||
this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
|
||||
@@ -93,7 +105,6 @@ public class InjectionMetaObjectHandler implements MetaObjectHandler {
|
||||
try {
|
||||
loginUser = LoginHelper.getLoginUser();
|
||||
} catch (Exception e) {
|
||||
log.warn("自动注入警告 => 用户未登录");
|
||||
return null;
|
||||
}
|
||||
return loginUser;
|
||||
|
||||
@@ -49,11 +49,6 @@ import java.util.function.Function;
|
||||
@Slf4j
|
||||
public class PlusDataPermissionHandler {
|
||||
|
||||
/**
|
||||
* 类名称与注解的映射关系缓存(由于aop无法拦截mybatis接口类上的注解 只能通过启动预扫描的方式进行)
|
||||
*/
|
||||
private final Map<String, DataPermission> dataPermissionCacheMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* spel 解析器
|
||||
*/
|
||||
@@ -64,27 +59,17 @@ public class PlusDataPermissionHandler {
|
||||
*/
|
||||
private final BeanResolver beanResolver = new BeanFactoryResolver(SpringUtils.getBeanFactory());
|
||||
|
||||
/**
|
||||
* 构造方法,扫描指定包下的 Mapper 类并初始化缓存
|
||||
*
|
||||
* @param mapperPackage Mapper 类所在的包路径
|
||||
*/
|
||||
public PlusDataPermissionHandler(String mapperPackage) {
|
||||
scanMapperClasses(mapperPackage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据过滤条件的 SQL 片段
|
||||
*
|
||||
* @param where 原始的查询条件表达式
|
||||
* @param mappedStatementId Mapper 方法的 ID
|
||||
* @param isSelect 是否为查询语句
|
||||
* @return 数据过滤条件的 SQL 片段
|
||||
*/
|
||||
public Expression getSqlSegment(Expression where, String mappedStatementId, boolean isSelect) {
|
||||
public Expression getSqlSegment(Expression where, boolean isSelect) {
|
||||
try {
|
||||
// 获取数据权限配置
|
||||
DataPermission dataPermission = getDataPermission(mappedStatementId);
|
||||
DataPermission dataPermission = getDataPermission();
|
||||
// 获取当前登录用户信息
|
||||
LoginUser currentUser = DataPermissionHelper.getVariable("user");
|
||||
if (ObjectUtil.isNull(currentUser)) {
|
||||
@@ -206,92 +191,22 @@ public class PlusDataPermissionHandler {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫描指定包下的 Mapper 类,并查找其中带有特定注解的方法或类
|
||||
*
|
||||
* @param mapperPackage Mapper 类所在的包路径
|
||||
*/
|
||||
private void scanMapperClasses(String mapperPackage) {
|
||||
// 创建资源解析器和元数据读取工厂
|
||||
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
|
||||
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
|
||||
// 将 Mapper 包路径按分隔符拆分为数组
|
||||
String[] packagePatternArray = StringUtils.splitPreserveAllTokens(mapperPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
|
||||
String classpath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX;
|
||||
try {
|
||||
for (String packagePattern : packagePatternArray) {
|
||||
// 将包路径转换为资源路径
|
||||
String path = ClassUtils.convertClassNameToResourcePath(packagePattern);
|
||||
// 获取指定路径下的所有 .class 文件资源
|
||||
Resource[] resources = resolver.getResources(classpath + path + "/*.class");
|
||||
for (Resource resource : resources) {
|
||||
// 获取资源的类元数据
|
||||
ClassMetadata classMetadata = factory.getMetadataReader(resource).getClassMetadata();
|
||||
// 获取资源对应的类对象
|
||||
Class<?> clazz = Resources.classForName(classMetadata.getClassName());
|
||||
// 查找类中的特定注解
|
||||
findAnnotation(clazz);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("初始化数据安全缓存时出错:{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在指定的类中查找特定的注解 DataPermission,并将带有这个注解的方法或类存储到 dataPermissionCacheMap 中
|
||||
*
|
||||
* @param clazz 要查找的类
|
||||
*/
|
||||
private void findAnnotation(Class<?> clazz) {
|
||||
DataPermission dataPermission;
|
||||
for (Method method : clazz.getMethods()) {
|
||||
if (method.isDefault() || method.isVarArgs()) {
|
||||
continue;
|
||||
}
|
||||
String mappedStatementId = clazz.getName() + "." + method.getName();
|
||||
if (AnnotationUtil.hasAnnotation(method, DataPermission.class)) {
|
||||
dataPermission = AnnotationUtil.getAnnotation(method, DataPermission.class);
|
||||
dataPermissionCacheMap.put(mappedStatementId, dataPermission);
|
||||
}
|
||||
}
|
||||
if (AnnotationUtil.hasAnnotation(clazz, DataPermission.class)) {
|
||||
dataPermission = AnnotationUtil.getAnnotation(clazz, DataPermission.class);
|
||||
dataPermissionCacheMap.put(clazz.getName(), dataPermission);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据映射语句 ID 或类名获取对应的 DataPermission 注解对象
|
||||
*
|
||||
* @param mapperId 映射语句 ID
|
||||
* @return DataPermission 注解对象,如果不存在则返回 null
|
||||
*/
|
||||
public DataPermission getDataPermission(String mapperId) {
|
||||
// 检查上下文中是否包含映射语句 ID 对应的 DataPermission 注解对象
|
||||
if (DataPermissionHelper.getPermission() != null) {
|
||||
public DataPermission getDataPermission() {
|
||||
return DataPermissionHelper.getPermission();
|
||||
}
|
||||
// 检查缓存中是否包含映射语句 ID 对应的 DataPermission 注解对象
|
||||
if (dataPermissionCacheMap.containsKey(mapperId)) {
|
||||
return dataPermissionCacheMap.get(mapperId);
|
||||
}
|
||||
// 如果缓存中不包含映射语句 ID 对应的 DataPermission 注解对象,则尝试使用类名作为键查找
|
||||
String clazzName = mapperId.substring(0, mapperId.lastIndexOf("."));
|
||||
if (dataPermissionCacheMap.containsKey(clazzName)) {
|
||||
return dataPermissionCacheMap.get(clazzName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查给定的映射语句 ID 是否有效,即是否能够找到对应的 DataPermission 注解对象
|
||||
*
|
||||
* @param mapperId 映射语句 ID
|
||||
* @return 如果找到对应的 DataPermission 注解对象,则返回 false;否则返回 true
|
||||
*/
|
||||
public boolean invalid(String mapperId) {
|
||||
return getDataPermission(mapperId) == null;
|
||||
public boolean invalid() {
|
||||
return getDataPermission() == null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -35,16 +35,7 @@ import java.util.List;
|
||||
@Slf4j
|
||||
public class PlusDataPermissionInterceptor extends BaseMultiTableInnerInterceptor implements InnerInterceptor {
|
||||
|
||||
private final PlusDataPermissionHandler dataPermissionHandler;
|
||||
|
||||
/**
|
||||
* 构造函数,初始化 PlusDataPermissionHandler 实例
|
||||
*
|
||||
* @param mapperPackage 扫描的映射器包
|
||||
*/
|
||||
public PlusDataPermissionInterceptor(String mapperPackage) {
|
||||
this.dataPermissionHandler = new PlusDataPermissionHandler(mapperPackage);
|
||||
}
|
||||
private final PlusDataPermissionHandler dataPermissionHandler = new PlusDataPermissionHandler();
|
||||
|
||||
/**
|
||||
* 在执行查询之前,检查并处理数据权限相关逻辑
|
||||
@@ -64,7 +55,7 @@ public class PlusDataPermissionInterceptor extends BaseMultiTableInnerIntercepto
|
||||
return;
|
||||
}
|
||||
// 检查是否缺少有效的数据权限注解
|
||||
if (dataPermissionHandler.invalid(ms.getId())) {
|
||||
if (dataPermissionHandler.invalid()) {
|
||||
return;
|
||||
}
|
||||
// 解析 sql 分配对应方法
|
||||
@@ -92,7 +83,7 @@ public class PlusDataPermissionInterceptor extends BaseMultiTableInnerIntercepto
|
||||
return;
|
||||
}
|
||||
// 检查是否缺少有效的数据权限注解
|
||||
if (dataPermissionHandler.invalid(ms.getId())) {
|
||||
if (dataPermissionHandler.invalid()) {
|
||||
return;
|
||||
}
|
||||
PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql();
|
||||
@@ -128,7 +119,7 @@ public class PlusDataPermissionInterceptor extends BaseMultiTableInnerIntercepto
|
||||
*/
|
||||
@Override
|
||||
protected void processUpdate(Update update, int index, String sql, Object obj) {
|
||||
Expression sqlSegment = dataPermissionHandler.getSqlSegment(update.getWhere(), (String) obj, false);
|
||||
Expression sqlSegment = dataPermissionHandler.getSqlSegment(update.getWhere(), false);
|
||||
if (null != sqlSegment) {
|
||||
update.setWhere(sqlSegment);
|
||||
}
|
||||
@@ -144,7 +135,7 @@ public class PlusDataPermissionInterceptor extends BaseMultiTableInnerIntercepto
|
||||
*/
|
||||
@Override
|
||||
protected void processDelete(Delete delete, int index, String sql, Object obj) {
|
||||
Expression sqlSegment = dataPermissionHandler.getSqlSegment(delete.getWhere(), (String) obj, false);
|
||||
Expression sqlSegment = dataPermissionHandler.getSqlSegment(delete.getWhere(), false);
|
||||
if (null != sqlSegment) {
|
||||
delete.setWhere(sqlSegment);
|
||||
}
|
||||
@@ -157,7 +148,7 @@ public class PlusDataPermissionInterceptor extends BaseMultiTableInnerIntercepto
|
||||
* @param mappedStatementId 映射语句的 ID
|
||||
*/
|
||||
protected void setWhere(PlainSelect plainSelect, String mappedStatementId) {
|
||||
Expression sqlSegment = dataPermissionHandler.getSqlSegment(plainSelect.getWhere(), mappedStatementId, true);
|
||||
Expression sqlSegment = dataPermissionHandler.getSqlSegment(plainSelect.getWhere(), true);
|
||||
if (null != sqlSegment) {
|
||||
plainSelect.setWhere(sqlSegment);
|
||||
}
|
||||
|
||||
@@ -177,12 +177,12 @@ public class OssClient {
|
||||
// 创建异步请求体(length如果为空会报错)
|
||||
BlockingInputStreamAsyncRequestBody body = BlockingInputStreamAsyncRequestBody.builder()
|
||||
.contentLength(length)
|
||||
.subscribeTimeout(Duration.ofSeconds(30))
|
||||
.subscribeTimeout(Duration.ofSeconds(120))
|
||||
.build();
|
||||
|
||||
// 使用 transferManager 进行上传
|
||||
Upload upload = transferManager.upload(
|
||||
x -> x.requestBody(body)
|
||||
x -> x.requestBody(body).addTransferListener(LoggingTransferListener.create())
|
||||
.putObjectRequest(
|
||||
y -> y.bucket(properties.getBucketName())
|
||||
.key(key)
|
||||
|
||||
@@ -16,7 +16,9 @@ import java.util.function.Function;
|
||||
*
|
||||
* @author Lion Li
|
||||
* @version 3.6.0 新增
|
||||
* @deprecated redisson 新版本已经将队列功能标记删除 一些技术问题无法解决 建议搭建MQ使用
|
||||
*/
|
||||
@Deprecated
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class QueueUtils {
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.dromara.common.redis.utils;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.dromara.common.core.utils.SpringUtils;
|
||||
@@ -10,6 +9,10 @@ import org.redisson.api.RIdGenerator;
|
||||
import org.redisson.api.RedissonClient;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
|
||||
/**
|
||||
* 发号器工具类
|
||||
@@ -23,12 +26,12 @@ public class SequenceUtils {
|
||||
/**
|
||||
* 默认初始值
|
||||
*/
|
||||
public static final Long DEFAULT_INIT_VALUE = 1L;
|
||||
public static final long DEFAULT_INIT_VALUE = 1L;
|
||||
|
||||
/**
|
||||
* 默认步长
|
||||
*/
|
||||
public static final Long DEFAULT_STEP_VALUE = 1L;
|
||||
public static final long DEFAULT_STEP_VALUE = 1L;
|
||||
|
||||
/**
|
||||
* 默认过期时间-天
|
||||
@@ -40,6 +43,11 @@ public class SequenceUtils {
|
||||
*/
|
||||
public static final Duration DEFAULT_EXPIRE_TIME_MINUTE = Duration.ofMinutes(1);
|
||||
|
||||
/**
|
||||
* 默认最小ID容量位数 - 6位数(即至少可以生成的ID为999999个)
|
||||
*/
|
||||
public static final int DEFAULT_MIN_ID_CAPACITY_BITS = 6;
|
||||
|
||||
/**
|
||||
* 获取Redisson客户端实例
|
||||
*/
|
||||
@@ -54,14 +62,11 @@ public class SequenceUtils {
|
||||
* @param stepValue ID步长
|
||||
* @return ID生成器
|
||||
*/
|
||||
private static RIdGenerator getIdGenerator(String key, Duration expireTime, Long initValue, Long stepValue) {
|
||||
if (initValue == null || initValue <= 0) {
|
||||
initValue = DEFAULT_INIT_VALUE;
|
||||
}
|
||||
if (stepValue == null || stepValue <= 0) {
|
||||
stepValue = DEFAULT_STEP_VALUE;
|
||||
}
|
||||
public static RIdGenerator getIdGenerator(String key, Duration expireTime, long initValue, long stepValue) {
|
||||
RIdGenerator idGenerator = REDISSON_CLIENT.getIdGenerator(key);
|
||||
// 初始值和步长不能小于等于0
|
||||
initValue = initValue <= 0 ? DEFAULT_INIT_VALUE : initValue;
|
||||
stepValue = stepValue <= 0 ? DEFAULT_STEP_VALUE : stepValue;
|
||||
// 设置初始值和步长
|
||||
idGenerator.tryInit(initValue, stepValue);
|
||||
// 设置过期时间
|
||||
@@ -69,6 +74,17 @@ public class SequenceUtils {
|
||||
return idGenerator;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取ID生成器
|
||||
*
|
||||
* @param key 业务key
|
||||
* @param expireTime 过期时间
|
||||
* @return ID生成器
|
||||
*/
|
||||
public static RIdGenerator getIdGenerator(String key, Duration expireTime) {
|
||||
return getIdGenerator(key, expireTime, DEFAULT_INIT_VALUE, DEFAULT_STEP_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定业务key的唯一id
|
||||
*
|
||||
@@ -78,10 +94,21 @@ public class SequenceUtils {
|
||||
* @param stepValue ID步长
|
||||
* @return 唯一id
|
||||
*/
|
||||
public static long nextId(String key, Duration expireTime, Long initValue, Long stepValue) {
|
||||
public static long getNextId(String key, Duration expireTime, long initValue, long stepValue) {
|
||||
return getIdGenerator(key, expireTime, initValue, stepValue).nextId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定业务key的唯一id (ID初始值=1,ID步长=1)
|
||||
*
|
||||
* @param key 业务key
|
||||
* @param expireTime 过期时间
|
||||
* @return 唯一id
|
||||
*/
|
||||
public static long getNextId(String key, Duration expireTime) {
|
||||
return getIdGenerator(key, expireTime).nextId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定业务key的唯一id字符串
|
||||
*
|
||||
@@ -91,19 +118,8 @@ public class SequenceUtils {
|
||||
* @param stepValue ID步长
|
||||
* @return 唯一id
|
||||
*/
|
||||
public static String nextIdStr(String key, Duration expireTime, Long initValue, Long stepValue) {
|
||||
return String.valueOf(nextId(key, expireTime, initValue, stepValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定业务key的唯一id (ID初始值=1,ID步长=1)
|
||||
*
|
||||
* @param key 业务key
|
||||
* @param expireTime 过期时间
|
||||
* @return 唯一id
|
||||
*/
|
||||
public static long nextId(String key, Duration expireTime) {
|
||||
return getIdGenerator(key, expireTime, DEFAULT_INIT_VALUE, DEFAULT_STEP_VALUE).nextId();
|
||||
public static String getNextIdString(String key, Duration expireTime, long initValue, long stepValue) {
|
||||
return String.valueOf(getNextId(key, expireTime, initValue, stepValue));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,8 +129,8 @@ public class SequenceUtils {
|
||||
* @param expireTime 过期时间
|
||||
* @return 唯一id
|
||||
*/
|
||||
public static String nextIdStr(String key, Duration expireTime) {
|
||||
return String.valueOf(nextId(key, expireTime));
|
||||
public static String getNextIdString(String key, Duration expireTime) {
|
||||
return String.valueOf(getNextId(key, expireTime));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,56 +141,210 @@ public class SequenceUtils {
|
||||
* @param width 位数,不足左补0
|
||||
* @return 补零后的唯一id字符串
|
||||
*/
|
||||
public static String nextPaddedIdStr(String key, Duration expireTime, Integer width) {
|
||||
return StringUtils.leftPad(nextIdStr(key, expireTime), width, '0');
|
||||
public static String getPaddedNextIdString(String key, Duration expireTime, Integer width) {
|
||||
return StringUtils.leftPad(getNextIdString(key, expireTime), width, '0');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 yyyyMMdd 开头的唯一id
|
||||
* 获取 yyyyMMdd 格式的唯一id
|
||||
*
|
||||
* @return 唯一id
|
||||
* @deprecated 请使用 {@link #getDateId(String)} 或 {@link #getDateId(String, boolean)}、{@link #getDateId(String, boolean, int)},确保不同业务的ID连续性
|
||||
*/
|
||||
public static String nextIdDate() {
|
||||
return nextIdDate("");
|
||||
@Deprecated
|
||||
public static String getDateId() {
|
||||
return getDateId("");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 prefix + yyyyMMdd 开头的唯一id
|
||||
* 获取 prefix + yyyyMMdd 格式的唯一id
|
||||
*
|
||||
* @param prefix 业务前缀
|
||||
* @return 唯一id
|
||||
*/
|
||||
public static String nextIdDate(String prefix) {
|
||||
// 前缀+日期 构建 prefixKey
|
||||
String prefixKey = StringUtils.format("{}{}", StringUtils.blankToDefault(prefix, ""), DateUtil.format(DateUtil.date(), DatePattern.PURE_DATE_FORMATTER));
|
||||
// 获取下一个id
|
||||
long nextId = getIdGenerator(prefixKey, DEFAULT_EXPIRE_TIME_DAY, DEFAULT_INIT_VALUE, DEFAULT_STEP_VALUE).nextId();
|
||||
// 返回完整id
|
||||
return StringUtils.format("{}{}", prefixKey, nextId);
|
||||
public static String getDateId(String prefix) {
|
||||
return getDateId(prefix, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 yyyyMMddHHmmss 开头的唯一id
|
||||
* 获取 prefix + yyyyMMdd 格式的唯一id
|
||||
*
|
||||
* @param prefix 业务前缀
|
||||
* @param isWithPrefix id是否携带业务前缀
|
||||
* @return 唯一id
|
||||
*/
|
||||
public static String nextIdDateTime() {
|
||||
return nextIdDateTime("");
|
||||
public static String getDateId(String prefix, boolean isWithPrefix) {
|
||||
return getDateId(prefix, isWithPrefix, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 prefix + yyyyMMddHHmmss 开头的唯一id
|
||||
* 获取 prefix + yyyyMMdd 格式的唯一id (启用ID补位,补位长度 = {@link #DEFAULT_MIN_ID_CAPACITY_BITS})})
|
||||
*
|
||||
* @param prefix 业务前缀
|
||||
* @param isWithPrefix id是否携带业务前缀
|
||||
* @return 唯一id
|
||||
*/
|
||||
public static String getPaddedDateId(String prefix, boolean isWithPrefix) {
|
||||
return getDateId(prefix, isWithPrefix, DEFAULT_MIN_ID_CAPACITY_BITS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 prefix + yyyyMMdd 格式的唯一id
|
||||
*
|
||||
* @param prefix 业务前缀
|
||||
* @param isWithPrefix id是否携带业务前缀
|
||||
* @param minIdCapacityBits 最小ID容量位数,小于该位数的ID,左补0(小于等于0表示不启用补位)
|
||||
* @return 唯一id
|
||||
*/
|
||||
public static String getDateId(String prefix, boolean isWithPrefix, int minIdCapacityBits) {
|
||||
return getDateId(prefix, isWithPrefix, minIdCapacityBits, LocalDate.now());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 prefix + yyyyMMdd 格式的唯一id
|
||||
*
|
||||
* @param prefix 业务前缀
|
||||
* @param isWithPrefix id是否携带业务前缀
|
||||
* @param minIdCapacityBits 最小ID容量位数,小于该位数的ID,左补0(小于等于0表示不启用补位)
|
||||
* @param time 时间
|
||||
* @return 唯一id
|
||||
*/
|
||||
public static String getDateId(String prefix, boolean isWithPrefix, int minIdCapacityBits, LocalDate time) {
|
||||
return getDateId(prefix, isWithPrefix, minIdCapacityBits, time, DEFAULT_INIT_VALUE, DEFAULT_STEP_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 prefix + yyyyMMdd 格式的唯一id
|
||||
*
|
||||
* @param prefix 业务前缀
|
||||
* @param isWithPrefix id是否携带业务前缀
|
||||
* @param minIdCapacityBits 最小ID容量位数,小于该位数的ID,左补0(小于等于0表示不启用补位)
|
||||
* @param time 时间
|
||||
* @param initValue ID初始值
|
||||
* @param stepValue ID步长
|
||||
* @return 唯一id
|
||||
*/
|
||||
public static String getDateId(String prefix, boolean isWithPrefix, int minIdCapacityBits, LocalDate time, long initValue, long stepValue) {
|
||||
return getDatePatternId(prefix, isWithPrefix, minIdCapacityBits, time, DatePattern.PURE_DATE_FORMATTER, DEFAULT_EXPIRE_TIME_DAY, initValue, stepValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 yyyyMMddHHmmss 格式的唯一id
|
||||
*
|
||||
* @return 唯一id
|
||||
* @deprecated 请使用 {@link #getDateTimeId(String)} 或 {@link #getDateTimeId(String, boolean)}、{@link #getDateTimeId(String, boolean, int)},确保不同业务的ID连续性
|
||||
*/
|
||||
@Deprecated
|
||||
public static String getDateTimeId() {
|
||||
return getDateTimeId("", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 prefix + yyyyMMddHHmmss 格式的唯一id
|
||||
*
|
||||
* @param prefix 业务前缀
|
||||
* @return 唯一id
|
||||
*/
|
||||
public static String nextIdDateTime(String prefix) {
|
||||
// 前缀+日期时间 构建 prefixKey
|
||||
String prefixKey = StringUtils.format("{}{}", StringUtils.blankToDefault(prefix, ""), DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_FORMATTER));
|
||||
// 获取下一个id
|
||||
long nextId = getIdGenerator(prefixKey, DEFAULT_EXPIRE_TIME_MINUTE, DEFAULT_INIT_VALUE, DEFAULT_STEP_VALUE).nextId();
|
||||
// 返回完整id
|
||||
return StringUtils.format("{}{}", prefixKey, nextId);
|
||||
public static String getDateTimeId(String prefix) {
|
||||
return getDateTimeId(prefix, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 prefix + yyyyMMddHHmmss 格式的唯一id
|
||||
*
|
||||
* @param prefix 业务前缀
|
||||
* @param isWithPrefix id是否携带业务前缀
|
||||
* @return 唯一id
|
||||
*/
|
||||
public static String getDateTimeId(String prefix, boolean isWithPrefix) {
|
||||
return getDateTimeId(prefix, isWithPrefix, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 prefix + yyyyMMddHHmmss 格式的唯一id (启用ID补位,补位长度 = {@link #DEFAULT_MIN_ID_CAPACITY_BITS})})
|
||||
*
|
||||
* @param prefix 业务前缀
|
||||
* @param isWithPrefix id是否携带业务前缀
|
||||
* @return 唯一id
|
||||
*/
|
||||
public static String getPaddedDateTimeId(String prefix, boolean isWithPrefix) {
|
||||
return getDateTimeId(prefix, isWithPrefix, DEFAULT_MIN_ID_CAPACITY_BITS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 prefix + yyyyMMddHHmmss 格式的唯一id
|
||||
*
|
||||
* @param prefix 业务前缀
|
||||
* @param isWithPrefix id是否携带业务前缀
|
||||
* @param minIdCapacityBits 最小ID容量位数,小于该位数的ID,左补0(小于等于0表示不启用补位)
|
||||
* @return 唯一id
|
||||
*/
|
||||
public static String getDateTimeId(String prefix, boolean isWithPrefix, int minIdCapacityBits) {
|
||||
return getDateTimeId(prefix, isWithPrefix, minIdCapacityBits, LocalDateTime.now());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 prefix + yyyyMMddHHmmss 格式的唯一id
|
||||
*
|
||||
* @param prefix 业务前缀
|
||||
* @param isWithPrefix id是否携带业务前缀
|
||||
* @param minIdCapacityBits 最小ID容量位数,小于该位数的ID,左补0(小于等于0表示不启用补位)
|
||||
* @param time 时间
|
||||
* @return 唯一id
|
||||
*/
|
||||
public static String getDateTimeId(String prefix, boolean isWithPrefix, int minIdCapacityBits, LocalDateTime time) {
|
||||
return getDateTimeId(prefix, isWithPrefix, minIdCapacityBits, time, DEFAULT_INIT_VALUE, DEFAULT_STEP_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 prefix + yyyyMMddHHmmss 格式的唯一id
|
||||
*
|
||||
* @param prefix 业务前缀
|
||||
* @param isWithPrefix id是否携带业务前缀
|
||||
* @param minIdCapacityBits 最小ID容量位数,小于该位数的ID,左补0(小于等于0表示不启用补位)
|
||||
* @param initValue ID初始值
|
||||
* @param stepValue ID步长
|
||||
* @return 唯一id
|
||||
*/
|
||||
public static String getDateTimeId(String prefix, boolean isWithPrefix, int minIdCapacityBits, LocalDateTime time, long initValue, long stepValue) {
|
||||
return getDatePatternId(prefix, isWithPrefix, minIdCapacityBits, time, DatePattern.PURE_DATETIME_FORMATTER, DEFAULT_EXPIRE_TIME_MINUTE, initValue, stepValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定业务key的指定时间格式的ID
|
||||
*
|
||||
* @param prefix 业务前缀
|
||||
* @param isWithPrefix id是否携带业务前缀
|
||||
* @param minIdCapacityBits 最小ID容量位数,小于该位数的ID,左补0(小于等于0表示不启用补位)
|
||||
* @param temporalAccessor 时间访问器
|
||||
* @param timeFormatter 时间格式
|
||||
* @param expireTime 过期时间
|
||||
* @param initValue ID初始值
|
||||
* @param stepValue ID步长
|
||||
* @return 唯一id
|
||||
*/
|
||||
private static String getDatePatternId(String prefix, boolean isWithPrefix, int minIdCapacityBits, TemporalAccessor temporalAccessor, DateTimeFormatter timeFormatter, Duration expireTime, long initValue, long stepValue) {
|
||||
// 时间前缀
|
||||
String timePrefix = timeFormatter.format(temporalAccessor);
|
||||
// 业务前缀 + 时间前缀 构建 prefixKey
|
||||
String prefixKey = StringUtils.format("{}{}", StringUtils.blankToDefault(prefix, ""), timePrefix);
|
||||
|
||||
// 获取id,例 -> 1
|
||||
String nextId = getNextIdString(prefixKey, expireTime, initValue, stepValue);
|
||||
|
||||
// minIdCapacityBits 大于0,且 nextId 的长度小于 minIdCapacityBits,则左补0
|
||||
if (minIdCapacityBits > 0 && nextId.length() < minIdCapacityBits) {
|
||||
nextId = StringUtils.leftPad(nextId, minIdCapacityBits, '0');
|
||||
}
|
||||
|
||||
// 是否携带业务前缀
|
||||
if (isWithPrefix) {
|
||||
// 例 -> P202507031
|
||||
// 其中 P 为业务前缀,202507031 为 yyyyMMdd 格式时间, 1 为nextId
|
||||
return StringUtils.format("{}{}", prefixKey, nextId);
|
||||
}
|
||||
// 例 -> 202507031
|
||||
// 其中 202507031 为 yyyyMMdd 格式时间, 1 为nextId
|
||||
return StringUtils.format("{}{}", timePrefix, nextId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,13 +52,9 @@ public class PlusSaTokenDao implements SaTokenDaoBySessionFollowObject {
|
||||
// 判断是否为永不过期
|
||||
if (timeout == NEVER_EXPIRE) {
|
||||
RedisUtils.setCacheObject(key, value);
|
||||
} else {
|
||||
if (RedisUtils.hasKey(key)) {
|
||||
RedisUtils.setCacheObject(key, value, true);
|
||||
} else {
|
||||
RedisUtils.setCacheObject(key, value, Duration.ofSeconds(timeout));
|
||||
}
|
||||
}
|
||||
CAFFEINE.invalidate(key);
|
||||
}
|
||||
|
||||
@@ -133,13 +129,9 @@ public class PlusSaTokenDao implements SaTokenDaoBySessionFollowObject {
|
||||
// 判断是否为永不过期
|
||||
if (timeout == NEVER_EXPIRE) {
|
||||
RedisUtils.setCacheObject(key, object);
|
||||
} else {
|
||||
if (RedisUtils.hasKey(key)) {
|
||||
RedisUtils.setCacheObject(key, object, true);
|
||||
} else {
|
||||
RedisUtils.setCacheObject(key, object, Duration.ofSeconds(timeout));
|
||||
}
|
||||
}
|
||||
CAFFEINE.invalidate(key);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
package org.dromara.common.satoken.core.service;
|
||||
|
||||
import cn.dev33.satoken.stp.StpInterface;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import org.dromara.common.core.domain.model.LoginUser;
|
||||
import org.dromara.common.core.enums.UserType;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.common.core.service.PermissionService;
|
||||
import org.dromara.common.core.utils.SpringUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -19,9 +21,6 @@ import java.util.List;
|
||||
*/
|
||||
public class SaPermissionImpl implements StpInterface {
|
||||
|
||||
@Autowired
|
||||
private PermissionService permissionService;
|
||||
|
||||
/**
|
||||
* 获取菜单权限列表
|
||||
*/
|
||||
@@ -29,15 +28,24 @@ public class SaPermissionImpl implements StpInterface {
|
||||
public List<String> getPermissionList(Object loginId, String loginType) {
|
||||
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||
if (ObjectUtil.isNull(loginUser) || !loginUser.getLoginId().equals(loginId)) {
|
||||
PermissionService permissionService = getPermissionService();
|
||||
if (ObjectUtil.isNotNull(permissionService)) {
|
||||
List<String> list = StringUtils.splitList(loginId.toString(), ":");
|
||||
return new ArrayList<>(permissionService.getMenuPermission(Long.parseLong(list.get(1))));
|
||||
} else {
|
||||
throw new ServiceException("PermissionService 实现类不存在");
|
||||
}
|
||||
}
|
||||
UserType userType = UserType.getUserType(loginUser.getUserType());
|
||||
if (userType == UserType.APP_USER) {
|
||||
// 其他端 自行根据业务编写
|
||||
}
|
||||
if (CollUtil.isNotEmpty(loginUser.getMenuPermission())) {
|
||||
// SYS_USER 默认返回权限
|
||||
return new ArrayList<>(loginUser.getMenuPermission());
|
||||
} else {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,14 +55,32 @@ public class SaPermissionImpl implements StpInterface {
|
||||
public List<String> getRoleList(Object loginId, String loginType) {
|
||||
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||
if (ObjectUtil.isNull(loginUser) || !loginUser.getLoginId().equals(loginId)) {
|
||||
PermissionService permissionService = getPermissionService();
|
||||
if (ObjectUtil.isNotNull(permissionService)) {
|
||||
List<String> list = StringUtils.splitList(loginId.toString(), ":");
|
||||
return new ArrayList<>(permissionService.getRolePermission(Long.parseLong(list.get(1))));
|
||||
} else {
|
||||
throw new ServiceException("PermissionService 实现类不存在");
|
||||
}
|
||||
}
|
||||
UserType userType = UserType.getUserType(loginUser.getUserType());
|
||||
if (userType == UserType.APP_USER) {
|
||||
// 其他端 自行根据业务编写
|
||||
}
|
||||
if (CollUtil.isNotEmpty(loginUser.getRolePermission())) {
|
||||
// SYS_USER 默认返回权限
|
||||
return new ArrayList<>(loginUser.getRolePermission());
|
||||
} else {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
private PermissionService getPermissionService() {
|
||||
try {
|
||||
return SpringUtils.getBean(PermissionService.class);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
package me.zhyd.oauth.request;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.HttpUtils;
|
||||
import me.zhyd.oauth.utils.StringUtils;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 企业微信登录父类
|
||||
* </p>
|
||||
*
|
||||
* @author liguanhua (347826496(a)qq.com)
|
||||
* @since 1.15.9
|
||||
*/
|
||||
public abstract class AbstractAuthWeChatEnterpriseRequest extends AuthDefaultRequest {
|
||||
|
||||
public AbstractAuthWeChatEnterpriseRequest(AuthConfig config, AuthSource source) {
|
||||
super(config,source);
|
||||
}
|
||||
|
||||
|
||||
public AbstractAuthWeChatEnterpriseRequest(AuthConfig config, AuthSource source, AuthStateCache authStateCache) {
|
||||
super(config, source, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
String response = doGetAuthorizationCode(accessTokenUrl(null));
|
||||
|
||||
JSONObject object = this.checkResponse(response);
|
||||
|
||||
return AuthToken.builder()
|
||||
.accessToken(object.getString("access_token"))
|
||||
.expireIn(object.getIntValue("expires_in"))
|
||||
.code(authCallback.getCode())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthUser getUserInfo(AuthToken authToken) {
|
||||
String response = doGetUserInfo(authToken);
|
||||
JSONObject object = this.checkResponse(response);
|
||||
|
||||
// 返回 OpenId 或其他,均代表非当前企业用户,不支持
|
||||
// https://github.com/justauth/JustAuth/issues/227 修复bug
|
||||
if (!object.containsKey("userid")) {
|
||||
throw new AuthException(AuthResponseStatus.UNIDENTIFIED_PLATFORM, source);
|
||||
}
|
||||
String userId = object.getString("userid");
|
||||
String userTicket = object.getString("user_ticket");
|
||||
JSONObject userDetail = getUserDetail(authToken.getAccessToken(), userId, userTicket);
|
||||
|
||||
return AuthUser.builder()
|
||||
.rawUserInfo(userDetail)
|
||||
.username(userDetail.getString("name"))
|
||||
.nickname(userDetail.getString("alias"))
|
||||
.avatar(userDetail.getString("avatar"))
|
||||
.location(userDetail.getString("address"))
|
||||
.email(userDetail.getString("email"))
|
||||
.uuid(userId)
|
||||
.gender(AuthUserGender.getWechatRealGender(userDetail.getString("gender")))
|
||||
.token(authToken)
|
||||
.source(source.toString())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验请求结果
|
||||
*
|
||||
* @param response 请求结果
|
||||
* @return 如果请求结果正常,则返回JSONObject
|
||||
*/
|
||||
private JSONObject checkResponse(String response) {
|
||||
JSONObject object = JSONObject.parseObject(response);
|
||||
|
||||
if (object.containsKey("errcode") && object.getIntValue("errcode") != 0) {
|
||||
throw new AuthException(object.getString("errmsg"), source);
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 返回获取accessToken的url
|
||||
*
|
||||
* @param code 授权码
|
||||
* @return 返回获取accessToken的url
|
||||
*/
|
||||
@Override
|
||||
protected String accessTokenUrl(String code) {
|
||||
return UrlBuilder.fromBaseUrl(source.accessToken())
|
||||
.queryParam("corpid", config.getClientId())
|
||||
.queryParam("corpsecret", config.getClientSecret())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回获取userInfo的url
|
||||
*
|
||||
* @param authToken 用户授权后的token
|
||||
* @return 返回获取userInfo的url
|
||||
*/
|
||||
@Override
|
||||
protected String userInfoUrl(AuthToken authToken) {
|
||||
return UrlBuilder.fromBaseUrl(source.userInfo())
|
||||
.queryParam("access_token", authToken.getAccessToken())
|
||||
.queryParam("code", authToken.getCode())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户详情
|
||||
*
|
||||
* @param accessToken accessToken
|
||||
* @param userId 企业内用户id
|
||||
* @param userTicket 成员票据,用于获取用户信息或敏感信息
|
||||
* @return 用户详情
|
||||
*/
|
||||
private JSONObject getUserDetail(String accessToken, String userId, String userTicket) {
|
||||
// 用户基础信息
|
||||
String userInfoUrl = UrlBuilder.fromBaseUrl("https://qyapi.weixin.qq.com/cgi-bin/user/get")
|
||||
.queryParam("access_token", accessToken)
|
||||
.queryParam("userid", userId)
|
||||
.build();
|
||||
String userInfoResponse = new HttpUtils(config.getHttpConfig()).get(userInfoUrl).getBody();
|
||||
JSONObject userInfo = checkResponse(userInfoResponse);
|
||||
|
||||
// 用户敏感信息
|
||||
if (StringUtils.isNotEmpty(userTicket)) {
|
||||
String userDetailUrl = UrlBuilder.fromBaseUrl("https://qyapi.weixin.qq.com/cgi-bin/auth/getuserdetail")
|
||||
.queryParam("access_token", accessToken)
|
||||
.build();
|
||||
JSONObject param = new JSONObject();
|
||||
param.put("user_ticket", userTicket);
|
||||
String userDetailResponse = new HttpUtils(config.getHttpConfig()).post(userDetailUrl, param.toJSONString()).getBody();
|
||||
JSONObject userDetail = checkResponse(userDetailResponse);
|
||||
|
||||
userInfo.putAll(userDetail);
|
||||
}
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.common.sse.core.SseEmitterManager;
|
||||
import org.dromara.common.sse.dto.SseMessageDto;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -14,8 +13,6 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* SSE 控制器
|
||||
*
|
||||
@@ -33,7 +30,9 @@ public class SseController implements DisposableBean {
|
||||
*/
|
||||
@GetMapping(value = "${sse.path}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||
public SseEmitter connect() {
|
||||
StpUtil.checkLogin();
|
||||
if (!StpUtil.isLogin()) {
|
||||
return null;
|
||||
}
|
||||
String tokenValue = StpUtil.getTokenValue();
|
||||
Long userId = LoginHelper.getUserId();
|
||||
return sseEmitterManager.connect(userId, tokenValue);
|
||||
@@ -51,31 +50,32 @@ public class SseController implements DisposableBean {
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 向特定用户发送消息
|
||||
*
|
||||
* @param userId 目标用户的 ID
|
||||
* @param msg 要发送的消息内容
|
||||
*/
|
||||
@GetMapping(value = "${sse.path}/send")
|
||||
public R<Void> send(Long userId, String msg) {
|
||||
SseMessageDto dto = new SseMessageDto();
|
||||
dto.setUserIds(List.of(userId));
|
||||
dto.setMessage(msg);
|
||||
sseEmitterManager.publishMessage(dto);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 向所有用户发送消息
|
||||
*
|
||||
* @param msg 要发送的消息内容
|
||||
*/
|
||||
@GetMapping(value = "${sse.path}/sendAll")
|
||||
public R<Void> send(String msg) {
|
||||
sseEmitterManager.publishAll(msg);
|
||||
return R.ok();
|
||||
}
|
||||
// 以下为demo仅供参考 禁止使用 请在业务逻辑中使用工具发送而不是用接口发送
|
||||
// /**
|
||||
// * 向特定用户发送消息
|
||||
// *
|
||||
// * @param userId 目标用户的 ID
|
||||
// * @param msg 要发送的消息内容
|
||||
// */
|
||||
// @GetMapping(value = "${sse.path}/send")
|
||||
// public R<Void> send(Long userId, String msg) {
|
||||
// SseMessageDto dto = new SseMessageDto();
|
||||
// dto.setUserIds(List.of(userId));
|
||||
// dto.setMessage(msg);
|
||||
// sseEmitterManager.publishMessage(dto);
|
||||
// return R.ok();
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 向所有用户发送消息
|
||||
// *
|
||||
// * @param msg 要发送的消息内容
|
||||
// */
|
||||
// @GetMapping(value = "${sse.path}/sendAll")
|
||||
// public R<Void> send(String msg) {
|
||||
// sseEmitterManager.publishAll(msg);
|
||||
// return R.ok();
|
||||
// }
|
||||
|
||||
/**
|
||||
* 清理资源。此方法目前不执行任何操作,但避免因未实现而导致错误
|
||||
|
||||
@@ -38,8 +38,8 @@ public class SseEmitterManager {
|
||||
// 每个用户可以有多个 SSE 连接,通过 token 进行区分
|
||||
Map<String, SseEmitter> emitters = USER_TOKEN_EMITTERS.computeIfAbsent(userId, k -> new ConcurrentHashMap<>());
|
||||
|
||||
// 创建一个新的 SseEmitter 实例,超时时间设置为 0 表示无限制
|
||||
SseEmitter emitter = new SseEmitter(0L);
|
||||
// 创建一个新的 SseEmitter 实例,超时时间设置为一天 避免连接之后直接关闭浏览器导致连接停滞
|
||||
SseEmitter emitter = new SseEmitter(86400000L);
|
||||
|
||||
emitters.put(token, emitter);
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ public class PlusTenantLineHandler implements TenantLineHandler {
|
||||
"gen_table_column"
|
||||
);
|
||||
tables.addAll(excludes);
|
||||
return StringUtils.containsAnyIgnoreCase(tableName, tables.toArray(new String[0]));
|
||||
return StringUtils.equalsAnyIgnoreCase(tableName, tables.toArray(new String[0]));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package org.dromara.common.web.config;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.web.handler.GlobalExceptionHandler;
|
||||
import org.dromara.common.web.interceptor.PlusWebInvokeTimeInterceptor;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.format.FormatterRegistry;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
@@ -11,6 +14,8 @@ import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 通用配置
|
||||
*
|
||||
@@ -25,6 +30,17 @@ public class ResourcesConfig implements WebMvcConfigurer {
|
||||
registry.addInterceptor(new PlusWebInvokeTimeInterceptor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFormatters(FormatterRegistry registry) {
|
||||
// 全局日期格式转换配置
|
||||
registry.addConverter(String.class, Date.class, source -> {
|
||||
if (StringUtils.isBlank(source)) {
|
||||
return null;
|
||||
}
|
||||
return DateUtil.parse(source);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 贝尔实验室 Spring 官方推荐镜像 JDK下载地址 https://bell-sw.com/pages/downloads/
|
||||
FROM bellsoft/liberica-openjdk-debian:17.0.11-cds
|
||||
#FROM bellsoft/liberica-openjdk-debian:21.0.5-cds
|
||||
FROM bellsoft/liberica-openjdk-rocky:17.0.15-cds
|
||||
#FROM bellsoft/liberica-openjdk-rocky:21.0.7-cds
|
||||
#FROM findepi/graalvm:java17-native
|
||||
|
||||
LABEL maintainer="Lion Li"
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.dromara.monitor.admin.config;
|
||||
import de.codecentric.boot.admin.server.config.AdminServerProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
@@ -10,7 +11,8 @@ import org.springframework.security.config.annotation.web.configurers.AbstractHt
|
||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
/**
|
||||
* admin 监控 安全配置
|
||||
@@ -28,7 +30,7 @@ public class SecurityConfig {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
|
||||
public SecurityFilterChain filterChain(HttpSecurity httpSecurity, MvcRequestMatcher.Builder mvc) throws Exception {
|
||||
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
|
||||
successHandler.setTargetUrlParameter("redirectTo");
|
||||
successHandler.setDefaultTargetUrl(adminContextPath + "/");
|
||||
@@ -38,8 +40,8 @@ public class SecurityConfig {
|
||||
header.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
|
||||
.authorizeHttpRequests((authorize) ->
|
||||
authorize.requestMatchers(
|
||||
new AntPathRequestMatcher(adminContextPath + "/assets/**"),
|
||||
new AntPathRequestMatcher(adminContextPath + "/login")
|
||||
mvc.pattern(adminContextPath + "/assets/**"),
|
||||
mvc.pattern(adminContextPath + "/login")
|
||||
).permitAll()
|
||||
.anyRequest().authenticated())
|
||||
.formLogin((formLogin) ->
|
||||
@@ -51,4 +53,10 @@ public class SecurityConfig {
|
||||
.build();
|
||||
}
|
||||
|
||||
@Scope("prototype")
|
||||
@Bean
|
||||
public MvcRequestMatcher.Builder mvc(HandlerMappingIntrospector introspector) {
|
||||
return new MvcRequestMatcher.Builder(introspector);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 贝尔实验室 Spring 官方推荐镜像 JDK下载地址 https://bell-sw.com/pages/downloads/
|
||||
FROM bellsoft/liberica-openjdk-debian:17.0.11-cds
|
||||
#FROM bellsoft/liberica-openjdk-debian:21.0.5-cds
|
||||
FROM bellsoft/liberica-openjdk-rocky:17.0.15-cds
|
||||
#FROM bellsoft/liberica-openjdk-rocky:21.0.7-cds
|
||||
#FROM findepi/graalvm:java17-native
|
||||
|
||||
LABEL maintainer="Lion Li"
|
||||
@@ -9,7 +9,7 @@ RUN mkdir -p /ruoyi/snailjob/logs
|
||||
|
||||
WORKDIR /ruoyi/snailjob
|
||||
|
||||
ENV LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS="-Xms512m -Xmx1024m"
|
||||
ENV LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS=""
|
||||
|
||||
EXPOSE 8800
|
||||
EXPOSE 17888
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
package com.aizuda.snailjob.server.common.register;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.aizuda.snailjob.common.core.enums.NodeTypeEnum;
|
||||
import com.aizuda.snailjob.common.core.util.JsonUtil;
|
||||
import com.aizuda.snailjob.common.core.util.NetUtil;
|
||||
import com.aizuda.snailjob.common.core.util.SnailJobVersion;
|
||||
import com.aizuda.snailjob.common.core.util.StreamUtils;
|
||||
import com.aizuda.snailjob.common.log.SnailJobLog;
|
||||
import com.aizuda.snailjob.server.common.cache.CacheConsumerGroup;
|
||||
import com.aizuda.snailjob.server.common.config.SystemProperties;
|
||||
import com.aizuda.snailjob.server.common.convert.RegisterNodeInfoConverter;
|
||||
import com.aizuda.snailjob.server.common.dto.ServerNodeExtAttrs;
|
||||
import com.aizuda.snailjob.server.common.handler.InstanceManager;
|
||||
import com.aizuda.snailjob.template.datasource.persistence.po.ServerNode;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 服务端注册
|
||||
*
|
||||
* @author opensnail
|
||||
* @date 2023-06-07
|
||||
* @since 1.6.0
|
||||
*/
|
||||
@Component(ServerRegister.BEAN_NAME)
|
||||
@RequiredArgsConstructor
|
||||
public class ServerRegister extends AbstractRegister {
|
||||
public static final String BEAN_NAME = "serverRegister";
|
||||
private final ScheduledExecutorService serverRegisterNode = Executors.newSingleThreadScheduledExecutor(r -> new Thread(r, "server-register-node"));
|
||||
public static final int DELAY_TIME = 30;
|
||||
public static final String CURRENT_CID;
|
||||
public static final String GROUP_NAME = "DEFAULT_SERVER";
|
||||
public static final String NAMESPACE_ID = "DEFAULT_SERVER_NAMESPACE_ID";
|
||||
private final InstanceManager instanceManager;
|
||||
private final SystemProperties systemProperties;
|
||||
private final ServerProperties serverProperties;
|
||||
|
||||
static {
|
||||
CURRENT_CID = IdUtil.getSnowflakeNextIdStr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(int type) {
|
||||
return getNodeType().equals(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void beforeProcessor(RegisterContext context) {
|
||||
// 新增扩展参数
|
||||
ServerNodeExtAttrs serverNodeExtAttrs = new ServerNodeExtAttrs();
|
||||
serverNodeExtAttrs.setWebPort(serverProperties.getPort());
|
||||
serverNodeExtAttrs.setSystemVersion(SnailJobVersion.getVersion());
|
||||
|
||||
context.setGroupName(GROUP_NAME);
|
||||
context.setHostId(CURRENT_CID);
|
||||
String serverHost = systemProperties.getServerHost();
|
||||
if (StrUtil.isEmptyIfStr(serverHost)) {
|
||||
serverHost = NetUtil.getLocalIpStr();
|
||||
}
|
||||
context.setHostIp(serverHost);
|
||||
context.setHostPort(systemProperties.getServerPort());
|
||||
context.setContextPath(Optional.ofNullable(serverProperties.getServlet().getContextPath()).orElse(StrUtil.EMPTY));
|
||||
context.setNamespaceId(NAMESPACE_ID);
|
||||
context.setExtAttrs(JsonUtil.toJsonString(serverNodeExtAttrs));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LocalDateTime getExpireAt() {
|
||||
return LocalDateTime.now().plusSeconds(DELAY_TIME);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean doRegister(RegisterContext context, ServerNode serverNode) {
|
||||
refreshExpireAt(Lists.newArrayList(serverNode));
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void afterProcessor(final ServerNode serverNode) {
|
||||
try {
|
||||
// 同步当前POD消费的组的节点信息
|
||||
// netty的client只会注册到一个服务端,若组分配的和client连接的不是一个POD则会导致当前POD没有其他客户端的注册信息
|
||||
ConcurrentMap<String /*groupName*/, Set<String>/*namespaceId*/> allConsumerGroupName = CacheConsumerGroup.getAllConsumerGroupName();
|
||||
if (CollUtil.isNotEmpty(allConsumerGroupName)) {
|
||||
Set<String> namespaceIdSets = StreamUtils.toSetByFlatMap(allConsumerGroupName.values(), Set::stream);
|
||||
if (CollUtil.isEmpty(namespaceIdSets)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<ServerNode> serverNodes = serverNodeMapper.selectList(
|
||||
new LambdaQueryWrapper<ServerNode>()
|
||||
.eq(ServerNode::getNodeType, NodeTypeEnum.CLIENT.getType())
|
||||
.in(ServerNode::getNamespaceId, namespaceIdSets)
|
||||
.in(ServerNode::getGroupName, allConsumerGroupName.keySet()));
|
||||
for (final ServerNode node : serverNodes) {
|
||||
// 刷新全量本地缓存
|
||||
instanceManager.registerOrUpdate(RegisterNodeInfoConverter.INSTANCE.toRegisterNodeInfo(node));
|
||||
// 刷新过期时间
|
||||
CacheConsumerGroup.addOrUpdate(node.getGroupName(), node.getNamespaceId());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
SnailJobLog.LOCAL.error("Client refresh failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer getNodeType() {
|
||||
return NodeTypeEnum.SERVER.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
SnailJobLog.LOCAL.info("ServerRegister start");
|
||||
|
||||
serverRegisterNode.scheduleAtFixedRate(() -> {
|
||||
try {
|
||||
this.register(new RegisterContext());
|
||||
} catch (Exception e) {
|
||||
SnailJobLog.LOCAL.error("Server-side registration failed", e);
|
||||
}
|
||||
}, 0, DELAY_TIME * 2 / 3, TimeUnit.SECONDS);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
SnailJobLog.LOCAL.info("ServerRegister close");
|
||||
}
|
||||
}
|
||||
@@ -16,15 +16,28 @@ spring:
|
||||
|
||||
--- # snail-job 服务端配置
|
||||
snail-job:
|
||||
# 拉取重试数据的每批次的大小
|
||||
retry-pull-page-size: 1000
|
||||
# 拉取重试数据的每批次的大小
|
||||
job-pull-page-size: 1000
|
||||
# 服务器端口
|
||||
# 服务端节点IP(默认按照`NetUtil.getLocalIpStr()`)
|
||||
server-host:
|
||||
# 服务端netty的端口号
|
||||
server-port: 17888
|
||||
# 日志保存时间(单位: day)
|
||||
# 合并日志默认保存天数
|
||||
merge-Log-days: 1
|
||||
# 合并日志默认的条数
|
||||
merge-Log-num: 500
|
||||
# 配置每批次拉取重试数据的大小
|
||||
retry-pull-page-size: 100
|
||||
# 配置日志保存时间(单位:天)
|
||||
log-storage: 7
|
||||
# bucket的总数量
|
||||
bucket-total: 128
|
||||
# Dashboard 任务容错天数
|
||||
summary-day: 7
|
||||
# 配置负载均衡周期时间
|
||||
load-balance-cycle-time: 10
|
||||
# 通知类型默认使用grpc(netty 已经下线)
|
||||
rpc-type: grpc
|
||||
# 重试任务拉取的并行度
|
||||
retry-max-pull-parallel: 2
|
||||
|
||||
--- # 监控中心配置
|
||||
spring.boot.admin.client:
|
||||
|
||||
@@ -16,15 +16,28 @@ spring:
|
||||
|
||||
--- # snail-job 服务端配置
|
||||
snail-job:
|
||||
# 拉取重试数据的每批次的大小
|
||||
retry-pull-page-size: 1000
|
||||
# 拉取重试数据的每批次的大小
|
||||
job-pull-page-size: 1000
|
||||
# 服务器端口
|
||||
# 服务端节点IP(默认按照`NetUtil.getLocalIpStr()`)
|
||||
server-host:
|
||||
# 服务端netty的端口号
|
||||
server-port: 17888
|
||||
# 日志保存时间(单位: day)
|
||||
# 合并日志默认保存天数
|
||||
merge-Log-days: 1
|
||||
# 合并日志默认的条数
|
||||
merge-Log-num: 500
|
||||
# 配置每批次拉取重试数据的大小
|
||||
retry-pull-page-size: 100
|
||||
# 配置日志保存时间(单位:天)
|
||||
log-storage: 7
|
||||
# bucket的总数量
|
||||
bucket-total: 128
|
||||
# Dashboard 任务容错天数
|
||||
summary-day: 7
|
||||
# 配置负载均衡周期时间
|
||||
load-balance-cycle-time: 10
|
||||
# 通知类型默认使用grpc(netty 已经下线)
|
||||
rpc-type: grpc
|
||||
# 重试任务拉取的并行度
|
||||
retry-max-pull-parallel: 2
|
||||
|
||||
--- # 监控中心配置
|
||||
spring.boot.admin.client:
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.dromara.demo.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.mail.utils.MailUtils;
|
||||
@@ -18,12 +17,11 @@ import java.util.Arrays;
|
||||
*
|
||||
* @author Michelle.Chung
|
||||
*/
|
||||
@SaIgnore
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/demo/mail")
|
||||
public class MailController {
|
||||
public class MailSendController {
|
||||
|
||||
/**
|
||||
* 发送邮件
|
||||
@@ -44,11 +42,11 @@ public class MailController {
|
||||
* @param to 接收人
|
||||
* @param subject 标题
|
||||
* @param text 内容
|
||||
* @param filePath 附件路径
|
||||
*/
|
||||
@GetMapping("/sendMessageWithAttachment")
|
||||
public R<Void> sendMessageWithAttachment(String to, String subject, String text, String filePath) {
|
||||
MailUtils.sendText(to, subject, text, new File(filePath));
|
||||
public R<Void> sendMessageWithAttachment(String to, String subject, String text) {
|
||||
// 附件路径 禁止前端传递 有任意读取系统文件风险
|
||||
MailUtils.sendText(to, subject, text, new File("/xxx/xxx"));
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@@ -58,10 +56,11 @@ public class MailController {
|
||||
* @param to 接收人
|
||||
* @param subject 标题
|
||||
* @param text 内容
|
||||
* @param paths 附件路径
|
||||
*/
|
||||
@GetMapping("/sendMessageWithAttachments")
|
||||
public R<Void> sendMessageWithAttachments(String to, String subject, String text, String[] paths) {
|
||||
public R<Void> sendMessageWithAttachments(String to, String subject, String text) {
|
||||
// 附件路径 禁止前端传递 有任意读取系统文件风险
|
||||
String[] paths = new String[]{"/xxx/xxx", "/xxx/xxx"};
|
||||
File[] array = Arrays.stream(paths).map(File::new).toArray(File[]::new);
|
||||
MailUtils.sendText(to, subject, text, array);
|
||||
return R.ok();
|
||||
@@ -1,11 +1,9 @@
|
||||
package org.dromara.demo.controller.queue;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.redis.utils.QueueUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.redisson.api.RBoundedBlockingQueue;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.redis.utils.QueueUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
@@ -20,7 +18,9 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
*
|
||||
* @author Lion Li
|
||||
* @version 3.6.0
|
||||
* @deprecated redisson 新版本已经将队列功能标记删除 一些技术问题无法解决 建议搭建MQ使用
|
||||
*/
|
||||
@Deprecated
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.dromara.demo.controller.queue;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.domain.R;
|
||||
@@ -23,8 +22,9 @@ import java.util.concurrent.TimeUnit;
|
||||
*
|
||||
* @author Lion Li
|
||||
* @version 3.6.0
|
||||
* @deprecated redisson 新版本已经将队列功能标记删除 一些技术问题无法解决 建议搭建MQ使用
|
||||
*/
|
||||
@SaIgnore
|
||||
@Deprecated
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
|
||||
@@ -8,7 +8,9 @@ import lombok.NoArgsConstructor;
|
||||
*
|
||||
* @author Lion Li
|
||||
* @version 3.6.0
|
||||
* @deprecated redisson 新版本已经将队列功能标记删除 一些技术问题无法解决 建议搭建MQ使用
|
||||
*/
|
||||
@Deprecated
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class PriorityDemo implements Comparable<PriorityDemo> {
|
||||
|
||||
@@ -19,7 +19,9 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
*
|
||||
* @author Lion Li
|
||||
* @version 3.6.0
|
||||
* @deprecated redisson 新版本已经将队列功能标记删除 一些技术问题无法解决 建议搭建MQ使用
|
||||
*/
|
||||
@Deprecated
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
|
||||
@@ -59,4 +59,9 @@ public class TestDemoBo extends BaseEntity {
|
||||
@NotBlank(message = "值不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private String value;
|
||||
|
||||
/**
|
||||
* 版本
|
||||
*/
|
||||
private Long version;
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.dromara.demo.domain.vo;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import cn.idev.excel.annotation.format.DateTimeFormat;
|
||||
import org.dromara.common.excel.annotation.ExcelNotation;
|
||||
import org.dromara.common.excel.annotation.ExcelRequired;
|
||||
import org.dromara.common.translation.annotation.Translation;
|
||||
@@ -46,7 +47,7 @@ public class TestDemoVo implements Serializable {
|
||||
* 用户id
|
||||
*/
|
||||
@ExcelRequired
|
||||
@ExcelProperty(value = "用户id")
|
||||
@ExcelProperty(value = "用户id", index = 5)
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
@@ -73,6 +74,8 @@ public class TestDemoVo implements Serializable {
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@ExcelRequired
|
||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||
@ExcelProperty(value = "创建时间")
|
||||
private Date createTime;
|
||||
|
||||
@@ -108,4 +111,9 @@ public class TestDemoVo implements Serializable {
|
||||
@ExcelProperty(value = "更新人账号")
|
||||
private String updateByName;
|
||||
|
||||
/**
|
||||
* 版本
|
||||
*/
|
||||
private Long version;
|
||||
|
||||
}
|
||||
|
||||
@@ -42,6 +42,11 @@
|
||||
<artifactId>ruoyi-common-log</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-idempotent</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--velocity代码生成使用模板 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.velocity</groupId>
|
||||
|
||||
@@ -3,21 +3,23 @@ package org.dromara.generator.controller;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import com.baomidou.lock.annotation.Lock4j;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.mybatis.helper.DataBaseHelper;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.helper.DataBaseHelper;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.generator.domain.GenTable;
|
||||
import org.dromara.generator.domain.GenTableColumn;
|
||||
import org.dromara.generator.service.IGenTableService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -50,6 +52,7 @@ public class GenController extends BaseController {
|
||||
*
|
||||
* @param tableId 表ID
|
||||
*/
|
||||
@RepeatSubmit()
|
||||
@SaCheckPermission("tool:gen:query")
|
||||
@GetMapping(value = "/{tableId}")
|
||||
public R<Map<String, Object>> getInfo(@PathVariable Long tableId) {
|
||||
@@ -80,11 +83,8 @@ public class GenController extends BaseController {
|
||||
@SaCheckPermission("tool:gen:list")
|
||||
@GetMapping(value = "/column/{tableId}")
|
||||
public TableDataInfo<GenTableColumn> columnList(@PathVariable("tableId") Long tableId) {
|
||||
TableDataInfo<GenTableColumn> dataInfo = new TableDataInfo<>();
|
||||
List<GenTableColumn> list = genTableService.selectGenTableColumnListByTableId(tableId);
|
||||
dataInfo.setRows(list);
|
||||
dataInfo.setTotal(list.size());
|
||||
return dataInfo;
|
||||
return TableDataInfo.build(list);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,6 +94,7 @@ public class GenController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("tool:gen:import")
|
||||
@Log(title = "代码生成", businessType = BusinessType.IMPORT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/importTable")
|
||||
public R<Void> importTableSave(String tables, String dataName) {
|
||||
String[] tableNames = Convert.toStrArray(tables);
|
||||
@@ -108,6 +109,7 @@ public class GenController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("tool:gen:edit")
|
||||
@Log(title = "代码生成", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping
|
||||
public R<Void> editSave(@Validated @RequestBody GenTable genTable) {
|
||||
genTableService.validateEdit(genTable);
|
||||
@@ -173,6 +175,7 @@ public class GenController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("tool:gen:edit")
|
||||
@Log(title = "代码生成", businessType = BusinessType.UPDATE)
|
||||
@Lock4j
|
||||
@GetMapping("/synchDb/{tableId}")
|
||||
public R<Void> synchDb(@PathVariable("tableId") Long tableId) {
|
||||
genTableService.synchDb(tableId);
|
||||
|
||||
@@ -297,13 +297,13 @@ public class GenTableServiceImpl implements IGenTableService {
|
||||
List<GenTableColumn> tableColumns = new ArrayList<>();
|
||||
columns.forEach((columnName, column) -> {
|
||||
GenTableColumn tableColumn = new GenTableColumn();
|
||||
tableColumn.setIsPk(String.valueOf(column.isPrimaryKey()));
|
||||
tableColumn.setIsPk(column.isPrimaryKey() ? "1" : "0");
|
||||
tableColumn.setColumnName(column.getName());
|
||||
tableColumn.setColumnComment(column.getComment());
|
||||
tableColumn.setColumnType(column.getOriginType().toLowerCase());
|
||||
tableColumn.setSort(column.getPosition());
|
||||
tableColumn.setIsRequired(column.isNullable() == 0 ? "1" : "0");
|
||||
tableColumn.setIsIncrement(column.isAutoIncrement() == -1 ? "0" : "1");
|
||||
tableColumn.setIsRequired(column.isNullable() ? "0" : "1");
|
||||
tableColumn.setIsIncrement(column.isAutoIncrement() ? "1" : "0");
|
||||
tableColumns.add(tableColumn);
|
||||
});
|
||||
return tableColumns;
|
||||
|
||||
@@ -6,6 +6,7 @@ import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.redisson.spring.data.connection.RedissonConnectionFactory;
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.core.RedisConnectionUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
@@ -31,8 +32,8 @@ public class CacheController {
|
||||
@GetMapping()
|
||||
public R<CacheListInfoVo> getInfo() throws Exception {
|
||||
RedisConnection connection = connectionFactory.getConnection();
|
||||
try {
|
||||
Properties commandStats = connection.commands().info("commandstats");
|
||||
|
||||
List<Map<String, String>> pieList = new ArrayList<>();
|
||||
if (commandStats != null) {
|
||||
commandStats.stringPropertyNames().forEach(key -> {
|
||||
@@ -43,10 +44,13 @@ public class CacheController {
|
||||
pieList.add(data);
|
||||
});
|
||||
}
|
||||
|
||||
return R.ok(new CacheListInfoVo(
|
||||
connection.commands().info(),
|
||||
connection.commands().dbSize(), pieList));
|
||||
} finally {
|
||||
// 归还连接给连接池
|
||||
RedisConnectionUtils.releaseConnection(connection, connectionFactory);
|
||||
}
|
||||
}
|
||||
|
||||
public record CacheListInfoVo(Properties info, Long dbSize, List<Map<String, String>> commandStats) {}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package org.dromara.system.controller.monitor;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.baomidou.lock.annotation.Lock4j;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.constant.CacheConstants;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
@@ -69,6 +71,7 @@ public class SysLogininforController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("monitor:logininfor:remove")
|
||||
@Log(title = "登录日志", businessType = BusinessType.CLEAN)
|
||||
@Lock4j
|
||||
@DeleteMapping("/clean")
|
||||
public R<Void> clean() {
|
||||
logininforService.cleanLogininfor();
|
||||
@@ -77,6 +80,7 @@ public class SysLogininforController extends BaseController {
|
||||
|
||||
@SaCheckPermission("monitor:logininfor:unlock")
|
||||
@Log(title = "账户解锁", businessType = BusinessType.OTHER)
|
||||
@RepeatSubmit()
|
||||
@GetMapping("/unlock/{userName}")
|
||||
public R<Void> unlock(@PathVariable("userName") String userName) {
|
||||
String loginName = CacheConstants.PWD_ERR_CNT_KEY + userName;
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
package org.dromara.system.controller.monitor;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import com.baomidou.lock.annotation.Lock4j;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.system.domain.bo.SysOperLogBo;
|
||||
import org.dromara.system.domain.vo.SysOperLogVo;
|
||||
import org.dromara.system.service.ISysOperLogService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -67,6 +68,7 @@ public class SysOperlogController extends BaseController {
|
||||
*/
|
||||
@Log(title = "操作日志", businessType = BusinessType.CLEAN)
|
||||
@SaCheckPermission("monitor:operlog:remove")
|
||||
@Lock4j
|
||||
@DeleteMapping("/clean")
|
||||
public R<Void> clean() {
|
||||
operLogService.cleanOperLog();
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.domain.dto.UserOnlineDTO;
|
||||
import org.dromara.common.core.utils.StreamUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
@@ -81,6 +82,7 @@ public class SysUserOnlineController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("monitor:online:forceLogout")
|
||||
@Log(title = "在线用户", businessType = BusinessType.FORCE)
|
||||
@RepeatSubmit()
|
||||
@DeleteMapping("/{tokenId}")
|
||||
public R<Void> forceLogout(@PathVariable String tokenId) {
|
||||
try {
|
||||
@@ -114,6 +116,7 @@ public class SysUserOnlineController extends BaseController {
|
||||
* @param tokenId token值
|
||||
*/
|
||||
@Log(title = "在线设备", businessType = BusinessType.FORCE)
|
||||
@RepeatSubmit()
|
||||
@DeleteMapping("/myself/{tokenId}")
|
||||
public R<Void> remove(@PathVariable("tokenId") String tokenId) {
|
||||
try {
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package org.dromara.system.controller.system;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
@@ -11,11 +14,10 @@ import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.system.domain.bo.SysConfigBo;
|
||||
import org.dromara.system.domain.vo.SysConfigVo;
|
||||
import org.dromara.system.service.ISysConfigService;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -77,6 +79,7 @@ public class SysConfigController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("system:config:add")
|
||||
@Log(title = "参数管理", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping
|
||||
public R<Void> add(@Validated @RequestBody SysConfigBo config) {
|
||||
if (!configService.checkConfigKeyUnique(config)) {
|
||||
@@ -91,6 +94,7 @@ public class SysConfigController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("system:config:edit")
|
||||
@Log(title = "参数管理", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping
|
||||
public R<Void> edit(@Validated @RequestBody SysConfigBo config) {
|
||||
if (!configService.checkConfigKeyUnique(config)) {
|
||||
@@ -105,6 +109,7 @@ public class SysConfigController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("system:config:edit")
|
||||
@Log(title = "参数管理", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/updateByKey")
|
||||
public R<Void> updateByKey(@RequestBody SysConfigBo config) {
|
||||
configService.updateConfig(config);
|
||||
@@ -120,7 +125,7 @@ public class SysConfigController extends BaseController {
|
||||
@Log(title = "参数管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{configIds}")
|
||||
public R<Void> remove(@PathVariable Long[] configIds) {
|
||||
configService.deleteConfigByIds(configIds);
|
||||
configService.deleteConfigByIds(Arrays.asList(configIds));
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.constant.SystemConstants;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
@@ -73,6 +74,7 @@ public class SysDeptController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("system:dept:add")
|
||||
@Log(title = "部门管理", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping
|
||||
public R<Void> add(@Validated @RequestBody SysDeptBo dept) {
|
||||
if (!deptService.checkDeptNameUnique(dept)) {
|
||||
@@ -86,6 +88,7 @@ public class SysDeptController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("system:dept:edit")
|
||||
@Log(title = "部门管理", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping
|
||||
public R<Void> edit(@Validated @RequestBody SysDeptBo dept) {
|
||||
Long deptId = dept.getDeptId();
|
||||
@@ -113,6 +116,9 @@ public class SysDeptController extends BaseController {
|
||||
@Log(title = "部门管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{deptId}")
|
||||
public R<Void> remove(@PathVariable Long deptId) {
|
||||
if (SystemConstants.DEFAULT_DEPT_ID.equals(deptId)) {
|
||||
return R.warn("默认部门,不允许删除");
|
||||
}
|
||||
if (deptService.hasChildByDeptId(deptId)) {
|
||||
return R.warn("存在下级部门,不允许删除");
|
||||
}
|
||||
|
||||
@@ -2,23 +2,25 @@ package org.dromara.system.controller.system;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.system.domain.bo.SysDictDataBo;
|
||||
import org.dromara.system.domain.vo.SysDictDataVo;
|
||||
import org.dromara.system.service.ISysDictDataService;
|
||||
import org.dromara.system.service.ISysDictTypeService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -85,6 +87,7 @@ public class SysDictDataController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("system:dict:add")
|
||||
@Log(title = "字典数据", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping
|
||||
public R<Void> add(@Validated @RequestBody SysDictDataBo dict) {
|
||||
if (!dictDataService.checkDictDataUnique(dict)) {
|
||||
@@ -99,6 +102,7 @@ public class SysDictDataController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("system:dict:edit")
|
||||
@Log(title = "字典数据", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping
|
||||
public R<Void> edit(@Validated @RequestBody SysDictDataBo dict) {
|
||||
if (!dictDataService.checkDictDataUnique(dict)) {
|
||||
@@ -117,7 +121,7 @@ public class SysDictDataController extends BaseController {
|
||||
@Log(title = "字典类型", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{dictCodes}")
|
||||
public R<Void> remove(@PathVariable Long[] dictCodes) {
|
||||
dictDataService.deleteDictDataByIds(dictCodes);
|
||||
dictDataService.deleteDictDataByIds(Arrays.asList(dictCodes));
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package org.dromara.system.controller.system;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.baomidou.lock.annotation.Lock4j;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
@@ -11,11 +15,10 @@ import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.system.domain.bo.SysDictTypeBo;
|
||||
import org.dromara.system.domain.vo.SysDictTypeVo;
|
||||
import org.dromara.system.service.ISysDictTypeService;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -67,6 +70,7 @@ public class SysDictTypeController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("system:dict:add")
|
||||
@Log(title = "字典类型", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping
|
||||
public R<Void> add(@Validated @RequestBody SysDictTypeBo dict) {
|
||||
if (!dictTypeService.checkDictTypeUnique(dict)) {
|
||||
@@ -81,6 +85,7 @@ public class SysDictTypeController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("system:dict:edit")
|
||||
@Log(title = "字典类型", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping
|
||||
public R<Void> edit(@Validated @RequestBody SysDictTypeBo dict) {
|
||||
if (!dictTypeService.checkDictTypeUnique(dict)) {
|
||||
@@ -99,7 +104,7 @@ public class SysDictTypeController extends BaseController {
|
||||
@Log(title = "字典类型", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{dictIds}")
|
||||
public R<Void> remove(@PathVariable Long[] dictIds) {
|
||||
dictTypeService.deleteDictTypeByIds(dictIds);
|
||||
dictTypeService.deleteDictTypeByIds(Arrays.asList(dictIds));
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@@ -108,6 +113,7 @@ public class SysDictTypeController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("system:dict:remove")
|
||||
@Log(title = "字典类型", businessType = BusinessType.CLEAN)
|
||||
@Lock4j
|
||||
@DeleteMapping("/refreshCache")
|
||||
public R<Void> refreshCache() {
|
||||
dictTypeService.resetDictCache();
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.dromara.common.core.constant.SystemConstants;
|
||||
import org.dromara.common.core.constant.TenantConstants;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
@@ -21,6 +22,7 @@ import org.dromara.system.service.ISysMenuService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -111,9 +113,14 @@ public class SysMenuController extends BaseController {
|
||||
@GetMapping(value = "/tenantPackageMenuTreeselect/{packageId}")
|
||||
public R<MenuTreeSelectVo> tenantPackageMenuTreeselect(@PathVariable("packageId") Long packageId) {
|
||||
List<SysMenuVo> menus = menuService.selectMenuList(LoginHelper.getUserId());
|
||||
MenuTreeSelectVo selectVo = new MenuTreeSelectVo(
|
||||
menuService.selectMenuListByPackageId(packageId),
|
||||
menuService.buildMenuTreeSelect(menus));
|
||||
List<Tree<Long>> list = menuService.buildMenuTreeSelect(menus);
|
||||
// 删除租户管理菜单
|
||||
list.removeIf(menu -> menu.getId() == 6L);
|
||||
List<Long> ids = new ArrayList<>();
|
||||
if (packageId > 0L) {
|
||||
ids = menuService.selectMenuListByPackageId(packageId);
|
||||
}
|
||||
MenuTreeSelectVo selectVo = new MenuTreeSelectVo(ids, list);
|
||||
return R.ok(selectVo);
|
||||
}
|
||||
|
||||
@@ -123,6 +130,7 @@ public class SysMenuController extends BaseController {
|
||||
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
|
||||
@SaCheckPermission("system:menu:add")
|
||||
@Log(title = "菜单管理", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping
|
||||
public R<Void> add(@Validated @RequestBody SysMenuBo menu) {
|
||||
if (!menuService.checkMenuNameUnique(menu)) {
|
||||
@@ -139,6 +147,7 @@ public class SysMenuController extends BaseController {
|
||||
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
|
||||
@SaCheckPermission("system:menu:edit")
|
||||
@Log(title = "菜单管理", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping
|
||||
public R<Void> edit(@Validated @RequestBody SysMenuBo menu) {
|
||||
if (!menuService.checkMenuNameUnique(menu)) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.service.DictService;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
@@ -55,6 +56,7 @@ public class SysNoticeController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("system:notice:add")
|
||||
@Log(title = "通知公告", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping
|
||||
public R<Void> add(@Validated @RequestBody SysNoticeBo notice) {
|
||||
int rows = noticeService.insertNotice(notice);
|
||||
@@ -71,6 +73,7 @@ public class SysNoticeController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("system:notice:edit")
|
||||
@Log(title = "通知公告", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping
|
||||
public R<Void> edit(@Validated @RequestBody SysNoticeBo notice) {
|
||||
return toAjax(noticeService.updateNotice(notice));
|
||||
|
||||
@@ -98,6 +98,7 @@ public class SysOssConfigController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("system:ossConfig:edit")
|
||||
@Log(title = "对象存储状态修改", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/changeStatus")
|
||||
public R<Void> changeStatus(@RequestBody SysOssConfigBo bo) {
|
||||
return toAjax(ossConfigService.updateOssConfigStatus(bo));
|
||||
|
||||
@@ -7,6 +7,7 @@ import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.constant.SystemConstants;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
@@ -19,6 +20,7 @@ import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -70,6 +72,7 @@ public class SysPostController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("system:post:add")
|
||||
@Log(title = "岗位管理", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping
|
||||
public R<Void> add(@Validated @RequestBody SysPostBo post) {
|
||||
if (!postService.checkPostNameUnique(post)) {
|
||||
@@ -85,6 +88,7 @@ public class SysPostController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("system:post:edit")
|
||||
@Log(title = "岗位管理", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping
|
||||
public R<Void> edit(@Validated @RequestBody SysPostBo post) {
|
||||
if (!postService.checkPostNameUnique(post)) {
|
||||
@@ -107,7 +111,7 @@ public class SysPostController extends BaseController {
|
||||
@Log(title = "岗位管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{postIds}")
|
||||
public R<Void> remove(@PathVariable Long[] postIds) {
|
||||
return toAjax(postService.deletePostByIds(postIds));
|
||||
return toAjax(postService.deletePostByIds(Arrays.asList(postIds)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,6 +17,7 @@ import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.system.domain.bo.SysUserBo;
|
||||
import org.dromara.system.domain.bo.SysUserPasswordBo;
|
||||
import org.dromara.system.domain.bo.SysUserProfileBo;
|
||||
import org.dromara.system.domain.vo.ProfileUserVo;
|
||||
import org.dromara.system.domain.vo.SysOssVo;
|
||||
import org.dromara.system.domain.vo.SysUserVo;
|
||||
import org.dromara.system.service.ISysOssService;
|
||||
@@ -50,7 +51,9 @@ public class SysProfileController extends BaseController {
|
||||
SysUserVo user = userService.selectUserById(LoginHelper.getUserId());
|
||||
String roleGroup = userService.selectUserRoleGroup(user.getUserId());
|
||||
String postGroup = userService.selectUserPostGroup(user.getUserId());
|
||||
ProfileVo profileVo = new ProfileVo(user, roleGroup, postGroup);
|
||||
// 单独做一个vo专门给个人中心用 避免数据被脱敏
|
||||
ProfileUserVo profileUser = BeanUtil.toBean(user, ProfileUserVo.class);
|
||||
ProfileVo profileVo = new ProfileVo(profileUser, roleGroup, postGroup);
|
||||
return R.ok(profileVo);
|
||||
}
|
||||
|
||||
@@ -128,6 +131,6 @@ public class SysProfileController extends BaseController {
|
||||
|
||||
public record AvatarVo(String imgUrl) {}
|
||||
|
||||
public record ProfileVo(SysUserVo user, String roleGroup, String postGroup) {}
|
||||
public record ProfileVo(ProfileUserVo user, String roleGroup, String postGroup) {}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
@@ -77,6 +78,7 @@ public class SysRoleController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("system:role:add")
|
||||
@Log(title = "角色管理", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping
|
||||
public R<Void> add(@Validated @RequestBody SysRoleBo role) {
|
||||
roleService.checkRoleAllowed(role);
|
||||
@@ -94,6 +96,7 @@ public class SysRoleController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("system:role:edit")
|
||||
@Log(title = "角色管理", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping
|
||||
public R<Void> edit(@Validated @RequestBody SysRoleBo role) {
|
||||
roleService.checkRoleAllowed(role);
|
||||
@@ -116,6 +119,7 @@ public class SysRoleController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("system:role:edit")
|
||||
@Log(title = "角色管理", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/dataScope")
|
||||
public R<Void> dataScope(@RequestBody SysRoleBo role) {
|
||||
roleService.checkRoleAllowed(role);
|
||||
@@ -128,6 +132,7 @@ public class SysRoleController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("system:role:edit")
|
||||
@Log(title = "角色管理", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/changeStatus")
|
||||
public R<Void> changeStatus(@RequestBody SysRoleBo role) {
|
||||
roleService.checkRoleAllowed(role);
|
||||
@@ -144,7 +149,7 @@ public class SysRoleController extends BaseController {
|
||||
@Log(title = "角色管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{roleIds}")
|
||||
public R<Void> remove(@PathVariable Long[] roleIds) {
|
||||
return toAjax(roleService.deleteRoleByIds(roleIds));
|
||||
return toAjax(roleService.deleteRoleByIds(List.of(roleIds)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,6 +186,7 @@ public class SysRoleController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("system:role:edit")
|
||||
@Log(title = "角色管理", businessType = BusinessType.GRANT)
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/authUser/cancel")
|
||||
public R<Void> cancelAuthUser(@RequestBody SysUserRole userRole) {
|
||||
return toAjax(roleService.deleteAuthUser(userRole));
|
||||
@@ -194,6 +200,7 @@ public class SysRoleController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("system:role:edit")
|
||||
@Log(title = "角色管理", businessType = BusinessType.GRANT)
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/authUser/cancelAll")
|
||||
public R<Void> cancelAuthUserAll(Long roleId, Long[] userIds) {
|
||||
return toAjax(roleService.deleteAuthUsers(roleId, userIds));
|
||||
@@ -207,6 +214,7 @@ public class SysRoleController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("system:role:edit")
|
||||
@Log(title = "角色管理", businessType = BusinessType.GRANT)
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/authUser/selectAll")
|
||||
public R<Void> selectAuthUserAll(Long roleId, Long[] userIds) {
|
||||
roleService.checkRoleDataScope(roleId);
|
||||
|
||||
@@ -118,6 +118,7 @@ public class SysTenantController extends BaseController {
|
||||
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
|
||||
@SaCheckPermission("system:tenant:edit")
|
||||
@Log(title = "租户管理", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/changeStatus")
|
||||
public R<Void> changeStatus(@RequestBody SysTenantBo bo) {
|
||||
tenantService.checkTenantAllowed(bo.getTenantId());
|
||||
@@ -170,6 +171,7 @@ public class SysTenantController extends BaseController {
|
||||
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
|
||||
@SaCheckPermission("system:tenant:edit")
|
||||
@Log(title = "租户管理", businessType = BusinessType.UPDATE)
|
||||
@Lock4j
|
||||
@GetMapping("/syncTenantPackage")
|
||||
public R<Void> syncTenantPackage(@NotBlank(message = "租户ID不能为空") String tenantId,
|
||||
@NotNull(message = "套餐ID不能为空") Long packageId) {
|
||||
@@ -181,6 +183,7 @@ public class SysTenantController extends BaseController {
|
||||
*/
|
||||
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
|
||||
@Log(title = "租户管理", businessType = BusinessType.INSERT)
|
||||
@Lock4j
|
||||
@GetMapping("/syncTenantDict")
|
||||
public R<Void> syncTenantDict() {
|
||||
if (!TenantHelper.isEnable()) {
|
||||
|
||||
@@ -121,6 +121,7 @@ public class SysTenantPackageController extends BaseController {
|
||||
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
|
||||
@SaCheckPermission("system:tenantPackage:edit")
|
||||
@Log(title = "租户套餐", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/changeStatus")
|
||||
public R<Void> changeStatus(@RequestBody SysTenantPackageBo bo) {
|
||||
return toAjax(tenantPackageService.updatePackageStatus(bo));
|
||||
|
||||
@@ -16,10 +16,12 @@ import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.encrypt.annotation.ApiEncrypt;
|
||||
import org.dromara.common.excel.core.ExcelResult;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.helper.DataPermissionHelper;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.common.tenant.helper.TenantHelper;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
@@ -110,7 +112,8 @@ public class SysUserController extends BaseController {
|
||||
// 超级管理员 如果重新加载用户信息需清除动态租户
|
||||
TenantHelper.clearDynamic();
|
||||
}
|
||||
SysUserVo user = userService.selectUserById(loginUser.getUserId());
|
||||
|
||||
SysUserVo user = DataPermissionHelper.ignore(() -> userService.selectUserById(loginUser.getUserId()));
|
||||
if (ObjectUtil.isNull(user)) {
|
||||
return R.fail("没有权限访问用户数据!");
|
||||
}
|
||||
@@ -154,6 +157,7 @@ public class SysUserController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("system:user:add")
|
||||
@Log(title = "用户管理", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping
|
||||
public R<Void> add(@Validated @RequestBody SysUserBo user) {
|
||||
deptService.checkDeptDataScope(user.getDeptId());
|
||||
@@ -178,6 +182,7 @@ public class SysUserController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("system:user:edit")
|
||||
@Log(title = "用户管理", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping
|
||||
public R<Void> edit(@Validated @RequestBody SysUserBo user) {
|
||||
userService.checkUserAllowed(user.getUserId());
|
||||
@@ -227,6 +232,7 @@ public class SysUserController extends BaseController {
|
||||
@ApiEncrypt
|
||||
@SaCheckPermission("system:user:resetPwd")
|
||||
@Log(title = "用户管理", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/resetPwd")
|
||||
public R<Void> resetPwd(@RequestBody SysUserBo user) {
|
||||
userService.checkUserAllowed(user.getUserId());
|
||||
@@ -240,6 +246,7 @@ public class SysUserController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("system:user:edit")
|
||||
@Log(title = "用户管理", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/changeStatus")
|
||||
public R<Void> changeStatus(@RequestBody SysUserBo user) {
|
||||
userService.checkUserAllowed(user.getUserId());
|
||||
@@ -272,6 +279,7 @@ public class SysUserController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("system:user:edit")
|
||||
@Log(title = "用户管理", businessType = BusinessType.GRANT)
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/authRole")
|
||||
public R<Void> insertAuthRole(Long userId, Long[] roleIds) {
|
||||
userService.checkUserDataScope(userId);
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
package org.dromara.system.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 附件扩展字段对象(存储在 SysOss.ext1 的 JSON 字符串中)
|
||||
*
|
||||
* @author AprilWind
|
||||
*/
|
||||
@Data
|
||||
public class SysOssExt implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 所属业务类型(如 avatar、report、contract)
|
||||
*/
|
||||
private String bizType;
|
||||
|
||||
/**
|
||||
* 文件大小(单位:字节)
|
||||
*/
|
||||
private Long fileSize;
|
||||
|
||||
/**
|
||||
* 文件类型(MIME类型,如 image/png)
|
||||
*/
|
||||
private String contentType;
|
||||
|
||||
/**
|
||||
* 来源标识(如 userUpload、systemImport)
|
||||
*/
|
||||
private String source;
|
||||
|
||||
/**
|
||||
* 上传 IP 地址,便于审计和追踪
|
||||
*/
|
||||
private String uploadIp;
|
||||
|
||||
/**
|
||||
* 附件说明或备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 附件标签,如 ["图片", "证件"]
|
||||
*/
|
||||
private List<String> tags;
|
||||
|
||||
/**
|
||||
* 业务绑定ID(如某业务记录ID)
|
||||
*/
|
||||
private String refId;
|
||||
|
||||
/**
|
||||
* 绑定业务类型
|
||||
*/
|
||||
private String refType;
|
||||
|
||||
/**
|
||||
* 是否为临时文件,用于区分正式或待清理
|
||||
*/
|
||||
private Boolean isTemp;
|
||||
|
||||
/**
|
||||
* 文件MD5值(可用于去重或校验)
|
||||
*/
|
||||
private String md5;
|
||||
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
package org.dromara.system.domain.bo;
|
||||
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.system.domain.SysTenant;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import jakarta.validation.constraints.*;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.system.domain.SysTenant;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
|
||||
/**
|
||||
* 租户业务对象 sys_tenant
|
||||
*
|
||||
@@ -62,6 +62,7 @@ public class SysTenantBo extends BaseEntity {
|
||||
* 密码(创建系统用户)
|
||||
*/
|
||||
@NotBlank(message = "密码不能为空", groups = { AddGroup.class })
|
||||
// @Pattern(regexp = RegexConstants.PASSWORD, message = "{user.password.format.valid}", groups = { AddGroup.class })
|
||||
private String password;
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
package org.dromara.system.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import org.dromara.common.translation.annotation.Translation;
|
||||
import org.dromara.common.translation.constant.TransConstant;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* 用户信息视图对象 sys_user
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Data
|
||||
public class ProfileUserVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 用户账号
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String nickName;
|
||||
|
||||
/**
|
||||
* 用户类型(sys_user系统用户)
|
||||
*/
|
||||
private String userType;
|
||||
|
||||
/**
|
||||
* 用户邮箱
|
||||
*/
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 手机号码
|
||||
*/
|
||||
private String phonenumber;
|
||||
|
||||
/**
|
||||
* 用户性别(0男 1女 2未知)
|
||||
*/
|
||||
private String sex;
|
||||
|
||||
/**
|
||||
* 头像地址
|
||||
*/
|
||||
@Translation(type = TransConstant.OSS_ID_TO_URL)
|
||||
private Long avatar;
|
||||
|
||||
/**
|
||||
* 最后登录IP
|
||||
*/
|
||||
private String loginIp;
|
||||
|
||||
/**
|
||||
* 最后登录时间
|
||||
*/
|
||||
private Date loginDate;
|
||||
|
||||
/**
|
||||
* 部门名
|
||||
*/
|
||||
@Translation(type = TransConstant.DEPT_ID_TO_NAME, mapper = "deptId")
|
||||
private String deptName;
|
||||
|
||||
}
|
||||
@@ -2,9 +2,8 @@ package org.dromara.system.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.dromara.common.core.utils.StreamUtils;
|
||||
import org.dromara.common.mybatis.annotation.DataColumn;
|
||||
import org.dromara.common.mybatis.annotation.DataPermission;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
@@ -21,6 +20,38 @@ import java.util.List;
|
||||
*/
|
||||
public interface SysDeptMapper extends BaseMapperPlus<SysDept, SysDeptVo> {
|
||||
|
||||
/**
|
||||
* 构建角色对应的部门 SQL 查询语句
|
||||
*
|
||||
* <p>该 SQL 用于查询某个角色关联的所有部门 ID,常用于数据权限控制</p>
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @return 查询部门ID的 SQL 语句字符串
|
||||
*/
|
||||
default String buildDeptByRoleSql(Long roleId) {
|
||||
return """
|
||||
select dept_id from sys_role_dept where role_id = %d
|
||||
""".formatted(roleId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建 SQL 查询,用于获取当前角色拥有的部门中所有的父部门ID
|
||||
*
|
||||
* <p>
|
||||
* 该 SQL 用于 deptCheckStrictly 场景下,排除非叶子节点(父节点)用。
|
||||
* </p>
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @return SQL 语句字符串,查询角色下部门的所有父部门ID
|
||||
*/
|
||||
default String buildParentDeptByRoleSql(Long roleId) {
|
||||
return """
|
||||
select parent_id from sys_dept where dept_id in (
|
||||
select dept_id from sys_role_dept where role_id = %d
|
||||
)
|
||||
""".formatted(roleId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询部门管理数据
|
||||
*
|
||||
@@ -30,18 +61,23 @@ public interface SysDeptMapper extends BaseMapperPlus<SysDept, SysDeptVo> {
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "dept_id")
|
||||
})
|
||||
List<SysDeptVo> selectDeptList(@Param(Constants.WRAPPER) Wrapper<SysDept> queryWrapper);
|
||||
default List<SysDeptVo> selectDeptList(Wrapper<SysDept> queryWrapper) {
|
||||
return this.selectVoList(queryWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询部门管理数据
|
||||
*
|
||||
* @param page 分页信息
|
||||
* @param queryWrapper 查询条件
|
||||
* @return 部门信息集合
|
||||
*/
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "dept_id"),
|
||||
})
|
||||
Page<SysDeptVo> selectPageDeptList(@Param("page") Page<SysDeptVo> page, @Param(Constants.WRAPPER) Wrapper<SysDept> queryWrapper);
|
||||
default Page<SysDeptVo> selectPageDeptList(Page<SysDept> page, Wrapper<SysDept> queryWrapper) {
|
||||
return this.selectVoPage(page, queryWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计指定部门ID的部门数量
|
||||
@@ -52,7 +88,9 @@ public interface SysDeptMapper extends BaseMapperPlus<SysDept, SysDeptVo> {
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "dept_id")
|
||||
})
|
||||
long countDeptById(Long deptId);
|
||||
default long countDeptById(Long deptId) {
|
||||
return this.selectCount(new LambdaQueryWrapper<SysDept>().eq(SysDept::getDeptId, deptId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据父部门ID查询其所有子部门的列表
|
||||
@@ -66,6 +104,19 @@ public interface SysDeptMapper extends BaseMapperPlus<SysDept, SysDeptVo> {
|
||||
.apply(DataBaseHelper.findInSet(parentId, "ancestors")));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询某个部门及其所有子部门ID(含自身)
|
||||
*
|
||||
* @param parentId 父部门ID
|
||||
* @return 部门ID集合
|
||||
*/
|
||||
default List<Long> selectDeptAndChildById(Long parentId) {
|
||||
List<SysDept> deptList = this.selectListByParentId(parentId);
|
||||
List<Long> deptIds = StreamUtils.toList(deptList, SysDept::getDeptId);
|
||||
deptIds.add(parentId);
|
||||
return deptIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据角色ID查询部门树信息
|
||||
*
|
||||
@@ -73,6 +124,16 @@ public interface SysDeptMapper extends BaseMapperPlus<SysDept, SysDeptVo> {
|
||||
* @param deptCheckStrictly 部门树选择项是否关联显示
|
||||
* @return 选中部门列表
|
||||
*/
|
||||
List<Long> selectDeptListByRoleId(@Param("roleId") Long roleId, @Param("deptCheckStrictly") boolean deptCheckStrictly);
|
||||
default List<Long> selectDeptListByRoleId(Long roleId, boolean deptCheckStrictly) {
|
||||
LambdaQueryWrapper<SysDept> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.select(SysDept::getDeptId)
|
||||
.inSql(SysDept::getDeptId, this.buildDeptByRoleSql(roleId))
|
||||
.orderByAsc(SysDept::getParentId)
|
||||
.orderByAsc(SysDept::getOrderNum);
|
||||
if (deptCheckStrictly) {
|
||||
wrapper.notInSql(SysDept::getDeptId, this.buildParentDeptByRoleSql(roleId));
|
||||
}
|
||||
return this.selectObjs(wrapper);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
package org.dromara.system.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.dromara.common.core.constant.SystemConstants;
|
||||
import org.dromara.common.core.utils.StreamUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.system.domain.SysMenu;
|
||||
import org.dromara.system.domain.vo.SysMenuVo;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 菜单表 数据层
|
||||
@@ -19,12 +20,58 @@ import java.util.List;
|
||||
public interface SysMenuMapper extends BaseMapperPlus<SysMenu, SysMenuVo> {
|
||||
|
||||
/**
|
||||
* 根据用户查询系统菜单列表
|
||||
* 构建用户权限菜单 SQL
|
||||
*
|
||||
* @param queryWrapper 查询条件
|
||||
* @return 菜单列表
|
||||
* <p>
|
||||
* 查询用户所属角色所拥有的菜单权限,用于权限判断、菜单加载等场景
|
||||
* </p>
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return SQL 字符串,用于 inSql 条件
|
||||
*/
|
||||
List<SysMenu> selectMenuListByUserId(@Param(Constants.WRAPPER) Wrapper<SysMenu> queryWrapper);
|
||||
default String buildMenuByUserSql(Long userId) {
|
||||
return """
|
||||
select menu_id from sys_role_menu where role_id in (
|
||||
select role_id from sys_user_role where user_id = %d
|
||||
)
|
||||
""".formatted(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建角色对应的菜单ID SQL 子查询
|
||||
*
|
||||
* <p>
|
||||
* 用于根据角色ID查询其所拥有的菜单权限(用于权限标识、菜单显示等场景)
|
||||
* 通常配合 inSql 使用
|
||||
* </p>
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @return 查询菜单ID的 SQL 子查询字符串
|
||||
*/
|
||||
default String buildMenuByRoleSql(Long roleId) {
|
||||
return """
|
||||
select menu_id from sys_role_menu where role_id = %d
|
||||
""".formatted(roleId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建角色所关联菜单的父菜单ID查询 SQL
|
||||
*
|
||||
* <p>
|
||||
* 用于配合菜单勾选树结构的 {@code menuCheckStrictly} 模式,过滤掉非叶子节点(父菜单),
|
||||
* 只返回角色实际勾选的末级菜单
|
||||
* </p>
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @return SQL 语句字符串(查询菜单的父菜单ID)
|
||||
*/
|
||||
default String buildParentMenuByRoleSql(Long roleId) {
|
||||
return """
|
||||
select parent_id from sys_menu where menu_id in (
|
||||
select menu_id from sys_role_menu where role_id = %d
|
||||
)
|
||||
""".formatted(roleId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID查询权限
|
||||
@@ -32,7 +79,15 @@ public interface SysMenuMapper extends BaseMapperPlus<SysMenu, SysMenuVo> {
|
||||
* @param userId 用户ID
|
||||
* @return 权限列表
|
||||
*/
|
||||
List<String> selectMenuPermsByUserId(Long userId);
|
||||
default Set<String> selectMenuPermsByUserId(Long userId) {
|
||||
List<String> list = this.selectObjs(
|
||||
new LambdaQueryWrapper<SysMenu>()
|
||||
.select(SysMenu::getPerms)
|
||||
.inSql(SysMenu::getMenuId, this.buildMenuByUserSql(userId))
|
||||
.isNotNull(SysMenu::getPerms)
|
||||
);
|
||||
return new HashSet<>(StreamUtils.filter(list, StringUtils::isNotBlank));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据角色ID查询权限
|
||||
@@ -40,7 +95,15 @@ public interface SysMenuMapper extends BaseMapperPlus<SysMenu, SysMenuVo> {
|
||||
* @param roleId 角色ID
|
||||
* @return 权限列表
|
||||
*/
|
||||
List<String> selectMenuPermsByRoleId(Long roleId);
|
||||
default Set<String> selectMenuPermsByRoleId(Long roleId) {
|
||||
List<String> list = this.selectObjs(
|
||||
new LambdaQueryWrapper<SysMenu>()
|
||||
.select(SysMenu::getPerms)
|
||||
.inSql(SysMenu::getMenuId, this.buildMenuByRoleSql(roleId))
|
||||
.isNotNull(SysMenu::getPerms)
|
||||
);
|
||||
return new HashSet<>(StreamUtils.filter(list, StringUtils::isNotBlank));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID查询菜单
|
||||
@@ -56,14 +119,6 @@ public interface SysMenuMapper extends BaseMapperPlus<SysMenu, SysMenuVo> {
|
||||
return this.selectList(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID查询菜单
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 菜单列表
|
||||
*/
|
||||
List<SysMenu> selectMenuTreeByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 根据角色ID查询菜单树信息
|
||||
*
|
||||
@@ -71,6 +126,16 @@ public interface SysMenuMapper extends BaseMapperPlus<SysMenu, SysMenuVo> {
|
||||
* @param menuCheckStrictly 菜单树选择项是否关联显示
|
||||
* @return 选中菜单列表
|
||||
*/
|
||||
List<Long> selectMenuListByRoleId(@Param("roleId") Long roleId, @Param("menuCheckStrictly") boolean menuCheckStrictly);
|
||||
default List<Long> selectMenuListByRoleId(Long roleId, boolean menuCheckStrictly) {
|
||||
LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.select(SysMenu::getMenuId)
|
||||
.inSql(SysMenu::getMenuId, buildMenuByRoleSql(roleId))
|
||||
.orderByAsc(SysMenu::getParentId)
|
||||
.orderByAsc(SysMenu::getOrderNum);
|
||||
if (menuCheckStrictly) {
|
||||
wrapper.notInSql(SysMenu::getMenuId, this.buildParentMenuByRoleSql(roleId));
|
||||
}
|
||||
return this.selectObjs(wrapper);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package org.dromara.system.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.dromara.common.mybatis.annotation.DataColumn;
|
||||
import org.dromara.common.mybatis.annotation.DataPermission;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
@@ -30,14 +29,47 @@ public interface SysPostMapper extends BaseMapperPlus<SysPost, SysPostVo> {
|
||||
@DataColumn(key = "deptName", value = "dept_id"),
|
||||
@DataColumn(key = "userName", value = "create_by")
|
||||
})
|
||||
Page<SysPostVo> selectPagePostList(@Param("page") Page<SysPostVo> page, @Param(Constants.WRAPPER) Wrapper<SysPost> queryWrapper);
|
||||
default Page<SysPostVo> selectPagePostList(Page<SysPost> page, Wrapper<SysPost> queryWrapper) {
|
||||
return this.selectVoPage(page, queryWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户所属岗位组
|
||||
* 查询岗位列表
|
||||
*
|
||||
* @param queryWrapper 查询条件
|
||||
* @return 岗位信息列表
|
||||
*/
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "dept_id"),
|
||||
@DataColumn(key = "userName", value = "create_by")
|
||||
})
|
||||
default List<SysPostVo> selectPostList(Wrapper<SysPost> queryWrapper) {
|
||||
return this.selectVoList(queryWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据岗位ID集合查询岗位数量
|
||||
*
|
||||
* @param postIds 岗位ID列表
|
||||
* @return 匹配的岗位数量
|
||||
*/
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "dept_id"),
|
||||
@DataColumn(key = "userName", value = "create_by")
|
||||
})
|
||||
default long selectPostCount(List<Long> postIds) {
|
||||
return this.selectCount(new LambdaQueryWrapper<SysPost>().in(SysPost::getPostId, postIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID查询其关联的岗位列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 结果
|
||||
* @return 岗位信息列表
|
||||
*/
|
||||
List<SysPostVo> selectPostsByUserId(Long userId);
|
||||
default List<SysPostVo> selectPostsByUserId(Long userId) {
|
||||
return this.selectVoList(new LambdaQueryWrapper<SysPost>()
|
||||
.inSql(SysPost::getPostId, "select post_id from sys_user_post where user_id = " + userId));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.dromara.system.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
@@ -19,6 +20,18 @@ import java.util.List;
|
||||
*/
|
||||
public interface SysRoleMapper extends BaseMapperPlus<SysRole, SysRoleVo> {
|
||||
|
||||
/**
|
||||
* 构建根据用户ID查询角色ID的SQL子查询
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 查询用户对应角色ID的SQL语句字符串
|
||||
*/
|
||||
default String buildRoleByUserSql(Long userId) {
|
||||
return """
|
||||
select role_id from sys_user_role where user_id = %d
|
||||
""".formatted(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询角色列表
|
||||
*
|
||||
@@ -27,22 +40,40 @@ public interface SysRoleMapper extends BaseMapperPlus<SysRole, SysRoleVo> {
|
||||
* @return 包含角色信息的分页结果
|
||||
*/
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "d.dept_id"),
|
||||
@DataColumn(key = "userName", value = "r.create_by")
|
||||
@DataColumn(key = "deptName", value = "create_dept"),
|
||||
@DataColumn(key = "userName", value = "create_by")
|
||||
})
|
||||
Page<SysRoleVo> selectPageRoleList(@Param("page") Page<SysRole> page, @Param(Constants.WRAPPER) Wrapper<SysRole> queryWrapper);
|
||||
default Page<SysRoleVo> selectPageRoleList(@Param("page") Page<SysRole> page, @Param(Constants.WRAPPER) Wrapper<SysRole> queryWrapper) {
|
||||
return this.selectVoPage(page, queryWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据条件分页查询角色数据
|
||||
* 根据条件查询角色数据
|
||||
*
|
||||
* @param queryWrapper 查询条件
|
||||
* @return 角色数据集合信息
|
||||
*/
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "d.dept_id"),
|
||||
@DataColumn(key = "userName", value = "r.create_by")
|
||||
@DataColumn(key = "deptName", value = "create_dept"),
|
||||
@DataColumn(key = "userName", value = "create_by")
|
||||
})
|
||||
List<SysRoleVo> selectRoleList(@Param(Constants.WRAPPER) Wrapper<SysRole> queryWrapper);
|
||||
default List<SysRoleVo> selectRoleList(@Param(Constants.WRAPPER) Wrapper<SysRole> queryWrapper) {
|
||||
return this.selectVoList(queryWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据角色ID集合查询角色数量
|
||||
*
|
||||
* @param roleIds 角色ID列表
|
||||
* @return 匹配的角色数量
|
||||
*/
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "create_dept"),
|
||||
@DataColumn(key = "userName", value = "create_by")
|
||||
})
|
||||
default long selectRoleCount(List<Long> roleIds) {
|
||||
return this.selectCount(new LambdaQueryWrapper<SysRole>().in(SysRole::getRoleId, roleIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据角色ID查询角色信息
|
||||
@@ -51,10 +82,12 @@ public interface SysRoleMapper extends BaseMapperPlus<SysRole, SysRoleVo> {
|
||||
* @return 对应的角色信息
|
||||
*/
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "d.dept_id"),
|
||||
@DataColumn(key = "userName", value = "r.create_by")
|
||||
@DataColumn(key = "deptName", value = "create_dept"),
|
||||
@DataColumn(key = "userName", value = "create_by")
|
||||
})
|
||||
SysRoleVo selectRoleById(Long roleId);
|
||||
default SysRoleVo selectRoleById(Long roleId) {
|
||||
return this.selectVoById(roleId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID查询角色
|
||||
@@ -62,14 +95,11 @@ public interface SysRoleMapper extends BaseMapperPlus<SysRole, SysRoleVo> {
|
||||
* @param userId 用户ID
|
||||
* @return 角色列表
|
||||
*/
|
||||
List<SysRoleVo> selectRolePermissionByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 根据用户ID查询角色
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 角色列表
|
||||
*/
|
||||
List<SysRoleVo> selectRolesByUserId(Long userId);
|
||||
default List<SysRoleVo> selectRolesByUserId(Long userId) {
|
||||
return this.selectVoList(new LambdaQueryWrapper<SysRole>()
|
||||
.select(SysRole::getRoleId, SysRole::getRoleName, SysRole::getRoleKey,
|
||||
SysRole::getRoleSort, SysRole::getDataScope, SysRole::getStatus)
|
||||
.inSql(SysRole::getRoleId, this.buildRoleByUserSql(userId)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,12 +16,11 @@ public interface SysRoleMenuMapper extends BaseMapperPlus<SysRoleMenu, SysRoleMe
|
||||
/**
|
||||
* 根据菜单ID串删除关联关系
|
||||
*
|
||||
* @param menuIds 菜单ID串
|
||||
* @return 结果
|
||||
*/
|
||||
default int deleteByMenuIds(List<Long> menuIds) {
|
||||
LambdaUpdateWrapper<SysRoleMenu> lqw = new LambdaUpdateWrapper<SysRoleMenu>()
|
||||
.in(SysRoleMenu::getMenuId, menuIds);
|
||||
return this.delete(lqw);
|
||||
return this.delete(new LambdaUpdateWrapper<SysRoleMenu>().in(SysRoleMenu::getMenuId, menuIds));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.dromara.system.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
@@ -28,10 +29,12 @@ public interface SysUserMapper extends BaseMapperPlus<SysUser, SysUserVo> {
|
||||
* @return 分页的用户信息
|
||||
*/
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "u.dept_id"),
|
||||
@DataColumn(key = "userName", value = "u.user_id")
|
||||
@DataColumn(key = "deptName", value = "dept_id"),
|
||||
@DataColumn(key = "userName", value = "create_by")
|
||||
})
|
||||
Page<SysUserVo> selectPageUserList(@Param("page") Page<SysUser> page, @Param(Constants.WRAPPER) Wrapper<SysUser> queryWrapper);
|
||||
default Page<SysUserVo> selectPageUserList(Page<SysUser> page, Wrapper<SysUser> queryWrapper) {
|
||||
return this.selectVoPage(page, queryWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户列表,并进行数据权限控制
|
||||
@@ -41,9 +44,11 @@ public interface SysUserMapper extends BaseMapperPlus<SysUser, SysUserVo> {
|
||||
*/
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "dept_id"),
|
||||
@DataColumn(key = "userName", value = "user_id")
|
||||
@DataColumn(key = "userName", value = "create_by")
|
||||
})
|
||||
List<SysUserVo> selectUserList(@Param(Constants.WRAPPER) Wrapper<SysUser> queryWrapper);
|
||||
default List<SysUserVo> selectUserList(Wrapper<SysUser> queryWrapper) {
|
||||
return this.selectVoList(queryWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据条件分页查询用户列表
|
||||
@@ -53,19 +58,20 @@ public interface SysUserMapper extends BaseMapperPlus<SysUser, SysUserVo> {
|
||||
*/
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "d.dept_id"),
|
||||
@DataColumn(key = "userName", value = "u.user_id")
|
||||
@DataColumn(key = "userName", value = "u.create_by")
|
||||
})
|
||||
List<SysUserExportVo> selectUserExportList(@Param(Constants.WRAPPER) Wrapper<SysUser> queryWrapper);
|
||||
|
||||
/**
|
||||
* 根据条件分页查询已配用户角色列表
|
||||
*
|
||||
* @param page 分页信息
|
||||
* @param queryWrapper 查询条件
|
||||
* @return 用户信息集合信息
|
||||
*/
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "d.dept_id"),
|
||||
@DataColumn(key = "userName", value = "u.user_id")
|
||||
@DataColumn(key = "userName", value = "u.create_by")
|
||||
})
|
||||
Page<SysUserVo> selectAllocatedList(@Param("page") Page<SysUser> page, @Param(Constants.WRAPPER) Wrapper<SysUser> queryWrapper);
|
||||
|
||||
@@ -77,7 +83,7 @@ public interface SysUserMapper extends BaseMapperPlus<SysUser, SysUserVo> {
|
||||
*/
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "d.dept_id"),
|
||||
@DataColumn(key = "userName", value = "u.user_id")
|
||||
@DataColumn(key = "userName", value = "u.create_by")
|
||||
})
|
||||
Page<SysUserVo> selectUnallocatedList(@Param("page") Page<SysUser> page, @Param(Constants.WRAPPER) Wrapper<SysUser> queryWrapper);
|
||||
|
||||
@@ -89,9 +95,11 @@ public interface SysUserMapper extends BaseMapperPlus<SysUser, SysUserVo> {
|
||||
*/
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "dept_id"),
|
||||
@DataColumn(key = "userName", value = "user_id")
|
||||
@DataColumn(key = "userName", value = "create_by")
|
||||
})
|
||||
long countUserById(Long userId);
|
||||
default long countUserById(Long userId) {
|
||||
return this.selectCount(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserId, userId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据条件更新用户数据
|
||||
@@ -103,7 +111,7 @@ public interface SysUserMapper extends BaseMapperPlus<SysUser, SysUserVo> {
|
||||
@Override
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "dept_id"),
|
||||
@DataColumn(key = "userName", value = "user_id")
|
||||
@DataColumn(key = "userName", value = "create_by")
|
||||
})
|
||||
int update(@Param(Constants.ENTITY) SysUser user, @Param(Constants.WRAPPER) Wrapper<SysUser> updateWrapper);
|
||||
|
||||
@@ -116,7 +124,7 @@ public interface SysUserMapper extends BaseMapperPlus<SysUser, SysUserVo> {
|
||||
@Override
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "dept_id"),
|
||||
@DataColumn(key = "userName", value = "user_id")
|
||||
@DataColumn(key = "userName", value = "create_by")
|
||||
})
|
||||
int updateById(@Param(Constants.ENTITY) SysUser user);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.dromara.system.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.system.domain.SysUserRole;
|
||||
|
||||
@@ -18,6 +19,10 @@ public interface SysUserRoleMapper extends BaseMapperPlus<SysUserRole, SysUserRo
|
||||
* @param roleId 角色ID
|
||||
* @return 关联到指定角色的用户ID列表
|
||||
*/
|
||||
List<Long> selectUserIdsByRoleId(Long roleId);
|
||||
default List<Long> selectUserIdsByRoleId(Long roleId) {
|
||||
return this.selectObjs(new LambdaQueryWrapper<SysUserRole>()
|
||||
.select(SysUserRole::getUserId).eq(SysUserRole::getRoleId, roleId)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,7 +14,13 @@ import java.util.List;
|
||||
*/
|
||||
public interface ISysConfigService {
|
||||
|
||||
|
||||
/**
|
||||
* 分页查询参数配置列表
|
||||
*
|
||||
* @param config 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 参数配置分页列表
|
||||
*/
|
||||
TableDataInfo<SysConfigVo> selectPageConfigList(SysConfigBo config, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
@@ -69,7 +75,7 @@ public interface ISysConfigService {
|
||||
*
|
||||
* @param configIds 需要删除的参数ID
|
||||
*/
|
||||
void deleteConfigByIds(Long[] configIds);
|
||||
void deleteConfigByIds(List<Long> configIds);
|
||||
|
||||
/**
|
||||
* 重置参数缓存数据
|
||||
|
||||
@@ -14,7 +14,13 @@ import java.util.List;
|
||||
*/
|
||||
public interface ISysDictDataService {
|
||||
|
||||
|
||||
/**
|
||||
* 分页查询字典数据列表
|
||||
*
|
||||
* @param dictData 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 字典数据分页列表
|
||||
*/
|
||||
TableDataInfo<SysDictDataVo> selectPageDictDataList(SysDictDataBo dictData, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
@@ -47,7 +53,7 @@ public interface ISysDictDataService {
|
||||
*
|
||||
* @param dictCodes 需要删除的字典数据ID
|
||||
*/
|
||||
void deleteDictDataByIds(Long[] dictCodes);
|
||||
void deleteDictDataByIds(List<Long> dictCodes);
|
||||
|
||||
/**
|
||||
* 新增保存字典数据信息
|
||||
|
||||
@@ -15,7 +15,13 @@ import java.util.List;
|
||||
*/
|
||||
public interface ISysDictTypeService {
|
||||
|
||||
|
||||
/**
|
||||
* 分页查询字典类型列表
|
||||
*
|
||||
* @param dictType 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 字典类型分页列表
|
||||
*/
|
||||
TableDataInfo<SysDictTypeVo> selectPageDictTypeList(SysDictTypeBo dictType, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
@@ -62,7 +68,7 @@ public interface ISysDictTypeService {
|
||||
*
|
||||
* @param dictIds 需要删除的字典ID
|
||||
*/
|
||||
void deleteDictTypeByIds(Long[] dictIds);
|
||||
void deleteDictTypeByIds(List<Long> dictIds);
|
||||
|
||||
/**
|
||||
* 重置字典缓存数据
|
||||
|
||||
@@ -14,7 +14,13 @@ import java.util.List;
|
||||
*/
|
||||
public interface ISysLogininforService {
|
||||
|
||||
|
||||
/**
|
||||
* 分页查询登录日志列表
|
||||
*
|
||||
* @param logininfor 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 登录日志分页列表
|
||||
*/
|
||||
TableDataInfo<SysLogininforVo> selectPageLogininforList(SysLogininforBo logininfor, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,7 +14,13 @@ import java.util.List;
|
||||
*/
|
||||
public interface ISysNoticeService {
|
||||
|
||||
|
||||
/**
|
||||
* 分页查询通知公告列表
|
||||
*
|
||||
* @param notice 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 通知公告分页列表
|
||||
*/
|
||||
TableDataInfo<SysNoticeVo> selectPageNoticeList(SysNoticeBo notice, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,6 +14,13 @@ import java.util.List;
|
||||
*/
|
||||
public interface ISysOperLogService {
|
||||
|
||||
/**
|
||||
* 分页查询操作日志列表
|
||||
*
|
||||
* @param operLog 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 操作日志分页列表
|
||||
*/
|
||||
TableDataInfo<SysOperLogVo> selectPageOperLogList(SysOperLogBo operLog, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,7 +14,13 @@ import java.util.List;
|
||||
*/
|
||||
public interface ISysPostService {
|
||||
|
||||
|
||||
/**
|
||||
* 分页查询岗位列表
|
||||
*
|
||||
* @param post 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 岗位分页列表
|
||||
*/
|
||||
TableDataInfo<SysPostVo> selectPagePostList(SysPostBo post, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
@@ -110,7 +116,7 @@ public interface ISysPostService {
|
||||
* @param postIds 需要删除的岗位ID
|
||||
* @return 结果
|
||||
*/
|
||||
int deletePostByIds(Long[] postIds);
|
||||
int deletePostByIds(List<Long> postIds);
|
||||
|
||||
/**
|
||||
* 新增保存岗位信息
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user