From 872b84f1aeb25772323cb559a27b37e91d69beb0 Mon Sep 17 00:00:00 2001 From: yangqicheng Date: Tue, 2 Jul 2024 16:04:06 +0800 Subject: [PATCH] =?UTF-8?q?REQ-2596,=E8=87=AA=E5=8A=A8=E8=BF=87=E5=AE=A1?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E4=B8=8D=E5=90=8C=E6=B5=81=E7=A8=8B=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E7=89=88=E6=9C=AC=E6=89=A7=E8=A1=8C=E4=B8=8D=E5=90=8C?= =?UTF-8?q?=E4=B8=9A=E5=8A=A1=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/common/utils/SpringContentUtils.java | 28 +++++ .../core/conf/FlowableConfiguration.java | 29 +++++ .../version/GetSpecifiedVersionBeanUtils.java | 33 ++++++ .../axzo/workflow/core/version/Versioned.java | 8 ++ .../task/AutoOperatorEvent_101_Listener.java | 88 ++------------- .../task/service/CheckApproveService.java | 11 ++ .../impl/CheckApproverServiceImpl.java | 103 ++++++++++++++++++ 7 files changed, 220 insertions(+), 80 deletions(-) create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/SpringContentUtils.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/version/GetSpecifiedVersionBeanUtils.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/version/Versioned.java create mode 100644 workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/service/CheckApproveService.java create mode 100644 workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/service/impl/CheckApproverServiceImpl.java diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/SpringContentUtils.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/SpringContentUtils.java new file mode 100644 index 000000000..202663f32 --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/SpringContentUtils.java @@ -0,0 +1,28 @@ +package cn.axzo.workflow.core.common.utils; + +import org.springframework.lang.Nullable; + +import java.util.Map; + +public class SpringContentUtils { + + private static SpringContentUtils.SpringContext springContext; + + public SpringContentUtils(SpringContentUtils.SpringContext springContext) { + SpringContentUtils.springContext = springContext; + } + + public static T getBean(Class clazz) { + return springContext.getBean(clazz); + } + + public static Map getBeansOfType(@Nullable Class type) { + return springContext.getBeansOfType(type); + } + + public interface SpringContext { + T getBean(Class var1); + + Map getBeansOfType(@Nullable Class type); + } +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java index 15302a561..11c6b1aeb 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java @@ -1,5 +1,6 @@ package cn.axzo.workflow.core.conf; +import cn.axzo.workflow.core.common.utils.SpringContentUtils; import cn.axzo.workflow.core.engine.behavior.CustomActivityBehaviorFactory; import cn.axzo.workflow.core.engine.cmd.CustomCommandContextFactory; import cn.axzo.workflow.core.engine.id.BasedNacosSnowflakeIdGenerator; @@ -20,19 +21,26 @@ import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; import com.alibaba.cloud.nacos.NacosDiscoveryProperties; import com.alibaba.cloud.nacos.NacosServiceManager; import com.google.common.collect.Lists; +import org.apache.ibatis.session.SqlSessionFactory; import org.flowable.common.engine.api.delegate.event.FlowableEventListener; import org.flowable.common.engine.impl.history.HistoryLevel; import org.flowable.form.spring.SpringFormEngineConfiguration; import org.flowable.job.service.JobProcessor; import org.flowable.spring.SpringProcessEngineConfiguration; import org.flowable.spring.boot.EngineConfigurationConfigurer; +import org.springframework.beans.BeansException; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.lang.Nullable; import java.time.Duration; import java.util.List; +import java.util.Map; import static org.flowable.common.engine.impl.AbstractEngineConfiguration.DB_SCHEMA_UPDATE_TRUE; @@ -105,4 +113,25 @@ public class FlowableConfiguration { return new CustomActivityBehaviorFactory(); } + @Configuration + @ConditionalOnBean({SqlSessionFactory.class}) + public static class SpringContext implements SpringContentUtils.SpringContext, ApplicationContextAware { + private ApplicationContext applicationContext; + + public SpringContext() { + } + + public T getBean(Class clazz) { + return this.applicationContext.getBean(clazz); + } + + public Map getBeansOfType(@Nullable Class type){ + return this.applicationContext.getBeansOfType(type); + } + + public void setApplicationContext(@Nullable ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + } + } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/version/GetSpecifiedVersionBeanUtils.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/version/GetSpecifiedVersionBeanUtils.java new file mode 100644 index 000000000..e2c938430 --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/version/GetSpecifiedVersionBeanUtils.java @@ -0,0 +1,33 @@ +package cn.axzo.workflow.core.version; + + +import cn.axzo.workflow.core.common.utils.SpringContentUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.maven.artifact.versioning.DefaultArtifactVersion; +import org.springframework.util.CollectionUtils; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class GetSpecifiedVersionBeanUtils { + public static T getSpecialVersionBean(Class clazz, String version) { + Map beans = SpringContentUtils.getBeansOfType(clazz); + if (CollectionUtils.isEmpty(beans)) { + throw new NullPointerException("no beans of type " + clazz.getName()); + } + if (StringUtils.isEmpty(version)) { + //todo 版本为空,需要一个默认处理类?? + } + //根据版本号排序 + List sortedList = beans.values().stream().sorted().collect(Collectors.toList()); + DefaultArtifactVersion targetVersion = new DefaultArtifactVersion(version); + for (int i = sortedList.size() - 1; i >= 0; i--) { + int flag = sortedList.get(i).getVersion().compareTo(targetVersion); + if (flag <= 0) { + return sortedList.get(i); + } + } + throw new NullPointerException("no beans of type " + clazz.getName() + " and version " + version); + } +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/version/Versioned.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/version/Versioned.java new file mode 100644 index 000000000..be73a4aa6 --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/version/Versioned.java @@ -0,0 +1,8 @@ +package cn.axzo.workflow.core.version; + +import org.apache.maven.artifact.versioning.DefaultArtifactVersion; + +public interface Versioned { + + DefaultArtifactVersion getVersion(); +} diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/AutoOperatorEvent_101_Listener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/AutoOperatorEvent_101_Listener.java index 5c6dc9f1a..a8c3d8746 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/AutoOperatorEvent_101_Listener.java +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/AutoOperatorEvent_101_Listener.java @@ -1,9 +1,7 @@ package cn.axzo.workflow.server.controller.listener.task; -import cn.axzo.workflow.common.enums.BpmnFlowNodeType; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; -import cn.axzo.workflow.common.model.request.bpmn.task.ExtHiTaskSearchDTO; import cn.axzo.workflow.core.common.context.TaskOperationContext; import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper; import cn.axzo.workflow.core.engine.cmd.CustomApproveTaskCmd; @@ -11,22 +9,20 @@ import cn.axzo.workflow.core.engine.job.AsyncApproveTaskJobHandler; import cn.axzo.workflow.core.engine.operation.DeleteProcessInstanceOperation; import cn.axzo.workflow.core.listener.AbstractBpmnEventListener; import cn.axzo.workflow.core.listener.BpmnTaskEventListener; -import cn.axzo.workflow.core.repository.entity.ExtAxHiTaskInst; import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; +import cn.axzo.workflow.core.version.GetSpecifiedVersionBeanUtils; +import cn.axzo.workflow.server.controller.listener.task.service.CheckApproveService; import cn.hutool.json.JSONUtil; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.flowable.bpmn.model.FlowElement; import org.flowable.bpmn.model.Process; import org.flowable.bpmn.model.UserTask; import org.flowable.common.engine.impl.interceptor.CommandContext; import org.flowable.common.engine.impl.interceptor.CommandExecutor; -import org.flowable.engine.HistoryService; import org.flowable.engine.RepositoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; -import org.flowable.engine.impl.persistence.entity.ActivityInstanceEntity; import org.flowable.engine.impl.util.CommandContextUtil; import org.flowable.job.service.JobService; import org.flowable.job.service.impl.persistence.entity.JobEntity; @@ -37,12 +33,10 @@ import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.concurrent.atomic.AtomicBoolean; import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE; import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC; @@ -54,10 +48,8 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_PROCESS_TYPE_REJECT; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO; import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE; -import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_EMPTY; +import static cn.axzo.workflow.common.constant.BpmnConstants.WORKFLOW_ENGINE_VERSION; import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER; -import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_TASK; -import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.REJECTED; import static cn.axzo.workflow.core.common.enums.BpmnProcessTaskResultEnum.REJECTION_AUTO_COMPLETED; @@ -80,7 +72,6 @@ public class AutoOperatorEvent_101_Listener extends AbstractBpmnEventListener autoApprovalOpt = BpmnMetaParserHelper.getAutoApprovalValue(userTask); - //自动过审配置为true才执行这段代码,默认为false,老数据默认不跳过审批 + //自动过审配置为true才执行这段代码,默认为false,老数据默认不自动过审 if (autoApprovalOpt.orElse(false)) { - boolean exists = checkApproverExists(delegateTask, userTask, mainProcess); + Object versionVar = delegateTask.getVariable(WORKFLOW_ENGINE_VERSION); + String version = versionVar == null ? null : String.valueOf(versionVar); + CheckApproveService checkApproveService = GetSpecifiedVersionBeanUtils.getSpecialVersionBean(CheckApproveService.class, version); + boolean exists = checkApproveService.checkApproverExists(delegateTask, userTask, mainProcess, getContext()); log.info("是否需要自动过程判断 exists:{}", exists); if (exists) { taskService.addComment(delegateTask.getId(), delegateTask.getProcessInstanceId(), COMMENT_TYPE_ADVICE, @@ -144,72 +138,6 @@ public class AutoOperatorEvent_101_Listener extends AbstractBpmnEventListener !Objects.equals(i.getActivityId(), userTask.getId())) - .filter(i -> !Objects.equals(i.getActivityType(), "exclusiveGateway")) - .filter(i -> !Objects.equals(i.getActivityType(), "sequenceFlow")) - .max(Comparator.comparing(ActivityInstanceEntity::getStartTime)) - .ifPresent(i -> { - // 与发起人比对 - if (Objects.equals(NODE_STARTER.getType(), i.getActivityId())) { - BpmnTaskDelegateAssigner initiator = BpmnTaskDelegateAssigner.toObjectCompatible(delegateTask.getVariable(INTERNAL_INITIATOR)); - if (Objects.nonNull(initiator) && initiator.comparePersonIdToOther(delegateTask.getAssignee())) { - exists.compareAndSet(false, true); - } - } else { - FlowElement flowElement = mainProcess.getFlowElement(i.getActivityId()); - BpmnMetaParserHelper.getNodeType(flowElement).ifPresent(j -> { - if (Objects.equals(NODE_TASK, j)) { - ExtHiTaskSearchDTO searchDTO = new ExtHiTaskSearchDTO(); - searchDTO.setProcessInstanceId(delegateTask.getProcessInstanceId()); - searchDTO.setTaskDefinitionKey(i.getActivityId()); - getContext().getExtAxHiTaskInsts(() -> extAxHiTaskInstService.queryList(searchDTO)) - .stream().filter(e -> Objects.equals(e.getStatus(), APPROVED.getStatus())) - .map(ExtAxHiTaskInst::getAssignee) - .filter(Objects::nonNull) - .filter(StringUtils::hasText) - .filter(k -> specialApproverComparison(k, delegateTask.getAssignee())) - .findAny().ifPresent(k -> exists.compareAndSet(false, true)); - } - }); - } - }); - return exists.get(); - } - - /** - * 特殊审批人字段的比对, 兼容旧迭代导致的数据格式 - * - * @return - */ - private boolean specialApproverComparison(String compareAssignee, String currentAssignee) { - if (StringUtils.hasText(compareAssignee) && StringUtils.hasText(currentAssignee)) { - String[] compareSplit = compareAssignee.split("\\|"); - String[] currentSplit = currentAssignee.split("\\|"); - if (compareSplit.length == 2 || currentSplit.length == 2) { - return Objects.equals(compareSplit[1], currentSplit[1]); - } - } - return false; - } - /** * 如果审批人为空时, 读取 approverEmptyHandleType = 自动通过或自动驳回 * diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/service/CheckApproveService.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/service/CheckApproveService.java new file mode 100644 index 000000000..9610f0b9c --- /dev/null +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/service/CheckApproveService.java @@ -0,0 +1,11 @@ +package cn.axzo.workflow.server.controller.listener.task.service; + +import cn.axzo.workflow.core.common.context.TaskOperationContext; +import cn.axzo.workflow.core.version.Versioned; +import org.flowable.bpmn.model.Process; +import org.flowable.bpmn.model.UserTask; +import org.flowable.task.service.delegate.DelegateTask; + +public interface CheckApproveService extends Versioned { + boolean checkApproverExists(DelegateTask delegateTask, UserTask userTask, Process mainProcess, TaskOperationContext taskOperationContext); +} diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/service/impl/CheckApproverServiceImpl.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/service/impl/CheckApproverServiceImpl.java new file mode 100644 index 000000000..4dcd2224b --- /dev/null +++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/task/service/impl/CheckApproverServiceImpl.java @@ -0,0 +1,103 @@ +package cn.axzo.workflow.server.controller.listener.task.service.impl; + +import cn.axzo.workflow.common.enums.BpmnFlowNodeType; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; +import cn.axzo.workflow.common.model.request.bpmn.task.ExtHiTaskSearchDTO; +import cn.axzo.workflow.core.common.context.TaskOperationContext; +import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper; +import cn.axzo.workflow.core.repository.entity.ExtAxHiTaskInst; +import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; +import cn.axzo.workflow.server.controller.listener.task.service.CheckApproveService; +import lombok.AllArgsConstructor; +import org.apache.maven.artifact.versioning.DefaultArtifactVersion; +import org.flowable.bpmn.model.FlowElement; +import org.flowable.bpmn.model.Process; +import org.flowable.bpmn.model.UserTask; +import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.engine.impl.persistence.entity.ActivityInstanceEntity; +import org.flowable.engine.impl.util.CommandContextUtil; +import org.flowable.task.service.delegate.DelegateTask; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import java.util.Comparator; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; + +import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION_130; +import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR; +import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_EMPTY; +import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER; +import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_TASK; +import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED; + +@Component +@AllArgsConstructor +public class CheckApproverServiceImpl implements CheckApproveService { + + private final ExtAxHiTaskInstService extAxHiTaskInstService; + + public boolean checkApproverExists(DelegateTask delegateTask, UserTask userTask, Process mainProcess, TaskOperationContext taskOperationContext) { + AtomicBoolean exists = new AtomicBoolean(false); + FlowElement currentFlowElement = mainProcess.getFlowElement(delegateTask.getTaskDefinitionKey()); + BpmnFlowNodeType currentNodeType = BpmnMetaParserHelper.getNodeType(currentFlowElement).orElse(NODE_EMPTY); + if (!Objects.equals(currentNodeType, NODE_TASK)) { + return exists.get(); + } + ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(); + processEngineConfiguration.getActivityInstanceEntityManager() + .findActivityInstancesByProcessInstanceId(delegateTask.getProcessInstanceId(), false) + .stream() + .filter(i -> !Objects.equals(i.getActivityId(), userTask.getId())) + .filter(i -> !Objects.equals(i.getActivityType(), "exclusiveGateway")) + .filter(i -> !Objects.equals(i.getActivityType(), "sequenceFlow")) + .max(Comparator.comparing(ActivityInstanceEntity::getStartTime)) + .ifPresent(i -> { + // 与发起人比对 + if (Objects.equals(NODE_STARTER.getType(), i.getActivityId())) { + BpmnTaskDelegateAssigner initiator = BpmnTaskDelegateAssigner.toObjectCompatible(delegateTask.getVariable(INTERNAL_INITIATOR)); + if (Objects.nonNull(initiator) && initiator.comparePersonIdToOther(delegateTask.getAssignee())) { + exists.compareAndSet(false, true); + } + } else { + FlowElement flowElement = mainProcess.getFlowElement(i.getActivityId()); + BpmnMetaParserHelper.getNodeType(flowElement).ifPresent(j -> { + if (Objects.equals(NODE_TASK, j)) { + ExtHiTaskSearchDTO searchDTO = new ExtHiTaskSearchDTO(); + searchDTO.setProcessInstanceId(delegateTask.getProcessInstanceId()); + searchDTO.setTaskDefinitionKey(i.getActivityId()); + taskOperationContext.getExtAxHiTaskInsts(() -> extAxHiTaskInstService.queryList(searchDTO)) + .stream().filter(e -> Objects.equals(e.getStatus(), APPROVED.getStatus())) + .map(ExtAxHiTaskInst::getAssignee) + .filter(Objects::nonNull) + .filter(StringUtils::hasText) + .filter(k -> specialApproverComparison(k, delegateTask.getAssignee())) + .findAny().ifPresent(k -> exists.compareAndSet(false, true)); + } + }); + } + }); + return exists.get(); + } + + /** + * 特殊审批人字段的比对, 兼容旧迭代导致的数据格式 + * + * @return + */ + private boolean specialApproverComparison(String compareAssignee, String currentAssignee) { + if (StringUtils.hasText(compareAssignee) && StringUtils.hasText(currentAssignee)) { + String[] compareSplit = compareAssignee.split("\\|"); + String[] currentSplit = currentAssignee.split("\\|"); + if (compareSplit.length == 2 || currentSplit.length == 2) { + return Objects.equals(compareSplit[1], currentSplit[1]); + } + } + return false; + } + + @Override + public DefaultArtifactVersion getVersion() { + return new DefaultArtifactVersion(FLOW_SERVER_VERSION_130); + } +}