tenantList(HttpServletRequest request) throws Exception {
// 返回对象
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java b/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java
index 0848170af..dcd04c5e1 100644
--- a/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java
+++ b/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java
@@ -131,15 +131,18 @@ public class CaptchaController {
String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + uuid;
// 生成验证码
CaptchaType captchaType = captchaProperties.getType();
- boolean isMath = CaptchaType.MATH == captchaType;
- Integer length = isMath ? captchaProperties.getNumberLength() : captchaProperties.getCharLength();
- CodeGenerator codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), length);
+ CodeGenerator codeGenerator;
+ if (CaptchaType.MATH == captchaType) {
+ codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), captchaProperties.getNumberLength(), false);
+ } else {
+ codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), captchaProperties.getCharLength());
+ }
AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz());
captcha.setGenerator(codeGenerator);
captcha.createCode();
// 如果是数学验证码,使用SpEL表达式处理验证码结果
String code = captcha.getCode();
- if (isMath) {
+ if (CaptchaType.MATH == captchaType) {
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression(StringUtils.remove(code, "="));
code = exp.getValue(String.class);
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java b/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java
index 567906e42..5a3351d05 100644
--- a/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java
+++ b/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java
@@ -87,7 +87,7 @@ public class SysRegisterService {
recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
throw new CaptchaExpireException();
}
- if (!code.equalsIgnoreCase(captcha)) {
+ if (!StringUtils.equalsIgnoreCase(code, captcha)) {
recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"));
throw new CaptchaException();
}
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java
index e579f9969..abf590b36 100644
--- a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java
+++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java
@@ -102,7 +102,7 @@ public class PasswordAuthStrategy implements IAuthStrategy {
loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
throw new CaptchaExpireException();
}
- if (!code.equalsIgnoreCase(captcha)) {
+ if (!StringUtils.equalsIgnoreCase(code, captcha)) {
loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"));
throw new CaptchaException();
}
diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml
index 5dd2e00fe..1b52fab96 100644
--- a/ruoyi-admin/src/main/resources/application-dev.yml
+++ b/ruoyi-admin/src/main/resources/application-dev.yml
@@ -27,8 +27,6 @@ snail-job:
port: 2${server.port}
# 客户端ip指定
host:
- # RPC类型: netty, grpc
- rpc-type: grpc
--- # 数据源配置
spring:
diff --git a/ruoyi-admin/src/main/resources/application-prod.yml b/ruoyi-admin/src/main/resources/application-prod.yml
index 435a9e856..d77ddf57c 100644
--- a/ruoyi-admin/src/main/resources/application-prod.yml
+++ b/ruoyi-admin/src/main/resources/application-prod.yml
@@ -30,8 +30,6 @@ snail-job:
port: 2${server.port}
# 客户端ip指定
host:
- # RPC类型: netty, grpc
- rpc-type: grpc
--- # 数据源配置
spring:
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index 03cb2f987..ff0b88f3b 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -57,6 +57,13 @@ spring:
# 开启虚拟线程 仅jdk21可用
virtual:
enabled: false
+ task:
+ execution:
+ # 从 springboot 3.5 开始 spring自带线程池
+ # 不再需要 AsyncConfig与ThreadPoolConfig 可直接注入线程池使用
+ thread-name-prefix: async-
+ # 由spring自己初始化线程池
+ mode: force
# 资源信息
messages:
# 国际化资源文件路径
@@ -127,6 +134,7 @@ tenant:
- sys_user_role
- sys_client
- sys_oss_config
+ - flow_spel
# MyBatisPlus配置
# https://baomidou.com/config/
@@ -189,13 +197,6 @@ springdoc:
name: Lion Li
email: crazylionli@163.com
url: https://gitee.com/dromara/RuoYi-Vue-Plus
- components:
- # 鉴权方式配置
- security-schemes:
- apiKey:
- type: APIKEY
- in: HEADER
- name: ${sa-token.token-name}
#这里定义了两个分组,可定义多个,也可以不定义
group-configs:
- group: 1.演示模块
@@ -213,20 +214,10 @@ springdoc:
xss:
# 过滤开关
enabled: true
- # 排除链接(多个用逗号分隔)
+ # 排除链接
excludeUrls:
- /system/notice
-# 全局线程池相关配置
-# 如使用JDK21请直接使用虚拟线程 不要开启此配置
-thread-pool:
- # 是否开启线程池
- enabled: false
- # 队列最大长度
- queueCapacity: 128
- # 线程池维护线程所允许的空闲时间
- keepAliveSeconds: 300
-
--- # 分布式锁 lock4j 全局配置
lock4j:
# 获取分布式锁超时时间,默认为 3000 毫秒
@@ -266,13 +257,7 @@ warm-flow:
enabled: true
# 是否开启设计器ui
ui: true
+ # 是否显示流程图顶部文字
+ top-text-show: true
# 默认Authorization,如果有多个token,用逗号分隔
token-name: ${sa-token.token-name},clientid
- # 流程状态对应的三元色
- chart-status-color:
- ## 未办理
- - 62,62,62
- ## 待办理
- - 255,205,23
- ## 已办理
- - 157,255,0
diff --git a/ruoyi-admin/src/main/resources/i18n/messages.properties b/ruoyi-admin/src/main/resources/i18n/messages.properties
index cce11c85d..f2777f77b 100644
--- a/ruoyi-admin/src/main/resources/i18n/messages.properties
+++ b/ruoyi-admin/src/main/resources/i18n/messages.properties
@@ -17,6 +17,7 @@ user.username.length.valid=账户长度必须在{min}到{max}个字符之间
user.password.not.blank=用户密码不能为空
user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间
user.password.not.valid=* 5-50个字符
+user.password.format.valid=密码必须包含大写字母、小写字母、数字和特殊字符
user.email.not.valid=邮箱格式错误
user.email.not.blank=邮箱不能为空
user.phonenumber.not.blank=用户手机号不能为空
diff --git a/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties b/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties
index f948c4ab8..306a48f6a 100644
--- a/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties
+++ b/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties
@@ -17,6 +17,7 @@ user.username.length.valid=Account length must be between {min} and {max} charac
user.password.not.blank=Password cannot be empty
user.password.length.valid=Password length must be between {min} and {max} characters
user.password.not.valid=* 5-50 characters
+user.password.format.valid=Password must contain uppercase, lowercase, digit, and special character
user.email.not.valid=Mailbox format error
user.email.not.blank=Mailbox cannot be blank
user.phonenumber.not.blank=Phone number cannot be blank
diff --git a/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties b/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties
index cce11c85d..f2777f77b 100644
--- a/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties
+++ b/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties
@@ -17,6 +17,7 @@ user.username.length.valid=账户长度必须在{min}到{max}个字符之间
user.password.not.blank=用户密码不能为空
user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间
user.password.not.valid=* 5-50个字符
+user.password.format.valid=密码必须包含大写字母、小写字母、数字和特殊字符
user.email.not.valid=邮箱格式错误
user.email.not.blank=邮箱不能为空
user.phonenumber.not.blank=用户手机号不能为空
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java
deleted file mode 100644
index cd01e33d5..000000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package org.dromara.common.core.config;
-
-import cn.hutool.core.util.ArrayUtil;
-import org.dromara.common.core.exception.ServiceException;
-import org.dromara.common.core.utils.SpringUtils;
-import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
-import org.springframework.boot.autoconfigure.AutoConfiguration;
-import org.springframework.core.task.VirtualThreadTaskExecutor;
-import org.springframework.scheduling.annotation.AsyncConfigurer;
-
-import java.util.Arrays;
-import java.util.concurrent.Executor;
-
-/**
- * 异步配置
- *
- * 如果未使用虚拟线程则生效
- *
- * @author Lion Li
- */
-@AutoConfiguration
-public class AsyncConfig implements AsyncConfigurer {
-
- /**
- * 自定义 @Async 注解使用系统线程池
- */
- @Override
- public Executor getAsyncExecutor() {
- if(SpringUtils.isVirtual()) {
- return new VirtualThreadTaskExecutor("async-");
- }
- return SpringUtils.getBean("scheduledExecutorService");
- }
-
- /**
- * 异步执行异常处理
- */
- @Override
- public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
- return (throwable, method, objects) -> {
- throwable.printStackTrace();
- StringBuilder sb = new StringBuilder();
- sb.append("Exception message - ").append(throwable.getMessage())
- .append(", Method name - ").append(method.getName());
- if (ArrayUtil.isNotEmpty(objects)) {
- sb.append(", Parameter value - ").append(Arrays.toString(objects));
- }
- throw new ServiceException(sb.toString());
- };
- }
-
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java
index 2630485a4..16f309d8f 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java
@@ -7,11 +7,9 @@ import org.dromara.common.core.config.properties.ThreadPoolProperties;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.Threads;
import org.springframework.boot.autoconfigure.AutoConfiguration;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.core.task.VirtualThreadTaskExecutor;
-import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
@@ -34,18 +32,6 @@ public class ThreadPoolConfig {
private ScheduledExecutorService scheduledExecutorService;
- @Bean(name = "threadPoolTaskExecutor")
- @ConditionalOnProperty(prefix = "thread-pool", name = "enabled", havingValue = "true")
- public ThreadPoolTaskExecutor threadPoolTaskExecutor(ThreadPoolProperties threadPoolProperties) {
- ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
- executor.setCorePoolSize(core);
- executor.setMaxPoolSize(core * 2);
- executor.setQueueCapacity(threadPoolProperties.getQueueCapacity());
- executor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds());
- executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
- return executor;
- }
-
/**
* 执行周期性或定时任务
*/
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/CompleteTaskDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/CompleteTaskDTO.java
index 2e63f8aca..e011874a2 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/CompleteTaskDTO.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/CompleteTaskDTO.java
@@ -50,6 +50,11 @@ public class CompleteTaskDTO implements Serializable {
*/
private String notice;
+ /**
+ * 办理人(可不填 用于覆盖当前节点办理人)
+ */
+ private String handler;
+
/**
* 流程变量
*/
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessDTO.java
index 3934ada55..a6d4cb3a8 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessDTO.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessDTO.java
@@ -30,6 +30,11 @@ public class StartProcessDTO implements Serializable {
*/
private String flowCode;
+ /**
+ * 办理人(可不填 用于覆盖当前节点办理人)
+ */
+ private String handler;
+
/**
* 流程变量,前端会提交一个元素{'entity': {业务详情数据对象}}
*/
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/TaskAssigneeDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/TaskAssigneeDTO.java
index 85893e1dc..78fb40ec9 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/TaskAssigneeDTO.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/TaskAssigneeDTO.java
@@ -52,17 +52,17 @@ public class TaskAssigneeDTO implements Serializable {
*/
public static List convertToHandlerList(
List sourceList,
- Function storageId,
+ Function storageId,
Function handlerCode,
Function handlerName,
- Function groupName,
+ Function groupName,
Function createTimeMapper) {
return sourceList.stream()
.map(item -> new TaskHandler(
- String.valueOf(storageId.apply(item)),
+ storageId.apply(item),
handlerCode.apply(item),
handlerName.apply(item),
- groupName != null ? String.valueOf(groupName.apply(item)) : null,
+ groupName.apply(item),
createTimeMapper.apply(item)
)).collect(Collectors.toList());
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessEvent.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessEvent.java
index 7b15b85ae..d830dbe03 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessEvent.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessEvent.java
@@ -27,6 +27,11 @@ public class ProcessEvent implements Serializable {
*/
private String flowCode;
+ /**
+ * 实例id
+ */
+ private Long instanceId;
+
/**
* 业务id
*/
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessTaskEvent.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessTaskEvent.java
index a9bcf7e93..0984727ac 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessTaskEvent.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessTaskEvent.java
@@ -4,6 +4,7 @@ import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
+import java.util.Map;
/**
* 流程任务监听
@@ -46,6 +47,11 @@ public class ProcessTaskEvent implements Serializable {
*/
private Long taskId;
+ /**
+ * 实例id
+ */
+ private Long instanceId;
+
/**
* 业务id
*/
@@ -56,4 +62,9 @@ public class ProcessTaskEvent implements Serializable {
*/
private String status;
+ /**
+ * 办理参数
+ */
+ private Map params;
+
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/PasswordLoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/PasswordLoginBody.java
index 36e33b24b..143c95907 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/PasswordLoginBody.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/PasswordLoginBody.java
@@ -26,6 +26,7 @@ public class PasswordLoginBody extends LoginBody {
*/
@NotBlank(message = "{user.password.not.blank}")
@Length(min = 5, max = 30, message = "{user.password.length.valid}")
+// @Pattern(regexp = RegexConstants.PASSWORD, message = "{user.password.format.valid}")
private String password;
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/RegisterBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/RegisterBody.java
index cced26b2b..3f232492a 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/RegisterBody.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/RegisterBody.java
@@ -26,8 +26,12 @@ public class RegisterBody extends LoginBody {
*/
@NotBlank(message = "{user.password.not.blank}")
@Length(min = 5, max = 30, message = "{user.password.length.valid}")
+// @Pattern(regexp = RegexConstants.PASSWORD, message = "{user.password.format.valid}")
private String password;
+ /**
+ * 用户类型
+ */
private String userType;
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java
index e9dc6ec9b..90f5752b1 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java
@@ -1,11 +1,15 @@
package org.dromara.common.core.exception;
-import lombok.*;
+import cn.hutool.core.text.StrFormatter;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
import java.io.Serial;
/**
- * 业务异常
+ * 业务异常(支持占位符 {} )
*
* @author ruoyi
*/
@@ -42,6 +46,10 @@ public final class ServiceException extends RuntimeException {
this.code = code;
}
+ public ServiceException(String message, Object... args) {
+ this.message = StrFormatter.format(message, args);
+ }
+
@Override
public String getMessage() {
return message;
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DeptService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DeptService.java
index f93d1778a..725718ae8 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DeptService.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DeptService.java
@@ -3,6 +3,7 @@ package org.dromara.common.core.service;
import org.dromara.common.core.domain.dto.DeptDTO;
import java.util.List;
+import java.util.Map;
/**
* 通用 部门服务
@@ -34,4 +35,12 @@ public interface DeptService {
*/
List selectDeptsByList();
+ /**
+ * 根据部门 ID 列表查询部门名称映射关系
+ *
+ * @param deptIds 部门 ID 列表
+ * @return Map,其中 key 为部门 ID,value 为对应的部门名称
+ */
+ Map selectDeptNamesByIds(List deptIds);
+
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/PostService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/PostService.java
index 41d4e8308..58c68d676 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/PostService.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/PostService.java
@@ -1,5 +1,8 @@
package org.dromara.common.core.service;
+import java.util.List;
+import java.util.Map;
+
/**
* 通用 岗位服务
*
@@ -7,4 +10,12 @@ package org.dromara.common.core.service;
*/
public interface PostService {
+ /**
+ * 根据岗位 ID 列表查询岗位名称映射关系
+ *
+ * @param postIds 岗位 ID 列表
+ * @return Map,其中 key 为岗位 ID,value 为对应的岗位名称
+ */
+ Map selectPostNamesByIds(List postIds);
+
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/RoleService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/RoleService.java
index ba62c82ae..d2805b7e0 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/RoleService.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/RoleService.java
@@ -1,5 +1,8 @@
package org.dromara.common.core.service;
+import java.util.List;
+import java.util.Map;
+
/**
* 通用 角色服务
*
@@ -7,4 +10,12 @@ package org.dromara.common.core.service;
*/
public interface RoleService {
+ /**
+ * 根据角色 ID 列表查询角色名称映射关系
+ *
+ * @param roleIds 角色 ID 列表
+ * @return Map,其中 key 为角色 ID,value 为对应的角色名称
+ */
+ Map selectRoleNamesByIds(List roleIds);
+
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java
index 4903c3860..eefeef011 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java
@@ -100,28 +100,4 @@ public interface UserService {
*/
Map selectUserNamesByIds(List userIds);
- /**
- * 根据角色 ID 列表查询角色名称映射关系
- *
- * @param roleIds 角色 ID 列表
- * @return Map,其中 key 为角色 ID,value 为对应的角色名称
- */
- Map selectRoleNamesByIds(List roleIds);
-
- /**
- * 根据部门 ID 列表查询部门名称映射关系
- *
- * @param deptIds 部门 ID 列表
- * @return Map,其中 key 为部门 ID,value 为对应的部门名称
- */
- Map selectDeptNamesByIds(List deptIds);
-
- /**
- * 根据岗位 ID 列表查询岗位名称映射关系
- *
- * @param postIds 岗位 ID 列表
- * @return Map,其中 key 为岗位 ID,value 为对应的岗位名称
- */
- Map selectPostNamesByIds(List postIds);
-
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/WorkflowService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/WorkflowService.java
index 9d1a90195..706d357e7 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/WorkflowService.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/WorkflowService.java
@@ -82,6 +82,7 @@ public interface WorkflowService {
* completeTask.getVariables().put("ignore", true);
*
* @param completeTask 参数
+ * @return 结果
*/
boolean completeTask(CompleteTaskDTO completeTask);
@@ -90,6 +91,15 @@ public interface WorkflowService {
*
* @param taskId 任务ID
* @param message 办理意见
+ * @return 结果
*/
boolean completeTask(Long taskId, String message);
+
+ /**
+ * 启动流程并办理第一个任务
+ *
+ * @param startProcess 参数
+ * @return 结果
+ */
+ boolean startCompleteTask(StartProcessDTO startProcess);
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java
index b52d95e16..b4d146242 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java
@@ -293,7 +293,7 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
// 校验时间跨度不超过最大限制
if (diff > maxValue) {
- throw new ServiceException("最大时间跨度为 " + maxValue + " " + unit.toString().toLowerCase());
+ throw new ServiceException("最大时间跨度为 {} {}", maxValue, unit.toString().toLowerCase());
}
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java
index bd1aab808..509026f72 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java
@@ -115,7 +115,7 @@ public class ServletUtils extends JakartaServletUtil {
public static Map getParamMap(ServletRequest request) {
Map params = new HashMap<>();
for (Map.Entry entry : getParams(request).entrySet()) {
- params.put(entry.getKey(), StringUtils.join(entry.getValue(), StringUtils.SEPARATOR));
+ params.put(entry.getKey(), StringUtils.joinComma(entry.getValue()));
}
return params;
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StreamUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StreamUtils.java
index 1342deb71..f9e53a508 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StreamUtils.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StreamUtils.java
@@ -7,7 +7,6 @@ import lombok.NoArgsConstructor;
import java.util.*;
import java.util.function.BiFunction;
-import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java
index 716573431..6eac2fcbe 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java
@@ -260,13 +260,13 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
if (s != null) {
final int len = s.length();
if (s.length() <= size) {
- sb.append(String.valueOf(c).repeat(size - len));
+ sb.append(Convert.toStr(c).repeat(size - len));
sb.append(s);
} else {
return s.substring(len - size, len);
}
} else {
- sb.append(String.valueOf(c).repeat(Math.max(0, size)));
+ sb.append(Convert.toStr(c).repeat(Math.max(0, size)));
}
return sb.toString();
}
@@ -361,5 +361,24 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
return input;
}
}
+ /**
+ * 将可迭代对象中的元素使用逗号拼接成字符串
+ *
+ * @param iterable 可迭代对象,如 List、Set 等
+ * @return 拼接后的字符串
+ */
+ public static String joinComma(Iterable> iterable) {
+ return StringUtils.join(iterable, SEPARATOR);
+ }
+
+ /**
+ * 将数组中的元素使用逗号拼接成字符串
+ *
+ * @param array 任意类型的数组
+ * @return 拼接后的字符串
+ */
+ public static String joinComma(Object[] array) {
+ return StringUtils.join(array, SEPARATOR);
+ }
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
index 43c7fcfe0..5c3db08a5 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
+++ b/ruoyi-common/ruoyi-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -1,5 +1,4 @@
org.dromara.common.core.config.ApplicationConfig
-org.dromara.common.core.config.AsyncConfig
org.dromara.common.core.config.ThreadPoolConfig
org.dromara.common.core.config.ValidatorConfig
org.dromara.common.core.utils.SpringUtils
diff --git a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java
index c199015c0..35b6ce9ea 100644
--- a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java
+++ b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java
@@ -54,14 +54,15 @@ public class SpringDocConfig {
openApi.externalDocs(properties.getExternalDocs());
openApi.tags(properties.getTags());
openApi.paths(properties.getPaths());
- openApi.components(properties.getComponents());
- Set keySet = properties.getComponents().getSecuritySchemes().keySet();
- List list = new ArrayList<>();
- SecurityRequirement securityRequirement = new SecurityRequirement();
- keySet.forEach(securityRequirement::addList);
- list.add(securityRequirement);
- openApi.security(list);
-
+ if (properties.getComponents() != null) {
+ openApi.components(properties.getComponents());
+ Set keySet = properties.getComponents().getSecuritySchemes().keySet();
+ List list = new ArrayList<>();
+ SecurityRequirement securityRequirement = new SecurityRequirement();
+ keySet.forEach(securityRequirement::addList);
+ list.add(securityRequirement);
+ openApi.security(list);
+ }
return openApi;
}
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/ApiDecryptAutoConfiguration.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/ApiDecryptAutoConfiguration.java
index 098f6bc8d..38b22f388 100644
--- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/ApiDecryptAutoConfiguration.java
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/ApiDecryptAutoConfiguration.java
@@ -6,6 +6,7 @@ import org.dromara.common.encrypt.properties.ApiDecryptProperties;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.web.servlet.FilterRegistration;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
@@ -20,13 +21,14 @@ import org.springframework.context.annotation.Bean;
public class ApiDecryptAutoConfiguration {
@Bean
- public FilterRegistrationBean cryptoFilterRegistration(ApiDecryptProperties properties) {
- FilterRegistrationBean registration = new FilterRegistrationBean<>();
- registration.setDispatcherTypes(DispatcherType.REQUEST);
- registration.setFilter(new CryptoFilter(properties));
- registration.addUrlPatterns("/*");
- registration.setName("cryptoFilter");
- registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
- return registration;
+ @FilterRegistration(
+ name = "cryptoFilter",
+ urlPatterns = "/*",
+ order = FilterRegistrationBean.HIGHEST_PRECEDENCE,
+ dispatcherTypes = DispatcherType.REQUEST
+ )
+ public CryptoFilter cryptoFilter(ApiDecryptProperties properties) {
+ return new CryptoFilter(properties);
}
+
}
diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeHandler.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeHandler.java
new file mode 100644
index 000000000..204a88e25
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeHandler.java
@@ -0,0 +1,200 @@
+package org.dromara.common.excel.core;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ReflectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.idev.excel.annotation.ExcelIgnore;
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import lombok.SneakyThrows;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.dromara.common.core.utils.reflect.ReflectUtils;
+import org.dromara.common.excel.annotation.CellMerge;
+
+import java.lang.reflect.Field;
+import java.util.*;
+
+/**
+ * 单元格合并处理器
+ *
+ * @author Lion Li
+ */
+public class CellMergeHandler {
+
+ private final boolean hasTitle;
+ private int rowIndex;
+
+ private CellMergeHandler(final boolean hasTitle) {
+ this.hasTitle = hasTitle;
+ // 行合并开始下标
+ this.rowIndex = hasTitle ? 1 : 0;
+ }
+
+ @SneakyThrows
+ public List handle(List> rows) {
+ // 如果入参为空集合则返回空集
+ if (CollUtil.isEmpty(rows)) {
+ return Collections.emptyList();
+ }
+
+ // 获取有合并注解的字段
+ Map mergeFields = getFieldColumnIndexMap(rows.get(0).getClass());
+ // 如果没有需要合并的字段则返回空集
+ if (CollUtil.isEmpty(mergeFields)) {
+ return Collections.emptyList();
+ }
+
+ // 结果集
+ List result = new ArrayList<>();
+
+ // 生成两两合并单元格
+ Map rowRepeatCellMap = new HashMap<>();
+ for (Map.Entry item : mergeFields.entrySet()) {
+ Field field = item.getKey();
+ FieldColumnIndex itemValue = item.getValue();
+ int colNum = itemValue.colIndex();
+ CellMerge cellMerge = itemValue.cellMerge();
+
+ for (int i = 0; i < rows.size(); i++) {
+ // 当前行数据
+ Object currentRowObj = rows.get(i);
+ // 当前行数据字段值
+ Object currentRowObjFieldVal = ReflectUtils.invokeGetter(currentRowObj, field.getName());
+
+ // 空值跳过不处理
+ if (currentRowObjFieldVal == null || "".equals(currentRowObjFieldVal)) {
+ continue;
+ }
+
+ // 单元格合并Map是否存在数据,如果不存在则添加当前行的字段值
+ if (!rowRepeatCellMap.containsKey(field)) {
+ rowRepeatCellMap.put(field, RepeatCell.of(currentRowObjFieldVal, i));
+ continue;
+ }
+
+ // 获取 单元格合并Map 中字段值
+ RepeatCell repeatCell = rowRepeatCellMap.get(field);
+ Object cellValue = repeatCell.value();
+ int current = repeatCell.current();
+
+ // 检查是否满足合并条件
+ // currentRowObj 当前行数据
+ // rows.get(i - 1) 上一行数据 注:由于 if (!rowRepeatCellMap.containsKey(field)) 条件的存在,所以该 i 必不可能小于1
+ // cellMerge 当前行字段合并注解
+ boolean merge = isMerge(currentRowObj, rows.get(i - 1), cellMerge);
+
+ // 是否添加到结果集
+ boolean isAddResult = false;
+ // 最新行
+ int lastRow = i + rowIndex - 1;
+
+ // 如果当前行字段值和缓存中的字段值不相等,或不满足合并条件,则替换
+ if (!currentRowObjFieldVal.equals(cellValue) || !merge) {
+ rowRepeatCellMap.put(field, RepeatCell.of(currentRowObjFieldVal, i));
+ isAddResult = true;
+ }
+
+ // 如果最后一行不能合并,检查之前的数据是否需要合并;如果最后一行可以合并,则直接合并到最后
+ if (i == rows.size() - 1) {
+ isAddResult = true;
+ if (i > current) {
+ lastRow = i + rowIndex;
+ }
+ }
+
+ if (isAddResult && i > current) {
+ result.add(new CellRangeAddress(current + rowIndex, lastRow, colNum, colNum));
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * 获取带有合并注解的字段列索引和合并注解信息Map集
+ */
+ private Map getFieldColumnIndexMap(Class> clazz) {
+ boolean annotationPresent = clazz.isAnnotationPresent(ExcelIgnoreUnannotated.class);
+ Field[] fields = ReflectUtils.getFields(clazz, field -> {
+ if ("serialVersionUID".equals(field.getName())) {
+ return false;
+ }
+ if (field.isAnnotationPresent(ExcelIgnore.class)) {
+ return false;
+ }
+ return !annotationPresent || field.isAnnotationPresent(ExcelProperty.class);
+ });
+
+ // 有注解的字段
+ Map mergeFields = new HashMap<>();
+ for (int i = 0; i < fields.length; i++) {
+ Field field = fields[i];
+ if (!field.isAnnotationPresent(CellMerge.class)) {
+ continue;
+ }
+ CellMerge cm = field.getAnnotation(CellMerge.class);
+ int index = cm.index() == -1 ? i : cm.index();
+ mergeFields.put(field, FieldColumnIndex.of(index, cm));
+
+ if (hasTitle) {
+ ExcelProperty property = field.getAnnotation(ExcelProperty.class);
+ rowIndex = Math.max(rowIndex, property.value().length);
+ }
+ }
+ return mergeFields;
+ }
+
+ private boolean isMerge(Object currentRow, Object preRow, CellMerge cellMerge) {
+ final String[] mergeBy = cellMerge.mergeBy();
+ if (StrUtil.isAllNotBlank(mergeBy)) {
+ //比对当前行和上一行的各个属性值一一比对 如果全为真 则为真
+ for (String fieldName : mergeBy) {
+ final Object valCurrent = ReflectUtil.getFieldValue(currentRow, fieldName);
+ final Object valPre = ReflectUtil.getFieldValue(preRow, fieldName);
+ if (!Objects.equals(valPre, valCurrent)) {
+ //依赖字段如有任一不等值,则标记为不可合并
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * 单元格合并
+ */
+ record RepeatCell(Object value, int current) {
+ static RepeatCell of(Object value, int current) {
+ return new RepeatCell(value, current);
+ }
+ }
+
+ /**
+ * 字段列索引和合并注解信息
+ */
+ record FieldColumnIndex(int colIndex, CellMerge cellMerge) {
+ static FieldColumnIndex of(int colIndex, CellMerge cellMerge) {
+ return new FieldColumnIndex(colIndex, cellMerge);
+ }
+ }
+
+ /**
+ * 创建一个单元格合并处理器实例
+ *
+ * @param hasTitle 是否合并标题
+ * @return 单元格合并处理器
+ */
+ public static CellMergeHandler of(final boolean hasTitle) {
+ return new CellMergeHandler(hasTitle);
+ }
+
+ /**
+ * 创建一个单元格合并处理器实例(默认不合并标题)
+ *
+ * @return 单元格合并处理器
+ */
+ public static CellMergeHandler of() {
+ return new CellMergeHandler(false);
+ }
+
+}
diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java
index 515f68e1b..34bf4a42f 100644
--- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java
+++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java
@@ -1,24 +1,15 @@
package org.dromara.common.excel.core;
import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.ReflectUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.idev.excel.annotation.ExcelProperty;
import cn.idev.excel.metadata.Head;
import cn.idev.excel.write.handler.WorkbookWriteHandler;
import cn.idev.excel.write.handler.context.WorkbookWriteHandlerContext;
import cn.idev.excel.write.merge.AbstractMergeStrategy;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
-import org.dromara.common.core.utils.reflect.ReflectUtils;
-import org.dromara.common.excel.annotation.CellMerge;
-import java.lang.reflect.Field;
import java.util.*;
/**
@@ -30,134 +21,39 @@ import java.util.*;
public class CellMergeStrategy extends AbstractMergeStrategy implements WorkbookWriteHandler {
private final List cellList;
- private final boolean hasTitle;
- private int rowIndex;
+
+ public CellMergeStrategy(List cellList) {
+ this.cellList = cellList;
+ }
public CellMergeStrategy(List> list, boolean hasTitle) {
- this.hasTitle = hasTitle;
- // 行合并开始下标
- this.rowIndex = hasTitle ? 1 : 0;
- this.cellList = handle(list, hasTitle);
+ this.cellList = CellMergeHandler.of(hasTitle).handle(list);
}
@Override
protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
+ if (CollUtil.isEmpty(cellList)){
+ return;
+ }
//单元格写入了,遍历合并区域,如果该Cell在区域内,但非首行,则清空
final int rowIndex = cell.getRowIndex();
- if (CollUtil.isNotEmpty(cellList)){
- for (CellRangeAddress cellAddresses : cellList) {
- final int firstRow = cellAddresses.getFirstRow();
- if (cellAddresses.isInRange(cell) && rowIndex != firstRow){
- cell.setBlank();
- }
+ for (CellRangeAddress cellAddresses : cellList) {
+ final int firstRow = cellAddresses.getFirstRow();
+ if (cellAddresses.isInRange(cell) && rowIndex != firstRow){
+ cell.setBlank();
}
}
}
@Override
public void afterWorkbookDispose(final WorkbookWriteHandlerContext context) {
+ if (CollUtil.isEmpty(cellList)){
+ return;
+ }
//当前表格写完后,统一写入
- if (CollUtil.isNotEmpty(cellList)){
- for (CellRangeAddress item : cellList) {
- context.getWriteContext().writeSheetHolder().getSheet().addMergedRegion(item);
- }
+ for (CellRangeAddress item : cellList) {
+ context.getWriteContext().writeSheetHolder().getSheet().addMergedRegion(item);
}
}
- @SneakyThrows
- private List handle(List> list, boolean hasTitle) {
- List cellList = new ArrayList<>();
- if (CollUtil.isEmpty(list)) {
- return cellList;
- }
- Field[] fields = ReflectUtils.getFields(list.get(0).getClass(), field -> !"serialVersionUID".equals(field.getName()));
-
- // 有注解的字段
- List mergeFields = new ArrayList<>();
- List mergeFieldsIndex = new ArrayList<>();
- for (int i = 0; i < fields.length; i++) {
- Field field = fields[i];
- if (field.isAnnotationPresent(CellMerge.class)) {
- CellMerge cm = field.getAnnotation(CellMerge.class);
- mergeFields.add(field);
- mergeFieldsIndex.add(cm.index() == -1 ? i : cm.index());
- if (hasTitle) {
- ExcelProperty property = field.getAnnotation(ExcelProperty.class);
- rowIndex = Math.max(rowIndex, property.value().length);
- }
- }
- }
-
- Map map = new HashMap<>();
- // 生成两两合并单元格
- for (int i = 0; i < list.size(); i++) {
- for (int j = 0; j < mergeFields.size(); j++) {
- Field field = mergeFields.get(j);
- Object val = ReflectUtils.invokeGetter(list.get(i), field.getName());
-
- int colNum = mergeFieldsIndex.get(j);
- if (!map.containsKey(field)) {
- map.put(field, new RepeatCell(val, i));
- } else {
- RepeatCell repeatCell = map.get(field);
- Object cellValue = repeatCell.getValue();
- if (cellValue == null || "".equals(cellValue)) {
- // 空值跳过不合并
- continue;
- }
-
- if (!cellValue.equals(val)) {
- if ((i - repeatCell.getCurrent() > 1)) {
- cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum));
- }
- map.put(field, new RepeatCell(val, i));
- } else if (i == list.size() - 1) {
- if (!isMerge(list, i, field)) {
- // 如果最后一行不能合并,检查之前的数据是否需要合并
- if (i - repeatCell.getCurrent() > 1) {
- cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum));
- }
- } else if (i > repeatCell.getCurrent()) {
- // 如果最后一行可以合并,则直接合并到最后
- cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex, colNum, colNum));
- }
- } else if (!isMerge(list, i, field)) {
- if ((i - repeatCell.getCurrent() > 1)) {
- cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum));
- }
- map.put(field, new RepeatCell(val, i));
- }
- }
- }
- }
- return cellList;
- }
-
- private boolean isMerge(List> list, int i, Field field) {
- boolean isMerge = true;
- CellMerge cm = field.getAnnotation(CellMerge.class);
- final String[] mergeBy = cm.mergeBy();
- if (StrUtil.isAllNotBlank(mergeBy)) {
- //比对当前list(i)和list(i - 1)的各个属性值一一比对 如果全为真 则为真
- for (String fieldName : mergeBy) {
- final Object valCurrent = ReflectUtil.getFieldValue(list.get(i), fieldName);
- final Object valPre = ReflectUtil.getFieldValue(list.get(i - 1), fieldName);
- if (!Objects.equals(valPre, valCurrent)) {
- //依赖字段如有任一不等值,则标记为不可合并
- isMerge = false;
- }
- }
- }
- return isMerge;
- }
-
- @Data
- @AllArgsConstructor
- static class RepeatCell {
-
- private Object value;
-
- private int current;
-
- }
}
diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DropDownOptions.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DropDownOptions.java
index 8b53a0ce0..7cdb5c5c0 100644
--- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DropDownOptions.java
+++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DropDownOptions.java
@@ -1,5 +1,6 @@
package org.dromara.common.excel.core;
+import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -65,7 +66,7 @@ public class DropDownOptions {
StringBuilder stringBuffer = new StringBuilder();
String regex = "^[\\S\\d\\u4e00-\\u9fa5]+$";
for (int i = 0; i < vars.length; i++) {
- String var = StrUtil.trimToEmpty(String.valueOf(vars[i]));
+ String var = StrUtil.trimToEmpty(Convert.toStr(vars[i]));
if (!var.matches(regex)) {
throw new ServiceException("选项数据不符合规则,仅允许使用中英文字符以及数字");
}
diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java
index f3b641545..139728390 100644
--- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java
+++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java
@@ -1,6 +1,7 @@
package org.dromara.common.excel.core;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.ObjectUtil;
@@ -103,7 +104,7 @@ public class ExcelDownHandler implements SheetWriteHandler {
if (StringUtils.isNotBlank(dictType)) {
// 如果传递了字典名,则依据字典建立下拉
Collection values = Optional.ofNullable(dictService.getAllDictByDictType(dictType))
- .orElseThrow(() -> new ServiceException(String.format("字典 %s 不存在", dictType)))
+ .orElseThrow(() -> new ServiceException("字典 {} 不存在", dictType))
.values();
options = new ArrayList<>(values);
} else if (StringUtils.isNotBlank(converterExp)) {
@@ -115,7 +116,7 @@ public class ExcelDownHandler implements SheetWriteHandler {
// 否则如果指定了@ExcelEnumFormat,则使用枚举的逻辑
ExcelEnumFormat format = field.getDeclaredAnnotation(ExcelEnumFormat.class);
List