messages = context.getMsgList();
+ Assert.isTrue(messages.size() == 1, "消息条数({})不正确", messages.size());
+ // 设置租户编号
+ String tenantId = messages.get(0).getUserProperty(HEADER_TENANT_ID);
+ if (StrUtil.isNotEmpty(tenantId)) {
+ TenantContextHolder.setTenantId(Long.parseLong(tenantId));
+ }
+ }
+
+ @Override
+ public void consumeMessageAfter(ConsumeMessageContext context) {
+ TenantContextHolder.clear();
+ }
+
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQInitializer.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQInitializer.java
new file mode 100644
index 000000000..7f12ac520
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQInitializer.java
@@ -0,0 +1,53 @@
+package cn.iocoder.yudao.framework.tenant.core.mq.rocketmq;
+
+import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
+import org.apache.rocketmq.client.impl.consumer.DefaultMQPushConsumerImpl;
+import org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl;
+import org.apache.rocketmq.client.producer.DefaultMQProducer;
+import org.apache.rocketmq.spring.core.RocketMQTemplate;
+import org.apache.rocketmq.spring.support.DefaultRocketMQListenerContainer;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+
+/**
+ * 多租户的 RocketMQ 初始化器
+ *
+ * @author 芋道源码
+ */
+public class TenantRocketMQInitializer implements BeanPostProcessor {
+
+ @Override
+ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
+ if (bean instanceof DefaultRocketMQListenerContainer) {
+ DefaultRocketMQListenerContainer container = (DefaultRocketMQListenerContainer) bean;
+ initTenantConsumer(container.getConsumer());
+ } else if (bean instanceof RocketMQTemplate) {
+ RocketMQTemplate template = (RocketMQTemplate) bean;
+ initTenantProducer(template.getProducer());
+ }
+ return bean;
+ }
+
+ private void initTenantProducer(DefaultMQProducer producer) {
+ if (producer == null) {
+ return;
+ }
+ DefaultMQProducerImpl producerImpl = producer.getDefaultMQProducerImpl();
+ if (producerImpl == null) {
+ return;
+ }
+ producerImpl.registerSendMessageHook(new TenantRocketMQSendMessageHook());
+ }
+
+ private void initTenantConsumer(DefaultMQPushConsumer consumer) {
+ if (consumer == null) {
+ return;
+ }
+ DefaultMQPushConsumerImpl consumerImpl = consumer.getDefaultMQPushConsumerImpl();
+ if (consumerImpl == null) {
+ return;
+ }
+ consumerImpl.registerConsumeMessageHook(new TenantRocketMQConsumeMessageHook());
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQSendMessageHook.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQSendMessageHook.java
new file mode 100644
index 000000000..4f0307465
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/rocketmq/TenantRocketMQSendMessageHook.java
@@ -0,0 +1,36 @@
+package cn.iocoder.yudao.framework.tenant.core.mq.rocketmq;
+
+import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
+import org.apache.rocketmq.client.hook.SendMessageContext;
+import org.apache.rocketmq.client.hook.SendMessageHook;
+
+import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID;
+
+/**
+ * RocketMQ 消息队列的多租户 {@link SendMessageHook} 实现类
+ *
+ * Producer 发送消息时,将 {@link TenantContextHolder} 租户编号,添加到消息的 Header 中
+ *
+ * @author 芋道源码
+ */
+public class TenantRocketMQSendMessageHook implements SendMessageHook {
+
+ @Override
+ public String hookName() {
+ return getClass().getSimpleName();
+ }
+
+ @Override
+ public void sendMessageBefore(SendMessageContext sendMessageContext) {
+ Long tenantId = TenantContextHolder.getTenantId();
+ if (tenantId == null) {
+ return;
+ }
+ sendMessageContext.getMessage().putUserProperty(HEADER_TENANT_ID, tenantId.toString());
+ }
+
+ @Override
+ public void sendMessageAfter(SendMessageContext sendMessageContext) {
+ }
+
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/org/springframework/messaging/handler/invocation/InvocableHandlerMethod.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/org/springframework/messaging/handler/invocation/InvocableHandlerMethod.java
new file mode 100644
index 000000000..059d8f97f
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/org/springframework/messaging/handler/invocation/InvocableHandlerMethod.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright 2002-2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.messaging.handler.invocation;
+
+import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
+import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
+import org.springframework.core.DefaultParameterNameDiscoverer;
+import org.springframework.core.MethodParameter;
+import org.springframework.core.ParameterNameDiscoverer;
+import org.springframework.core.ResolvableType;
+import org.springframework.lang.Nullable;
+import org.springframework.messaging.Message;
+import org.springframework.messaging.handler.HandlerMethod;
+import org.springframework.util.ObjectUtils;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+
+import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID;
+
+/**
+ * Extension of {@link HandlerMethod} that invokes the underlying method with
+ * argument values resolved from the current HTTP request through a list of
+ * {@link HandlerMethodArgumentResolver}.
+ *
+ * 针对 rabbitmq-spring 和 kafka-spring,不存在合适的拓展点,可以实现 Consumer 消费前,读取 Header 中的 tenant-id 设置到 {@link TenantContextHolder} 中
+ * TODO 芋艿:持续跟进,看看有没新的拓展点
+ *
+ * @author Rossen Stoyanchev
+ * @author Juergen Hoeller
+ * @since 4.0
+ */
+public class InvocableHandlerMethod extends HandlerMethod {
+
+ private static final Object[] EMPTY_ARGS = new Object[0];
+
+ private HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite();
+
+ private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
+
+ /**
+ * Create an instance from a {@code HandlerMethod}.
+ */
+ public InvocableHandlerMethod(HandlerMethod handlerMethod) {
+ super(handlerMethod);
+ }
+
+ /**
+ * Create an instance from a bean instance and a method.
+ */
+ public InvocableHandlerMethod(Object bean, Method method) {
+ super(bean, method);
+ }
+
+ /**
+ * Construct a new handler method with the given bean instance, method name and parameters.
+ * @param bean the object bean
+ * @param methodName the method name
+ * @param parameterTypes the method parameter types
+ * @throws NoSuchMethodException when the method cannot be found
+ */
+ public InvocableHandlerMethod(Object bean, String methodName, Class>... parameterTypes)
+ throws NoSuchMethodException {
+
+ super(bean, methodName, parameterTypes);
+ }
+
+ /**
+ * Set {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers} to use for resolving method argument values.
+ */
+ public void setMessageMethodArgumentResolvers(HandlerMethodArgumentResolverComposite argumentResolvers) {
+ this.resolvers = argumentResolvers;
+ }
+
+ /**
+ * Set the ParameterNameDiscoverer for resolving parameter names when needed
+ * (e.g. default request attribute name).
+ * Default is a {@link DefaultParameterNameDiscoverer}.
+ */
+ public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) {
+ this.parameterNameDiscoverer = parameterNameDiscoverer;
+ }
+
+ /**
+ * Invoke the method after resolving its argument values in the context of the given message.
+ *
Argument values are commonly resolved through
+ * {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers}.
+ * The {@code providedArgs} parameter however may supply argument values to be used directly,
+ * i.e. without argument resolution.
+ *
Delegates to {@link #getMethodArgumentValues} and calls {@link #doInvoke} with the
+ * resolved arguments.
+ * @param message the current message being processed
+ * @param providedArgs "given" arguments matched by type, not resolved
+ * @return the raw value returned by the invoked method
+ * @throws Exception raised if no suitable argument resolver can be found,
+ * or if the method raised an exception
+ * @see #getMethodArgumentValues
+ * @see #doInvoke
+ */
+ @Nullable
+ public Object invoke(Message> message, Object... providedArgs) throws Exception {
+ Object[] args = getMethodArgumentValues(message, providedArgs);
+ if (logger.isTraceEnabled()) {
+ logger.trace("Arguments: " + Arrays.toString(args));
+ }
+ // 注意:如下是本类的改动点!!!
+ // 情况一:无租户编号的情况
+ Long tenantId= parseTenantId(message);
+ if (tenantId == null) {
+ return doInvoke(args);
+ }
+ // 情况二:有租户的情况下
+ return TenantUtils.execute(tenantId, () -> doInvoke(args));
+ }
+
+ private Long parseTenantId(Message> message) {
+ Object tenantId = message.getHeaders().get(HEADER_TENANT_ID);
+ if (tenantId == null) {
+ return null;
+ }
+ if (tenantId instanceof Long) {
+ return (Long) tenantId;
+ }
+ if (tenantId instanceof Number) {
+ return ((Number) tenantId).longValue();
+ }
+ if (tenantId instanceof String) {
+ return Long.parseLong((String) tenantId);
+ }
+ if (tenantId instanceof byte[]) {
+ return Long.parseLong(new String((byte[]) tenantId));
+ }
+ throw new IllegalArgumentException("未知的数据类型:" + tenantId);
+ }
+
+ /**
+ * Get the method argument values for the current message, checking the provided
+ * argument values and falling back to the configured argument resolvers.
+ *
The resulting array will be passed into {@link #doInvoke}.
+ * @since 5.1.2
+ */
+ protected Object[] getMethodArgumentValues(Message> message, Object... providedArgs) throws Exception {
+ MethodParameter[] parameters = getMethodParameters();
+ if (ObjectUtils.isEmpty(parameters)) {
+ return EMPTY_ARGS;
+ }
+
+ Object[] args = new Object[parameters.length];
+ for (int i = 0; i < parameters.length; i++) {
+ MethodParameter parameter = parameters[i];
+ parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
+ args[i] = findProvidedArgument(parameter, providedArgs);
+ if (args[i] != null) {
+ continue;
+ }
+ if (!this.resolvers.supportsParameter(parameter)) {
+ throw new MethodArgumentResolutionException(
+ message, parameter, formatArgumentError(parameter, "No suitable resolver"));
+ }
+ try {
+ args[i] = this.resolvers.resolveArgument(parameter, message);
+ }
+ catch (Exception ex) {
+ // Leave stack trace for later, exception may actually be resolved and handled...
+ if (logger.isDebugEnabled()) {
+ String exMsg = ex.getMessage();
+ if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
+ logger.debug(formatArgumentError(parameter, exMsg));
+ }
+ }
+ throw ex;
+ }
+ }
+ return args;
+ }
+
+ /**
+ * Invoke the handler method with the given argument values.
+ */
+ @Nullable
+ protected Object doInvoke(Object... args) throws Exception {
+ try {
+ return getBridgedMethod().invoke(getBean(), args);
+ }
+ catch (IllegalArgumentException ex) {
+ assertTargetBean(getBridgedMethod(), getBean(), args);
+ String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
+ throw new IllegalStateException(formatInvokeError(text, args), ex);
+ }
+ catch (InvocationTargetException ex) {
+ // Unwrap for HandlerExceptionResolvers ...
+ Throwable targetException = ex.getTargetException();
+ if (targetException instanceof RuntimeException) {
+ throw (RuntimeException) targetException;
+ }
+ else if (targetException instanceof Error) {
+ throw (Error) targetException;
+ }
+ else if (targetException instanceof Exception) {
+ throw (Exception) targetException;
+ }
+ else {
+ throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException);
+ }
+ }
+ }
+
+ MethodParameter getAsyncReturnValueType(@Nullable Object returnValue) {
+ return new AsyncResultMethodParameter(returnValue);
+ }
+
+ private class AsyncResultMethodParameter extends HandlerMethodParameter {
+
+ @Nullable
+ private final Object returnValue;
+
+ private final ResolvableType returnType;
+
+ public AsyncResultMethodParameter(@Nullable Object returnValue) {
+ super(-1);
+ this.returnValue = returnValue;
+ this.returnType = ResolvableType.forType(super.getGenericParameterType()).getGeneric();
+ }
+
+ protected AsyncResultMethodParameter(AsyncResultMethodParameter original) {
+ super(original);
+ this.returnValue = original.returnValue;
+ this.returnType = original.returnType;
+ }
+
+ @Override
+ public Class> getParameterType() {
+ if (this.returnValue != null) {
+ return this.returnValue.getClass();
+ }
+ if (!ResolvableType.NONE.equals(this.returnType)) {
+ return this.returnType.toClass();
+ }
+ return super.getParameterType();
+ }
+
+ @Override
+ public Type getGenericParameterType() {
+ return this.returnType.getType();
+ }
+
+ @Override
+ public AsyncResultMethodParameter clone() {
+ return new AsyncResultMethodParameter(this);
+ }
+ }
+
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/resources/META-INF/spring.factories b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/resources/META-INF/spring.factories
new file mode 100644
index 000000000..a495842a0
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,2 @@
+org.springframework.boot.env.EnvironmentPostProcessor=\
+ cn.iocoder.yudao.framework.tenant.core.mq.kafka.TenantKafkaEnvironmentPostProcessor
diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/test/java/cn/iocoder/yudao/framework/tenant/core/job/TestJob.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/test/java/cn/iocoder/yudao/framework/tenant/core/job/TestJob.java
deleted file mode 100644
index 2a6d200c4..000000000
--- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/test/java/cn/iocoder/yudao/framework/tenant/core/job/TestJob.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package cn.iocoder.yudao.framework.tenant.core.job;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
-import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
-import org.springframework.stereotype.Component;
-
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-@Component
-public class TestJob implements JobHandler {
-
- private final List tenantIds = new CopyOnWriteArrayList<>();
-
- @Override
- @TenantJob // 标记多租户
- public String execute(String param) throws Exception {
- tenantIds.add(TenantContextHolder.getTenantId());
- return "success";
- }
-
- public List getTenantIds() {
- CollUtil.sort(tenantIds, Long::compareTo);
- return tenantIds;
- }
-
-}
diff --git a/yudao-framework/yudao-spring-boot-starter-mq/pom.xml b/yudao-framework/yudao-spring-boot-starter-mq/pom.xml
index 75303d4e3..c8972f16b 100644
--- a/yudao-framework/yudao-spring-boot-starter-mq/pom.xml
+++ b/yudao-framework/yudao-spring-boot-starter-mq/pom.xml
@@ -12,7 +12,7 @@
jar
${project.artifactId}
- 消息队列,基于 Redis Pub/Sub 实现广播消费,基于 Stream 实现集群消费
+ 消息队列,支持 Redis、RocketMQ、RabbitMQ、Kafka 四种
https://github.com/YunaiV/ruoyi-vue-pro
@@ -21,6 +21,23 @@
cn.iocoder.boot
yudao-spring-boot-starter-redis
+
+
+
+ org.springframework.kafka
+ spring-kafka
+ true
+
+
+ org.springframework.amqp
+ spring-rabbit
+ true
+
+
+ org.apache.rocketmq
+ rocketmq-spring-boot-starter
+ true
+
-
+
\ No newline at end of file
diff --git a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/pubsub/AbstractChannelMessage.java b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/pubsub/AbstractChannelMessage.java
deleted file mode 100644
index fbc2a2826..000000000
--- a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/pubsub/AbstractChannelMessage.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package cn.iocoder.yudao.framework.mq.core.pubsub;
-
-import cn.iocoder.yudao.framework.mq.core.message.AbstractRedisMessage;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-
-/**
- * Redis Channel Message 抽象类
- *
- * @author 芋道源码
- */
-public abstract class AbstractChannelMessage extends AbstractRedisMessage {
-
- /**
- * 获得 Redis Channel
- *
- * @return Channel
- */
- @JsonIgnore // 避免序列化。原因是,Redis 发布 Channel 消息的时候,已经会指定。
- public abstract String getChannel();
-
-}
diff --git a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/stream/AbstractStreamMessage.java b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/stream/AbstractStreamMessage.java
deleted file mode 100644
index 29ea833f3..000000000
--- a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/stream/AbstractStreamMessage.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package cn.iocoder.yudao.framework.mq.core.stream;
-
-import cn.iocoder.yudao.framework.mq.core.message.AbstractRedisMessage;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-
-/**
- * Redis Stream Message 抽象类
- *
- * @author 芋道源码
- */
-public abstract class AbstractStreamMessage extends AbstractRedisMessage {
-
- /**
- * 获得 Redis Stream Key
- *
- * @return Channel
- */
- @JsonIgnore // 避免序列化
- public abstract String getStreamKey();
-
-}
diff --git a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/package-info.java b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/package-info.java
index 48eaf2386..3b716cb77 100644
--- a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/package-info.java
+++ b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/package-info.java
@@ -1,6 +1,4 @@
/**
- * 消息队列,基于 Redis 提供:
- * 1. 基于 Pub/Sub 实现广播消费
- * 2. 基于 Stream 实现集群消费
+ * 消息队列,支持 Redis、RocketMQ、RabbitMQ、Kafka 四种
*/
package cn.iocoder.yudao.framework.mq;
diff --git a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/config/YudaoRabbitMQAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/config/YudaoRabbitMQAutoConfiguration.java
new file mode 100644
index 000000000..770c50ff7
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/config/YudaoRabbitMQAutoConfiguration.java
@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.framework.mq.rabbitmq.config;
+
+import cn.hutool.core.util.ReflectUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.amqp.utils.SerializationUtils;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+
+import java.lang.reflect.Field;
+
+/**
+ * RabbitMQ 消息队列配置类
+ *
+ * @author 芋道源码
+ */
+@AutoConfiguration
+@Slf4j
+@ConditionalOnClass(name = "org.springframework.amqp.rabbit.core.RabbitTemplate")
+public class YudaoRabbitMQAutoConfiguration {
+
+ static {
+ // 强制设置 SerializationUtils 的 TRUST_ALL 为 true,避免 RabbitMQ Consumer 反序列化消息报错
+ // 为什么不通过设置 spring.amqp.deserialization.trust.all 呢?因为可能在 SerializationUtils static 初始化后
+ Field trustAllField = ReflectUtil.getField(SerializationUtils.class, "TRUST_ALL");
+ ReflectUtil.removeFinalModify(trustAllField);
+ ReflectUtil.setFieldValue(SerializationUtils.class, trustAllField, true);
+ }
+
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/core/package-info.java b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/core/package-info.java
new file mode 100644
index 000000000..2773b5828
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/core/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * 占位符,无特殊逻辑
+ */
+package cn.iocoder.yudao.framework.mq.rabbitmq.core;
\ No newline at end of file
diff --git a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/package-info.java b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/package-info.java
new file mode 100644
index 000000000..9f6032c92
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * 消息队列,基于 RabbitMQ 提供
+ */
+package cn.iocoder.yudao.framework.mq.rabbitmq;
diff --git a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/config/YudaoMQAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/config/YudaoRedisMQAutoConfiguration.java
similarity index 77%
rename from yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/config/YudaoMQAutoConfiguration.java
rename to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/config/YudaoRedisMQAutoConfiguration.java
index e300b1ad5..bbc63b719 100644
--- a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/config/YudaoMQAutoConfiguration.java
+++ b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/config/YudaoRedisMQAutoConfiguration.java
@@ -1,21 +1,20 @@
-package cn.iocoder.yudao.framework.mq.config;
+package cn.iocoder.yudao.framework.mq.redis.config;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.system.SystemUtil;
import cn.iocoder.yudao.framework.common.enums.DocumentEnum;
-import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
-import cn.iocoder.yudao.framework.mq.core.interceptor.RedisMessageInterceptor;
-import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
-import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener;
-import cn.iocoder.yudao.framework.mq.job.RedisPendingMessageResendJob;
+import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate;
+import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor;
+import cn.iocoder.yudao.framework.mq.redis.core.job.RedisPendingMessageResendJob;
+import cn.iocoder.yudao.framework.mq.redis.core.pubsub.AbstractRedisChannelMessageListener;
+import cn.iocoder.yudao.framework.mq.redis.core.stream.AbstractRedisStreamMessageListener;
import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisServerCommands;
import org.springframework.data.redis.connection.stream.Consumer;
@@ -27,7 +26,6 @@ import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
-import org.springframework.data.redis.stream.DefaultStreamMessageListenerContainerX;
import org.springframework.data.redis.stream.StreamMessageListenerContainer;
import org.springframework.scheduling.annotation.EnableScheduling;
@@ -42,7 +40,7 @@ import java.util.Properties;
@Slf4j
@EnableScheduling // 启用定时任务,用于 RedisPendingMessageResendJob 重发消息
@AutoConfiguration(after = YudaoRedisAutoConfiguration.class)
-public class YudaoMQAutoConfiguration {
+public class YudaoRedisMQAutoConfiguration {
@Bean
public RedisMQTemplate redisMQTemplate(StringRedisTemplate redisTemplate,
@@ -59,10 +57,9 @@ public class YudaoMQAutoConfiguration {
* 创建 Redis Pub/Sub 广播消费的容器
*/
@Bean(initMethod = "start", destroyMethod = "stop")
- @ConditionalOnBean(AbstractChannelMessageListener.class) // 只有 AbstractChannelMessageListener 存在的时候,才需要注册 Redis pubsub 监听
- @ConditionalOnProperty(prefix = "yudao.mq.redis.pubsub", value = "enable", matchIfMissing = true) // 允许使用 yudao.mq.redis.pubsub.enable=false 禁用多租户
+ @ConditionalOnBean(AbstractRedisChannelMessageListener.class) // 只有 AbstractChannelMessageListener 存在的时候,才需要注册 Redis pubsub 监听
public RedisMessageListenerContainer redisMessageListenerContainer(
- RedisMQTemplate redisMQTemplate, List> listeners) {
+ RedisMQTemplate redisMQTemplate, List> listeners) {
// 创建 RedisMessageListenerContainer 对象
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
// 设置 RedisConnection 工厂。
@@ -81,9 +78,8 @@ public class YudaoMQAutoConfiguration {
* 创建 Redis Stream 重新消费的任务
*/
@Bean
- @ConditionalOnBean(AbstractStreamMessageListener.class) // 只有 AbstractStreamMessageListener 存在的时候,才需要注册 Redis pubsub 监听
- @ConditionalOnProperty(prefix = "yudao.mq.redis.stream", value = "enable", matchIfMissing = true) // 允许使用 yudao.mq.redis.stream.enable=false 禁用多租户
- public RedisPendingMessageResendJob redisPendingMessageResendJob(List> listeners,
+ @ConditionalOnBean(AbstractRedisStreamMessageListener.class) // 只有 AbstractStreamMessageListener 存在的时候,才需要注册 Redis pubsub 监听
+ public RedisPendingMessageResendJob redisPendingMessageResendJob(List> listeners,
RedisMQTemplate redisTemplate,
@Value("${spring.application.name}") String groupName,
RedissonClient redissonClient) {
@@ -92,14 +88,13 @@ public class YudaoMQAutoConfiguration {
/**
* 创建 Redis Stream 集群消费的容器
- *
- * Redis Stream 的 xreadgroup 命令:https://www.geek-book.com/src/docs/redis/redis/redis.io/commands/xreadgroup.html
+ *
+ * 基础知识:Redis Stream 的 xreadgroup 命令
*/
@Bean(initMethod = "start", destroyMethod = "stop")
- @ConditionalOnBean(AbstractStreamMessageListener.class) // 只有 AbstractStreamMessageListener 存在的时候,才需要注册 Redis pubsub 监听
- @ConditionalOnProperty(prefix = "yudao.mq.redis.stream", value = "enable", matchIfMissing = true) // 允许使用 yudao.mq.redis.stream.enable=false 禁用多租户
+ @ConditionalOnBean(AbstractRedisStreamMessageListener.class) // 只有 AbstractStreamMessageListener 存在的时候,才需要注册 Redis pubsub 监听
public StreamMessageListenerContainer> redisStreamMessageListenerContainer(
- RedisMQTemplate redisMQTemplate, List> listeners) {
+ RedisMQTemplate redisMQTemplate, List> listeners) {
RedisTemplate redisTemplate = redisMQTemplate.getRedisTemplate();
checkRedisVersion(redisTemplate);
// 第一步,创建 StreamMessageListenerContainer 容器
@@ -111,8 +106,7 @@ public class YudaoMQAutoConfiguration {
.build();
// 创建 container 对象
StreamMessageListenerContainer> container =
-// StreamMessageListenerContainer.create(redisTemplate.getRequiredConnectionFactory(), containerOptions);
- DefaultStreamMessageListenerContainerX.create(redisMQTemplate.getRedisTemplate().getRequiredConnectionFactory(), containerOptions);
+ StreamMessageListenerContainer.create(redisMQTemplate.getRedisTemplate().getRequiredConnectionFactory(), containerOptions);
// 第二步,注册监听器,消费对应的 Stream 主题
String consumerName = buildConsumerName();
diff --git a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/RedisMQTemplate.java b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/RedisMQTemplate.java
similarity index 80%
rename from yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/RedisMQTemplate.java
rename to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/RedisMQTemplate.java
index 8a31feda7..5755ffa51 100644
--- a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/RedisMQTemplate.java
+++ b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/RedisMQTemplate.java
@@ -1,10 +1,10 @@
-package cn.iocoder.yudao.framework.mq.core;
+package cn.iocoder.yudao.framework.mq.redis.core;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
-import cn.iocoder.yudao.framework.mq.core.interceptor.RedisMessageInterceptor;
-import cn.iocoder.yudao.framework.mq.core.message.AbstractRedisMessage;
-import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
-import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessage;
+import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor;
+import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage;
+import cn.iocoder.yudao.framework.mq.redis.core.pubsub.AbstractRedisChannelMessage;
+import cn.iocoder.yudao.framework.mq.redis.core.stream.AbstractRedisStreamMessage;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.data.redis.connection.stream.RecordId;
@@ -35,7 +35,7 @@ public class RedisMQTemplate {
*
* @param message 消息
*/
- public void send(T message) {
+ public void send(T message) {
try {
sendMessageBefore(message);
// 发送消息
@@ -51,7 +51,7 @@ public class RedisMQTemplate {
* @param message 消息
* @return 消息记录的编号对象
*/
- public RecordId send(T message) {
+ public RecordId send(T message) {
try {
sendMessageBefore(message);
// 发送消息
diff --git a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/interceptor/RedisMessageInterceptor.java b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/interceptor/RedisMessageInterceptor.java
similarity index 79%
rename from yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/interceptor/RedisMessageInterceptor.java
rename to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/interceptor/RedisMessageInterceptor.java
index 11d8e1337..dbcee7fe2 100644
--- a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/interceptor/RedisMessageInterceptor.java
+++ b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/interceptor/RedisMessageInterceptor.java
@@ -1,6 +1,6 @@
-package cn.iocoder.yudao.framework.mq.core.interceptor;
+package cn.iocoder.yudao.framework.mq.redis.core.interceptor;
-import cn.iocoder.yudao.framework.mq.core.message.AbstractRedisMessage;
+import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage;
/**
* {@link AbstractRedisMessage} 消息拦截器
diff --git a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/job/RedisPendingMessageResendJob.java b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/job/RedisPendingMessageResendJob.java
similarity index 93%
rename from yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/job/RedisPendingMessageResendJob.java
rename to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/job/RedisPendingMessageResendJob.java
index ea0f53d19..b84f17c15 100644
--- a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/job/RedisPendingMessageResendJob.java
+++ b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/job/RedisPendingMessageResendJob.java
@@ -1,8 +1,8 @@
-package cn.iocoder.yudao.framework.mq.job;
+package cn.iocoder.yudao.framework.mq.redis.core.job;
import cn.hutool.core.collection.CollUtil;
-import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
-import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener;
+import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate;
+import cn.iocoder.yudao.framework.mq.redis.core.stream.AbstractRedisStreamMessageListener;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
@@ -33,7 +33,7 @@ public class RedisPendingMessageResendJob {
*/
private static final int EXPIRE_TIME = 5 * 60;
- private final List> listeners;
+ private final List> listeners;
private final RedisMQTemplate redisTemplate;
private final String groupName;
private final RedissonClient redissonClient;
diff --git a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/message/AbstractRedisMessage.java b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/message/AbstractRedisMessage.java
similarity index 88%
rename from yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/message/AbstractRedisMessage.java
rename to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/message/AbstractRedisMessage.java
index f02e89d6f..ee40814dd 100644
--- a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/message/AbstractRedisMessage.java
+++ b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/message/AbstractRedisMessage.java
@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.framework.mq.core.message;
+package cn.iocoder.yudao.framework.mq.redis.core.message;
import lombok.Data;
diff --git a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/pubsub/AbstractRedisChannelMessage.java b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/pubsub/AbstractRedisChannelMessage.java
new file mode 100644
index 000000000..d5ea5b9d5
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/pubsub/AbstractRedisChannelMessage.java
@@ -0,0 +1,23 @@
+package cn.iocoder.yudao.framework.mq.redis.core.pubsub;
+
+import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+/**
+ * Redis Channel Message 抽象类
+ *
+ * @author 芋道源码
+ */
+public abstract class AbstractRedisChannelMessage extends AbstractRedisMessage {
+
+ /**
+ * 获得 Redis Channel,默认使用类名
+ *
+ * @return Channel
+ */
+ @JsonIgnore // 避免序列化。原因是,Redis 发布 Channel 消息的时候,已经会指定。
+ public String getChannel() {
+ return getClass().getSimpleName();
+ }
+
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/pubsub/AbstractChannelMessageListener.java b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/pubsub/AbstractRedisChannelMessageListener.java
similarity index 85%
rename from yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/pubsub/AbstractChannelMessageListener.java
rename to yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/pubsub/AbstractRedisChannelMessageListener.java
index e7d737d1b..fd7c910c9 100644
--- a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/core/pubsub/AbstractChannelMessageListener.java
+++ b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/pubsub/AbstractRedisChannelMessageListener.java
@@ -1,10 +1,10 @@
-package cn.iocoder.yudao.framework.mq.core.pubsub;
+package cn.iocoder.yudao.framework.mq.redis.core.pubsub;
import cn.hutool.core.util.TypeUtil;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
-import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
-import cn.iocoder.yudao.framework.mq.core.interceptor.RedisMessageInterceptor;
-import cn.iocoder.yudao.framework.mq.core.message.AbstractRedisMessage;
+import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate;
+import cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor;
+import cn.iocoder.yudao.framework.mq.redis.core.message.AbstractRedisMessage;
import lombok.Setter;
import lombok.SneakyThrows;
import org.springframework.data.redis.connection.Message;
@@ -20,7 +20,7 @@ import java.util.List;
*
* @author 芋道源码
*/
-public abstract class AbstractChannelMessageListener implements MessageListener {
+public abstract class AbstractRedisChannelMessageListener implements MessageListener {
/**
* 消息类型
@@ -37,7 +37,7 @@ public abstract class AbstractChannelMessageListener
+public abstract class AbstractRedisStreamMessageListener
implements StreamListener> {
/**
@@ -48,7 +48,7 @@ public abstract class AbstractStreamMessageListener> extends DefaultStreamMessageListenerContainer {
-
- /**
- * 参考 {@link StreamMessageListenerContainer#create(RedisConnectionFactory, StreamMessageListenerContainerOptions)} 的实现
- */
- public static > StreamMessageListenerContainer create(RedisConnectionFactory connectionFactory, StreamMessageListenerContainer.StreamMessageListenerContainerOptions options) {
- Assert.notNull(connectionFactory, "RedisConnectionFactory must not be null!");
- Assert.notNull(options, "StreamMessageListenerContainerOptions must not be null!");
- return new DefaultStreamMessageListenerContainerX<>(connectionFactory, options);
- }
-
- public DefaultStreamMessageListenerContainerX(RedisConnectionFactory connectionFactory, StreamMessageListenerContainerOptions containerOptions) {
- super(connectionFactory, containerOptions);
- }
-
- /**
- * 参考 {@link DefaultStreamMessageListenerContainer#register(StreamReadRequest, StreamListener)} 的实现
- */
- @Override
- public Subscription register(StreamReadRequest streamRequest, StreamListener listener) {
- return this.doRegisterX(getReadTaskX(streamRequest, listener));
- }
-
- @SuppressWarnings("unchecked")
- private StreamPollTask getReadTaskX(StreamReadRequest streamRequest, StreamListener listener) {
- StreamPollTask task = ReflectUtil.invoke(this, "getReadTask", streamRequest, listener);
- // 修改 readFunction 方法
- Function> readFunction = (Function>) ReflectUtil.getFieldValue(task, "readFunction");
- ReflectUtil.setFieldValue(task, "readFunction", (Function>) readOffset -> {
- List records = readFunction.apply(readOffset);
- //【重点】保证 records 不是空,避免 NPE 的问题!!!
- return records != null ? records : Collections.emptyList();
- });
- return task;
- }
-
- private Subscription doRegisterX(Task task) {
- return ReflectUtil.invoke(this, "doRegister", task);
- }
-
-}
-
diff --git a/yudao-framework/yudao-spring-boot-starter-mq/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/yudao-framework/yudao-spring-boot-starter-mq/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
index c47aa4d7b..660865453 100644
--- a/yudao-framework/yudao-spring-boot-starter-mq/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
+++ b/yudao-framework/yudao-spring-boot-starter-mq/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -1 +1,2 @@
-cn.iocoder.yudao.framework.mq.config.YudaoMQAutoConfiguration
\ No newline at end of file
+cn.iocoder.yudao.framework.mq.redis.config.YudaoRedisMQAutoConfiguration
+cn.iocoder.yudao.framework.mq.rabbitmq.config.YudaoRabbitMQAutoConfiguration
\ No newline at end of file
diff --git a/yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 事件机制 Event 入门》.md b/yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 事件机制 Event 入门》.md
new file mode 100644
index 000000000..08586b379
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 事件机制 Event 入门》.md
@@ -0,0 +1 @@
+
diff --git a/yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 Kafka 入门》.md b/yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 Kafka 入门》.md
new file mode 100644
index 000000000..b66d6334c
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 Kafka 入门》.md
@@ -0,0 +1 @@
+
diff --git a/yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 RabbitMQ 入门》.md b/yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 RabbitMQ 入门》.md
new file mode 100644
index 000000000..eff46e2f7
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 RabbitMQ 入门》.md
@@ -0,0 +1 @@
+
diff --git a/yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 RocketMQ 入门》.md b/yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 RocketMQ 入门》.md
new file mode 100644
index 000000000..08586b379
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-mq/《芋道 Spring Boot 消息队列 RocketMQ 入门》.md
@@ -0,0 +1 @@
+
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/service/ApiAccessLog.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/service/ApiAccessLog.java
index ffbeb39e1..7799c42f6 100644
--- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/service/ApiAccessLog.java
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/service/ApiAccessLog.java
@@ -5,7 +5,6 @@ import lombok.Data;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
-// TODO @小吉祥:搞个 job,清理 14 天外的访问日志;
/**
* API 访问日志
*
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/service/ApiErrorLog.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/service/ApiErrorLog.java
index cae595a7c..087dd5d08 100644
--- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/service/ApiErrorLog.java
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/service/ApiErrorLog.java
@@ -5,7 +5,6 @@ import lombok.Data;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
-// TODO @小吉祥:搞个 job,清理 14 天外的异常日志;
/**
* API 错误日志
*
diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java
index 67a4a222e..89d56b3c0 100644
--- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java
+++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java
@@ -20,16 +20,16 @@ public enum BpmCommentTypeEnum {
;
/**
- * 结果
+ * 操作类型
*/
private final Integer type;
/**
- * 描述
+ * 操作名字
*/
- private final String desc;
+ private final String name;
/**
- * 模板信息
+ * 操作描述
*/
- private final String templateComment;
+ private final String comment;
}
diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceResultEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceResultEnum.java
index 519c7c68c..615416c73 100644
--- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceResultEnum.java
+++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceResultEnum.java
@@ -30,13 +30,13 @@ public enum BpmProcessInstanceResultEnum {
* 相当于是 通过 APPROVE 的特殊状态
* 例如:A审批, A 后加签了 B,并且审批通过了任务,但是 B 还未审批,则当前任务状态为“待后加签任务完成”
*/
- ADD_SIGN_AFTER(7, "待后加签任务完成"),
+ SIGN_AFTER(7, "待后加签任务完成"),
/**
* 【加签】源任务未审批,但是向前加签了,所以源任务状态变为“待前加签任务完成”
* 相当于是 处理中 PROCESS 的特殊状态
* 例如:A 审批, A 前加签了 B,B 还未审核
*/
- ADD_SIGN_BEFORE(8, "待前加签任务完成"),
+ SIGN_BEFORE(8, "待前加签任务完成"),
/**
* 【加签】后加签任务被创建时的初始状态
* 相当于是 处理中 PROCESS 的特殊状态
@@ -71,7 +71,7 @@ public enum BpmProcessInstanceResultEnum {
public static boolean isEndResult(Integer result) {
return ObjectUtils.equalsAny(result, APPROVE.getResult(), REJECT.getResult(),
CANCEL.getResult(), BACK.getResult(),
- ADD_SIGN_AFTER.getResult());
+ SIGN_AFTER.getResult());
}
}
diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskAddSignTypeEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskAddSignTypeEnum.java
index 3bf41a153..42c212e28 100644
--- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskAddSignTypeEnum.java
+++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmTaskAddSignTypeEnum.java
@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.bpm.enums.task;
import lombok.AllArgsConstructor;
import lombok.Getter;
-
/**
* 流程任务 -- 加签类型枚举类型
*/
diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java
index a67af2eeb..dcfab78ef 100644
--- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java
+++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java
@@ -74,7 +74,7 @@ public class BpmTaskController {
return success(true);
}
- @GetMapping("/get-return-list")
+ @GetMapping("/return-list")
@Operation(summary = "获取所有可回退的节点", description = "用于【流程详情】的【回退】按钮")
@Parameter(name = "taskId", description = "当前任务ID", required = true)
@PreAuthorize("@ss.hasPermission('bpm:task:update')")
@@ -98,27 +98,28 @@ public class BpmTaskController {
return success(true);
}
- @PutMapping("/add-sign")
+ @PutMapping("/create-sign")
@Operation(summary = "加签", description = "before 前加签,after 后加签")
@PreAuthorize("@ss.hasPermission('bpm:task:update')")
- public CommonResult addSignTask(@Valid @RequestBody BpmTaskAddSignReqVO reqVO) {
- taskService.addSignTask(getLoginUserId(), reqVO);
+ public CommonResult createSignTask(@Valid @RequestBody BpmTaskAddSignReqVO reqVO) {
+ taskService.createSignTask(getLoginUserId(), reqVO);
return success(true);
}
- @PutMapping("/sub-sign")
+ @DeleteMapping("/delete-sign")
@Operation(summary = "减签")
@PreAuthorize("@ss.hasPermission('bpm:task:update')")
- public CommonResult subSignTask(@Valid @RequestBody BpmTaskSubSignReqVO reqVO) {
- taskService.subSignTask(getLoginUserId(), reqVO);
+ public CommonResult deleteSignTask(@Valid @RequestBody BpmTaskSubSignReqVO reqVO) {
+ taskService.deleteSignTask(getLoginUserId(), reqVO);
return success(true);
}
- @GetMapping("/get-children-task-list")
+ @GetMapping("children-list")
@Operation(summary = "获取能被减签的任务")
+ @Parameter(name = "parentId", description = "父级任务 ID", required = true)
@PreAuthorize("@ss.hasPermission('bpm:task:update')")
- public CommonResult> getChildrenTaskList(@RequestParam("taskId") String taskId) {
- return success(taskService.getChildrenTaskList(taskId));
+ public CommonResult> getChildrenTaskList(@RequestParam("parentId") String parentId) {
+ return success(taskService.getChildrenTaskList(parentId));
}
}
diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskAddSignReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskAddSignReqVO.java
index 93b95d3fd..cabb91be1 100644
--- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskAddSignReqVO.java
+++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskAddSignReqVO.java
@@ -6,6 +6,7 @@ import lombok.Data;
import javax.validation.constraints.NotEmpty;
import java.util.Set;
+// TODO @海洋:类名,应该是 create 哈
@Schema(description = "管理后台 - 加签流程任务的 Request VO")
@Data
public class BpmTaskAddSignReqVO {
@@ -26,4 +27,4 @@ public class BpmTaskAddSignReqVO {
@NotEmpty(message = "加签原因不能为空")
private String reason;
-}
\ No newline at end of file
+}
diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSubSignReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSubSignReqVO.java
index 665a9aec8..731e4804a 100644
--- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSubSignReqVO.java
+++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskSubSignReqVO.java
@@ -5,6 +5,7 @@ import lombok.Data;
import javax.validation.constraints.NotEmpty;
+// TODO @海洋:类名,应该是 delete 哈
@Schema(description = "管理后台 - 减签流程任务的 Request VO")
@Data
public class BpmTaskSubSignReqVO {
diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java
index 0d55a82eb..60ce84021 100644
--- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java
+++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java
@@ -1,9 +1,10 @@
package cn.iocoder.yudao.module.bpm.convert.task;
-import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
+import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
@@ -25,6 +26,9 @@ import java.util.Date;
import java.util.List;
import java.util.Map;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
+
/**
* Bpm 任务 Convert
*
@@ -167,32 +171,31 @@ public interface BpmTaskConvert {
default List convertList(List bpmTaskExtDOList,
Map userMap,
Map idTaskMap){
- return CollectionUtils.convertList(bpmTaskExtDOList, task->{
- BpmTaskSubSignRespVO bpmTaskSubSignRespVO = new BpmTaskSubSignRespVO();
- bpmTaskSubSignRespVO.setName(task.getName());
- bpmTaskSubSignRespVO.setId(task.getTaskId());
- Task sourceTask = idTaskMap.get(task.getTaskId());
+ return CollectionUtils.convertList(bpmTaskExtDOList, task -> {
+ BpmTaskSubSignRespVO bpmTaskSubSignRespVO = new BpmTaskSubSignRespVO()
+ .setId(task.getTaskId()).setName(task.getName());
// 后加签任务不会直接设置 assignee ,所以不存在 assignee 的情况,则去取 owner
- String assignee = StrUtil.isNotEmpty(sourceTask.getAssignee()) ? sourceTask.getAssignee() : sourceTask.getOwner();
- AdminUserRespDTO assignUser = userMap.get(NumberUtils.parseLong(assignee));
- if (assignUser != null) {
- bpmTaskSubSignRespVO.setAssigneeUser(convert3(assignUser));
- }
+ Task sourceTask = idTaskMap.get(task.getTaskId());
+ String assignee = ObjectUtil.defaultIfBlank(sourceTask.getOwner(),sourceTask.getAssignee());
+ MapUtils.findAndThen(userMap,NumberUtils.parseLong(assignee),
+ assignUser-> bpmTaskSubSignRespVO.setAssigneeUser(convert3(assignUser)));
return bpmTaskSubSignRespVO;
});
}
/**
* 转换任务为父子级
+ *
* @param sourceList 原始数据
* @return 转换后的父子级数组
*/
- default List convertChildrenList(List sourceList){
- List childrenTaskList = CollectionUtils.filterList(sourceList, r -> StrUtil.isNotEmpty(r.getParentTaskId()));
- Map> parentChildrenTaskListMap = CollectionUtils.convertMultiMap(childrenTaskList, BpmTaskRespVO::getParentTaskId);
+ default List convertChildrenList(List sourceList) {
+ List childrenTaskList = filterList(sourceList, r -> StrUtil.isNotEmpty(r.getParentTaskId()));
+ Map> parentChildrenTaskListMap = convertMultiMap(childrenTaskList, BpmTaskRespVO::getParentTaskId);
for (BpmTaskRespVO bpmTaskRespVO : sourceList) {
bpmTaskRespVO.setChildren(parentChildrenTaskListMap.get(bpmTaskRespVO.getId()));
}
- return CollectionUtils.filterList(sourceList, r -> StrUtil.isEmpty(r.getParentTaskId()));
+ return filterList(sourceList, r -> StrUtil.isEmpty(r.getParentTaskId()));
}
+
}
diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java
index 852ccb2e0..8108e613d 100644
--- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java
+++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java
@@ -21,13 +21,13 @@ public interface BpmTaskExtMapper extends BaseMapperX {
return selectList(BpmTaskExtDO::getTaskId, taskIds);
}
+ // TODO @海:BpmProcessInstanceResultEnum.CAN_SUB_SIGN_STATUS_LIST) 应该作为条件,mapper 不要有业务
default List selectProcessListByTaskIds(Collection taskIds) {
return selectList(new LambdaQueryWrapperX()
.in(BpmTaskExtDO::getTaskId, taskIds)
.in(BpmTaskExtDO::getResult, BpmProcessInstanceResultEnum.CAN_SUB_SIGN_STATUS_LIST));
}
-
default BpmTaskExtDO selectByTaskId(String taskId) {
return selectOne(BpmTaskExtDO::getTaskId, taskId);
}
diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/config/BpmSecurityConfiguration.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/config/BpmSecurityConfiguration.java
deleted file mode 100644
index 2069f7d11..000000000
--- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/config/BpmSecurityConfiguration.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package cn.iocoder.yudao.module.bpm.framework.bpm.config;
-
-import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
-
-/**
- * @author kemengkai
- * @create 2022-05-07 08:15
- */
-@Configuration("bpmSecurityConfiguration")
-public class BpmSecurityConfiguration {
-
- @Bean("bpmAuthorizeRequestsCustomizer")
- public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() {
- return new AuthorizeRequestsCustomizer() {
-
- @Override
- public void customize(ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry registry) {
- // 任务回退接口
- registry.antMatchers(buildAdminApi("/bpm/task/back")).permitAll();
- }
-
- };
- }
-}
diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java
index 0addde074..03fc99e03 100644
--- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java
+++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java
@@ -12,6 +12,7 @@ import javax.validation.Valid;
* @author yunlongn
*/
public interface BpmModelService {
+
/**
* 获得流程模型分页
*
diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java
index 81c437710..8f7e3996b 100644
--- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java
+++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java
@@ -288,5 +288,4 @@ public class BpmModelServiceImpl implements BpmModelService {
processDefinitionService.updateProcessDefinitionState(oldDefinition.getId(), SuspensionState.SUSPENDED.getStateCode());
}
-
}
diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java
index 772425b66..42be9260a 100644
--- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java
+++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java
@@ -163,7 +163,7 @@ public interface BpmTaskService {
* @param userId 被加签的用户和任务 ID,加签类型
* @param reqVO 当前用户 ID
*/
- void addSignTask(Long userId, BpmTaskAddSignReqVO reqVO);
+ void createSignTask(Long userId, BpmTaskAddSignReqVO reqVO);
/**
* 任务减签名
@@ -171,14 +171,14 @@ public interface BpmTaskService {
* @param userId 当前用户ID
* @param reqVO 被减签的任务 ID,理由
*/
- void subSignTask(Long userId, BpmTaskSubSignReqVO reqVO);
+ void deleteSignTask(Long userId, BpmTaskSubSignReqVO reqVO);
/**
* 获取指定任务的子任务和审批人信息
*
- * @param taskId 指定任务ID
+ * @param parentId 指定任务ID
* @return 子任务列表
*/
- List getChildrenTaskList(String taskId);
+ List getChildrenTaskList(String parentId);
}
diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
index 6bf2fb5b8..2b0e18e70 100644
--- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
+++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
@@ -53,7 +53,6 @@ import javax.annotation.Resource;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.*;
-import java.util.stream.Collectors;
import java.util.stream.Stream;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -240,10 +239,11 @@ public class BpmTaskServiceImpl implements BpmTaskService {
handleParentTask(task);
}
+
/**
* 审批通过存在“后加签”的任务。
*
- * 注意:该任务不能马上完成,需要一个中间状态(ADD_SIGN_AFTER),并激活剩余所有子任务(PROCESS)为可审批处理
+ * 注意:该任务不能马上完成,需要一个中间状态(SIGN_AFTER),并激活剩余所有子任务(PROCESS)为可审批处理
*
* @param task 当前任务
* @param reqVO 前端请求参数
@@ -251,7 +251,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
private void approveAfterSignTask(Task task, BpmTaskApproveReqVO reqVO) {
// 1. 有向后加签,则该任务状态临时设置为 ADD_SIGN_AFTER 状态
taskExtMapper.updateByTaskId(
- new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.ADD_SIGN_AFTER.getResult())
+ new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.SIGN_AFTER.getResult())
.setReason(reqVO.getReason()).setEndTime(LocalDateTime.now()));
// 2. 激活子任务
@@ -265,7 +265,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
}
/**
- * 处理当前任务的父任务
+ * 处理当前任务的父任务,主要处理“加签”的情况
*
* @param task 当前任务
*/
@@ -274,76 +274,79 @@ public class BpmTaskServiceImpl implements BpmTaskService {
if (StrUtil.isBlank(parentTaskId)) {
return;
}
- if (StrUtil.isNotBlank(parentTaskId)) {
- // 1. 判断当前任务的父任务是否还有子任务
- Long childrenTaskCount = getChildrenTaskCount(parentTaskId);
- if (childrenTaskCount > 0) {
- return;
- }
- // 2. 获取父任务
- Task parentTask = validateTaskExist(parentTaskId);
-
- // 3. 情况一:处理向前加签
- String scopeType = parentTask.getScopeType();
- if (BpmTaskAddSignTypeEnum.BEFORE.getType().equals(scopeType)) {
- // 3.1 如果是向前加签的任务,则调用 resolveTask 指派父任务,将 owner 重新赋值给父任务的 assignee
- taskService.resolveTask(parentTaskId);
- // 3.2 更新任务拓展表为处理中
- taskExtMapper.updateByTaskId(
- new BpmTaskExtDO().setTaskId(parentTask.getId()).setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()));
- } else if (BpmTaskAddSignTypeEnum.AFTER.getType().equals(scopeType)) {
- // 3. 情况二:处理向后加签
- handleAfterSign(parentTask);
- }
-
- // 4. 子任务已处理完成,清空 scopeType 字段,修改 parentTask 信息,方便后续可以继续向前后向后加签
- // 再查询一次的原因是避免报错:Task was updated by another transaction concurrently
- // 因为前面处理后可能会导致 parentTask rev 字段被修改,需要重新获取最新的
- parentTask = getTask(parentTaskId);
- if (parentTask == null) {
- // 为空的情况是:已经通过 handleAfterSign 方法将任务完成了,所以 ru_task 表会查不到数据
- return;
- }
- clearTaskScopeTypeAndSave(parentTask);
+ // 1. 判断当前任务的父任务是否还有子任务
+ Long childrenTaskCount = getChildrenTaskCount(parentTaskId);
+ if (childrenTaskCount > 0) {
+ return;
}
+ // 2. 获取父任务
+ Task parentTask = validateTaskExist(parentTaskId);
+
+ // 3. 处理加签情况
+ String scopeType = parentTask.getScopeType();
+ if(!validateSignType(scopeType)){
+ return;
+ }
+ // 3.1 情况一:处理向前加签
+ if (BpmTaskAddSignTypeEnum.BEFORE.getType().equals(scopeType)) {
+ // 3.1.1 如果是向前加签的任务,则调用 resolveTask 指派父任务,将 owner 重新赋值给父任务的 assignee,这样它就可以被审批
+ taskService.resolveTask(parentTaskId);
+ // 3.1.2 更新任务拓展表为处理中
+ taskExtMapper.updateByTaskId(
+ new BpmTaskExtDO().setTaskId(parentTask.getId()).setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()));
+ } else if (BpmTaskAddSignTypeEnum.AFTER.getType().equals(scopeType)) {
+ // 3.2 情况二:处理向后加签
+ handleParentTaskForAfterSign(parentTask);
+ }
+
+ // 4. 子任务已处理完成,清空 scopeType 字段,修改 parentTask 信息,方便后续可以继续向前后向后加签
+ // 再查询一次的原因是避免报错:Task was updated by another transaction concurrently
+ // 因为前面处理后可能会导致 parentTask rev 字段被修改,需要重新获取最新的
+ parentTask = getTask(parentTaskId);
+ if (parentTask == null) {
+ // 为空的情况是:已经通过 handleAfterSign 方法将任务完成了,所以 ru_task 表会查不到数据
+ return;
+ }
+ clearTaskScopeTypeAndSave(parentTask);
}
+
/**
* 处理后加签任务
*
* @param parentTask 当前审批任务的父任务
*/
- private void handleAfterSign(Task parentTask) {
+ // TODO @海:这个逻辑,怎么感觉可以是 parentTask 的 parent,再去调用 handleParentTask 方法;可以微信聊下;
+ private void handleParentTaskForAfterSign(Task parentTask) {
String parentTaskId = parentTask.getId();
- //1. 更新 parentTask 的任务拓展表为通过,并调用 complete 完成自己
+ // 1. 更新 parentTask 的任务拓展表为通过,并调用 complete 完成自己
BpmTaskExtDO currentTaskExt = taskExtMapper.selectByTaskId(parentTask.getId());
- BpmTaskExtDO currentTaskUpdateEntity = new BpmTaskExtDO().setTaskId(parentTask.getId())
+ BpmTaskExtDO currentTaskExtUpdateObj = new BpmTaskExtDO().setTaskId(parentTask.getId())
.setResult(BpmProcessInstanceResultEnum.APPROVE.getResult());
if (currentTaskExt.getEndTime() == null) {
// 1.1 有这个判断是因为,以前没设置过结束时间,才去设置
- currentTaskUpdateEntity.setEndTime(LocalDateTime.now());
+ currentTaskExtUpdateObj.setEndTime(LocalDateTime.now());
}
- // 1.2 完成自己
- taskExtMapper.updateByTaskId(currentTaskUpdateEntity);
+ taskExtMapper.updateByTaskId(currentTaskExtUpdateObj);
+ // 1.2 完成自己(因为它已经没有子任务,所以也可以完成)
taskService.complete(parentTaskId);
// 2. 如果有父级,递归查询上级任务是否都已经完成
if (StrUtil.isEmpty(parentTask.getParentTaskId())) {
return;
}
- // TODO @海:这块待讨论,脑子略乱;感觉 handleAfterSign 的后半段,和 handleParentTask 有点重叠???
// 2.1 判断整条链路的任务是否完成
// 例如从 A 任务加签了一个 B 任务,B 任务又加签了一个 C 任务,C 任务加签了 D 任务
// 此时,D 任务完成,要一直往上找到祖先任务 A调用 complete 方法完成 A 任务
boolean allChildrenTaskFinish = true;
while (StrUtil.isNotBlank(parentTask.getParentTaskId())) {
parentTask = validateTaskExist(parentTask.getParentTaskId());
- BpmTaskExtDO bpmTaskExtDO = taskExtMapper.selectByTaskId(parentTask.getId());
- if (bpmTaskExtDO == null) {
+ BpmTaskExtDO parentTaskExt = taskExtMapper.selectByTaskId(parentTask.getId());
+ if (parentTaskExt == null) {
break;
}
- boolean currentTaskFinish = BpmProcessInstanceResultEnum.isEndResult(bpmTaskExtDO.getResult());
- // 2.2 如果 allChildrenTaskFinish 已经被赋值为 false ,则不会再赋值为 true,因为整个链路没有完成
+ boolean currentTaskFinish = BpmProcessInstanceResultEnum.isEndResult(parentTaskExt.getResult());
+ // 2.2 如果 allChildrenTaskFinish 已经被赋值为 false,则不会再赋值为 true,因为整个链路没有完成
if (allChildrenTaskFinish) {
allChildrenTaskFinish = currentTaskFinish;
}
@@ -354,19 +357,19 @@ public class BpmTaskServiceImpl implements BpmTaskService {
// 3 处理非完成状态的任务
// 3.1 判断当前任务的父任务是否还有子任务
- Long childrenTaskCount = getChildrenTaskCount(bpmTaskExtDO.getTaskId());
+ Long childrenTaskCount = getChildrenTaskCount(parentTaskExt.getTaskId());
if (childrenTaskCount > 0) {
continue;
}
// 3.2 没有子任务,判断当前任务状态是否为 ADD_SIGN_BEFORE 待前加签任务完成
- if (BpmProcessInstanceResultEnum.ADD_SIGN_BEFORE.getResult().equals(bpmTaskExtDO.getResult())) {
+ if (BpmProcessInstanceResultEnum.SIGN_BEFORE.getResult().equals(parentTaskExt.getResult())) {
// 3.3 需要修改该任务状态为处理中
- taskService.resolveTask(bpmTaskExtDO.getTaskId());
- bpmTaskExtDO.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
- taskExtMapper.updateByTaskId(bpmTaskExtDO);
+ taskService.resolveTask(parentTaskExt.getTaskId());
+ parentTaskExt.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
+ taskExtMapper.updateByTaskId(parentTaskExt);
}
// 3.4 清空 scopeType 字段,用于任务没有子任务时使用该方法,方便任务可以再次被不同的方式加签
- parentTask = validateTaskExist(bpmTaskExtDO.getTaskId());
+ parentTask = validateTaskExist(parentTaskExt.getTaskId());
clearTaskScopeTypeAndSave(parentTask);
}
@@ -387,7 +390,6 @@ public class BpmTaskServiceImpl implements BpmTaskService {
taskService.saveTask(task);
}
-
/**
* 获取子任务个数
*
@@ -709,7 +711,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
@Override
@Transactional(rollbackFor = Exception.class)
- public void addSignTask(Long userId, BpmTaskAddSignReqVO reqVO) {
+ public void createSignTask(Long userId, BpmTaskAddSignReqVO reqVO) {
// 1. 获取和校验任务
TaskEntityImpl taskEntity = validateAddSign(userId, reqVO);
List userList = adminUserApi.getUserList(reqVO.getUserIdList());
@@ -728,7 +730,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
// 2.3 更新扩展表状态
taskExtMapper.updateByTaskId(
new BpmTaskExtDO().setTaskId(taskEntity.getId())
- .setResult(BpmProcessInstanceResultEnum.ADD_SIGN_BEFORE.getResult())
+ .setResult(BpmProcessInstanceResultEnum.SIGN_BEFORE.getResult())
.setReason(reqVO.getReason()));
}
// 2.4 记录加签方式,完成任务时需要用到判断
@@ -737,12 +739,12 @@ public class BpmTaskServiceImpl implements BpmTaskService {
taskService.saveTask(taskEntity);
// 3. 创建加签任务
- createAddSignChildrenTasks(convertList(reqVO.getUserIdList(), String::valueOf), taskEntity);
+ createSignTask(convertList(reqVO.getUserIdList(), String::valueOf), taskEntity);
// 4. 记录加签 comment,拼接结果为: [当前用户]向前加签/向后加签给了[多个用户],理由为:reason
AdminUserRespDTO currentUser = adminUserApi.getUser(userId);
- String comment = StrUtil.format(BpmCommentTypeEnum.ADD_SIGN.getTemplateComment(), currentUser.getNickname(), BpmTaskAddSignTypeEnum.formatDesc(reqVO.getType()),
- String.join(",", convertList(userList, AdminUserRespDTO::getNickname)), reqVO.getReason());
+ String comment = StrUtil.format(BpmCommentTypeEnum.ADD_SIGN.getComment(), currentUser.getNickname(),
+ BpmTaskAddSignTypeEnum.formatDesc(reqVO.getType()), String.join(",", convertList(userList, AdminUserRespDTO::getNickname)), reqVO.getReason());
taskService.addComment(reqVO.getId(), taskEntity.getProcessInstanceId(),
BpmCommentTypeEnum.ADD_SIGN.getType().toString(), comment);
}
@@ -786,7 +788,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
* @param addSingUserIdList 被加签的用户 ID
* @param taskEntity 被加签的任务
*/
- private void createAddSignChildrenTasks(List addSingUserIdList, TaskEntityImpl taskEntity) {
+ private void createSignTask(List addSingUserIdList, TaskEntityImpl taskEntity) {
if (CollUtil.isEmpty(addSingUserIdList)) {
return;
}
@@ -795,23 +797,22 @@ public class BpmTaskServiceImpl implements BpmTaskService {
if (StrUtil.isBlank(addSignId)) {
continue;
}
- createChildrenTask(taskEntity, addSignId);
+ createSignTask(taskEntity, addSignId);
}
}
/**
- * 创建子任务
+ * 创建加签子任务
*
* @param parentTask 父任务
* @param assignee 子任务的执行人
- * @return
*/
- private void createChildrenTask(TaskEntityImpl parentTask, String assignee) {
+ private void createSignTask(TaskEntityImpl parentTask, String assignee) {
// 1. 生成子任务
TaskEntityImpl task = (TaskEntityImpl) taskService.newTask(IdUtil.fastSimpleUUID());
task = BpmTaskConvert.INSTANCE.convert(task, parentTask);
if (BpmTaskAddSignTypeEnum.BEFORE.getType().equals(parentTask.getScopeType())) {
- // 2.1 前加签,才设置审批人,否则设置 owner
+ // 2.1 前加签,设置审批人
task.setAssignee(assignee);
} else {
// 2.2.1 设置 owner 不设置 assignee 是因为不能同时审批,需要等父任务完成
@@ -825,9 +826,10 @@ public class BpmTaskServiceImpl implements BpmTaskService {
@Override
@Transactional(rollbackFor = Exception.class)
- public void subSignTask(Long userId, BpmTaskSubSignReqVO reqVO) {
+ public void deleteSignTask(Long userId, BpmTaskSubSignReqVO reqVO) {
+ // 1.1 校验 task 可以被减签
Task task = validateSubSign(reqVO.getId());
- AdminUserRespDTO user = adminUserApi.getUser(userId);
+ // 1.2 校验取消人存在
AdminUserRespDTO cancelUser = null;
if (StrUtil.isNotBlank(task.getAssignee())) {
cancelUser = adminUserApi.getUser(NumberUtils.parseLong(task.getAssignee()));
@@ -836,20 +838,24 @@ public class BpmTaskServiceImpl implements BpmTaskService {
cancelUser = adminUserApi.getUser(NumberUtils.parseLong(task.getOwner()));
}
Assert.notNull(cancelUser, "任务中没有所有者和审批人,数据错误");
- //1. 获取所有需要删除的任务 ID ,包含当前任务和所有子任务
+
+ // 2. 删除任务和对应子任务
+ // 2.1 获取所有需要删除的任务 ID ,包含当前任务和所有子任务
List allTaskIdList = getAllChildTaskIds(task.getId());
- //2. 删除任务和所有子任务
+ // 2.2 删除任务和所有子任务
taskService.deleteTasks(allTaskIdList);
- //3. 修改扩展表状态为取消
+ // 2.3 修改扩展表状态为取消
+ AdminUserRespDTO user = adminUserApi.getUser(userId);
taskExtMapper.updateBatchByTaskIdList(allTaskIdList, new BpmTaskExtDO().setResult(BpmProcessInstanceResultEnum.CANCEL.getResult())
.setReason(StrUtil.format("由于{}操作[减签],任务被取消", user.getNickname())));
- //4.记录日志到父任务中 先记录日志是因为,通过 handleParentTask 方法之后,任务可能被完成了,并且不存在了,会报异常,所以先记录
- String comment = StrUtil.format(BpmCommentTypeEnum.SUB_SIGN.getTemplateComment(), user.getNickname(), cancelUser.getNickname());
+
+ // 3. 记录日志到父任务中。先记录日志是因为,通过 handleParentTask 方法之后,任务可能被完成了,并且不存在了,会报异常,所以先记录
+ String comment = StrUtil.format(BpmCommentTypeEnum.SUB_SIGN.getComment(), user.getNickname(), cancelUser.getNickname());
taskService.addComment(task.getParentTaskId(), task.getProcessInstanceId(),
BpmCommentTypeEnum.SUB_SIGN.getType().toString(), comment);
- //5. 处理当前任务的父任务
- this.handleParentTask(task);
+ // 4. 处理当前任务的父任务
+ handleParentTask(task);
}
/**
@@ -860,13 +866,28 @@ public class BpmTaskServiceImpl implements BpmTaskService {
*/
private Task validateSubSign(String id) {
Task task = validateTaskExist(id);
- //必须有parentId
- if (StrUtil.isEmpty(task.getParentTaskId())) {
+
+ // 必须有 scopeType
+ String scopeType = task.getScopeType();
+ if (StrUtil.isEmpty(scopeType)) {
+ throw exception(TASK_SUB_SIGN_NO_PARENT);
+ }
+ // 并且值为 向前和向后加签
+ if (!validateSignType(scopeType)) {
throw exception(TASK_SUB_SIGN_NO_PARENT);
}
return task;
}
+ /**
+ * 判断当前类型是否为加签
+ * @param scopeType 任务的 scopeType
+ * @return 当前 scopeType 为加签则返回 true
+ */
+ private boolean validateSignType(String scopeType){
+ return StrUtil.equalsAny(scopeType,BpmTaskAddSignTypeEnum.BEFORE.getType(),scopeType, BpmTaskAddSignTypeEnum.AFTER.getType());
+ }
+
/**
* 获取所有要被取消的删除的任务 ID 集合
*
@@ -875,25 +896,30 @@ public class BpmTaskServiceImpl implements BpmTaskService {
*/
public List getAllChildTaskIds(String parentTaskId) {
List allChildTaskIds = new ArrayList<>();
- //1. 先将自己放入
- allChildTaskIds.add(parentTaskId);
- //2. 递归获取子级
- recursiveGetChildTaskIds(parentTaskId, allChildTaskIds);
- return allChildTaskIds;
- }
-
- /**
- * 递归处理子级任务
- *
- * @param taskId 当前任务ID
- * @param taskIds 结果
- */
- private void recursiveGetChildTaskIds(String taskId, List taskIds) {
- List childrenTaskIdList = getChildrenTaskIdList(taskId);
- for (String childTaskId : childrenTaskIdList) {
- taskIds.add(childTaskId); // 将子任务的ID添加到集合中
- recursiveGetChildTaskIds(childTaskId, taskIds); // 递归获取子任务的子任务
+ // 1. 递归获取子级
+ Stack stack = new Stack<>();
+ // 1.1 将根任务ID入栈
+ stack.push(parentTaskId);
+ //控制遍历的次数不超过 Byte.MAX_VALUE,避免脏数据造成死循环
+ int count = 0;
+ // TODO @海:< 的前后空格,要注意哈;
+ while (!stack.isEmpty() && count childrenTaskIdList = getChildrenTaskIdList(taskId);
+ if (CollUtil.isNotEmpty(childrenTaskIdList)) {
+ for (String childTaskId : childrenTaskIdList) {
+ // 1.5 将子任务ID入栈,以便后续处理
+ stack.push(childTaskId);
+ }
+ }
+ count++;
}
+ return allChildTaskIds;
}
/**
@@ -903,32 +929,41 @@ public class BpmTaskServiceImpl implements BpmTaskService {
* @return 所有子任务的 ID 集合
*/
private List getChildrenTaskIdList(String parentTaskId) {
- String tableName = managementService.getTableName(TaskEntity.class);
- String sql = "select ID_ from " + tableName + " where PARENT_TASK_ID_=#{parentTaskId}";
- List childrenTaskList = taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).list();
- return convertList(childrenTaskList, Task::getId);
+ return convertList(getChildrenTaskList0(parentTaskId), Task::getId);
}
+ /**
+ * 获取指定父级任务的所有子任务 ID 集合
+ *
+ * @param parentTaskId 父任务 ID
+ * @return 所有子任务的 ID 集合
+ */
+ private List getChildrenTaskList0(String parentTaskId) {
+ String tableName = managementService.getTableName(TaskEntity.class);
+ // taskService.createTaskQuery() 没有 parentId 参数,所以写 sql 查询
+ String sql = "select ID_,OWNER_,ASSIGNEE_ from " + tableName + " where PARENT_TASK_ID_=#{parentTaskId}";
+ return taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).list();
+ }
+
+
@Override
- public List getChildrenTaskList(String taskId) {
- List childrenTaskIdList = getChildrenTaskIdList(taskId);
- if (CollUtil.isEmpty(childrenTaskIdList)) {
+ public List getChildrenTaskList(String parentId) {
+ // 1. 只查询进行中的任务 后加签的任务,可能不存在 assignee,所以还需要查询 owner
+ List taskList = getChildrenTaskList0(parentId);
+ if (CollUtil.isEmpty(taskList)) {
return Collections.emptyList();
}
- //1. 只查询进行中的任务
- List bpmTaskExtDOList = taskExtMapper.selectProcessListByTaskIds(childrenTaskIdList);
- //2. 后加签的任务,可能不存在 assignee,所以还需要查询 owner
- List taskList = taskService.createTaskQuery().taskIds(childrenTaskIdList).list();
- Map idTaskMap = convertMap(taskList, TaskInfo::getId);
- //3. 将 owner 和 assignee 统一到一个集合中
- List userIds = taskList.stream()
- .flatMap(control ->
- Stream.of(control.getAssignee(), control.getOwner())
- .filter(Objects::nonNull))
- .distinct()
- .map(NumberUtils::parseLong)
- .collect(Collectors.toList());
+ List childrenTaskIdList = convertList(taskList, Task::getId);
+
+ // 2.1 将 owner 和 assignee 统一到一个集合中
+ List userIds = convertListByFlatMap(taskList, control ->
+ Stream.of(NumberUtils.parseLong(control.getAssignee()), NumberUtils.parseLong(control.getOwner()))
+ .filter(Objects::nonNull));
+ // 2.2 组装数据
Map userMap = adminUserApi.getUserMap(userIds);
- return BpmTaskConvert.INSTANCE.convertList(bpmTaskExtDOList, userMap, idTaskMap);
+ List taskExtList = taskExtMapper.selectProcessListByTaskIds(childrenTaskIdList);
+ Map idTaskMap = convertMap(taskList, TaskInfo::getId);
+ return BpmTaskConvert.INSTANCE.convertList(taskExtList, userMap, idTaskMap);
}
+
}
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/DatabaseDocController.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/DatabaseDocController.java
index 6e05844de..beef57f99 100644
--- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/DatabaseDocController.java
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/DatabaseDocController.java
@@ -147,7 +147,7 @@ public class DatabaseDocController {
*/
private static ProcessConfig buildProcessConfig() {
return ProcessConfig.builder()
- .ignoreTablePrefix(Arrays.asList("QRTZ_", "ACT_")) // 忽略表前缀
+ .ignoreTablePrefix(Arrays.asList("QRTZ_", "ACT_", "FLW_")) // 忽略表前缀
.build();
}
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/security/config/SecurityConfiguration.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/security/config/SecurityConfiguration.java
index 01b5714ba..2f22f4fb9 100644
--- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/security/config/SecurityConfiguration.java
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/security/config/SecurityConfiguration.java
@@ -29,8 +29,6 @@ public class SecurityConfiguration {
.antMatchers("/swagger-resources/**").anonymous()
.antMatchers("/webjars/**").anonymous()
.antMatchers("/*/api-docs").anonymous();
- // 积木报表
- registry.antMatchers("/jmreport/**").permitAll();
// Spring Boot Actuator 的安全配置
registry.antMatchers("/actuator").anonymous()
.antMatchers("/actuator/**").anonymous();
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/logger/JobLogCleanJob.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/job/JobLogCleanJob.java
similarity index 88%
rename from yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/logger/JobLogCleanJob.java
rename to yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/job/JobLogCleanJob.java
index 4d8c955a1..3f9d29333 100644
--- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/logger/JobLogCleanJob.java
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/job/JobLogCleanJob.java
@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.infra.job.logger;
+package cn.iocoder.yudao.module.infra.job.job;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
@@ -33,7 +33,7 @@ public class JobLogCleanJob implements JobHandler {
@TenantIgnore
public String execute(String param) {
Integer count = jobLogService.cleanJobLog(JOB_CLEAN_RETAIN_DAY, DELETE_LIMIT);
- log.info("[count][定时执行清理定时任务日志数量 ({}) 个]", count);
+ log.info("[execute][定时执行清理定时任务日志数量 ({}) 个]", count);
return String.format("定时执行清理定时任务日志数量 %s 个", count);
}
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/job/AccessLogCleanJob.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/logger/AccessLogCleanJob.java
similarity index 88%
rename from yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/job/AccessLogCleanJob.java
rename to yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/logger/AccessLogCleanJob.java
index 2e7198de0..9ddab4163 100644
--- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/job/AccessLogCleanJob.java
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/logger/AccessLogCleanJob.java
@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.infra.job.job;
+package cn.iocoder.yudao.module.infra.job.logger;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
@@ -34,7 +34,7 @@ public class AccessLogCleanJob implements JobHandler {
@TenantIgnore
public String execute(String param) {
Integer count = apiAccessLogService.cleanAccessLog(JOB_CLEAN_RETAIN_DAY, DELETE_LIMIT);
- log.info("[count][定时执行清理访问日志数量 ({}) 个]", count);
+ log.info("[execute][定时执行清理访问日志数量 ({}) 个]", count);
return String.format("定时执行清理错误日志数量 %s 个", count);
}
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/job/ErrorLogCleanJob.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/logger/ErrorLogCleanJob.java
similarity index 88%
rename from yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/job/ErrorLogCleanJob.java
rename to yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/logger/ErrorLogCleanJob.java
index 7e69fd272..9b50aaf5c 100644
--- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/job/ErrorLogCleanJob.java
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/job/logger/ErrorLogCleanJob.java
@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.infra.job.job;
+package cn.iocoder.yudao.module.infra.job.logger;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
@@ -34,7 +34,7 @@ public class ErrorLogCleanJob implements JobHandler {
@TenantIgnore
public String execute(String param) {
Integer count = apiErrorLogService.cleanErrorLog(JOB_CLEAN_RETAIN_DAY,DELETE_LIMIT);
- log.info("[count][定时执行清理错误日志数量 ({}) 个]", count);
+ log.info("[execute][定时执行清理错误日志数量 ({}) 个]", count);
return String.format("定时执行清理错误日志数量 %s 个", count);
}
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java
index 5c94c99e1..4b54efc2f 100755
--- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java
@@ -58,9 +58,9 @@ public class FileConfigServiceImpl implements FileConfigService {
FileConfigDO config = Objects.equals(CACHE_MASTER_ID, id) ?
fileConfigMapper.selectByMaster() : fileConfigMapper.selectById(id);
if (config != null) {
- fileClientFactory.createOrUpdateFileClient(id, config.getStorage(), config.getConfig());
+ fileClientFactory.createOrUpdateFileClient(config.getId(), config.getStorage(), config.getConfig());
}
- return fileClientFactory.getFileClient(id);
+ return fileClientFactory.getFileClient(null == config ? id : config.getId());
}
});
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/api/api.ts.vm b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/api/api.ts.vm
index c7283a121..b7f26510e 100644
--- a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/api/api.ts.vm
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/api/api.ts.vm
@@ -28,5 +28,5 @@ export function delete${simpleClassName}(id: number) {
// 导出${table.classComment} Excel
export function export${simpleClassName}(params) {
- return defHttp.download({ url: '${baseURL}/export-excel', params }, '${table.classComment}.xls')
+ return defHttp.download({ url: '${baseURL}/export-excel', params }, '${table.classComment}.xls')
}
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/data.ts.vm b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/data.ts.vm
index 5557b38c9..92d3b2d75 100644
--- a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/data.ts.vm
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/data.ts.vm
@@ -1,6 +1,6 @@
-import type { BasicColumn, FormSchema } from '@/components/Table'
-import { useRender } from '@/components/Table'
-import { DICT_TYPE, getDictOptions } from '@/utils/dict'
+import type {BasicColumn, FormSchema} from '@/components/Table'
+import {useRender} from '@/components/Table'
+import {DICT_TYPE, getDictOptions} from '@/utils/dict'
export const columns: BasicColumn[] = [
#foreach($column in $columns)
@@ -50,7 +50,7 @@ export const searchFormSchema: FormSchema[] = [
field: '${javaField}',
#if ($column.htmlType == "input")
component: 'Input',
- #elseif ($column.htmlType == "select" || $column.htmlType == "radio")
+ #elseif ($column.htmlType == "select")
component: 'Select',
componentProps: {
#if ("" != $dictType)## 设置了 dictType 数据字典的情况
@@ -59,6 +59,15 @@ export const searchFormSchema: FormSchema[] = [
options: [],
#end
},
+ #elseif ($column.htmlType == "radio")
+ component: 'Radio',
+ componentProps: {
+ #if ("" != $dictType)## 设置了 dictType 数据字典的情况
+ options: getDictOptions(DICT_TYPE.$dictType.toUpperCase()),
+ #else## 未设置 dictType 数据字典的情况
+ options: [],
+ #end
+ },
#elseif($column.htmlType == "datetime")
component: 'RangePicker',
#end
@@ -181,7 +190,8 @@ export const updateFormSchema: FormSchema[] = [
fileType: 'file',
maxCount: 1,
},
- #elseif($column.htmlType == "editor")## 文本编辑器component: 'Editor',
+ #elseif($column.htmlType == "editor")## 文本编辑器
+ component: 'Editor',
#elseif($column.htmlType == "select")## 下拉框
component: 'Select',
componentProps: {
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/index.vue.vm b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/index.vue.vm
index 07f3285c1..7f794585c 100644
--- a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/index.vue.vm
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/index.vue.vm
@@ -1,12 +1,11 @@
-
-
-
-点击如下按钮,发起支付的测试
-
-
-
-
-
-