!591 发布 5.2.3 正式版

Merge pull request !591 from 疯狂的狮子Li/dev
This commit is contained in:
疯狂的狮子Li 2024-10-25 03:09:23 +00:00 committed by Gitee
commit 015b406001
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
71 changed files with 587 additions and 310 deletions

View File

@ -2,7 +2,7 @@
<configuration default="false" name="ruoyi-monitor-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker"> <configuration default="false" name="ruoyi-monitor-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
<deployment type="dockerfile"> <deployment type="dockerfile">
<settings> <settings>
<option name="imageTag" value="ruoyi/ruoyi-monitor-admin:5.2.2" /> <option name="imageTag" value="ruoyi/ruoyi-monitor-admin:5.2.3" />
<option name="buildOnly" value="true" /> <option name="buildOnly" value="true" />
<option name="sourceFilePath" value="ruoyi-extend/ruoyi-monitor-admin/Dockerfile" /> <option name="sourceFilePath" value="ruoyi-extend/ruoyi-monitor-admin/Dockerfile" />
</settings> </settings>

View File

@ -2,7 +2,7 @@
<configuration default="false" name="ruoyi-server" type="docker-deploy" factoryName="dockerfile" server-name="演示机"> <configuration default="false" name="ruoyi-server" type="docker-deploy" factoryName="dockerfile" server-name="演示机">
<deployment type="dockerfile"> <deployment type="dockerfile">
<settings> <settings>
<option name="imageTag" value="ruoyi/ruoyi-server:5.2.2" /> <option name="imageTag" value="ruoyi/ruoyi-server:5.2.3" />
<option name="buildOnly" value="true" /> <option name="buildOnly" value="true" />
<option name="sourceFilePath" value="ruoyi-admin/Dockerfile" /> <option name="sourceFilePath" value="ruoyi-admin/Dockerfile" />
</settings> </settings>

View File

@ -2,7 +2,7 @@
<configuration default="false" name="ruoyi-snailjob-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker"> <configuration default="false" name="ruoyi-snailjob-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
<deployment type="dockerfile"> <deployment type="dockerfile">
<settings> <settings>
<option name="imageTag" value="ruoyi/ruoyi-snailjob-server:5.2.2" /> <option name="imageTag" value="ruoyi/ruoyi-snailjob-server:5.2.3" />
<option name="buildOnly" value="true" /> <option name="buildOnly" value="true" />
<option name="sourceFilePath" value="ruoyi-extend/ruoyi-snailjob-server/Dockerfile" /> <option name="sourceFilePath" value="ruoyi-extend/ruoyi-snailjob-server/Dockerfile" />
</settings> </settings>

View File

@ -9,7 +9,7 @@
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/master/LICENSE) [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/master/LICENSE)
[![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=RuoYi-Vue-Plus) [![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
<br> <br>
[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-5.2.2-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus) [![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-5.2.3-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus)
[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.2-blue.svg)]() [![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.2-blue.svg)]()
[![JDK-17](https://img.shields.io/badge/JDK-17-green.svg)]() [![JDK-17](https://img.shields.io/badge/JDK-17-green.svg)]()
[![JDK-21](https://img.shields.io/badge/JDK-21-green.svg)]() [![JDK-21](https://img.shields.io/badge/JDK-21-green.svg)]()

58
pom.xml
View File

@ -13,44 +13,42 @@
<description>RuoYi-Vue-Plus多租户管理系统</description> <description>RuoYi-Vue-Plus多租户管理系统</description>
<properties> <properties>
<revision>5.2.2</revision> <revision>5.2.3</revision>
<spring-boot.version>3.2.9</spring-boot.version> <spring-boot.version>3.2.11</spring-boot.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>17</java.version> <java.version>17</java.version>
<mybatis.version>3.5.16</mybatis.version> <mybatis.version>3.5.16</mybatis.version>
<springdoc.version>2.6.0</springdoc.version> <springdoc.version>2.6.0</springdoc.version>
<therapi-javadoc.version>0.15.0</therapi-javadoc.version> <therapi-javadoc.version>0.15.0</therapi-javadoc.version>
<easyexcel.version>4.0.2</easyexcel.version> <easyexcel.version>4.0.3</easyexcel.version>
<velocity.version>2.3</velocity.version> <velocity.version>2.3</velocity.version>
<satoken.version>1.38.0</satoken.version> <satoken.version>1.39.0</satoken.version>
<mybatis-plus.version>3.5.7</mybatis-plus.version> <mybatis-plus.version>3.5.8</mybatis-plus.version>
<p6spy.version>3.9.1</p6spy.version> <p6spy.version>3.9.1</p6spy.version>
<hutool.version>5.8.31</hutool.version> <hutool.version>5.8.31</hutool.version>
<okhttp.version>4.10.0</okhttp.version>
<spring-boot-admin.version>3.2.3</spring-boot-admin.version> <spring-boot-admin.version>3.2.3</spring-boot-admin.version>
<redisson.version>3.34.1</redisson.version> <redisson.version>3.37.0</redisson.version>
<lock4j.version>2.2.7</lock4j.version> <lock4j.version>2.2.7</lock4j.version>
<dynamic-ds.version>4.3.1</dynamic-ds.version> <dynamic-ds.version>4.3.1</dynamic-ds.version>
<snailjob.version>1.1.2</snailjob.version> <snailjob.version>1.1.2</snailjob.version>
<mapstruct-plus.version>1.4.4</mapstruct-plus.version> <mapstruct-plus.version>1.4.5</mapstruct-plus.version>
<mapstruct-plus.lombok.version>0.2.0</mapstruct-plus.lombok.version> <mapstruct-plus.lombok.version>0.2.0</mapstruct-plus.lombok.version>
<lombok.version>1.18.34</lombok.version> <lombok.version>1.18.34</lombok.version>
<bouncycastle.version>1.76</bouncycastle.version> <bouncycastle.version>1.76</bouncycastle.version>
<justauth.version>1.16.6</justauth.version> <justauth.version>1.16.6</justauth.version>
<!-- 离线IP地址定位库 --> <!-- 离线IP地址定位库 -->
<ip2region.version>2.7.0</ip2region.version> <ip2region.version>2.7.0</ip2region.version>
<undertow.version>2.3.15.Final</undertow.version>
<!-- OSS 配置 --> <!-- OSS 配置 -->
<aws.sdk.version>2.25.15</aws.sdk.version> <aws.sdk.version>2.28.22</aws.sdk.version>
<aws.crt.version>0.29.13</aws.crt.version> <aws.crt.version>0.31.3</aws.crt.version>
<!-- SMS 配置 --> <!-- SMS 配置 -->
<sms4j.version>3.3.2</sms4j.version> <sms4j.version>3.3.3</sms4j.version>
<!-- 限制框架中的fastjson版本 --> <!-- 限制框架中的fastjson版本 -->
<fastjson.version>1.2.83</fastjson.version> <fastjson.version>1.2.83</fastjson.version>
<!-- 面向运行时的D-ORM依赖 --> <!-- 面向运行时的D-ORM依赖 -->
<anyline.version>8.7.2-20240808</anyline.version> <anyline.version>8.7.2-20241022</anyline.version>
<!--工作流配置--> <!--工作流配置-->
<flowable.version>7.0.1</flowable.version> <flowable.version>7.0.1</flowable.version>
@ -69,6 +67,8 @@
<!-- 环境标识,需要与配置文件的名称相对应 --> <!-- 环境标识,需要与配置文件的名称相对应 -->
<profiles.active>local</profiles.active> <profiles.active>local</profiles.active>
<logging.level>info</logging.level> <logging.level>info</logging.level>
<monitor.username>ruoyi</monitor.username>
<monitor.password>123456</monitor.password>
</properties> </properties>
</profile> </profile>
<profile> <profile>
@ -77,6 +77,8 @@
<!-- 环境标识,需要与配置文件的名称相对应 --> <!-- 环境标识,需要与配置文件的名称相对应 -->
<profiles.active>dev</profiles.active> <profiles.active>dev</profiles.active>
<logging.level>info</logging.level> <logging.level>info</logging.level>
<monitor.username>ruoyi</monitor.username>
<monitor.password>123456</monitor.password>
</properties> </properties>
<activation> <activation>
<!-- 默认环境 --> <!-- 默认环境 -->
@ -88,6 +90,8 @@
<properties> <properties>
<profiles.active>prod</profiles.active> <profiles.active>prod</profiles.active>
<logging.level>warn</logging.level> <logging.level>warn</logging.level>
<monitor.username>ruoyi</monitor.username>
<monitor.password>123456</monitor.password>
</properties> </properties>
</profile> </profile>
</profiles> </profiles>
@ -225,12 +229,6 @@
<version>${p6spy.version}</version> <version>${p6spy.version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp.version}</version>
</dependency>
<!-- AWS SDK for Java 2.x --> <!-- AWS SDK for Java 2.x -->
<dependency> <dependency>
<groupId>software.amazon.awssdk</groupId> <groupId>software.amazon.awssdk</groupId>
@ -313,25 +311,9 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.undertow</groupId> <groupId>commons-io</groupId>
<artifactId>undertow-core</artifactId> <artifactId>commons-io</artifactId>
<version>${undertow.version}</version> <version>2.15.0</version>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-servlet</artifactId>
<version>${undertow.version}</version>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-websockets-jsr</artifactId>
<version>${undertow.version}</version>
</dependency>
<dependency>
<artifactId>commons-compress</artifactId>
<groupId>org.apache.commons</groupId>
<version>1.26.2</version>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -8,8 +8,8 @@ spring.boot.admin.client:
metadata: metadata:
username: ${spring.boot.admin.client.username} username: ${spring.boot.admin.client.username}
userpassword: ${spring.boot.admin.client.password} userpassword: ${spring.boot.admin.client.password}
username: ruoyi username: @monitor.username@
password: 123456 password: @monitor.password@
--- # snail-job 配置 --- # snail-job 配置
snail-job: snail-job:
@ -25,6 +25,8 @@ snail-job:
namespace: ${spring.profiles.active} namespace: ${spring.profiles.active}
# 随主应用端口飘逸 # 随主应用端口飘逸
port: 2${server.port} port: 2${server.port}
# 客户端ip指定
host:
--- # 数据源配置 --- # 数据源配置
spring: spring:

View File

@ -11,8 +11,8 @@ spring.boot.admin.client:
metadata: metadata:
username: ${spring.boot.admin.client.username} username: ${spring.boot.admin.client.username}
userpassword: ${spring.boot.admin.client.password} userpassword: ${spring.boot.admin.client.password}
username: ruoyi username: @monitor.username@
password: 123456 password: @monitor.password@
--- # snail-job 配置 --- # snail-job 配置
snail-job: snail-job:
@ -28,6 +28,8 @@ snail-job:
namespace: ${spring.profiles.active} namespace: ${spring.profiles.active}
# 随主应用端口飘逸 # 随主应用端口飘逸
port: 2${server.port} port: 2${server.port}
# 客户端ip指定
host:
--- # 数据源配置 --- # 数据源配置
spring: spring:

View File

@ -223,9 +223,10 @@ xss:
# 过滤开关 # 过滤开关
enabled: true enabled: true
# 排除链接(多个用逗号分隔) # 排除链接(多个用逗号分隔)
excludes: /system/notice excludeUrls:
# 匹配链接 - /system/notice
urlPatterns: /system/*,/monitor/*,/tool/* - /workflow/model/save
- /workflow/model/editModelXml
# 全局线程池相关配置 # 全局线程池相关配置
# 如使用JDK21请直接使用虚拟线程 不要开启此配置 # 如使用JDK21请直接使用虚拟线程 不要开启此配置

View File

@ -14,7 +14,7 @@
</description> </description>
<properties> <properties>
<revision>5.2.2</revision> <revision>5.2.3</revision>
</properties> </properties>
<dependencyManagement> <dependencyManagement>

View File

@ -0,0 +1,62 @@
package org.dromara.common.core.exception;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.io.Serial;
/**
* sse 特制异常
*
* @author LionLi
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
public final class SseException extends RuntimeException {
@Serial
private static final long serialVersionUID = 1L;
/**
* 错误码
*/
private Integer code;
/**
* 错误提示
*/
private String message;
/**
* 错误明细内部调试错误
*/
private String detailMessage;
public SseException(String message) {
this.message = message;
}
public SseException(String message, Integer code) {
this.message = message;
this.code = code;
}
@Override
public String getMessage() {
return message;
}
public SseException setMessage(String message) {
this.message = message;
return this;
}
public SseException setDetailMessage(String detailMessage) {
this.detailMessage = detailMessage;
return this;
}
}

View File

@ -5,11 +5,13 @@ import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig; import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil; import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.lang.tree.parser.NodeParser; import cn.hutool.core.lang.tree.parser.NodeParser;
import org.dromara.common.core.utils.reflect.ReflectUtils;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.dromara.common.core.utils.reflect.ReflectUtils;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/** /**
* 扩展 hutool TreeUtil 封装系统树构建 * 扩展 hutool TreeUtil 封装系统树构建
@ -24,12 +26,54 @@ public class TreeBuildUtils extends TreeUtil {
*/ */
public static final TreeNodeConfig DEFAULT_CONFIG = TreeNodeConfig.DEFAULT_CONFIG.setNameKey("label"); public static final TreeNodeConfig DEFAULT_CONFIG = TreeNodeConfig.DEFAULT_CONFIG.setNameKey("label");
/**
* 构建树形结构
*
* @param <T> 输入节点的类型
* @param <K> 节点ID的类型
* @param list 节点列表其中包含了要构建树形结构的所有节点
* @param nodeParser 解析器用于将输入节点转换为树节点
* @return 构建好的树形结构列表
*/
public static <T, K> List<Tree<K>> build(List<T> list, NodeParser<T, K> nodeParser) { public static <T, K> List<Tree<K>> build(List<T> list, NodeParser<T, K> nodeParser) {
if (CollUtil.isEmpty(list)) { if (CollUtil.isEmpty(list)) {
return null; return CollUtil.newArrayList();
} }
K k = ReflectUtils.invokeGetter(list.get(0), "parentId"); K k = ReflectUtils.invokeGetter(list.get(0), "parentId");
return TreeUtil.build(list, k, DEFAULT_CONFIG, nodeParser); return TreeUtil.build(list, k, DEFAULT_CONFIG, nodeParser);
} }
/**
* 获取节点列表中所有节点的叶子节点
*
* @param <K> 节点ID的类型
* @param nodes 节点列表
* @return 包含所有叶子节点的列表
*/
public static <K> List<Tree<K>> getLeafNodes(List<Tree<K>> nodes) {
if (CollUtil.isEmpty(nodes)) {
return CollUtil.newArrayList();
}
return nodes.stream()
.flatMap(TreeBuildUtils::extractLeafNodes)
.collect(Collectors.toList());
}
/**
* 获取指定节点下的所有叶子节点
*
* @param <K> 节点ID的类型
* @param node 要查找叶子节点的根节点
* @return 包含所有叶子节点的列表
*/
private static <K> Stream<Tree<K>> extractLeafNodes(Tree<K> node) {
if (!node.hasChild()) {
return Stream.of(node);
} else {
// 递归调用获取所有子节点的叶子节点
return node.getChildren().stream()
.flatMap(TreeBuildUtils::extractLeafNodes);
}
}
} }

View File

@ -21,7 +21,8 @@ public final class RegexUtils extends ReUtil {
*/ */
public static String extractFromString(String input, String regex, String defaultInput) { public static String extractFromString(String input, String regex, String defaultInput) {
try { try {
return ReUtil.get(regex, input, 1); String str = ReUtil.get(regex, input, 1);
return str == null ? defaultInput : str;
} catch (Exception e) { } catch (Exception e) {
return defaultInput; return defaultInput;
} }

View File

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

View File

@ -17,7 +17,10 @@ import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.*; import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -34,7 +37,7 @@ public class EncryptorManager {
/** /**
* 缓存加密器 * 缓存加密器
*/ */
Map<EncryptContext, IEncryptor> encryptorMap = new ConcurrentHashMap<>(); Map<Integer, IEncryptor> encryptorMap = new ConcurrentHashMap<>();
/** /**
* 类加密字段缓存 * 类加密字段缓存
@ -67,11 +70,12 @@ public class EncryptorManager {
* @param encryptContext 加密执行者需要的相关配置参数 * @param encryptContext 加密执行者需要的相关配置参数
*/ */
public IEncryptor registAndGetEncryptor(EncryptContext encryptContext) { public IEncryptor registAndGetEncryptor(EncryptContext encryptContext) {
if (encryptorMap.containsKey(encryptContext)) { int key = encryptContext.hashCode();
return encryptorMap.get(encryptContext); if (encryptorMap.containsKey(key)) {
return encryptorMap.get(key);
} }
IEncryptor encryptor = ReflectUtil.newInstance(encryptContext.getAlgorithm().getClazz(), encryptContext); IEncryptor encryptor = ReflectUtil.newInstance(encryptContext.getAlgorithm().getClazz(), encryptContext);
encryptorMap.put(encryptContext, encryptor); encryptorMap.put(key, encryptor);
return encryptor; return encryptor;
} }
@ -81,7 +85,7 @@ public class EncryptorManager {
* @param encryptContext 加密执行者需要的相关配置参数 * @param encryptContext 加密执行者需要的相关配置参数
*/ */
public void removeEncryptor(EncryptContext encryptContext) { public void removeEncryptor(EncryptContext encryptContext) {
this.encryptorMap.remove(encryptContext); this.encryptorMap.remove(encryptContext.hashCode());
} }
/** /**

View File

@ -99,7 +99,7 @@ public class CryptoFilter implements Filter {
} }
} }
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); return null;
} }
return null; return null;
} }

View File

@ -25,11 +25,6 @@
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId> <artifactId>easyexcel</artifactId>
</dependency> </dependency>
<dependency>
<artifactId>commons-compress</artifactId>
<groupId>org.apache.commons</groupId>
<version>1.26.2</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -159,8 +159,7 @@ public class LogAspect {
private void setRequestValue(JoinPoint joinPoint, OperLogEvent operLog, String[] excludeParamNames) throws Exception { private void setRequestValue(JoinPoint joinPoint, OperLogEvent operLog, String[] excludeParamNames) throws Exception {
Map<String, String> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest()); Map<String, String> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest());
String requestMethod = operLog.getRequestMethod(); String requestMethod = operLog.getRequestMethod();
if (MapUtil.isEmpty(paramsMap) if (MapUtil.isEmpty(paramsMap) && StringUtils.equalsAny(requestMethod, HttpMethod.PUT.name(), HttpMethod.POST.name(), HttpMethod.DELETE.name())) {
&& HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) {
String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames); String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);
operLog.setOperParam(StringUtils.substring(params, 0, 2000)); operLog.setOperParam(StringUtils.substring(params, 0, 2000));
} else { } else {

View File

@ -18,9 +18,7 @@ import java.io.Serializable;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors;
/** /**
* 自定义 Mapper 接口, 实现 自定义扩展 * 自定义 Mapper 接口, 实现 自定义扩展
@ -69,9 +67,7 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
* @return 插入操作是否成功的布尔值 * @return 插入操作是否成功的布尔值
*/ */
default boolean insertBatch(Collection<T> entityList) { default boolean insertBatch(Collection<T> entityList) {
Db.saveBatch(entityList); return Db.saveBatch(entityList);
// 临时解决 新版本 mp 插入状态判断错误问题
return true;
} }
/** /**
@ -81,9 +77,7 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
* @return 更新操作是否成功的布尔值 * @return 更新操作是否成功的布尔值
*/ */
default boolean updateBatchById(Collection<T> entityList) { default boolean updateBatchById(Collection<T> entityList) {
Db.updateBatchById(entityList); return Db.updateBatchById(entityList);
// 临时解决 新版本 mp 插入状态判断错误问题
return true;
} }
/** /**
@ -93,9 +87,7 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
* @return 插入或更新操作是否成功的布尔值 * @return 插入或更新操作是否成功的布尔值
*/ */
default boolean insertOrUpdateBatch(Collection<T> entityList) { default boolean insertOrUpdateBatch(Collection<T> entityList) {
Db.saveOrUpdateBatch(entityList); return Db.saveOrUpdateBatch(entityList);
// 临时解决 新版本 mp 插入状态判断错误问题
return true;
} }
/** /**
@ -106,9 +98,7 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
* @return 插入操作是否成功的布尔值 * @return 插入操作是否成功的布尔值
*/ */
default boolean insertBatch(Collection<T> entityList, int batchSize) { default boolean insertBatch(Collection<T> entityList, int batchSize) {
Db.saveBatch(entityList, batchSize); return Db.saveBatch(entityList, batchSize);
// 临时解决 新版本 mp 插入状态判断错误问题
return true;
} }
/** /**
@ -119,9 +109,7 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
* @return 更新操作是否成功的布尔值 * @return 更新操作是否成功的布尔值
*/ */
default boolean updateBatchById(Collection<T> entityList, int batchSize) { default boolean updateBatchById(Collection<T> entityList, int batchSize) {
Db.updateBatchById(entityList, batchSize); return Db.updateBatchById(entityList, batchSize);
// 临时解决 新版本 mp 插入状态判断错误问题
return true;
} }
/** /**
@ -132,9 +120,7 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
* @return 插入或更新操作是否成功的布尔值 * @return 插入或更新操作是否成功的布尔值
*/ */
default boolean insertOrUpdateBatch(Collection<T> entityList, int batchSize) { default boolean insertOrUpdateBatch(Collection<T> entityList, int batchSize) {
Db.saveOrUpdateBatch(entityList, batchSize); return Db.saveOrUpdateBatch(entityList, batchSize);
// 临时解决 新版本 mp 插入状态判断错误问题
return true;
} }
/** /**
@ -169,8 +155,8 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
* @param idList 主键ID集合 * @param idList 主键ID集合
* @return 查询到的VO对象列表 * @return 查询到的VO对象列表
*/ */
default List<V> selectVoBatchIds(Collection<? extends Serializable> idList) { default List<V> selectVoByIds(Collection<? extends Serializable> idList) {
return selectVoBatchIds(idList, this.currentVoClass()); return selectVoByIds(idList, this.currentVoClass());
} }
/** /**
@ -181,8 +167,8 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
* @param <C> VO类的类型 * @param <C> VO类的类型
* @return 查询到的VO对象列表经过转换为指定的VO类后返回 * @return 查询到的VO对象列表经过转换为指定的VO类后返回
*/ */
default <C> List<C> selectVoBatchIds(Collection<? extends Serializable> idList, Class<C> voClass) { default <C> List<C> selectVoByIds(Collection<? extends Serializable> idList, Class<C> voClass) {
List<T> list = this.selectBatchIds(idList); List<T> list = this.selectByIds(idList);
if (CollUtil.isEmpty(list)) { if (CollUtil.isEmpty(list)) {
return CollUtil.newArrayList(); return CollUtil.newArrayList();
} }

View File

@ -6,8 +6,8 @@ import cn.hutool.core.util.ObjectUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression; import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList;
import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import org.apache.ibatis.io.Resources; import org.apache.ibatis.io.Resources;
import org.dromara.common.core.domain.dto.RoleDTO; import org.dromara.common.core.domain.dto.RoleDTO;
@ -106,7 +106,7 @@ public class PlusDataPermissionHandler {
try { try {
Expression expression = CCJSqlParserUtil.parseExpression(dataFilterSql); Expression expression = CCJSqlParserUtil.parseExpression(dataFilterSql);
// 数据权限使用单独的括号 防止与其他条件冲突 // 数据权限使用单独的括号 防止与其他条件冲突
Parenthesis parenthesis = new Parenthesis(expression); ParenthesedExpressionList<Expression> parenthesis = new ParenthesedExpressionList<>(expression);
if (ObjectUtil.isNotNull(where)) { if (ObjectUtil.isNotNull(where)) {
return new AndExpression(where, parenthesis); return new AndExpression(where, parenthesis);
} else { } else {

View File

@ -62,8 +62,8 @@ public class DataBaseHelper {
// charindex(',100,' , ',0,100,101,') <> 0 // charindex(',100,' , ',0,100,101,') <> 0
return "charindex(',%s,' , ','+%s+',') <> 0".formatted(var, var2); return "charindex(',%s,' , ','+%s+',') <> 0".formatted(var, var2);
} else if (dataBasyType == DataBaseType.POSTGRE_SQL) { } else if (dataBasyType == DataBaseType.POSTGRE_SQL) {
// (select position(',100,' in ',0,100,101,')) <> 0 // (select strpos(',0,100,101,' , ',100,')) <> 0
return "(select position(',%s,' in ','||%s||',')) <> 0".formatted(var, var2); return "(select strpos(','||%s||',' , ',%s,')) <> 0".formatted(var2, var);
} else if (dataBasyType == DataBaseType.ORACLE) { } else if (dataBasyType == DataBaseType.ORACLE) {
// instr(',0,100,101,' , ',100,') <> 0 // instr(',0,100,101,' , ',100,') <> 0
return "instr(','||%s||',' , ',%s,') <> 0".formatted(var2, var); return "instr(','||%s||',' , ',%s,') <> 0".formatted(var2, var);

View File

@ -15,12 +15,12 @@ import org.dromara.common.oss.properties.OssProperties;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.core.ResponseInputStream; import software.amazon.awssdk.core.ResponseInputStream;
import software.amazon.awssdk.core.async.AsyncRequestBody;
import software.amazon.awssdk.core.async.AsyncResponseTransformer; import software.amazon.awssdk.core.async.AsyncResponseTransformer;
import software.amazon.awssdk.core.async.BlockingInputStreamAsyncRequestBody; import software.amazon.awssdk.core.async.BlockingInputStreamAsyncRequestBody;
import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3AsyncClient; import software.amazon.awssdk.services.s3.S3AsyncClient;
import software.amazon.awssdk.services.s3.S3Configuration; import software.amazon.awssdk.services.s3.S3Configuration;
import software.amazon.awssdk.services.s3.crt.S3CrtHttpConfiguration;
import software.amazon.awssdk.services.s3.model.GetObjectResponse; import software.amazon.awssdk.services.s3.model.GetObjectResponse;
import software.amazon.awssdk.services.s3.model.NoSuchBucketException; import software.amazon.awssdk.services.s3.model.NoSuchBucketException;
import software.amazon.awssdk.services.s3.model.S3Exception; import software.amazon.awssdk.services.s3.model.S3Exception;
@ -83,8 +83,8 @@ public class OssClient {
StaticCredentialsProvider credentialsProvider = StaticCredentialsProvider.create( StaticCredentialsProvider credentialsProvider = StaticCredentialsProvider.create(
AwsBasicCredentials.create(properties.getAccessKey(), properties.getSecretKey())); AwsBasicCredentials.create(properties.getAccessKey(), properties.getSecretKey()));
//MinIO 使用 HTTPS 限制使用域名访问站点填域名需要启用路径样式访问 //使用对象存储服务时要求明确配置访问样式路径样式或虚拟托管样式需要启用路径样式访问
boolean isStyle = !StringUtils.containsAny(properties.getEndpoint(), OssConstant.CLOUD_SERVICE); boolean isStyle = true;
//创建AWS基于 CRT S3 客户端 //创建AWS基于 CRT S3 客户端
this.client = S3AsyncClient.crtBuilder() this.client = S3AsyncClient.crtBuilder()
@ -95,6 +95,9 @@ public class OssClient {
.minimumPartSizeInBytes(10 * 1025 * 1024L) .minimumPartSizeInBytes(10 * 1025 * 1024L)
.checksumValidationEnabled(false) .checksumValidationEnabled(false)
.forcePathStyle(isStyle) .forcePathStyle(isStyle)
.httpConfiguration(S3CrtHttpConfiguration.builder()
.connectionTimeout(Duration.ofSeconds(60)) // 设置连接超时
.build())
.build(); .build();
//AWS基于 CRT S3 AsyncClient 实例用作 S3 传输管理器的底层客户端 //AWS基于 CRT S3 AsyncClient 实例用作 S3 传输管理器的底层客户端
@ -178,7 +181,9 @@ public class OssClient {
.key(key) .key(key)
.contentMD5(StringUtils.isNotEmpty(md5Digest) ? md5Digest : null) .contentMD5(StringUtils.isNotEmpty(md5Digest) ? md5Digest : null)
.contentType(contentType) .contentType(contentType)
.acl(getAccessPolicy().getObjectCannedACL()) // 用于设置对象的访问控制列表ACL不同云厂商对ACL的支持和实现方式有所不同
// 因此根据具体的云服务提供商你可能需要进行不同的配置自行开启阿里云有acl权限配置腾讯云没有acl权限配置
//.acl(getAccessPolicy().getObjectCannedACL())
.build()) .build())
.addTransferListener(LoggingTransferListener.create()) .addTransferListener(LoggingTransferListener.create())
.source(filePath).build()); .source(filePath).build());
@ -215,7 +220,10 @@ public class OssClient {
} }
try { try {
// 创建异步请求体length如果为空会报错 // 创建异步请求体length如果为空会报错
BlockingInputStreamAsyncRequestBody body = AsyncRequestBody.forBlockingInputStream(length); BlockingInputStreamAsyncRequestBody body = BlockingInputStreamAsyncRequestBody.builder()
.contentLength(length)
.subscribeTimeout(Duration.ofSeconds(30))
.build();
// 使用 transferManager 进行上传 // 使用 transferManager 进行上传
Upload upload = transferManager.upload( Upload upload = transferManager.upload(
@ -224,7 +232,9 @@ public class OssClient {
y -> y.bucket(properties.getBucketName()) y -> y.bucket(properties.getBucketName())
.key(key) .key(key)
.contentType(contentType) .contentType(contentType)
.acl(getAccessPolicy().getObjectCannedACL()) // 用于设置对象的访问控制列表ACL不同云厂商对ACL的支持和实现方式有所不同
// 因此根据具体的云服务提供商你可能需要进行不同的配置自行开启阿里云有acl权限配置腾讯云没有acl权限配置
//.acl(getAccessPolicy().getObjectCannedACL())
.build()) .build())
.build()); .build());
@ -340,8 +350,8 @@ public class OssClient {
* @return UploadResult 包含上传后的文件信息 * @return UploadResult 包含上传后的文件信息
* @throws OssException 如果上传失败抛出自定义异常 * @throws OssException 如果上传失败抛出自定义异常
*/ */
public UploadResult uploadSuffix(byte[] data, String suffix) { public UploadResult uploadSuffix(byte[] data, String suffix, String contentType) {
return upload(new ByteArrayInputStream(data), getPath(properties.getPrefix(), suffix), Long.valueOf(data.length), FileUtils.getMimeType(suffix)); return upload(new ByteArrayInputStream(data), getPath(properties.getPrefix(), suffix), Long.valueOf(data.length), contentType);
} }
/** /**
@ -353,8 +363,8 @@ public class OssClient {
* @return UploadResult 包含上传后的文件信息 * @return UploadResult 包含上传后的文件信息
* @throws OssException 如果上传失败抛出自定义异常 * @throws OssException 如果上传失败抛出自定义异常
*/ */
public UploadResult uploadSuffix(InputStream inputStream, String suffix, Long length) { public UploadResult uploadSuffix(InputStream inputStream, String suffix, Long length, String contentType) {
return upload(inputStream, getPath(properties.getPrefix(), suffix), length, FileUtils.getMimeType(suffix)); return upload(inputStream, getPath(properties.getPrefix(), suffix), length, contentType);
} }
/** /**

View File

@ -44,6 +44,7 @@ public class CaffeineCacheDecorator implements Cache {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override
public <T> T get(Object key, Class<T> type) { public <T> T get(Object key, Class<T> type) {
Object o = CAFFEINE.get(getUniqueKey(key), k -> cache.get(key, type)); Object o = CAFFEINE.get(getUniqueKey(key), k -> cache.get(key, type));
return (T) o; return (T) o;
@ -55,6 +56,7 @@ public class CaffeineCacheDecorator implements Cache {
cache.put(key, value); cache.put(key, value);
} }
@Override
public ValueWrapper putIfAbsent(Object key, Object value) { public ValueWrapper putIfAbsent(Object key, Object value) {
CAFFEINE.invalidate(getUniqueKey(key)); CAFFEINE.invalidate(getUniqueKey(key));
return cache.putIfAbsent(key, value); return cache.putIfAbsent(key, value);
@ -65,6 +67,7 @@ public class CaffeineCacheDecorator implements Cache {
evictIfPresent(key); evictIfPresent(key);
} }
@Override
public boolean evictIfPresent(Object key) { public boolean evictIfPresent(Object key) {
boolean b = cache.evictIfPresent(key); boolean b = cache.evictIfPresent(key);
if (b) { if (b) {
@ -78,6 +81,7 @@ public class CaffeineCacheDecorator implements Cache {
cache.clear(); cache.clear();
} }
@Override
public boolean invalidate() { public boolean invalidate() {
return cache.invalidate(); return cache.invalidate();
} }

View File

@ -1,19 +1,15 @@
package org.dromara.common.redis.utils; package org.dromara.common.redis.utils;
import org.dromara.common.core.utils.SpringUtils;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.redisson.api.RMap; import org.dromara.common.core.utils.SpringUtils;
import org.springframework.cache.Cache; import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager; import org.springframework.cache.CacheManager;
import java.util.Set;
/** /**
* 缓存操作工具类 {@link } * 缓存操作工具类
* *
* @author Michelle.Chung * @author Michelle.Chung
* @date 2022/8/13
*/ */
@NoArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PRIVATE)
@SuppressWarnings(value = {"unchecked"}) @SuppressWarnings(value = {"unchecked"})
@ -21,16 +17,6 @@ public class CacheUtils {
private static final CacheManager CACHE_MANAGER = SpringUtils.getBean(CacheManager.class); private static final CacheManager CACHE_MANAGER = SpringUtils.getBean(CacheManager.class);
/**
* 获取缓存组内所有的KEY
*
* @param cacheNames 缓存组名称
*/
public static Set<Object> keys(String cacheNames) {
RMap<Object, Object> rmap = (RMap<Object, Object>) CACHE_MANAGER.getCache(cacheNames).getNativeCache();
return rmap.keySet();
}
/** /**
* 获取缓存值 * 获取缓存值
* *

View File

@ -517,7 +517,7 @@ public class RedisUtils {
} }
/** /**
* 获得缓存的基本对象列表 * 获得缓存的基本对象列表(全局匹配忽略租户 自行拼接租户id)
* *
* @param pattern 字符串前缀 * @param pattern 字符串前缀
* @return 对象列表 * @return 对象列表
@ -528,7 +528,7 @@ public class RedisUtils {
} }
/** /**
* 删除缓存的基本对象列表 * 删除缓存的基本对象列表(全局匹配忽略租户 自行拼接租户id)
* *
* @param pattern 字符串前缀 * @param pattern 字符串前缀
*/ */

View File

@ -7,9 +7,11 @@ import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.router.SaRouter; import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult; import cn.dev33.satoken.util.SaResult;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.HttpStatus; import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.SseException;
import org.dromara.common.core.utils.ServletUtils; import org.dromara.common.core.utils.ServletUtils;
import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
@ -50,11 +52,20 @@ public class SecurityConfig implements WebMvcConfigurer {
.match(allUrlHandler.getUrls()) .match(allUrlHandler.getUrls())
// 对未排除的路径进行检查 // 对未排除的路径进行检查
.check(() -> { .check(() -> {
HttpServletRequest request = ServletUtils.getRequest();
// 检查是否登录 是否有token // 检查是否登录 是否有token
try {
StpUtil.checkLogin(); StpUtil.checkLogin();
} catch (NotLoginException e) {
if (request.getRequestURI().contains("sse")) {
throw new SseException(e.getMessage(), e.getCode());
} else {
throw e;
}
}
// 检查 header param 里的 clientid token 里的是否一致 // 检查 header param 里的 clientid token 里的是否一致
String headerCid = ServletUtils.getRequest().getHeader(LoginHelper.CLIENT_KEY); String headerCid = request.getHeader(LoginHelper.CLIENT_KEY);
String paramCid = ServletUtils.getParameter(LoginHelper.CLIENT_KEY); String paramCid = ServletUtils.getParameter(LoginHelper.CLIENT_KEY);
String clientId = StpUtil.getExtra(LoginHelper.CLIENT_KEY).toString(); String clientId = StpUtil.getExtra(LoginHelper.CLIENT_KEY).toString();
if (!StringUtils.equalsAny(clientId, headerCid, paramCid)) { if (!StringUtils.equalsAny(clientId, headerCid, paramCid)) {

View File

@ -1,14 +1,11 @@
package org.dromara.common.sse.core; package org.dromara.common.sse.core;
import cn.hutool.core.collection.CollUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.common.redis.utils.RedisUtils; import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.sse.dto.SseMessageDto; import org.dromara.common.sse.dto.SseMessageDto;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -124,26 +121,14 @@ public class SseEmitterManager {
* @param sseMessageDto 要发布的SSE消息对象 * @param sseMessageDto 要发布的SSE消息对象
*/ */
public void publishMessage(SseMessageDto sseMessageDto) { public void publishMessage(SseMessageDto sseMessageDto) {
List<Long> unsentUserIds = new ArrayList<>();
// 当前服务内用户,直接发送消息
for (Long userId : sseMessageDto.getUserIds()) {
if (USER_TOKEN_EMITTERS.containsKey(userId)) {
sendMessage(userId, sseMessageDto.getMessage());
continue;
}
unsentUserIds.add(userId);
}
// 不在当前服务内用户,发布订阅消息
if (CollUtil.isNotEmpty(unsentUserIds)) {
SseMessageDto broadcastMessage = new SseMessageDto(); SseMessageDto broadcastMessage = new SseMessageDto();
broadcastMessage.setMessage(sseMessageDto.getMessage()); broadcastMessage.setMessage(sseMessageDto.getMessage());
broadcastMessage.setUserIds(unsentUserIds); broadcastMessage.setUserIds(sseMessageDto.getUserIds());
RedisUtils.publish(SSE_TOPIC, broadcastMessage, consumer -> { RedisUtils.publish(SSE_TOPIC, broadcastMessage, consumer -> {
log.info("SSE发送主题订阅消息topic:{} session keys:{} message:{}", log.info("SSE发送主题订阅消息topic:{} session keys:{} message:{}",
SSE_TOPIC, unsentUserIds, sseMessageDto.getMessage()); SSE_TOPIC, sseMessageDto.getUserIds(), sseMessageDto.getMessage());
}); });
} }
}
/** /**
* 向所有的用户发布订阅的消息(群发) * 向所有的用户发布订阅的消息(群发)

View File

@ -35,7 +35,8 @@ public class TenantKeyPrefixHandler extends KeyPrefixHandler {
} }
String tenantId = TenantHelper.getTenantId(); String tenantId = TenantHelper.getTenantId();
if (StringUtils.isBlank(tenantId)) { if (StringUtils.isBlank(tenantId)) {
log.error("无法获取有效的租户id -> Null"); log.debug("无法获取有效的租户id -> Null");
return super.map(name);
} }
if (StringUtils.startsWith(name, tenantId + "")) { if (StringUtils.startsWith(name, tenantId + "")) {
// 如果存在则直接返回 // 如果存在则直接返回
@ -61,7 +62,8 @@ public class TenantKeyPrefixHandler extends KeyPrefixHandler {
} }
String tenantId = TenantHelper.getTenantId(); String tenantId = TenantHelper.getTenantId();
if (StringUtils.isBlank(tenantId)) { if (StringUtils.isBlank(tenantId)) {
log.error("无法获取有效的租户id -> Null"); log.debug("无法获取有效的租户id -> Null");
return super.unmap(name);
} }
if (StringUtils.startsWith(unmap, tenantId + "")) { if (StringUtils.startsWith(unmap, tenantId + "")) {
// 如果存在则删除 // 如果存在则删除

View File

@ -1,6 +1,5 @@
package org.dromara.common.tenant.helper; package org.dromara.common.tenant.helper;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
@ -130,7 +129,7 @@ public class TenantHelper {
if (!isEnable()) { if (!isEnable()) {
return; return;
} }
if (!isLogin() || !global) { if (!LoginHelper.isLogin() || !global) {
TEMP_DYNAMIC_TENANT.set(tenantId); TEMP_DYNAMIC_TENANT.set(tenantId);
return; return;
} }
@ -147,7 +146,7 @@ public class TenantHelper {
if (!isEnable()) { if (!isEnable()) {
return null; return null;
} }
if (!isLogin()) { if (!LoginHelper.isLogin()) {
return TEMP_DYNAMIC_TENANT.get(); return TEMP_DYNAMIC_TENANT.get();
} }
// 如果线程内有值 优先返回 // 如果线程内有值 优先返回
@ -167,7 +166,7 @@ public class TenantHelper {
if (!isEnable()) { if (!isEnable()) {
return; return;
} }
if (!isLogin()) { if (!LoginHelper.isLogin()) {
TEMP_DYNAMIC_TENANT.remove(); TEMP_DYNAMIC_TENANT.remove();
return; return;
} }
@ -218,13 +217,4 @@ public class TenantHelper {
return tenantId; return tenantId;
} }
private static boolean isLogin() {
try {
StpUtil.checkLogin();
return true;
} catch (Exception e) {
return false;
}
}
} }

View File

@ -43,19 +43,6 @@
<artifactId>spring-boot-starter-undertow</artifactId> <artifactId>spring-boot-starter-undertow</artifactId>
</dependency> </dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-core</artifactId>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-servlet</artifactId>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-websockets-jsr</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId> <artifactId>spring-boot-starter-actuator</artifactId>

View File

@ -1,19 +1,15 @@
package org.dromara.common.web.config; package org.dromara.common.web.config;
import org.dromara.common.core.utils.StringUtils; import jakarta.servlet.DispatcherType;
import org.dromara.common.web.config.properties.XssProperties; import org.dromara.common.web.config.properties.XssProperties;
import org.dromara.common.web.filter.RepeatableFilter; import org.dromara.common.web.filter.RepeatableFilter;
import org.dromara.common.web.filter.XssFilter; import org.dromara.common.web.filter.XssFilter;
import jakarta.servlet.DispatcherType;
import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import java.util.HashMap;
import java.util.Map;
/** /**
* Filter配置 * Filter配置
* *
@ -23,26 +19,21 @@ import java.util.Map;
@EnableConfigurationProperties(XssProperties.class) @EnableConfigurationProperties(XssProperties.class)
public class FilterConfig { public class FilterConfig {
@SuppressWarnings({"rawtypes", "unchecked"})
@Bean @Bean
@ConditionalOnProperty(value = "xss.enabled", havingValue = "true") @ConditionalOnProperty(value = "xss.enabled", havingValue = "true")
public FilterRegistrationBean xssFilterRegistration(XssProperties xssProperties) { public FilterRegistrationBean<XssFilter> xssFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean(); FilterRegistrationBean<XssFilter> registration = new FilterRegistrationBean<>();
registration.setDispatcherTypes(DispatcherType.REQUEST); registration.setDispatcherTypes(DispatcherType.REQUEST);
registration.setFilter(new XssFilter()); registration.setFilter(new XssFilter());
registration.addUrlPatterns(StringUtils.split(xssProperties.getUrlPatterns(), StringUtils.SEPARATOR)); registration.addUrlPatterns("/*");
registration.setName("xssFilter"); registration.setName("xssFilter");
registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE); registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE + 1);
Map<String, String> initParameters = new HashMap<>();
initParameters.put("excludes", xssProperties.getExcludes());
registration.setInitParameters(initParameters);
return registration; return registration;
} }
@SuppressWarnings({"rawtypes", "unchecked"})
@Bean @Bean
public FilterRegistrationBean someFilterRegistration() { public FilterRegistrationBean<RepeatableFilter> someFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean(); FilterRegistrationBean<RepeatableFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new RepeatableFilter()); registration.setFilter(new RepeatableFilter());
registration.addUrlPatterns("/*"); registration.addUrlPatterns("/*");
registration.setName("repeatableFilter"); registration.setName("repeatableFilter");

View File

@ -3,6 +3,9 @@ package org.dromara.common.web.config.properties;
import lombok.Data; import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.ArrayList;
import java.util.List;
/** /**
* xss过滤 配置属性 * xss过滤 配置属性
* *
@ -13,18 +16,13 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
public class XssProperties { public class XssProperties {
/** /**
* 过滤开关 * Xss开关
*/ */
private String enabled; private Boolean enabled;
/** /**
* 排除链接多个用逗号分隔 * 排除路径
*/ */
private String excludes; private List<String> excludeUrls = new ArrayList<>();
/**
* 匹配链接
*/
private String urlPatterns;
} }

View File

@ -1,6 +1,8 @@
package org.dromara.common.web.filter; package org.dromara.common.web.filter;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.web.config.properties.XssProperties;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import jakarta.servlet.*; import jakarta.servlet.*;
@ -23,13 +25,8 @@ public class XssFilter implements Filter {
@Override @Override
public void init(FilterConfig filterConfig) throws ServletException { public void init(FilterConfig filterConfig) throws ServletException {
String tempExcludes = filterConfig.getInitParameter("excludes"); XssProperties properties = SpringUtils.getBean(XssProperties.class);
if (StringUtils.isNotEmpty(tempExcludes)) { excludes.addAll(properties.getExcludeUrls());
String[] url = tempExcludes.split(StringUtils.SEPARATOR);
for (int i = 0; url != null && i < url.length; i++) {
excludes.add(url[i]);
}
}
} }
@Override @Override

View File

@ -14,6 +14,7 @@ import jakarta.servlet.http.HttpServletRequestWrapper;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Map;
/** /**
* XSS过滤处理 * XSS过滤处理
@ -28,6 +29,33 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
super(request); super(request);
} }
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
if (value != null) {
return HtmlUtil.cleanHtmlTag(value).trim();
}
return value;
}
@Override
public Map<String, String[]> getParameterMap() {
Map<String, String[]> valueMap = super.getParameterMap();
for (Map.Entry<String, String[]> entry : valueMap.entrySet()) {
String[] values = entry.getValue();
if (values != null) {
int length = values.length;
String[] escapseValues = new String[length];
for (int i = 0; i < length; i++) {
// 防xss攻击和过滤前后空格
escapseValues[i] = HtmlUtil.cleanHtmlTag(values[i]).trim();
}
valueMap.put(entry.getKey(), escapseValues);
}
}
return valueMap;
}
@Override @Override
public String[] getParameterValues(String name) { public String[] getParameterValues(String name) {
String[] values = super.getParameterValues(name); String[] values = super.getParameterValues(name);
@ -40,7 +68,7 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
} }
return escapseValues; return escapseValues;
} }
return super.getParameterValues(name); return values;
} }
@Override @Override

View File

@ -2,14 +2,17 @@ package org.dromara.common.web.handler;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpStatus; import cn.hutool.http.HttpStatus;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolation; import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException; import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R; import org.dromara.common.core.domain.R;
import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.exception.SseException;
import org.dromara.common.core.exception.base.BaseException; import org.dromara.common.core.exception.base.BaseException;
import org.dromara.common.core.utils.StreamUtils; import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.springframework.context.support.DefaultMessageSourceResolvable; import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.validation.BindException; import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.HttpRequestMethodNotSupportedException;
@ -53,6 +56,27 @@ public class GlobalExceptionHandler {
return ObjectUtil.isNotNull(code) ? R.fail(code, e.getMessage()) : R.fail(e.getMessage()); return ObjectUtil.isNotNull(code) ? R.fail(code, e.getMessage()) : R.fail(e.getMessage());
} }
/**
* 认证失败
*/
@ResponseStatus(org.springframework.http.HttpStatus.UNAUTHORIZED)
@ExceptionHandler(SseException.class)
public String handleNotLoginException(SseException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',认证失败'{}',无法访问系统资源", requestURI, e.getMessage());
return JsonUtils.toJsonString(R.fail(HttpStatus.HTTP_UNAUTHORIZED, "认证失败,无法访问系统资源"));
}
/**
* servlet异常
*/
@ExceptionHandler(ServletException.class)
public R<Void> handleServletException(ServletException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',发生未知异常.", requestURI, e);
return R.fail(e.getMessage());
}
/** /**
* 业务异常 * 业务异常
*/ */
@ -152,7 +176,7 @@ public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class) @ExceptionHandler(MethodArgumentNotValidException.class)
public R<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { public R<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
log.error(e.getMessage()); log.error(e.getMessage());
String message = e.getBindingResult().getFieldError().getDefaultMessage(); String message = StreamUtils.join(e.getBindingResult().getAllErrors(), DefaultMessageSourceResolvable::getDefaultMessage, ", ");
return R.fail(message); return R.fail(message);
} }

View File

@ -2,6 +2,7 @@ package org.dromara.common.web.interceptor;
import cn.hutool.core.io.IoUtil; import cn.hutool.core.io.IoUtil;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -64,10 +65,12 @@ public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor {
@Override @Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
StopWatch stopWatch = KEY_CACHE.get(); StopWatch stopWatch = KEY_CACHE.get();
if (ObjectUtil.isNotNull(stopWatch)) {
stopWatch.stop(); stopWatch.stop();
log.info("[PLUS]结束请求 => URL[{}],耗时:[{}]毫秒", request.getMethod() + " " + request.getRequestURI(), stopWatch.getTime()); log.info("[PLUS]结束请求 => URL[{}],耗时:[{}]毫秒", request.getMethod() + " " + request.getRequestURI(), stopWatch.getTime());
KEY_CACHE.remove(); KEY_CACHE.remove();
} }
}
/** /**
* 判断本次请求的数据类型是否为json * 判断本次请求的数据类型是否为json

View File

@ -13,8 +13,8 @@ logging:
spring: spring:
security: security:
user: user:
name: ruoyi name: @monitor.username@
password: 123456 password: @monitor.password@
boot: boot:
admin: admin:
ui: ui:
@ -44,5 +44,5 @@ spring.boot.admin.client:
metadata: metadata:
username: ${spring.boot.admin.client.username} username: ${spring.boot.admin.client.username}
userpassword: ${spring.boot.admin.client.password} userpassword: ${spring.boot.admin.client.password}
username: ruoyi username: @monitor.username@
password: 123456 password: @monitor.password@

View File

@ -16,6 +16,18 @@
<groupId>com.aizuda</groupId> <groupId>com.aizuda</groupId>
<artifactId>snail-job-server-starter</artifactId> <artifactId>snail-job-server-starter</artifactId>
<version>${snailjob.version}</version> <version>${snailjob.version}</version>
<exclusions>
<exclusion>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.13.9</version>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -46,5 +46,5 @@ spring.boot.admin.client:
metadata: metadata:
username: ${spring.boot.admin.client.username} username: ${spring.boot.admin.client.username}
userpassword: ${spring.boot.admin.client.password} userpassword: ${spring.boot.admin.client.password}
username: ruoyi username: @monitor.username@
password: 123456 password: @monitor.password@

View File

@ -46,5 +46,5 @@ spring.boot.admin.client:
metadata: metadata:
username: ${spring.boot.admin.client.username} username: ${spring.boot.admin.client.username}
userpassword: ${spring.boot.admin.client.password} userpassword: ${spring.boot.admin.client.password}
username: ruoyi username: @monitor.username@
password: 123456 password: @monitor.password@

View File

@ -48,7 +48,7 @@ public interface TestDemoMapper extends BaseMapperPlus<TestDemo, TestDemoVo> {
@DataColumn(key = "deptName", value = "dept_id"), @DataColumn(key = "deptName", value = "dept_id"),
@DataColumn(key = "userName", value = "user_id") @DataColumn(key = "userName", value = "user_id")
}, joinStr = "AND") }, joinStr = "AND")
List<TestDemo> selectBatchIds(@Param(Constants.COLL) Collection<? extends Serializable> idList); List<TestDemo> selectByIds(@Param(Constants.COLL) Collection<? extends Serializable> idList);
@Override @Override
@DataPermission({ @DataPermission({

View File

@ -101,7 +101,7 @@ public class TestDemoServiceImpl implements ITestDemoService {
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) { public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) { if (isValid) {
// 做一些业务上的校验,判断是否需要校验 // 做一些业务上的校验,判断是否需要校验
List<TestDemo> list = baseMapper.selectBatchIds(ids); List<TestDemo> list = baseMapper.selectByIds(ids);
if (list.size() != ids.size()) { if (list.size() != ids.size()) {
throw new ServiceException("您没有删除权限!"); throw new ServiceException("您没有删除权限!");
} }

View File

@ -56,13 +56,13 @@ public interface GenConstants {
* 数据库时间类型 * 数据库时间类型
*/ */
String[] COLUMNTYPE_TIME = {"datetime", "time", "date", "timestamp", "year", "interval", String[] COLUMNTYPE_TIME = {"datetime", "time", "date", "timestamp", "year", "interval",
"smalldatetime", "datetime2", "datetimeoffset"}; "smalldatetime", "datetime2", "datetimeoffset", "timestamptz"};
/** /**
* 数据库数字类型 * 数据库数字类型
*/ */
String[] COLUMNTYPE_NUMBER = {"tinyint", "smallint", "mediumint", "int", "number", "integer", String[] COLUMNTYPE_NUMBER = {"tinyint", "smallint", "mediumint", "int", "int2", "int4", "int8", "number", "integer",
"bit", "bigint", "float", "double", "decimal", "numeric", "real", "double precision", "bit", "bigint", "float", "float4", "float8", "double", "decimal", "numeric", "real", "double precision",
"smallserial", "serial", "bigserial", "money", "smallmoney"}; "smallserial", "serial", "bigserial", "money", "smallmoney"};
/** /**

View File

@ -162,7 +162,7 @@ public class GenTable extends BaseEntity {
* 上级菜单ID字段 * 上级菜单ID字段
*/ */
@TableField(exist = false) @TableField(exist = false)
private String parentMenuId; private Long parentMenuId;
/** /**
* 上级菜单名称字段 * 上级菜单名称字段

View File

@ -2,10 +2,8 @@ package org.dromara.generator.mapper;
import com.baomidou.dynamic.datasource.annotation.DS; import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore; import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.dromara.generator.domain.GenTable; import org.dromara.generator.domain.GenTable;
import org.apache.ibatis.annotations.Param;
import java.util.List; import java.util.List;
@ -40,6 +38,14 @@ public interface GenTableMapper extends BaseMapperPlus<GenTable, GenTable> {
*/ */
GenTable selectGenTableByName(String tableName); GenTable selectGenTableByName(String tableName);
/**
* 查询指定数据源下的所有表名列表
*
* @param dataName 数据源名称用于选择不同的数据源
* @return 当前数据库中的表名列表
*
* @DS("") 使用默认数据源执行查询操作
*/
@DS("") @DS("")
List<String> selectTableNameList(String dataName); List<String> selectTableNameList(String dataName);
} }

View File

@ -137,7 +137,7 @@ public class GenTableServiceImpl implements IGenTableService {
} }
// 过滤并转换表格数据 // 过滤并转换表格数据
List<GenTable> tables = tablesMap.values().stream() List<GenTable> tables = tablesMap.values().stream()
.filter(x -> !StringUtils.containsAnyIgnoreCase(x.getName(), TABLE_IGNORE)) .filter(x -> !startWithAnyIgnoreCase(x.getName(), TABLE_IGNORE))
.filter(x -> { .filter(x -> {
if (CollUtil.isEmpty(tableNames)) { if (CollUtil.isEmpty(tableNames)) {
return true; return true;
@ -174,6 +174,16 @@ public class GenTableServiceImpl implements IGenTableService {
return TableDataInfo.build(page); return TableDataInfo.build(page);
} }
public static boolean startWithAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences) {
// 判断是否是以指定字符串开头
for (CharSequence searchCharSequence : searchCharSequences) {
if (StringUtils.startsWithIgnoreCase(cs, searchCharSequence)) {
return true;
}
}
return false;
}
/** /**
* 查询据库列表 * 查询据库列表
* *
@ -548,7 +558,7 @@ public class GenTableServiceImpl implements IGenTableService {
String treeCode = paramsObj.getStr(GenConstants.TREE_CODE); String treeCode = paramsObj.getStr(GenConstants.TREE_CODE);
String treeParentCode = paramsObj.getStr(GenConstants.TREE_PARENT_CODE); String treeParentCode = paramsObj.getStr(GenConstants.TREE_PARENT_CODE);
String treeName = paramsObj.getStr(GenConstants.TREE_NAME); String treeName = paramsObj.getStr(GenConstants.TREE_NAME);
String parentMenuId = paramsObj.getStr(GenConstants.PARENT_MENU_ID); Long parentMenuId = paramsObj.getLong(GenConstants.PARENT_MENU_ID);
String parentMenuName = paramsObj.getStr(GenConstants.PARENT_MENU_NAME); String parentMenuName = paramsObj.getStr(GenConstants.PARENT_MENU_NAME);
genTable.setTreeCode(treeCode); genTable.setTreeCode(treeCode);

View File

@ -58,7 +58,7 @@ public class ${ClassName}Vo implements Serializable {
* ${column.columnComment}Url * ${column.columnComment}Url
*/ */
@Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "${column.javaField}") @Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "${column.javaField}")
private String ${column.javaField}Url"; private String ${column.javaField}Url;
#end #end
#end #end
#end #end

View File

@ -176,4 +176,18 @@ public class SysTenantController extends BaseController {
return toAjax(TenantHelper.ignore(() -> tenantService.syncTenantPackage(tenantId, packageId))); return toAjax(TenantHelper.ignore(() -> tenantService.syncTenantPackage(tenantId, packageId)));
} }
/**
* 同步租户字典
*/
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
@Log(title = "同步租户字典", businessType = BusinessType.INSERT)
@GetMapping("/syncTenantDict")
public R<Void> syncTenantDict() {
if (!TenantHelper.isEnable()) {
return R.fail("当前未开启租户模式");
}
tenantService.syncTenantDict();
return R.ok("同步租户字典成功");
}
} }

View File

@ -3,10 +3,14 @@ package org.dromara.system.listener;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.BCrypt; import cn.hutool.crypto.digest.BCrypt;
import cn.hutool.http.HtmlUtil;
import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.event.AnalysisEventListener;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.ValidatorUtils; import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.excel.core.ExcelListener; import org.dromara.common.excel.core.ExcelListener;
import org.dromara.common.excel.core.ExcelResult; import org.dromara.common.excel.core.ExcelResult;
@ -79,8 +83,12 @@ public class SysUserImportListener extends AnalysisEventListener<SysUserImportVo
} }
} catch (Exception e) { } catch (Exception e) {
failureNum++; failureNum++;
String msg = "<br/>" + failureNum + "、账号 " + userVo.getUserName() + " 导入失败:"; String msg = "<br/>" + failureNum + "、账号 " + HtmlUtil.cleanHtmlTag(userVo.getUserName()) + " 导入失败:";
failureMsg.append(msg).append(e.getMessage()); String message = e.getMessage();
if (e instanceof ConstraintViolationException cvException) {
message = StreamUtils.join(cvException.getConstraintViolations(), ConstraintViolation::getMessage, ", ");
}
failureMsg.append(msg).append(message);
log.error(msg, e); log.error(msg, e);
} }
} }

View File

@ -79,4 +79,9 @@ public interface ISysTenantService {
* 同步租户套餐 * 同步租户套餐
*/ */
Boolean syncTenantPackage(String tenantId, Long packageId); Boolean syncTenantPackage(String tenantId, Long packageId);
/**
* 同步租户字典
*/
void syncTenantDict();
} }

View File

@ -275,6 +275,8 @@ public class SysDeptServiceImpl implements ISysDeptService, DeptService {
dept.setAncestors(newAncestors); dept.setAncestors(newAncestors);
updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors); updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors);
} }
} else {
dept.setAncestors(oldDept.getAncestors());
} }
int result = baseMapper.updateById(dept); int result = baseMapper.updateById(dept);
if (UserConstants.DEPT_NORMAL.equals(dept.getStatus()) && StringUtils.isNotEmpty(dept.getAncestors()) if (UserConstants.DEPT_NORMAL.equals(dept.getStatus()) && StringUtils.isNotEmpty(dept.getAncestors())

View File

@ -3,18 +3,18 @@ package org.dromara.system.service.impl;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.utils.MapstructUtils; import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.ip.AddressUtils; import org.dromara.common.core.utils.ip.AddressUtils;
import org.dromara.common.log.event.OperLogEvent; import org.dromara.common.log.event.OperLogEvent;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.system.domain.SysOperLog; import org.dromara.system.domain.SysOperLog;
import org.dromara.system.domain.bo.SysOperLogBo; import org.dromara.system.domain.bo.SysOperLogBo;
import org.dromara.system.domain.vo.SysOperLogVo; import org.dromara.system.domain.vo.SysOperLogVo;
import org.dromara.system.mapper.SysOperLogMapper; import org.dromara.system.mapper.SysOperLogMapper;
import org.dromara.system.service.ISysOperLogService; import org.dromara.system.service.ISysOperLogService;
import lombok.RequiredArgsConstructor;
import org.springframework.context.event.EventListener; import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -51,8 +51,18 @@ public class SysOperLogServiceImpl implements ISysOperLogService {
@Override @Override
public TableDataInfo<SysOperLogVo> selectPageOperLogList(SysOperLogBo operLog, PageQuery pageQuery) { public TableDataInfo<SysOperLogVo> selectPageOperLogList(SysOperLogBo operLog, PageQuery pageQuery) {
LambdaQueryWrapper<SysOperLog> lqw = buildQueryWrapper(operLog);
if (StringUtils.isBlank(pageQuery.getOrderByColumn())) {
pageQuery.setOrderByColumn("oper_id");
pageQuery.setIsAsc("desc");
}
Page<SysOperLogVo> page = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(page);
}
private LambdaQueryWrapper<SysOperLog> buildQueryWrapper(SysOperLogBo operLog) {
Map<String, Object> params = operLog.getParams(); Map<String, Object> params = operLog.getParams();
LambdaQueryWrapper<SysOperLog> lqw = new LambdaQueryWrapper<SysOperLog>() return new LambdaQueryWrapper<SysOperLog>()
.like(StringUtils.isNotBlank(operLog.getOperIp()), SysOperLog::getOperIp, operLog.getOperIp()) .like(StringUtils.isNotBlank(operLog.getOperIp()), SysOperLog::getOperIp, operLog.getOperIp())
.like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle()) .like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle())
.eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0, .eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0,
@ -67,12 +77,6 @@ public class SysOperLogServiceImpl implements ISysOperLogService {
.like(StringUtils.isNotBlank(operLog.getOperName()), SysOperLog::getOperName, operLog.getOperName()) .like(StringUtils.isNotBlank(operLog.getOperName()), SysOperLog::getOperName, operLog.getOperName())
.between(params.get("beginTime") != null && params.get("endTime") != null, .between(params.get("beginTime") != null && params.get("endTime") != null,
SysOperLog::getOperTime, params.get("beginTime"), params.get("endTime")); SysOperLog::getOperTime, params.get("beginTime"), params.get("endTime"));
if (StringUtils.isBlank(pageQuery.getOrderByColumn())) {
pageQuery.setOrderByColumn("oper_id");
pageQuery.setIsAsc("desc");
}
Page<SysOperLogVo> page = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(page);
} }
/** /**
@ -95,23 +99,8 @@ public class SysOperLogServiceImpl implements ISysOperLogService {
*/ */
@Override @Override
public List<SysOperLogVo> selectOperLogList(SysOperLogBo operLog) { public List<SysOperLogVo> selectOperLogList(SysOperLogBo operLog) {
Map<String, Object> params = operLog.getParams(); LambdaQueryWrapper<SysOperLog> lqw = buildQueryWrapper(operLog);
return baseMapper.selectVoList(new LambdaQueryWrapper<SysOperLog>() return baseMapper.selectVoList(lqw.orderByDesc(SysOperLog::getOperId));
.like(StringUtils.isNotBlank(operLog.getOperIp()), SysOperLog::getOperIp, operLog.getOperIp())
.like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle())
.eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0,
SysOperLog::getBusinessType, operLog.getBusinessType())
.func(f -> {
if (ArrayUtil.isNotEmpty(operLog.getBusinessTypes())) {
f.in(SysOperLog::getBusinessType, Arrays.asList(operLog.getBusinessTypes()));
}
})
.eq(operLog.getStatus() != null && operLog.getStatus() > 0,
SysOperLog::getStatus, operLog.getStatus())
.like(StringUtils.isNotBlank(operLog.getOperName()), SysOperLog::getOperName, operLog.getOperName())
.between(params.get("beginTime") != null && params.get("endTime") != null,
SysOperLog::getOperTime, params.get("beginTime"), params.get("endTime"))
.orderByDesc(SysOperLog::getOperId));
} }
/** /**

View File

@ -195,7 +195,7 @@ public class SysOssServiceImpl implements ISysOssService, OssService {
OssClient storage = OssFactory.instance(); OssClient storage = OssFactory.instance();
UploadResult uploadResult; UploadResult uploadResult;
try { try {
uploadResult = storage.uploadSuffix(file.getBytes(), suffix); uploadResult = storage.uploadSuffix(file.getBytes(), suffix, file.getContentType());
} catch (IOException e) { } catch (IOException e) {
throw new ServiceException(e.getMessage()); throw new ServiceException(e.getMessage());
} }
@ -244,7 +244,7 @@ public class SysOssServiceImpl implements ISysOssService, OssService {
if (isValid) { if (isValid) {
// 做一些业务上的校验,判断是否需要校验 // 做一些业务上的校验,判断是否需要校验
} }
List<SysOss> list = baseMapper.selectBatchIds(ids); List<SysOss> list = baseMapper.selectByIds(ids);
for (SysOss sysOss : list) { for (SysOss sysOss : list) {
OssClient storage = OssFactory.instance(sysOss.getService()); OssClient storage = OssFactory.instance(sysOss.getService());
storage.delete(sysOss.getUrl()); storage.delete(sysOss.getUrl());

View File

@ -1,6 +1,8 @@
package org.dromara.system.service.impl; package org.dromara.system.service.impl;
import cn.dev33.satoken.secure.BCrypt; import cn.dev33.satoken.secure.BCrypt;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.RandomUtil;
@ -14,9 +16,13 @@ import org.dromara.common.core.constant.TenantConstants;
import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils; import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.redis.utils.CacheUtils;
import org.dromara.common.tenant.core.TenantEntity;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.system.domain.*; import org.dromara.system.domain.*;
import org.dromara.system.domain.bo.SysTenantBo; import org.dromara.system.domain.bo.SysTenantBo;
import org.dromara.system.domain.vo.SysTenantVo; import org.dromara.system.domain.vo.SysTenantVo;
@ -27,10 +33,7 @@ import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList; import java.util.*;
import java.util.Collection;
import java.util.Date;
import java.util.List;
/** /**
* 租户Service业务层处理 * 租户Service业务层处理
@ -201,7 +204,7 @@ public class SysTenantServiceImpl implements ISysTenantService {
String numbers = RandomUtil.randomNumbers(6); String numbers = RandomUtil.randomNumbers(6);
// 判断是否存在如果存在则重新生成 // 判断是否存在如果存在则重新生成
if (tenantIds.contains(numbers)) { if (tenantIds.contains(numbers)) {
generateTenantId(tenantIds); return generateTenantId(tenantIds);
} }
return numbers; return numbers;
} }
@ -266,7 +269,9 @@ public class SysTenantServiceImpl implements ISysTenantService {
@CacheEvict(cacheNames = CacheNames.SYS_TENANT, key = "#bo.tenantId") @CacheEvict(cacheNames = CacheNames.SYS_TENANT, key = "#bo.tenantId")
@Override @Override
public int updateTenantStatus(SysTenantBo bo) { public int updateTenantStatus(SysTenantBo bo) {
SysTenant tenant = MapstructUtils.convert(bo, SysTenant.class); SysTenant tenant = new SysTenant();
tenant.setId(bo.getId());
tenant.setStatus(bo.getStatus());
return baseMapper.updateById(tenant); return baseMapper.updateById(tenant);
} }
@ -369,4 +374,91 @@ public class SysTenantServiceImpl implements ISysTenantService {
} }
return true; return true;
} }
/**
* 同步租户字典
*/
@Transactional(rollbackFor = Exception.class)
@Override
public void syncTenantDict() {
// 查询超管 所有字典数据
List<SysDictType> dictTypeList = new ArrayList<>();
List<SysDictData> dictDataList = new ArrayList<>();
TenantHelper.ignore(() -> {
dictTypeList.addAll(dictTypeMapper.selectList());
dictDataList.addAll(dictDataMapper.selectList());
});
Map<String, List<SysDictType>> typeMap = StreamUtils.groupByKey(dictTypeList, TenantEntity::getTenantId);
Map<String, Map<String, List<SysDictData>>> typeDataMap = StreamUtils.groupBy2Key(
dictDataList, TenantEntity::getTenantId, SysDictData::getDictType);
// 管理租户字典数据
List<SysDictType> defaultTypeMap = typeMap.get(TenantConstants.DEFAULT_TENANT_ID);
Map<String, List<SysDictData>> defaultTypeDataMap = typeDataMap.get(TenantConstants.DEFAULT_TENANT_ID);
// 获取所有租户编号
List<String> tenantIds = baseMapper.selectObjs(
new LambdaQueryWrapper<SysTenant>().select(SysTenant::getTenantId)
.eq(SysTenant::getStatus, TenantConstants.NORMAL), x -> {return Convert.toStr(x);});
List<SysDictType> saveTypeList = new ArrayList<>();
List<SysDictData> saveDataList = new ArrayList<>();
Set<String> set = new HashSet<>();
for (String tenantId : tenantIds) {
if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) {
continue;
}
for (SysDictType dictType : defaultTypeMap) {
List<String> typeList = StreamUtils.toList(typeMap.get(tenantId), SysDictType::getDictType);
List<SysDictData> dataList = defaultTypeDataMap.get(dictType.getDictType());
if (typeList.contains(dictType.getDictType())) {
List<SysDictData> dataListTenant = typeDataMap.get(tenantId).get(dictType.getDictType());
Map<String, SysDictData> map = StreamUtils.toIdentityMap(dataListTenant, SysDictData::getDictValue);
for (SysDictData dictData : dataList) {
if (!map.containsKey(dictData.getDictValue())) {
SysDictData data = BeanUtil.toBean(dictData, SysDictData.class);
// 设置字典编码为 null
data.setDictCode(null);
data.setTenantId(tenantId);
data.setCreateTime(null);
data.setUpdateTime(null);
set.add(tenantId);
saveDataList.add(data);
}
}
} else {
SysDictType type = BeanUtil.toBean(dictType, SysDictType.class);
type.setDictId(null);
type.setTenantId(tenantId);
type.setCreateTime(null);
type.setUpdateTime(null);
set.add(tenantId);
saveTypeList.add(type);
if (CollUtil.isNotEmpty(dataList)) {
// 筛选出 dictType 对应的 data
for (SysDictData dictData : dataList) {
SysDictData data = BeanUtil.toBean(dictData, SysDictData.class);
// 设置字典编码为 null
data.setDictCode(null);
data.setTenantId(tenantId);
data.setCreateTime(null);
data.setUpdateTime(null);
set.add(tenantId);
saveDataList.add(data);
}
}
}
}
}
TenantHelper.ignore(() -> {
if (CollUtil.isNotEmpty(saveTypeList)) {
dictTypeMapper.insertBatch(saveTypeList);
}
if (CollUtil.isNotEmpty(saveDataList)) {
dictDataMapper.insertBatch(saveDataList);
}
});
for (String tenantId : set) {
TenantHelper.dynamic(tenantId, () -> CacheUtils.clear(CacheNames.SYS_DICT));
}
}
} }

View File

@ -42,6 +42,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
/** /**
* 用户 业务层处理 * 用户 业务层处理
@ -628,6 +629,12 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
return ObjectUtil.isNull(sysUser) ? null : sysUser.getEmail(); return ObjectUtil.isNull(sysUser) ? null : sysUser.getEmail();
} }
/**
* 通过用户ID查询用户列表
*
* @param userIds 用户ids
* @return 用户列表
*/
@Override @Override
public List<UserDTO> selectListByIds(List<Long> userIds) { public List<UserDTO> selectListByIds(List<Long> userIds) {
if (CollUtil.isEmpty(userIds)) { if (CollUtil.isEmpty(userIds)) {
@ -636,28 +643,54 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
List<SysUserVo> list = baseMapper.selectVoList(new LambdaQueryWrapper<SysUser>() List<SysUserVo> list = baseMapper.selectVoList(new LambdaQueryWrapper<SysUser>()
.select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName, SysUser::getEmail, SysUser::getPhonenumber) .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName, SysUser::getEmail, SysUser::getPhonenumber)
.eq(SysUser::getStatus, UserConstants.USER_NORMAL) .eq(SysUser::getStatus, UserConstants.USER_NORMAL)
.in(CollUtil.isNotEmpty(userIds), SysUser::getUserId, userIds)); .in(SysUser::getUserId, userIds));
return BeanUtil.copyToList(list, UserDTO.class); return BeanUtil.copyToList(list, UserDTO.class);
} }
/**
* 通过角色ID查询用户ID
*
* @param roleIds 角色ids
* @return 用户ids
*/
@Override @Override
public List<Long> selectUserIdsByRoleIds(List<Long> roleIds) { public List<Long> selectUserIdsByRoleIds(List<Long> roleIds) {
List<SysUserRole> userRoles = userRoleMapper.selectList(
new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getRoleId, roleIds));
return StreamUtils.toList(userRoles, SysUserRole::getUserId);
}
@Override
public List<UserDTO> selectUsersByRoleIds(List<Long> roleIds) {
if (CollUtil.isEmpty(roleIds)) { if (CollUtil.isEmpty(roleIds)) {
return List.of(); return List.of();
} }
List<SysUserRole> userRoles = userRoleMapper.selectList( List<SysUserRole> userRoles = userRoleMapper.selectList(
new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getRoleId, roleIds)); new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getRoleId, roleIds));
List<Long> userIds = StreamUtils.toList(userRoles, SysUserRole::getUserId); return StreamUtils.toList(userRoles, SysUserRole::getUserId);
return selectListByIds(userIds);
} }
/**
* 通过角色ID查询用户
*
* @param roleIds 角色ids
* @return 用户
*/
@Override
public List<UserDTO> selectUsersByRoleIds(List<Long> roleIds) {
if (CollUtil.isEmpty(roleIds)) {
return List.of();
}
// 通过角色ID获取用户角色信息
List<SysUserRole> userRoles = userRoleMapper.selectList(
new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getRoleId, roleIds));
// 获取用户ID列表
Set<Long> userIds = StreamUtils.toSet(userRoles, SysUserRole::getUserId);
return selectListByIds(new ArrayList<>(userIds));
}
/**
* 通过部门ID查询用户
*
* @param deptIds 部门ids
* @return 用户
*/
@Override @Override
public List<UserDTO> selectUsersByDeptIds(List<Long> deptIds) { public List<UserDTO> selectUsersByDeptIds(List<Long> deptIds) {
if (CollUtil.isEmpty(deptIds)) { if (CollUtil.isEmpty(deptIds)) {
@ -666,7 +699,7 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
List<SysUserVo> list = baseMapper.selectVoList(new LambdaQueryWrapper<SysUser>() List<SysUserVo> list = baseMapper.selectVoList(new LambdaQueryWrapper<SysUser>()
.select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName, SysUser::getEmail, SysUser::getPhonenumber) .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName, SysUser::getEmail, SysUser::getPhonenumber)
.eq(SysUser::getStatus, UserConstants.USER_NORMAL) .eq(SysUser::getStatus, UserConstants.USER_NORMAL)
.in(CollUtil.isNotEmpty(deptIds), SysUser::getDeptId, deptIds)); .in(SysUser::getDeptId, deptIds));
return BeanUtil.copyToList(list, UserDTO.class); return BeanUtil.copyToList(list, UserDTO.class);
} }
} }

View File

@ -277,6 +277,7 @@ public class ActTaskServiceImpl implements IActTaskService {
if (StringUtils.isNotBlank(taskBo.getProcessDefinitionKey())) { if (StringUtils.isNotBlank(taskBo.getProcessDefinitionKey())) {
queryWrapper.eq("t.processDefinitionKey", taskBo.getProcessDefinitionKey()); queryWrapper.eq("t.processDefinitionKey", taskBo.getProcessDefinitionKey());
} }
queryWrapper.orderByDesc("t.CREATE_TIME_");
Page<TaskVo> page = actTaskMapper.getTaskWaitByPage(pageQuery.build(), queryWrapper); Page<TaskVo> page = actTaskMapper.getTaskWaitByPage(pageQuery.build(), queryWrapper);
List<TaskVo> taskList = page.getRecords(); List<TaskVo> taskList = page.getRecords();
@ -366,6 +367,7 @@ public class ActTaskServiceImpl implements IActTaskService {
queryWrapper.like(StringUtils.isNotBlank(taskBo.getProcessDefinitionName()), "t.processDefinitionName", taskBo.getProcessDefinitionName()); queryWrapper.like(StringUtils.isNotBlank(taskBo.getProcessDefinitionName()), "t.processDefinitionName", taskBo.getProcessDefinitionName());
queryWrapper.eq(StringUtils.isNotBlank(taskBo.getProcessDefinitionKey()), "t.processDefinitionKey", taskBo.getProcessDefinitionKey()); queryWrapper.eq(StringUtils.isNotBlank(taskBo.getProcessDefinitionKey()), "t.processDefinitionKey", taskBo.getProcessDefinitionKey());
queryWrapper.eq("t.assignee_", userId); queryWrapper.eq("t.assignee_", userId);
queryWrapper.orderByDesc("t.START_TIME_");
Page<TaskVo> page = actTaskMapper.getTaskFinishByPage(pageQuery.build(), queryWrapper); Page<TaskVo> page = actTaskMapper.getTaskFinishByPage(pageQuery.build(), queryWrapper);
List<TaskVo> taskList = page.getRecords(); List<TaskVo> taskList = page.getRecords();
@ -402,6 +404,7 @@ public class ActTaskServiceImpl implements IActTaskService {
queryWrapper.eq("t.processDefinitionKey", taskBo.getProcessDefinitionKey()); queryWrapper.eq("t.processDefinitionKey", taskBo.getProcessDefinitionKey());
} }
queryWrapper.eq("t.assignee_", userId); queryWrapper.eq("t.assignee_", userId);
queryWrapper.orderByDesc("t.START_TIME_");
Page<TaskVo> page = actTaskMapper.getTaskCopyByPage(pageQuery.build(), queryWrapper); Page<TaskVo> page = actTaskMapper.getTaskCopyByPage(pageQuery.build(), queryWrapper);
List<TaskVo> taskList = page.getRecords(); List<TaskVo> taskList = page.getRecords();

View File

@ -142,11 +142,16 @@ public class TestLeaveServiceImpl implements ITestLeaveService {
* *
* @param processTaskEvent 参数 * @param processTaskEvent 参数
*/ */
@EventListener(condition = "#processTaskEvent.key=='leave1' && #processTaskEvent.taskDefinitionKey=='Activity_14633hx'") @EventListener(condition = "#processTaskEvent.key.startsWith('leave')")
public void processTaskHandler(ProcessTaskEvent processTaskEvent) { public void processTaskHandler(ProcessTaskEvent processTaskEvent) {
// 所有demo案例的申请人节点id
String[] ids = {"Activity_14633hx", "Activity_19b1i4j", "Activity_0uscrk3",
"Activity_0uscrk3", "Activity_0x6b71j", "Activity_0zy3g6j", "Activity_06a55t0"};
if (StringUtils.equalsAny(processTaskEvent.getTaskDefinitionKey(), ids)) {
log.info("当前任务执行了{}", processTaskEvent.toString()); log.info("当前任务执行了{}", processTaskEvent.toString());
TestLeave testLeave = baseMapper.selectById(Long.valueOf(processTaskEvent.getBusinessKey())); TestLeave testLeave = baseMapper.selectById(Long.valueOf(processTaskEvent.getBusinessKey()));
testLeave.setStatus(BusinessStatusEnum.WAITING.getStatus()); testLeave.setStatus(BusinessStatusEnum.WAITING.getStatus());
baseMapper.updateById(testLeave); baseMapper.updateById(testLeave);
} }
} }
}

View File

@ -96,7 +96,7 @@ public class WfDefinitionConfigServiceImpl implements IWfDefinitionConfigService
baseMapper.delete(new LambdaQueryWrapper<WfDefinitionConfig>().eq(WfDefinitionConfig::getTableName, bo.getTableName())); baseMapper.delete(new LambdaQueryWrapper<WfDefinitionConfig>().eq(WfDefinitionConfig::getTableName, bo.getTableName()));
add.setTableName(add.getTableName().toLowerCase()); add.setTableName(add.getTableName().toLowerCase());
boolean flag = baseMapper.insertOrUpdate(add); boolean flag = baseMapper.insertOrUpdate(add);
if (baseMapper.insertOrUpdate(add)) { if (flag) {
bo.setId(add.getId()); bo.setId(add.getId());
} }
return flag; return flag;

View File

@ -41,7 +41,7 @@ public class WfFormManageServiceImpl implements IWfFormManageService {
@Override @Override
public List<WfFormManageVo> queryByIds(List<Long> ids) { public List<WfFormManageVo> queryByIds(List<Long> ids) {
return baseMapper.selectVoBatchIds(ids); return baseMapper.selectVoByIds(ids);
} }
/** /**

View File

@ -7,7 +7,7 @@ import org.dromara.workflow.domain.ActHiProcinst;
import org.dromara.workflow.service.IActHiProcinstService; import org.dromara.workflow.service.IActHiProcinstService;
import org.dromara.workflow.service.IActProcessInstanceService; import org.dromara.workflow.service.IActProcessInstanceService;
import org.dromara.workflow.utils.WorkflowUtils; import org.dromara.workflow.utils.WorkflowUtils;
import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -24,9 +24,9 @@ import java.util.Map;
public class WorkflowServiceImpl implements WorkflowService { public class WorkflowServiceImpl implements WorkflowService {
@Autowired(required = false) @Autowired(required = false)
private RuntimeService runtimeService; private TaskService taskService;
private final IActProcessInstanceService iActProcessInstanceService; private final IActProcessInstanceService actProcessInstanceService;
private final IActHiProcinstService iActHiProcinstService; private final IActHiProcinstService actHiProcinstService;
/** /**
* 运行中的实例 删除程实例删除历史记录删除业务与流程关联信息 * 运行中的实例 删除程实例删除历史记录删除业务与流程关联信息
* *
@ -35,7 +35,7 @@ public class WorkflowServiceImpl implements WorkflowService {
*/ */
@Override @Override
public boolean deleteRunAndHisInstance(List<String> businessKeys) { public boolean deleteRunAndHisInstance(List<String> businessKeys) {
return iActProcessInstanceService.deleteRunAndHisInstance(businessKeys); return actProcessInstanceService.deleteRunAndHisInstance(businessKeys);
} }
/** /**
@ -67,7 +67,7 @@ public class WorkflowServiceImpl implements WorkflowService {
*/ */
@Override @Override
public void setVariable(String taskId, String variableName, Object value) { public void setVariable(String taskId, String variableName, Object value) {
runtimeService.setVariable(taskId, variableName, value); taskService.setVariable(taskId, variableName, value);
} }
/** /**
@ -78,7 +78,7 @@ public class WorkflowServiceImpl implements WorkflowService {
*/ */
@Override @Override
public void setVariables(String taskId, Map<String, Object> variables) { public void setVariables(String taskId, Map<String, Object> variables) {
runtimeService.setVariables(taskId, variables); taskService.setVariables(taskId, variables);
} }
/** /**
@ -90,7 +90,7 @@ public class WorkflowServiceImpl implements WorkflowService {
*/ */
@Override @Override
public void setVariableLocal(String taskId, String variableName, Object value) { public void setVariableLocal(String taskId, String variableName, Object value) {
runtimeService.setVariableLocal(taskId, variableName, value); taskService.setVariableLocal(taskId, variableName, value);
} }
/** /**
@ -101,7 +101,7 @@ public class WorkflowServiceImpl implements WorkflowService {
*/ */
@Override @Override
public void setVariablesLocal(String taskId, Map<String, Object> variables) { public void setVariablesLocal(String taskId, Map<String, Object> variables) {
runtimeService.setVariablesLocal(taskId, variables); taskService.setVariablesLocal(taskId, variables);
} }
/** /**
@ -112,7 +112,7 @@ public class WorkflowServiceImpl implements WorkflowService {
*/ */
@Override @Override
public String getInstanceIdByBusinessKey(String businessKey) { public String getInstanceIdByBusinessKey(String businessKey) {
ActHiProcinst actHiProcinst = iActHiProcinstService.selectByBusinessKey(businessKey); ActHiProcinst actHiProcinst = actHiProcinstService.selectByBusinessKey(businessKey);
if (actHiProcinst == null) { if (actHiProcinst == null) {
return StrUtil.EMPTY; return StrUtil.EMPTY;
} }

View File

@ -41,8 +41,7 @@
FROM ACT_RU_TASK RES FROM ACT_RU_TASK RES
INNER JOIN ACT_HI_PROCINST AHP ON RES.PROC_INST_ID_ = AHP.PROC_INST_ID_ INNER JOIN ACT_HI_PROCINST AHP ON RES.PROC_INST_ID_ = AHP.PROC_INST_ID_
INNER JOIN ACT_RE_PROCDEF ARP ON ARP.ID_ = RES.PROC_DEF_ID_ INNER JOIN ACT_RE_PROCDEF ARP ON ARP.ID_ = RES.PROC_DEF_ID_
WHERE RES.PARENT_TASK_ID_ IS NULL WHERE RES.PARENT_TASK_ID_ IS NULL) t ${ew.getCustomSqlSegment}
ORDER BY RES.CREATE_TIME_ DESC) t ${ew.getCustomSqlSegment}
</select> </select>
<select id="getTaskFinishByPage" resultMap="TaskVoResult"> <select id="getTaskFinishByPage" resultMap="TaskVoResult">
@ -57,7 +56,7 @@
INNER JOIN ACT_HI_PROCINST AHP ON HTI.PROC_INST_ID_ = AHP.PROC_INST_ID_ INNER JOIN ACT_HI_PROCINST AHP ON HTI.PROC_INST_ID_ = AHP.PROC_INST_ID_
INNER JOIN ACT_RE_PROCDEF ARP ON ARP.ID_ = HTI.PROC_DEF_ID_ INNER JOIN ACT_RE_PROCDEF ARP ON ARP.ID_ = HTI.PROC_DEF_ID_
WHERE HTI.PARENT_TASK_ID_ IS NULL AND HTI.END_TIME_ IS NOT NULL WHERE HTI.PARENT_TASK_ID_ IS NULL AND HTI.END_TIME_ IS NOT NULL
ORDER BY HTI.START_TIME_ DESC) t ${ew.getCustomSqlSegment} ) t ${ew.getCustomSqlSegment}
</select> </select>
<select id="getTaskCopyByPage" resultMap="TaskVoResult"> <select id="getTaskCopyByPage" resultMap="TaskVoResult">
@ -73,6 +72,6 @@
INNER JOIN ACT_RE_PROCDEF ARP ON ARP.ID_ = AHT.PROC_DEF_ID_ INNER JOIN ACT_RE_PROCDEF ARP ON ARP.ID_ = AHT.PROC_DEF_ID_
WHERE AHT.PARENT_TASK_ID_ IS NOT NULL WHERE AHT.PARENT_TASK_ID_ IS NOT NULL
and AHT.scope_type_ = 'copy' and AHT.scope_type_ = 'copy'
ORDER BY AHT.START_TIME_ DESC) t ${ew.getCustomSqlSegment} ) t ${ew.getCustomSqlSegment}
</select> </select>
</mapper> </mapper>

View File

@ -100,7 +100,7 @@ services:
network_mode: "host" network_mode: "host"
ruoyi-server1: ruoyi-server1:
image: ruoyi/ruoyi-server:5.2.2 image: ruoyi/ruoyi-server:5.2.3
container_name: ruoyi-server1 container_name: ruoyi-server1
environment: environment:
# 时区上海 # 时区上海
@ -115,7 +115,7 @@ services:
network_mode: "host" network_mode: "host"
ruoyi-server2: ruoyi-server2:
image: ruoyi/ruoyi-server:5.2.2 image: ruoyi/ruoyi-server:5.2.3
container_name: ruoyi-server2 container_name: ruoyi-server2
environment: environment:
# 时区上海 # 时区上海
@ -130,7 +130,7 @@ services:
network_mode: "host" network_mode: "host"
ruoyi-monitor-admin: ruoyi-monitor-admin:
image: ruoyi/ruoyi-monitor-admin:5.2.2 image: ruoyi/ruoyi-monitor-admin:5.2.3
container_name: ruoyi-monitor-admin container_name: ruoyi-monitor-admin
environment: environment:
# 时区上海 # 时区上海
@ -142,7 +142,7 @@ services:
network_mode: "host" network_mode: "host"
ruoyi-snailjob-server: ruoyi-snailjob-server:
image: ruoyi/ruoyi-snailjob-server:5.2.2 image: ruoyi/ruoyi-snailjob-server:5.2.3
container_name: ruoyi-snailjob-server container_name: ruoyi-snailjob-server
environment: environment:
# 时区上海 # 时区上海

View File

@ -74,6 +74,7 @@ COMMENT ON COLUMN sj_group_config.update_dt IS '修改时间';
COMMENT ON TABLE sj_group_config IS '组配置'; COMMENT ON TABLE sj_group_config IS '组配置';
INSERT INTO sj_group_config (namespace_id, group_name, description, token, group_status, version, group_partition, id_generator_mode, init_scene, bucket_index, create_dt, update_dt) VALUES ('dev', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, sysdate, sysdate); INSERT INTO sj_group_config (namespace_id, group_name, description, token, group_status, version, group_partition, id_generator_mode, init_scene, bucket_index, create_dt, update_dt) VALUES ('dev', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, sysdate, sysdate);
INSERT INTO sj_group_config (namespace_id, group_name, description, token, group_status, version, group_partition, id_generator_mode, init_scene, bucket_index, create_dt, update_dt) VALUES ('prod', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, sysdate, sysdate);
-- sj_notify_config -- sj_notify_config
CREATE TABLE sj_notify_config CREATE TABLE sj_notify_config

View File

@ -68,6 +68,7 @@ COMMENT ON COLUMN sj_group_config.update_dt IS '修改时间';
COMMENT ON TABLE sj_group_config IS '组配置'; COMMENT ON TABLE sj_group_config IS '组配置';
INSERT INTO sj_group_config VALUES (1, 'dev', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, now(), now()); INSERT INTO sj_group_config VALUES (1, 'dev', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, now(), now());
INSERT INTO sj_group_config VALUES (2, 'prod', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, now(), now());
-- sj_notify_config -- sj_notify_config
CREATE TABLE sj_notify_config CREATE TABLE sj_notify_config

View File

@ -427,7 +427,7 @@ comment on column sys_menu.remark is '备注';
-- ---------------------------- -- ----------------------------
-- 一级菜单 -- 一级菜单
insert into sys_menu values('1', '系统管理', '0', '1', 'system', null, '', '1', '0', 'M', '0', '0', '', 'system', 103, 1, now(), null, null, '系统管理目录'); insert into sys_menu values('1', '系统管理', '0', '1', 'system', null, '', '1', '0', 'M', '0', '0', '', 'system', 103, 1, now(), null, null, '系统管理目录');
insert into sys_menu values('6', '系统管理', '0', '2', 'tenant', null, '', '1', '0', 'M', '0', '0', '', 'chart', 103, 1, now(), null, null, '租户管理目录'); insert into sys_menu values('6', '租户管理', '0', '2', 'tenant', null, '', '1', '0', 'M', '0', '0', '', 'chart', 103, 1, now(), null, null, '租户管理目录');
insert into sys_menu values('2', '系统监控', '0', '3', 'monitor', null, '', '1', '0', 'M', '0', '0', '', 'monitor', 103, 1, now(), null, null, '系统监控目录'); insert into sys_menu values('2', '系统监控', '0', '3', 'monitor', null, '', '1', '0', 'M', '0', '0', '', 'monitor', 103, 1, now(), null, null, '系统监控目录');
insert into sys_menu values('3', '系统工具', '0', '4', 'tool', null, '', '1', '0', 'M', '0', '0', '', 'tool', 103, 1, now(), null, null, '系统工具目录'); insert into sys_menu values('3', '系统工具', '0', '4', 'tool', null, '', '1', '0', 'M', '0', '0', '', 'tool', 103, 1, now(), null, null, '系统工具目录');
insert into sys_menu values('4', 'PLUS官网', '0', '5', 'https://gitee.com/dromara/RuoYi-Vue-Plus', null, '', '0', '0', 'M', '0', '0', '', 'guide', 103, 1, now(), null, null, 'RuoYi-Vue-Plus官网地址'); insert into sys_menu values('4', 'PLUS官网', '0', '5', 'https://gitee.com/dromara/RuoYi-Vue-Plus', null, '', '0', '0', 'M', '0', '0', '', 'guide', 103, 1, now(), null, null, 'RuoYi-Vue-Plus官网地址');

View File

@ -40,6 +40,7 @@ CREATE TABLE `sj_group_config`
DEFAULT CHARSET = utf8mb4 COMMENT ='组配置'; DEFAULT CHARSET = utf8mb4 COMMENT ='组配置';
INSERT INTO `sj_group_config` VALUES (1, 'dev', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, now(), now()); INSERT INTO `sj_group_config` VALUES (1, 'dev', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, now(), now());
INSERT INTO `sj_group_config` VALUES (2, 'prod', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, now(), now());
CREATE TABLE `sj_notify_config` CREATE TABLE `sj_notify_config`
( (

View File

@ -203,6 +203,8 @@ GO
INSERT INTO sj_group_config(namespace_id, group_name, description, token, group_status, version, group_partition, id_generator_mode, init_scene, bucket_index, create_dt, update_dt) VALUES (N'dev', N'ruoyi_group', N'', N'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', N'1', N'1', N'0', N'1', N'1', N'4', getdate(), getdate()) INSERT INTO sj_group_config(namespace_id, group_name, description, token, group_status, version, group_partition, id_generator_mode, init_scene, bucket_index, create_dt, update_dt) VALUES (N'dev', N'ruoyi_group', N'', N'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', N'1', N'1', N'0', N'1', N'1', N'4', getdate(), getdate())
GO GO
INSERT INTO sj_group_config(namespace_id, group_name, description, token, group_status, version, group_partition, id_generator_mode, init_scene, bucket_index, create_dt, update_dt) VALUES (N'prod', N'ruoyi_group', N'', N'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', N'1', N'1', N'0', N'1', N'1', N'4', getdate(), getdate())
GO
-- sj_notify_config -- sj_notify_config
CREATE TABLE sj_notify_config CREATE TABLE sj_notify_config