Merge remote-tracking branch 'refs/remotes/origin/feature/starter' into feature/merge-all

This commit is contained in:
yangqicheng 2024-07-29 10:18:46 +08:00
commit 5b2fa9e0ed
177 changed files with 6705 additions and 284 deletions

View File

@ -1,5 +1,13 @@
# Change logs
### 1.4.0-SNAPSHOT
> - 新增 workflow-engine-spring-boot-starter 组件,大幅简化业务方接入使用的难度。
> - 在 Starter 中新增 MQ 监控功能,避免死信依赖运维。
> - 优化发送待办时,提前判断是否有按钮,以及能否支持批量处理。
> - 修复同一个实例下,多个人同时操作任务,可能导致数据库的 FK 异常等问题。
> - 修复其他的一些小问题
### 1.3.3-SNAPSHOT
> - 支持“政务”类型的模型管理。

29
pom.xml
View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
@ -15,7 +16,7 @@
<name>workflow-engine</name>
<properties>
<revision>1.3.3-SNAPSHOT</revision>
<revision>1.4.0-SNAPSHOT</revision>
<axzo-bom.version>2.0.0-SNAPSHOT</axzo-bom.version>
<axzo-dependencies.version>2.0.0-SNAPSHOT</axzo-dependencies.version>
<feign-httpclient.version>11.8</feign-httpclient.version>
@ -25,6 +26,7 @@
<dingtalk.version>2.0.0</dingtalk.version>
<arthas.version>3.7.1</arthas.version>
<apache-maven.version>3.2.5</apache-maven.version>
<javaparse.version>3.26.0</javaparse.version>
</properties>
<dependencyManagement>
@ -64,11 +66,21 @@
<artifactId>workflow-engine-core</artifactId>
<version>${project.version}</version>
</dependency>
<!--<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>workflow-auto-gen</artifactId>
<version>1.3.3-SNAPSHOT</version>
</dependency>-->
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>workflow-engine-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>cn.axzo.workflow</groupId>
<artifactId>workflow-engine-spring-boot-starter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>cn.axzo.maokai</groupId>
<artifactId>maokai-api</artifactId>
@ -99,6 +111,11 @@
<artifactId>maven-artifact</artifactId>
<version>${apache-maven.version}</version>
</dependency>
<dependency>
<groupId>com.github.javaparser</groupId>
<artifactId>javaparser-core</artifactId>
<version>${javaparse.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
@ -120,6 +137,11 @@
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
<path>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring.boot.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
@ -138,6 +160,7 @@
<module>workflow-engine-common</module>
<module>workflow-engine-core</module>
<module>workflow-engine-server</module>
<module>workflow-engine-support</module>
<module>workflow-engine-spring-boot-starter</module>
</modules>
</project>

View File

@ -11,7 +11,7 @@
<artifactId>workflow-engine-api</artifactId>
<packaging>jar</packaging>
<name>workflow-engine-api</name>
<name>Workflow Engine Api</name>
<dependencies>
<dependency>

View File

@ -32,7 +32,7 @@ import java.util.regex.Pattern;
* @Date: 2022/9/17
* @Description:
*/
@EnableFeignClients(basePackages = {"cn.axzo.workflow.client.feign"})
//@EnableFeignClients(basePackages = {"cn.axzo.workflow.client.feign"})
@Configuration(proxyBeanMethods = false)
@Slf4j
public class WorkflowEngineClientAutoConfiguration {

View File

@ -20,9 +20,9 @@ public class WorkflowRequestInterceptor implements RequestInterceptor {
this.environment = environment;
}
public static final String HEADER_HTTP_CLIENT = "http-client";
public static final String HEADER_HTTP_CLIENT_VALUE = "workflowEngine-feign";
public static final String HEADER_API_VERSION = "service-version";
public static final String HEADER_HTTP_CLIENT = "Http-Client";
public static final String HEADER_HTTP_CLIENT_VALUE = "WorkflowEngine-Feign";
public static final String HEADER_API_VERSION = "Service-Version";
public static final String HEADER_SERVER_NAME = "X-SERVER-NAME";

View File

@ -3,6 +3,7 @@ package cn.axzo.workflow.client.feign.bpmn;
import cn.axzo.workflow.client.config.CommonFeignConfiguration;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO;
import cn.azxo.framework.common.model.CommonResponse;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
@ -18,26 +19,29 @@ import javax.validation.constraints.NotBlank;
* @author wangli
* @since 2023/11/17 16:28
*/
@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class)
//@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class)
public interface ProcessActivityApi {
/**
* 业务节点唤醒
* <p>
* 当模型中使用了业务节点且设置了不设置审批人模式则当业务监听到 PROCESS_ACTIVITY_START 事件时可通过该接口推动流程继续运行
*/
@GetMapping("/api/process/activity/old/trigger")
CommonResponse<Boolean> trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId);
@GetMapping("/api/process/activity/trigger")
CommonResponse<Boolean> trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId,
@RequestParam(required = false, defaultValue = "false") Boolean async);
CommonResponse<Boolean> trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId);
/**
* 业务节点设置审批人, 不支持重复设置
* <p>
* 当模型中使用了业务节点且设置了业务指定审批人模式则当业务监听到 PROCESS_ACTIVITY_WAIT_ASSIGNEE 事件时可通过该接口设置动态设置审批人
* <p>
* <strong color=orange>注意如果调用接口时传入的审批人集合为空流程引擎将对该审批流程实例自动中止</strong>
*
* @param dto
* @return
*/
@PostMapping("/api/process/activity/assignee/set")
@Operation(summary = "业务节点设置审批人,不支持重复调用设置审批人,需一次性传入所有审批人")
CommonResponse<Boolean> setAssignee(@Validated @RequestBody BpmnActivitySetAssigneeDTO dto);
}

View File

@ -1,6 +1,8 @@
package cn.axzo.workflow.client.feign.bpmn;
import cn.axzo.workflow.client.config.CommonFeignConfiguration;
import cn.axzo.workflow.common.annotation.InvokeMode;
import cn.axzo.workflow.common.annotation.Manageable;
import cn.axzo.workflow.common.model.request.bpmn.definition.BpmnProcessDefinitionUpdateDTO;
import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelUpdateDTO;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessDefinitionPageDTO;
@ -17,13 +19,16 @@ import org.springframework.web.bind.annotation.RequestParam;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC;
/**
* 流程定义 API
*
* @author wangli
* @since 2023/9/21 16:25
*/
@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class)
//@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class)
@Manageable
public interface ProcessDefinitionApi {
@ -31,6 +36,7 @@ public interface ProcessDefinitionApi {
* 获取活跃的流程定义分页
*/
@GetMapping("/api/process/definition/page")
@InvokeMode(SYNC)
CommonResponse<BpmPageResult<BpmnProcessDefinitionVO>> getProcessDefinitionPage(@Validated @RequestBody BpmnProcessDefinitionPageDTO dto);
/**
@ -40,6 +46,7 @@ public interface ProcessDefinitionApi {
* @return
*/
@PutMapping("/api/process/definition/update")
@InvokeMode(SYNC)
CommonResponse<Boolean> updateProcessDefinition(@Validated @RequestBody BpmnProcessDefinitionUpdateDTO dto);
/**
@ -49,6 +56,7 @@ public interface ProcessDefinitionApi {
* @return 流程定义
*/
@GetMapping("/api/process/definition/get")
@InvokeMode(SYNC)
CommonResponse<BpmnProcessDefinitionVO> getProcessDefinition(@NotBlank(message = "流程定义 ID 不能为空") @RequestParam String processDefinitionId);
/**
@ -58,6 +66,7 @@ public interface ProcessDefinitionApi {
* @return 流程定义
*/
@GetMapping("/api/process/definition/getByDeploymentId")
@InvokeMode(SYNC)
CommonResponse<BpmnProcessDefinitionVO> getProcessDefinitionByDeploymentId(
@NotBlank(message = "流程部署 ID 不能为空") @RequestParam String deploymentId);
@ -69,6 +78,7 @@ public interface ProcessDefinitionApi {
* @return 流程定义
*/
@GetMapping("/api/process/definition/active/getByKey")
@InvokeMode(SYNC)
CommonResponse<BpmnProcessDefinitionVO> getActiveProcessDefinitionByKey(@NotBlank(message = "模型定义KEY不能为空") @RequestParam String key);
@ -79,6 +89,7 @@ public interface ProcessDefinitionApi {
* {@see SuspensionState}
*/
@PutMapping("/api/process/definition/state/update")
@InvokeMode(SYNC)
CommonResponse<Boolean> getActiveProcessDefinitionByKey(@NotBlank(message = "流程定义ID不能为空") @RequestParam String processDefinitionId,
@NotNull(message = "状态不能为空") @RequestParam Integer state);
@ -88,6 +99,7 @@ public interface ProcessDefinitionApi {
* @return 流程定义ID
*/
@GetMapping("/api/process/definition/active/getByCategory")
@InvokeMode(SYNC)
CommonResponse<String> getActiveProcessDefinitionId(@RequestParam(required = false) String tenantId,
@NotBlank(message = "分类不能为空") @RequestParam(required = false) String category);
@ -97,6 +109,7 @@ public interface ProcessDefinitionApi {
* @return 流程定义ID
*/
@GetMapping("/api/process/definition/active/json/model")
@InvokeMode(SYNC)
CommonResponse<BpmnModelUpdateDTO> getActiveProcessDefinitionJsonModel(@NotBlank(message = "模型 ID 不能为空") @RequestParam(required = false) String modelId,
@NotBlank(message = "分类不能为空") @RequestParam(required = false) String category,
@RequestParam(required = false) String tenantId);
@ -109,6 +122,7 @@ public interface ProcessDefinitionApi {
* @return
*/
@GetMapping("/api/process/definition/delete")
@InvokeMode(SYNC)
CommonResponse<Void> delete(@NotBlank(message = "流程定义部署 ID 不能为空") String deploymentId,
@RequestParam(required = false) Boolean cascade);
}

View File

@ -1,6 +1,8 @@
package cn.axzo.workflow.client.feign.bpmn;
import cn.axzo.workflow.client.config.CommonFeignConfiguration;
import cn.axzo.workflow.common.annotation.InvokeMode;
import cn.axzo.workflow.common.annotation.Manageable;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO;
@ -34,28 +36,16 @@ import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Map;
import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC;
/**
* 流程实例 API
*
* @author wangli
* @since 2023/9/21 16:26
*/
@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class)
//@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class)
public interface ProcessInstanceApi {
/**
* 查询所有的审批流
*
* @return
*/
@PostMapping("/api/process/instance/page/all")
CommonResponse<BpmPageResult<BpmnProcessInstanceAdminPageItemVO>> getAllProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceAdminPageReqVO dto);
/**
* 我发起的审批列表
*/
@PostMapping("/api/process/instance/page/my")
CommonResponse<BpmPageResult<BpmnProcessInstancePageItemVO>> getMyProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceMyPageReqVO dto);
/**
* 创建审批流程
*
@ -67,18 +57,11 @@ public interface ProcessInstanceApi {
*
* @param dto {@link BpmnProcessInstanceCreateDTO}
*/
@Operation(summary = "创建审批流程, MQ 触发规则:1. 当前流程实例会依次触发 process-instance-created 和 process-instance-started 事件,2. 第一个审批任务会依次触发 process-task-assigned 和 process-task-created 事件")
@PostMapping("/api/process/instance/create")
@InvokeMode(SYNC)
CommonResponse<String> createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto);
/**
* 创建审批流程并带上表单
*
* @param dto
* @return
*/
@PostMapping("/api/process/instance/form/create")
CommonResponse<String> createProcessInstanceWith(@Validated @RequestBody BpmnProcessInstanceCreateWithFormDTO dto);
/**
* 发起人主动撤回审核
*
@ -91,6 +74,7 @@ public interface ProcessInstanceApi {
* @param dto {@link BpmnProcessInstanceCancelDTO}
* @return
*/
@Operation(summary = "发起人主动撤回审核,MQ 触发规则:1. 当前流程实例中现存的任务会依次触发 process-task-deleted 事件,2. 当前流程实例会触发 process-instance-cancelled 事件")
@DeleteMapping("/api/process/instance/cancel")
CommonResponse<Boolean> cancelProcessInstance(@Validated @RequestBody BpmnProcessInstanceCancelDTO dto);
@ -100,6 +84,7 @@ public interface ProcessInstanceApi {
* @param dto
* @return
*/
@Operation(summary = "中止流程实例")
@DeleteMapping("/api/process/instance/abort")
CommonResponse<Boolean> abortProcessInstance(@Validated @RequestBody BpmnProcessInstanceAbortDTO dto);
@ -109,16 +94,19 @@ public interface ProcessInstanceApi {
* @param dtos
* @return
*/
@Operation(summary = "批量中止流程实例")
@DeleteMapping("/api/process/instance/batch/abort")
CommonResponse<BatchOperationResultVO> batchAbortProcessInstance(@Validated @RequestBody List<BpmnProcessInstanceAbortDTO> dtos);
/**
* 抄送流程实例
* 抄送流程实例未实现
*
* @param dto
* @return
*/
@Operation(summary = "抄送流程实例")
@PostMapping("/api/process/instance/carbon-copy")
@Deprecated
CommonResponse<Boolean> carbonCopyProcessInstance(@Validated @RequestBody BpmnProcessInstanceCarbonCopyDTO dto);
/**
@ -127,9 +115,56 @@ public interface ProcessInstanceApi {
* @param dto {@link BpmnProcessInstanceQueryDTO} 可根据 Id,BusinessKey进行查询
* @return 流程实例, 租户Id不必传
*/
@Operation(summary = "获得流程实例")
@GetMapping("/api/process/instance/get")
@InvokeMode(SYNC)
CommonResponse<BpmnProcessInstanceVO> getProcessInstanceVO(@Validated @RequestBody BpmnProcessInstanceQueryDTO dto);
/**
* 获取指定流程实例的流程变量
*
* @param processInstanceId
* @param tenantId
* @return
*/
@Operation(summary = "获取指定流程实例的流程变量")
@GetMapping("/api/process/instance/cooperation-org")
@InvokeMode(SYNC)
CommonResponse<Map<String, Object>> getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId,
@Nullable @RequestParam(required = false) String tenantId);
/**
* 创建审批流程并带上表单
*
* @param dto
* @return
*/
@Operation(summary = "创建审批流程并带上表单")
@PostMapping("/api/process/instance/form/create")
@Manageable
@InvokeMode(SYNC)
CommonResponse<String> createProcessInstanceWith(@Validated @RequestBody BpmnProcessInstanceCreateWithFormDTO dto);
/**
* 查询所有的审批流
*
* @return
*/
@Operation(summary = "查询所有的审批流")
@PostMapping("/api/process/instance/page/all")
@Manageable
@InvokeMode(SYNC)
CommonResponse<BpmPageResult<BpmnProcessInstanceAdminPageItemVO>> getAllProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceAdminPageReqVO dto);
/**
* 我发起的审批列表
*/
@Operation(summary = "我发起的审批列表")
@PostMapping("/api/process/instance/page/my")
@Manageable
@InvokeMode(SYNC)
CommonResponse<BpmPageResult<BpmnProcessInstancePageItemVO>> getMyProcessInstancePage(@Validated @RequestBody BpmnProcessInstanceMyPageReqVO dto);
/**
* 更新流程定义的状态
*
@ -138,6 +173,8 @@ public interface ProcessInstanceApi {
*/
@Operation(summary = "更新指定流程定义的版本的状态, 处于 suspended 状态的流程模型将不能再发起实例")
@PutMapping("/api/process/instance/status/update")
@Manageable
@InvokeMode(SYNC)
CommonResponse<Boolean> updateProcessStatus(@NotBlank(message = "流程定义 ID 不能为空") @RequestParam String processDefinitionId,
@NotNull(message = "状态不能为空") @RequestParam Integer status);
@ -148,7 +185,10 @@ public interface ProcessInstanceApi {
* @param tenantId
* @return
*/
@Operation(summary = "获取审批流程实例的运行图")
@GetMapping("/api/process/instance/graphical")
@Manageable
@InvokeMode(SYNC)
CommonResponse<ObjectNode> processInstanceGraphical(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId,
@Nullable @RequestParam(required = false) String tenantId);
@ -157,7 +197,10 @@ public interface ProcessInstanceApi {
*
* @return
*/
@Operation(summary = "推断指定流程实例的所有节点执行顺序")
@GetMapping("/api/process/instance/node/forecasting")
@Manageable
@InvokeMode(SYNC)
CommonResponse<List<ProcessNodeDetailVO>> processInstanceNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId,
@Nullable @RequestParam(required = false) String tenantId);
@ -168,23 +211,15 @@ public interface ProcessInstanceApi {
* 如果为假时,才结合 nodeDefinitionKeys 过滤掉传入的节点
* @return
*/
@Operation(summary = "推断指定流程实例的过滤掉部分节点执行顺序")
@GetMapping("/api/process/instance/node/filter/forecasting")
@Manageable
@InvokeMode(SYNC)
CommonResponse<List<ProcessNodeDetailVO>> processInstanceFilterNodeForecast(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam(required = false) String processInstanceId,
@Nullable @RequestParam(required = false) String tenantId,
@RequestParam(required = false, defaultValue = "false") Boolean allNode,
@Nullable @RequestParam(required = false) List<String> nodeDefinitionKeys);
/**
* 获取指定流程实例的流程变量
*
* @param processInstanceId
* @param tenantId
* @return
*/
@GetMapping("/api/process/instance/cooperation-org")
CommonResponse<Map<String, Object>> getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId,
@Nullable @RequestParam(required = false) String tenantId);
/**
* 查询实例的租户集合
*
@ -192,6 +227,8 @@ public interface ProcessInstanceApi {
*/
@Operation(summary = "查询实例的租户集合")
@GetMapping("/api/process/instance/tenant/ids")
@Manageable
@InvokeMode(SYNC)
CommonResponse<List<String>> getTenantIds();
/**
@ -201,5 +238,7 @@ public interface ProcessInstanceApi {
*/
@Operation(summary = "校验指定流程实例下,是否存在指定的审批人")
@PostMapping("/api/process/instance/check/approver")
@Manageable
@InvokeMode(SYNC)
CommonResponse<Boolean> checkInstanceApprover(@Validated @RequestBody BpmnProcessInstanceCheckApproverDTO dto);
}

View File

@ -1,15 +1,30 @@
package cn.axzo.workflow.client.feign.bpmn;
import cn.axzo.workflow.client.config.CommonFeignConfiguration;
import cn.axzo.workflow.common.annotation.InvokeMode;
import cn.axzo.workflow.common.annotation.Manageable;
import cn.azxo.framework.common.model.CommonResponse;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class)
import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC;
//@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class)
public interface ProcessJobApi {
/**
* 将死信队列中的任务转移到正常 JOB 队列中
* <p>
* 入参是二选一当只有 jobId 仅将指定的 JOB 转移到正常的队列中
* 而传入的是具体的实例 ID那么会将这个流程下的所有在死信队列中的任务都转移到正常的队列中
*
* @param jobId 具体的 JOB ID
* @param procInstId 具体的实例 ID
* @return
*/
@GetMapping("/api/process/job/dead-letter/resume")
@Manageable
CommonResponse<Void> executeDeadLetterJobAction(@RequestParam(required = false) String jobId,
@RequestParam(required = false) String procInstId);
}

View File

@ -1,6 +1,8 @@
package cn.axzo.workflow.client.feign.bpmn;
import cn.axzo.workflow.client.config.CommonFeignConfiguration;
import cn.axzo.workflow.common.annotation.InvokeMode;
import cn.axzo.workflow.common.annotation.Manageable;
import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelCreateDTO;
import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelSearchDTO;
import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelUpdateDTO;
@ -22,13 +24,16 @@ import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.List;
import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC;
/**
* 流程模型 API
*
* @author wangli
* @since 2023/9/21 15:47
*/
@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class)
//@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class)
@Manageable
public interface ProcessModelApi {
/**
@ -39,6 +44,7 @@ public interface ProcessModelApi {
*/
@Operation(summary = "流程模型列表")
@GetMapping("/api/process/model/page")
@InvokeMode(SYNC)
CommonResponse<BpmPageResult<BpmnModelDetailVO>> page(@Validated @RequestBody BpmnModelSearchDTO dto);
/**
@ -47,6 +53,7 @@ public interface ProcessModelApi {
*/
@Operation(summary = "创建流程模型")
@PostMapping("/api/process/model/create")
@InvokeMode(SYNC)
CommonResponse<String> create(@Validated @RequestBody BpmnModelCreateDTO dto);
/**
@ -54,6 +61,7 @@ public interface ProcessModelApi {
*/
@Operation(summary = "通过模型ID查询指定流程模型")
@GetMapping("/api/process/model/get")
@InvokeMode(SYNC)
CommonResponse<BpmnModelDetailVO> getById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam(required = false) String processModelId,
@RequestParam(required = false) String tenantId);
@ -62,6 +70,7 @@ public interface ProcessModelApi {
*/
@Operation(summary = "通过模型KEY查询指定流程模型")
@GetMapping("/api/process/model/getByKey")
@InvokeMode(SYNC)
CommonResponse<BpmnModelDetailVO> getByKey(@NotBlank(message = "流程模型 KEY 不能为空") @RequestParam(required = false) String processModelKey,
@NotBlank(message = "租户不能为空") @RequestParam(required = false) String tenantId);
@ -74,6 +83,7 @@ public interface ProcessModelApi {
*/
@Operation(summary = "获取指定模型的扩展属性")
@GetMapping("/api/process/model/ext")
@InvokeMode(SYNC)
CommonResponse<BpmnModelExtVO> getModelExt(@NotBlank(message = "模型 ID 不能为空") @RequestParam(required = false) String modelId);
/**
@ -81,6 +91,7 @@ public interface ProcessModelApi {
*/
@Operation(summary = "更新流程模型")
@PutMapping("/api/process/model/update")
@InvokeMode(SYNC)
CommonResponse<String> update(@RequestBody BpmnModelUpdateDTO dto);
@ -91,6 +102,7 @@ public interface ProcessModelApi {
*/
@Operation(summary = "通过模型 ID 部署流程模型")
@PostMapping("/api/process/model/deploy")
@InvokeMode(SYNC)
CommonResponse<String> deployById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam(required = false) String processModelId,
@RequestParam(required = false, defaultValue = "") String modelTenantId,
@RequestParam(required = false) String operator);
@ -102,6 +114,7 @@ public interface ProcessModelApi {
*/
@Operation(summary = "通过模型 KEY 部署流程模型")
@PostMapping("/api/process/model/deployByKey")
@InvokeMode(SYNC)
CommonResponse<String> deployByKey(@NotBlank(message = "流程模型 KEY 不能为空") @RequestParam(required = false) String processModelKey,
@NotBlank(message = "租户不能为空") @RequestParam(required = false) String modelTenantId,
@RequestParam(required = false) String operator);
@ -116,6 +129,7 @@ public interface ProcessModelApi {
*/
@Operation(summary = "通过模型 ID 取消部署流程模型")
@PostMapping("/api/process/model/undeploy")
@InvokeMode(SYNC)
CommonResponse<Void> unDeployById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam(required = false) String processModelId,
@RequestParam(required = false, defaultValue = "") String tenantId,
@RequestParam(required = false) String operator);
@ -125,6 +139,7 @@ public interface ProcessModelApi {
*/
@Operation(summary = "删除指定模型 ID 的流程模型")
@DeleteMapping("/api/process/model/delete")
@InvokeMode(SYNC)
CommonResponse<Void> deleteById(@NotBlank(message = "流程模型 ID 不能为空") @RequestParam String processModelId,
@RequestParam(required = false, defaultValue = "") String tenantId);
@ -137,6 +152,7 @@ public interface ProcessModelApi {
*/
@Operation(summary = "删除指定模型 KEY 的流程模型")
@DeleteMapping("/api/process/model/deleteByKey")
@InvokeMode(SYNC)
CommonResponse<Void> deleteByKey(@NotBlank(message = "流程模型 KEY 不能为空") @RequestParam String processModelKey,
@RequestParam(required = false, defaultValue = "") String tenantId);
@ -150,6 +166,7 @@ public interface ProcessModelApi {
*/
@Operation(summary = "修改模型状态")
@PostMapping("/api/process/model/changeStatus")
@InvokeMode(SYNC)
CommonResponse<Void> changeStatus(@NotBlank(message = "模型 ID 不能为空") @RequestParam String modelId,
@NotNull(message = "状态不能为空") @RequestParam Integer status,
@RequestParam(required = false) String operator);
@ -161,6 +178,7 @@ public interface ProcessModelApi {
*/
@Operation(summary = "查询流程模型使用的分类列表")
@GetMapping("/api/process/model/category/ids")
@InvokeMode(SYNC)
CommonResponse<List<String>> getModelCategoryList();
/**
@ -170,5 +188,6 @@ public interface ProcessModelApi {
*/
@Operation(summary = "查询模型的租户集合")
@GetMapping("/api/process/model/tenant/ids")
CommonResponse<List<String>> getTenantIds();
@InvokeMode(SYNC)
CommonResponse<List<String>> getModelTenantIds();
}

View File

@ -1,6 +1,8 @@
package cn.axzo.workflow.client.feign.bpmn;
import cn.axzo.workflow.client.config.CommonFeignConfiguration;
import cn.axzo.workflow.common.annotation.InvokeMode;
import cn.axzo.workflow.common.annotation.Manageable;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO;
@ -28,10 +30,12 @@ import org.springframework.web.bind.annotation.RequestParam;
import javax.annotation.Nullable;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.NotEmpty;
import java.util.List;
import java.util.Map;
import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC;
/**
* 流程任务 API
@ -39,46 +43,9 @@ import java.util.Map;
* @author wangli
* @since 2023/9/21 16:26
*/
@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class)
//@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class)
public interface ProcessTaskApi {
/**
* 待审核列表
*/
@GetMapping("/api/process/task/page/todo")
CommonResponse<BpmPageResult<BpmnTaskTodoPageItemVO>> getTodoTaskPage(@Validated @RequestBody BpmnTaskPageSearchDTO dto);
/**
* 已完成的审批列表
*/
@GetMapping("/api/process/task/page/done")
CommonResponse<BpmPageResult<BpmnTaskDonePageItemVO>> getDoneTaskPage(@Validated @RequestBody BpmnTaskPageSearchDTO dto);
/**
* 获取指定流程实例的审批过程信息
* <p>
* 同一层级结构
*/
@GetMapping("/api/process/task/list/flat")
CommonResponse<List<BpmnHistoricTaskInstanceVO>> getTaskListFlatByProcessInstanceId(@NotBlank(message = "流程实例 ID " +
"不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId);
/**
* 获取指定流程实例的审批过程信息
* <p>
* 分组结构
*/
@GetMapping("/api/process/task/list/group")
CommonResponse<List<BpmnHistoricTaskInstanceGroupVO>> getTaskListGroupByProcessInstanceId(@NotBlank(message =
"流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId);
/**
* 获取实例正在审核的人列表
*/
@GetMapping("/api/process/task/active/list")
CommonResponse<List<BpmnTaskInstanceVO>> getActiveTasksByProcessInstanceId(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId,
@NotBlank(message = "租户不能为空") @RequestParam String tenantId);
/**
* 同意
*
@ -90,6 +57,7 @@ public interface ProcessTaskApi {
* 2.2. 流程实例正常结束会触发 process-instance-completed 事件
* </pre>
*/
@Operation(summary = "同意MQ 触发规则:1. 当前审批任务会依次触发 process-task-completed 和 process-task-deleted 事件(如果有下一级审批,则会触发第 2.1 点中的事件,如果当前审核任务最后一级审批,则会触发第 2.2 点中的事件)2.1. 下一级审批任务会依次触发 process-task-assigned 和 process-task-created 事件2.2. 流程实例正常结束会触发 process-instance-completed 事件")
@PostMapping("/api/process/task/approve")
CommonResponse<Boolean> approveTask(@Validated @RequestBody BpmnTaskAuditDTO dto);
@ -99,6 +67,7 @@ public interface ProcessTaskApi {
* @param dtos
* @return
*/
@Operation(summary = "批量同意")
@PostMapping("/api/process/task/batch/approve")
CommonResponse<BatchOperationResultVO> batchApproveTask(@Validated @RequestBody List<BpmnTaskAuditDTO> dtos);
@ -111,6 +80,7 @@ public interface ProcessTaskApi {
* 2. 当前流程实例会触发 process-instance-rejected 事件
* </pre>
*/
@Operation(summary = "驳回MQ 触发规则1. 当前审批任务会触发 process-task-deleted 事件, 2. 当前流程实例会触发 process-instance-rejected 事件")
@PostMapping("/api/process/task/reject")
CommonResponse<Boolean> rejectTask(@Validated @RequestBody BpmnTaskAuditDTO dto);
@ -153,16 +123,6 @@ public interface ProcessTaskApi {
@PostMapping("/api/process/task/comment")
CommonResponse<Boolean> commentTask(@Validated @RequestBody BpmnTaskCommentDTO dto);
/**
* 添加附件
*
* @param dto
* @return
*/
@Operation(summary = "添加附件")
@PostMapping("/api/process/task/attachment")
CommonResponse<Void> addAttachment(@Validated @RequestBody BpmnTaskAttachmentDTO dto);
/**
* 加签
*
@ -181,6 +141,8 @@ public interface ProcessTaskApi {
*/
@Operation(summary = "审批流程催办")
@PostMapping("/api/process/task/remind")
@Manageable
@InvokeMode(SYNC)
CommonResponse<Boolean> remindTask(@Validated @RequestBody BpmnTaskRemindDTO dto);
/**
@ -203,6 +165,69 @@ public interface ProcessTaskApi {
@PostMapping("/api/process/task/robot/complete")
CommonResponse<Boolean> completeRobotTask(@Validated @RequestBody BpmnRobotTaskCompleteDTO dto);
/**
* 添加附件
*
* @param dto
* @return
*/
@Operation(summary = "添加附件")
@PostMapping("/api/process/task/attachment")
@Manageable
CommonResponse<Void> addAttachment(@Validated @RequestBody BpmnTaskAttachmentDTO dto);
/**
* 待审核列表
*/
@Operation(summary = "待审核列表")
@GetMapping("/api/process/task/page/todo")
@Manageable
@InvokeMode(SYNC)
CommonResponse<BpmPageResult<BpmnTaskTodoPageItemVO>> getTodoTaskPage(@Validated @RequestBody BpmnTaskPageSearchDTO dto);
/**
* 已完成的审批列表
*/
@Operation(summary = "已完成的审批列表")
@GetMapping("/api/process/task/page/done")
@Manageable
@InvokeMode(SYNC)
CommonResponse<BpmPageResult<BpmnTaskDonePageItemVO>> getDoneTaskPage(@Validated @RequestBody BpmnTaskPageSearchDTO dto);
/**
* 获取指定流程实例的审批过程信息
* <p>
* 同一层级结构
*/
@Operation(summary = "获取指定流程实例的审批过程信息")
@GetMapping("/api/process/task/list/flat")
@Manageable
@InvokeMode(SYNC)
CommonResponse<List<BpmnHistoricTaskInstanceVO>> getTaskListFlatByProcessInstanceId(@NotBlank(message = "流程实例 ID " +
"不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId);
/**
* 获取指定流程实例的审批过程信息
* <p>
* 分组结构
*/
@Operation(summary = "获取指定流程实例的审批过程信息")
@GetMapping("/api/process/task/list/group")
@Manageable
@InvokeMode(SYNC)
CommonResponse<List<BpmnHistoricTaskInstanceGroupVO>> getTaskListGroupByProcessInstanceId(@NotBlank(message =
"流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId);
/**
* 获取实例正在审核的人列表
*/
@Operation(summary = "获取实例正在审核的人列表")
@GetMapping("/api/process/task/active/list")
@Manageable
@InvokeMode(SYNC)
CommonResponse<List<BpmnTaskInstanceVO>> getActiveTasksByProcessInstanceId(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId,
@NotBlank(message = "租户不能为空") @RequestParam String tenantId);
/**
* 根据实例 ID 和自然人 ID 查询对应待处理的任务 ID
*
@ -210,6 +235,8 @@ public interface ProcessTaskApi {
*/
@Operation(summary = "根据实例 ID 和自然人 ID 查询对应待处理的任务 ID")
@GetMapping("/api/process/task/find")
@Manageable
@InvokeMode(SYNC)
CommonResponse<String> findTaskIdByInstanceIdAndPersonId(@RequestParam(required = false) @NotBlank(message = "流程实例 ID 不能为空") String processInstanceId,
@RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId);
@ -220,6 +247,8 @@ public interface ProcessTaskApi {
*/
@Operation(summary = "根据实例 ID列表 和自然人 ID 查询对应待处理的任务 ID")
@GetMapping("/api/process/task/batch/find")
CommonResponse<Map<String, String>> findTaskIdByInstanceIdsAndPersonId(@RequestParam(required = false) @NotNull(message = "流程实例 ID列表 不能为空") List<String> processInstanceIds,
@Manageable
@InvokeMode(SYNC)
CommonResponse<Map<String, String>> findTaskIdByInstanceIdsAndPersonId(@RequestParam(required = false) @NotEmpty(message = "流程实例 ID列表 不能为空") List<String> processInstanceIds,
@RequestParam(required = false) @NotBlank(message = "自然人 ID 不能为空") String personId);
}

View File

@ -1,6 +1,8 @@
package cn.axzo.workflow.client.feign.bpmn;
import cn.axzo.workflow.client.config.CommonFeignConfiguration;
import cn.axzo.workflow.common.annotation.InvokeMode;
import cn.axzo.workflow.common.annotation.Manageable;
import cn.axzo.workflow.common.model.request.bpmn.RestBpmnProcessVariable;
import cn.azxo.framework.common.model.CommonResponse;
import org.springframework.cloud.openfeign.FeignClient;
@ -13,16 +15,20 @@ import org.springframework.web.bind.annotation.RequestParam;
import javax.validation.constraints.NotBlank;
import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC;
/**
* 流程变量api
*/
@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class)
//@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class)
@Manageable
public interface ProcessVariableApi {
/**
* 为指定流程新增变量
*/
@PostMapping("/api/process/variable/create/{executionId}")
@InvokeMode(SYNC)
CommonResponse<Void> createVariable(@PathVariable @NotBlank(message = "流程实例 ID 不能为空") String executionId,
@RequestBody @Validated RestBpmnProcessVariable restVariable);
@ -34,6 +40,7 @@ public interface ProcessVariableApi {
* @return
*/
@PostMapping("/api/process/variable/update/{executionId}")
@InvokeMode(SYNC)
CommonResponse<Void> updateVariable(@PathVariable @NotBlank(message = "流程实例 ID 不能为空") String executionId,
@RequestBody @Validated RestBpmnProcessVariable restVariable);
@ -41,6 +48,7 @@ public interface ProcessVariableApi {
* 批量删除流程变量
*/
@DeleteMapping("/api/process/variable/delete/{executionId}")
@InvokeMode(SYNC)
CommonResponse<Void> deleteVariables(@PathVariable("executionId") String executionId,
@RequestParam String variableNames,
@RequestParam(value = "scope", required = false) String scope);

View File

@ -1,6 +1,8 @@
package cn.axzo.workflow.client.feign.manage;
import cn.axzo.workflow.client.config.CommonFeignConfiguration;
import cn.axzo.workflow.common.annotation.InvokeMode;
import cn.axzo.workflow.common.annotation.Manageable;
import cn.axzo.workflow.common.model.request.category.CategoryConfigCreateDTO;
import cn.axzo.workflow.common.model.request.category.CategoryConfigSearchDTO;
import cn.axzo.workflow.common.model.request.category.CategoryCreateDTO;
@ -22,6 +24,8 @@ import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC;
/**
* OMS流程业务管理API
@ -31,7 +35,8 @@ import java.util.List;
* @date 2023/11/6 16:01
*/
@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class)
//@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class)
@Manageable
public interface ProcessCategoryApi {
/**
@ -40,6 +45,7 @@ public interface ProcessCategoryApi {
* @return
*/
@GetMapping("/api/process/category/get")
@InvokeMode(SYNC)
CommonResponse<CategoryItemVO> get(@RequestParam Long id);
/**
@ -49,6 +55,7 @@ public interface ProcessCategoryApi {
* @return
*/
@GetMapping("/api/process/category/getByIds")
@InvokeMode(SYNC)
CommonResponse<List<CategoryItemVO>> getByIds(@RequestParam List<Long> ids);
/**
@ -58,6 +65,7 @@ public interface ProcessCategoryApi {
* @return
*/
@GetMapping("/api/process/category/getByValues")
@InvokeMode(SYNC)
CommonResponse<List<CategoryItemVO>> getByValues(@RequestParam List<String> values);
/**
@ -66,6 +74,7 @@ public interface ProcessCategoryApi {
* @return
*/
@PostMapping("/api/process/category/create")
@InvokeMode(SYNC)
CommonResponse<CategoryItemVO> create(@Validated @RequestBody CategoryCreateDTO req);
/**
@ -74,6 +83,7 @@ public interface ProcessCategoryApi {
* @return
*/
@PutMapping("/api/process/category/update")
@InvokeMode(SYNC)
CommonResponse<CategoryItemVO> update(@Validated @RequestBody CategoryUpdateDTO dto);
/**
@ -83,6 +93,7 @@ public interface ProcessCategoryApi {
* @return
*/
@DeleteMapping("/api/process/category/delete")
@InvokeMode(SYNC)
CommonResponse<Boolean> delete(@RequestParam Long id);
/**
@ -93,6 +104,7 @@ public interface ProcessCategoryApi {
* @return
*/
@PutMapping("/api/process/category/update/state")
@InvokeMode(SYNC)
CommonResponse<Boolean> updateState(@RequestParam Long id, @RequestParam Boolean state);
/**
@ -101,6 +113,7 @@ public interface ProcessCategoryApi {
* @return
*/
@PostMapping("/api/process/category/list")
@InvokeMode(SYNC)
CommonResponse<List<CategoryItemVO>> list(@RequestBody CategorySearchDTO dto);
/**
@ -109,6 +122,7 @@ public interface ProcessCategoryApi {
* @return
*/
@PostMapping("/api/process/category/page/search")
@InvokeMode(SYNC)
CommonResponse<BpmPageResult<CategoryItemVO>> search(@RequestBody CategorySearchDTO dto);
/**
@ -118,6 +132,7 @@ public interface ProcessCategoryApi {
* @return
*/
@PostMapping("/api/process/category/config/create")
@InvokeMode(SYNC)
CommonResponse<Boolean> createConfig(@RequestBody CategoryConfigCreateDTO dto);
/**
@ -127,6 +142,7 @@ public interface ProcessCategoryApi {
* @return
*/
@DeleteMapping("/api/process/category/config/delete/{id}")
@InvokeMode(SYNC)
CommonResponse<Boolean> deleteConfig(@PathVariable Long id);
/**
@ -135,6 +151,7 @@ public interface ProcessCategoryApi {
* @return
*/
@PostMapping("/api/process/category/config/page/search")
@InvokeMode(SYNC)
CommonResponse<BpmPageResult<CategoryConfigItemVO>> configSearch(@RequestBody CategoryConfigSearchDTO dto);
/**
@ -145,6 +162,7 @@ public interface ProcessCategoryApi {
* @return
*/
@PostMapping("/api/process/category/config/type/update")
@InvokeMode(SYNC)
CommonResponse<Boolean> updateCategoryConfigType(@RequestParam Long id, @RequestParam String configType);
/**
@ -155,5 +173,6 @@ public interface ProcessCategoryApi {
* @return true: 可以发起创建流程实例, false: 不可用
*/
@GetMapping("/api/process/category/check/status")
@InvokeMode(SYNC)
CommonResponse<Boolean> checkCategoryStatus(@RequestParam Long tenantId, @RequestParam String categoryCode);
}

View File

@ -1,6 +1,8 @@
package cn.axzo.workflow.client.feign.manage;
import cn.axzo.workflow.client.config.CommonFeignConfiguration;
import cn.axzo.workflow.common.annotation.InvokeMode;
import cn.axzo.workflow.common.annotation.Manageable;
import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonMetaInfo;
import cn.azxo.framework.common.model.CommonResponse;
import org.springframework.cloud.openfeign.FeignClient;
@ -8,6 +10,8 @@ import org.springframework.web.bind.annotation.GetMapping;
import java.util.List;
import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC;
/**
* OMS流程业务管理API
@ -17,7 +21,8 @@ import java.util.List;
* @date 2023/11/6 16:01
*/
@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class)
//@FeignClient(name = "workflow-engine", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = CommonFeignConfiguration.class)
@Manageable
public interface ProcessConfigApi {
/**
@ -26,6 +31,7 @@ public interface ProcessConfigApi {
* @return 流程操作按钮列表
*/
@GetMapping("/api/process/config/button/list")
@InvokeMode(SYNC)
CommonResponse<List<BpmnButtonMetaInfo>> getDefaultButtons();

View File

@ -11,7 +11,7 @@
<artifactId>workflow-engine-common</artifactId>
<packaging>jar</packaging>
<name>workflow-engine-common</name>
<name>workflow Engine Common</name>
<dependencies>
<dependency>

View File

@ -0,0 +1,28 @@
package cn.axzo.workflow.common.annotation;
import cn.axzo.workflow.common.enums.RpcInvokeModeEnum;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC;
/**
* 用于标记接口的方法调用模式
*
* @author wangli
* @since 2024/6/1 19:01
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface InvokeMode {
/**
* 调用模式, 默认异步
*/
RpcInvokeModeEnum value() default ASYNC;
}

View File

@ -0,0 +1,10 @@
package cn.axzo.workflow.common.annotation;
/**
* 控制接口是否调用受限标记了注解的方法表示受控不允许暴露给客户端使用
*
* @author wangli
* @since 2024/6/7 18:21
*/
public @interface Manageable {
}

View File

@ -11,6 +11,7 @@ public interface BpmnConstants {
*/
String FLOWABLE_SKIP_EXPRESSION_ENABLE = "[_FLOWABLE_SKIP_EXPRESSION_ENABLED_]";
String MQ_UNIQUE_ID = "[_MQ_UNIQUE_ID_]";
String PROCESS_OWNERSHIP_APPLICATION = "[_PROCESS_OWNERSHIP_APPLICATION_]";
String WORKFLOW_ENGINE_VERSION = "[_WORKFLOW_ENGINE_VERSION_]";
String INTERNAL_INITIATOR = "[_INTERNAL_INITIATOR_]";
@Deprecated
@ -154,5 +155,6 @@ public interface BpmnConstants {
/**
* 用于 MQ Header 记录当前事件的归属应用
*/
String MQ_OWNERSHIP_APP = "MQ_OWNERSHIP_APPLICATION";
String MQ_OWNERSHIP_APPLICATION = "MQ_OWNERSHIP_APPLICATION";
String MQ_OWNERSHIP_PROCESS_DEFINITION_KEY = "MQ_OWNERSHIP_PROCESS_DEFINITION_KEY";
}

View File

@ -0,0 +1,16 @@
package cn.axzo.workflow.common.constant;
/**
* Starter 常量类
*
* @author wangli
* @since 2024/5/29 11:13
*/
public interface StarterConstants {
String STARTER_INVOKE_MODE = "WORKFLOW-ENGINE-STARTER-INVOKE-MODE";
String DEBUGGING_MQ_SUFFIX = "_debugging";
String K8S_POD_NAME_SPACE = "MY_POD_NAMESPACE";
String NACOS_PROFILES_ACTIVE = "NACOS_PROFILES_ACTIVE";
String MQ_GID_NAME_SEGMENT = "GID_SEGMENT";
String ENABLE_MANAGEABLE = "ENABLE_MANAGEABLE";
}

View File

@ -0,0 +1,12 @@
package cn.axzo.workflow.common.enums;
/**
* PRC 调用模式枚举
*
* @author wangli
* @since 2024/5/29 10:27
*/
public enum RpcInvokeModeEnum {
SYNC,
ASYNC,
}

View File

@ -11,7 +11,7 @@ import cn.axzo.framework.rocketmq.Event;
public enum WorkflowEngineEventEnum {
WORKFLOW_ENGINE_SERVER("workflow-engine", "workflow-engine-server", "引擎服务端事件"),
WORKFLOW_ENGINE_CLIENT("workflow-engine", "workflow-engine-client-%s", "引擎客户端事件"),
WORKFLOW_ENGINE_STARTER("workflow-engine", "workflow-engine-starter-%s", "引擎客户端事件"),
;
private final String module;
@ -34,4 +34,16 @@ public enum WorkflowEngineEventEnum {
return eventCode;
}
public String getModule() {
return module;
}
public String getTag() {
return eventCode.getName();
}
public String getDesc() {
return desc;
}
}

View File

@ -20,6 +20,7 @@ import java.util.List;
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class CooperationOrgDTO implements Serializable {
private static final long serialVersionUID = 4739924705980062997L;

View File

@ -22,9 +22,9 @@ public class BpmnProcessVariable {
@NotBlank(message = "流程变量名称不能为空")
private String name;
@ApiModelProperty(value = "流程变量类型")
@NotBlank(message = "流程变量类型不能为空")
private String type;
// @ApiModelProperty(value = "流程变量类型")
// @NotBlank(message = "流程变量类型不能为空")
// private String type;
@ApiModelProperty(value = "流程变量值")
@NotNull(message = "流程变量值不能为空")

View File

@ -20,7 +20,7 @@ public class RestBpmnProcessVariable extends BpmnProcessVariable {
/**
* 变量作用域 目前支持 LOCAL局部变量 GLOBAL全局变量
*/
private RestVariableScope scope;
private RestVariableScope scope = RestVariableScope.GLOBAL;
public String getVariableScope() {
String scope = null;

View File

@ -2,7 +2,10 @@ package cn.axzo.workflow.common.model.request.bpmn.process;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import javax.annotation.Nullable;
@ -17,6 +20,9 @@ import javax.validation.constraints.NotBlank;
@ApiModel("最基础的流程实例查询入参模型")
@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BpmnBasicProcessInstanceQueryDTO {
/**
* 流程实例 ID

View File

@ -2,7 +2,10 @@ package cn.axzo.workflow.common.model.request.bpmn.process;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotBlank;
@ -15,6 +18,9 @@ import javax.validation.constraints.NotBlank;
*/
@ApiModel("中止流程实例的入参模型")
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BpmnProcessInstanceAbortDTO {
/**

View File

@ -3,7 +3,10 @@ package cn.axzo.workflow.common.model.request.bpmn.process;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
@ -17,6 +20,9 @@ import javax.validation.constraints.NotNull;
*/
@ApiModel("取消流程实例的入参模型")
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BpmnProcessInstanceCancelDTO {
/**

View File

@ -4,7 +4,10 @@ import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
@ -18,6 +21,9 @@ import java.util.List;
*/
@ApiModel("抄送流程实例的入参模型")
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BpmnProcessInstanceCarbonCopyDTO {
/**

View File

@ -4,7 +4,10 @@ import cn.axzo.workflow.common.model.dto.CooperationOrgDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
@ -17,6 +20,9 @@ import java.util.Map;
*/
@ApiModel("创建流程实例的入参模型")
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BpmnProcessInstanceCreateDTO {
/**
@ -28,7 +34,7 @@ public class BpmnProcessInstanceCreateDTO {
/**
* 流程定义的标识
* <p>
* [对应业务分类的 businessId]
* [对应 OMS 系统中审批业务的业务 ID]
*/
@NotEmpty(message = "流程定义的标识不能为空")
private String processDefinitionKey;
@ -56,6 +62,7 @@ public class BpmnProcessInstanceCreateDTO {
* <p>
* 用于流程引擎计算对应节点的审批人, 例如第一个审批节点配置的是劳务分包的岗位,第二个审批节点配置的专业分包的角色,
* 那么, 组织关系就需要传入劳务分包的信息以及专业分包的信息,如果还有更多的审批节点配置,以此类推.
* 同时该属性还会用于计算抄送人以及消息通知的目标接收人
*/
@ApiModelProperty(value = "组织关系")
@NotNull(message = "组织关系不能为空")
@ -81,17 +88,9 @@ public class BpmnProcessInstanceCreateDTO {
private String customProcessInstanceName;
/**
* 是否异步执行
* 是否异步执行该异步是引擎的一种运行模式
*/
@ApiModelProperty(value = "是否异步", notes = "异步时,只接收请求便返回数据")
private Boolean async = true;
/**
* 废弃
* 下级审批人
*/
// @ApiModelProperty(value = "下级审批人", notes = "可为空,定义选择审批人,如果不为空,则覆盖下一级任务的审核人")
// @Deprecated
// private BpmnTaskDelegateAssigner nextApprover;
}

View File

@ -2,8 +2,11 @@ package cn.axzo.workflow.common.model.request.bpmn.process;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
/**

View File

@ -2,7 +2,10 @@ package cn.axzo.workflow.common.model.request.bpmn.task;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
@ -16,6 +19,9 @@ import java.util.List;
*/
@ApiModel("业务节点设置审批人")
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BpmnActivitySetAssigneeDTO {
/**
* PROCESS_ACTIVITY_WAIT_ASSIGNEE 事件中的触发 ID

View File

@ -2,7 +2,10 @@ package cn.axzo.workflow.common.model.request.bpmn.task;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
@ -15,6 +18,9 @@ import javax.validation.constraints.NotBlank;
*/
@ApiModel("完成机器人节点的入参模型")
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BpmnRobotTaskCompleteDTO {
/**

View File

@ -2,7 +2,10 @@ package cn.axzo.workflow.common.model.request.bpmn.task;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
@ -16,6 +19,9 @@ import javax.validation.constraints.NotNull;
*/
@ApiModel("创建机器人节点的入参模型")
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BpmnRobotTaskCreateDTO {
/**
* 流程实例 ID

View File

@ -3,7 +3,10 @@ package cn.axzo.workflow.common.model.request.bpmn.task;
import cn.axzo.workflow.common.enums.BpmnFlowNodeType;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.validation.annotation.Validated;
import javax.validation.Valid;
@ -19,6 +22,9 @@ import java.util.List;
@ApiModel("审批任务节点的入参模型")
@Data
@Validated
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BpmnTaskAuditDTO {
@ApiModelProperty(value = "任务编号", required = true, example = "1024")

View File

@ -2,7 +2,10 @@ package cn.axzo.workflow.common.model.request.bpmn.task;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
import javax.validation.Valid;
@ -19,6 +22,9 @@ import java.util.List;
*/
@ApiModel("评论的入参模型")
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BpmnTaskCommentDTO implements Serializable {
/**

View File

@ -2,7 +2,10 @@ package cn.axzo.workflow.common.model.request.bpmn.task;
import cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import javax.validation.Valid;
@ -21,6 +24,9 @@ import java.util.List;
*/
@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BpmnTaskCountersignDTO implements Serializable {
private static final long serialVersionUID = -8106887960942113552L;

View File

@ -44,7 +44,7 @@ public class BpmnTaskDelegateAssigner implements Serializable {
private static final long serialVersionUID = -8106887960942113552L;
/**
* 审核人标识, 应该必传
* 废弃审核人标识, 应该必传
* <p>
* 枢智:用户 ID
* 安心筑:身份 ID
@ -53,7 +53,7 @@ public class BpmnTaskDelegateAssigner implements Serializable {
private String assignee;
/**
* 审核人标识扩展信息
* 废弃审核人标识扩展信息
* <p>
* 枢智:可不传
* 安心筑:身份 Type 应该必传

View File

@ -2,7 +2,10 @@ package cn.axzo.workflow.common.model.request.bpmn.task;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
@ -16,6 +19,9 @@ import java.util.List;
*/
@ApiModel("转交审批任务的入参模型")
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BpmnTaskTransferDTO {
/**

View File

@ -31,6 +31,11 @@ public class MessagePushDTO implements Serializable {
*/
private String processInstanceId;
/**
* 业务 ID
*/
private String processDefinitionKey;
/**
* 流程任务 ID
*/

View File

@ -28,8 +28,11 @@ public class ProcessTaskDTO implements Serializable {
private ProcessTaskEventEnum type;
/**
* 请使用 {@link ProcessTaskDTO#processDefinitionKey} 代替访问此属性未来将逐步废弃
* <p>
* 流程实例所属业务分类同时也等于流程模型对应的业务分类 ID
*/
@Deprecated
private String category;
/**
@ -41,6 +44,10 @@ public class ProcessTaskDTO implements Serializable {
* 流程实例 ID
*/
private String processInstanceId;
/**
* 流程实例所属业务分类同时也等于流程模型对应的业务分类 ID
*/
private String processDefinitionKey;
/**
* 流程定义中当前任务节点 Key

View File

@ -0,0 +1,44 @@
package cn.axzo.workflow.common.model.response.mq;
import java.io.Serializable;
import java.util.List;
/**
* Starter RPC 调用事件模型
*
* @author wangli
* @since 2024/5/30 11:21
*/
public class WorkflowEngineStarterRpcInvokeDTO implements Serializable {
private static final long serialVersionUID = -1L;
private String className;
private String methodName;
private List<String> parameters;
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public List<String> getParameters() {
return parameters;
}
public void setParameters(List<String> parameters) {
this.parameters = parameters;
}
}

View File

@ -0,0 +1,27 @@
package cn.axzo.workflow.common.util;
import cn.axzo.workflow.common.enums.RpcInvokeModeEnum;
/**
* TODO
*
* @author wangli
* @since 2024/5/29 23:57
*/
public class ThreadUtil {
final static InheritableThreadLocal<RpcInvokeModeEnum> threadLocal = new InheritableThreadLocal<>();
public static void set(RpcInvokeModeEnum rpcInvokeMode) {
threadLocal.set(rpcInvokeMode);
}
public static RpcInvokeModeEnum get() {
return threadLocal.get();
}
public static void clear() {
threadLocal.remove();
}
}

View File

@ -9,8 +9,7 @@
<version>${revision}</version>
<artifactId>workflow-engine-core</artifactId>
<packaging>jar</packaging>
<name>workflow-engine-core</name>
<name>Workflow Engine Core</name>
<properties>
<flowable.version>6.7.2</flowable.version>
<axzo-bom.version>2.0.0-SNAPSHOT</axzo-bom.version>
@ -98,5 +97,9 @@
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -33,6 +33,7 @@ public enum BpmnTaskRespCode implements IModuleRespCode {
FIND_TASK_BY_PERSON_ID_ERROR("018", "流程实例中:【{}】未查找指定自然人:【{}】的待处理的流程任务!"),
PROCESS_INSTANCE_IS_NOT_EXIST("019", "Execution:{} 对应流程实例不存在,流程状态异常!"),
TASK_TYPE_MISMATCH("020", "节点类型不匹配,当前节点类型:【{}】,指定节点类型:【{}】!"),
PROCESS_CANT_SET_ASSIGNEE("021", "当前审批状态不允许设置审批人"),
;
private String code;

View File

@ -18,6 +18,8 @@ public enum FlowableEngineRespCode implements IModuleRespCode {
ENGINE_USER_TASK_TYPE_NOT_SUPPORT("003", "审批指定方式暂不支持"),
ENGINE_USER_TASK_PARAM_ERROR("004", "构建后的查询审批人入参为空. 任务节点【nodeId:{}】, 该节点选择的\"审批人所在范围\"是:【{}】,请检查 cooperationOrg 参数"),
ENGINE_NOTICE_CUSTOM_FLOW_ELEMENT_ERROR("005", "查询通知目标用户前参数发生异常,未获取到 WorkspaceType"),
ENGINE_ASYNC_COMMAND_EXECUTION_ERROR("006", "引擎出现 SQL 相关异常, 异常信息:【{}】"),
ENGINE_ASYNC_COMMAND_EXECUTION_RETRY_GIVE_UP("007", "命令重试尝试【{}】次仍然失败,并出现异常, 将放弃"),
;
private String code;

View File

@ -0,0 +1,24 @@
package cn.axzo.workflow.core.common.utils;
import org.slf4j.MDC;
import org.springframework.util.StringUtils;
import static cn.axzo.workflow.common.constant.LogFieldConstants.X_REQUEST_ID;
import static cn.azxo.framework.common.constatns.Constants.CTX_LOG_ID_MDC;
/**
* 获取 TraceId
*
* @author wangli
* @since 2024/7/3 10:14
*/
public final class TraceUtil {
private TraceUtil() {
}
public static String traceId() {
String xRequestId = MDC.get(X_REQUEST_ID);
return StringUtils.hasText(xRequestId) ? xRequestId : MDC.get(CTX_LOG_ID_MDC);
}
}

View File

@ -3,6 +3,7 @@ package cn.axzo.workflow.core.conf;
import cn.axzo.workflow.core.engine.behavior.CustomActivityBehaviorFactory;
import cn.axzo.workflow.core.engine.cmd.CustomCommandContextFactory;
import cn.axzo.workflow.core.engine.id.BasedNacosSnowflakeIdGenerator;
import cn.axzo.workflow.core.engine.interceptor.CustomRetryInterceptor;
import cn.axzo.workflow.core.engine.job.AsyncAbortProcessInstanceHandler;
import cn.axzo.workflow.core.engine.job.AsyncApproveTaskJobHandler;
import cn.axzo.workflow.core.engine.job.AsyncBpmnProcessActivityJobHandler;
@ -30,6 +31,7 @@ import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.time.Duration;
import java.util.List;
@ -56,7 +58,8 @@ public class FlowableConfiguration {
BpmnProcessActivityService bpmnProcessActivityService,
List<JobProcessor> jobProcessors,
NacosServiceManager nacosServiceManager,
NacosDiscoveryProperties nacosDiscoveryProperties) {
NacosDiscoveryProperties nacosDiscoveryProperties,
StringRedisTemplate redisTemplate) {
return configuration -> {
configuration.setEnableHistoricTaskLogging(true);
configuration.setHistoryLevel(HistoryLevel.AUDIT);
@ -92,6 +95,9 @@ public class FlowableConfiguration {
new CustomWorkflowEngineExceptionHandler(),
new CustomAsyncRunnableExceptionExceptionHandler()));
configuration.setCommandContextFactory(new CustomCommandContextFactory());
configuration.setCustomPreCommandInterceptors(Lists.newArrayList(
new CustomRetryInterceptor()
));
};
}

View File

@ -0,0 +1,15 @@
package cn.axzo.workflow.core.engine.cmd;
import org.flowable.common.engine.impl.interceptor.Command;
/**
* TODO
*
* @author wangli
* @since 2024/7/1 13:59
*/
public abstract class AbstractCommand<T> implements Command<T> {
public abstract String paramToJsonString();
}

View File

@ -4,7 +4,7 @@ import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbo
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
import cn.axzo.workflow.core.engine.job.AsyncAbortProcessInstanceHandler;
import cn.hutool.json.JSONUtil;
import org.flowable.common.engine.impl.interceptor.Command;
import com.alibaba.fastjson.JSON;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.HistoryService;
import org.flowable.engine.history.HistoricProcessInstance;
@ -23,7 +23,7 @@ import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INS
import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_CANT_ABORT;
import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_NOT_EXISTS;
public class CustomAbortProcessInstanceAsyncCmd implements Command<Void>, Serializable {
public class CustomAbortProcessInstanceAsyncCmd extends AbstractCommand<Void> implements Serializable {
private final BpmnProcessInstanceAbortDTO dto;
@ -31,6 +31,11 @@ public class CustomAbortProcessInstanceAsyncCmd implements Command<Void>, Serial
this.dto = dto;
}
@Override
public String paramToJsonString() {
return JSON.toJSONString(dto);
}
@Override
public Void execute(CommandContext commandContext) {
String processInstanceId = dto.getProcessInstanceId();
@ -80,4 +85,5 @@ public class CustomAbortProcessInstanceAsyncCmd implements Command<Void>, Serial
jobService.createAsyncJob(job, false);
jobService.scheduleAsyncJob(job);
}
}

View File

@ -4,6 +4,8 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
import cn.axzo.workflow.core.engine.operation.DeleteProcessInstanceOperation;
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
import com.alibaba.fastjson.JSON;
import liquibase.pro.packaged.V;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.HistoryService;
@ -44,7 +46,7 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.createVir
* @author wangli
* @since 2024/1/2 18:19
*/
public class CustomAbortProcessInstanceCmd implements Command<Void>, Serializable {
public class CustomAbortProcessInstanceCmd extends AbstractCommand<Void> implements Serializable {
private final String processInstanceId;
private final String tenantId;
private final String reason;
@ -58,6 +60,15 @@ public class CustomAbortProcessInstanceCmd implements Command<Void>, Serializabl
this.extAxHiTaskInstService = extAxHiTaskInstService;
}
@Override
public String paramToJsonString() {
Map<String, Object> params = new HashMap<>();
params.put("processInstanceId", processInstanceId);
params.put("tenantId", tenantId);
params.put("reason", reason);
return JSON.toJSONString(params);
}
@Override
public Void execute(CommandContext commandContext) {
ProcessEngineConfigurationImpl processEngineConfiguration =
@ -102,4 +113,5 @@ public class CustomAbortProcessInstanceCmd implements Command<Void>, Serializabl
runtimeService.setVariable(task.getProcessInstanceId(), TASK_COMPLETE_OPERATION_TYPE + task.getId(), ABORTED);
return null;
}
}

View File

@ -3,6 +3,7 @@ package cn.axzo.workflow.core.engine.cmd;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO;
import cn.axzo.workflow.core.engine.job.AsyncApproveTaskJobHandler;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.TaskService;
@ -18,6 +19,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask;
@ -28,7 +31,7 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask
* @author wangli
* @since 2024/1/4 15:50
*/
public class CustomApproveTaskAsyncCmd implements Command<Void>, Serializable {
public class CustomApproveTaskAsyncCmd extends AbstractCommand<Void> implements Serializable {
private static final Logger log = LoggerFactory.getLogger(CustomApproveTaskAsyncCmd.class);
private final BpmnTaskAuditDTO dto;
@ -37,6 +40,11 @@ public class CustomApproveTaskAsyncCmd implements Command<Void>, Serializable {
this.dto = dto;
}
@Override
public String paramToJsonString() {
return JSON.toJSONString(dto);
}
@Override
public Void execute(CommandContext commandContext) {
ProcessEngineConfigurationImpl processEngineConfiguration =

View File

@ -4,12 +4,14 @@ import cn.axzo.workflow.common.enums.BpmnFlowNodeType;
import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import com.alibaba.fastjson.JSON;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.context.Context;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
@ -20,7 +22,9 @@ import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE;
@ -38,7 +42,7 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask
* @author wangli
* @since 2024/1/4 15:50
*/
public class CustomApproveTaskCmd implements Command<Void>, Serializable {
public class CustomApproveTaskCmd extends AbstractCommand<Void> implements Serializable {
private static final Logger log = LoggerFactory.getLogger(CustomApproveTaskCmd.class);
private final String taskId;
@ -62,6 +66,18 @@ public class CustomApproveTaskCmd implements Command<Void>, Serializable {
*/
private List<BpmnFlowNodeType> nodeTypes;
@Override
public String paramToJsonString() {
Map<String, Object> params = new HashMap<>();
params.put("taskId", taskId);
params.put("advice", advice);
params.put("operationDesc", operationDesc);
params.put("attachmentList", JSON.toJSONString(attachmentList));
params.put("approver", JSON.toJSONString(approver));
params.put("nextApprover", JSON.toJSONString(nextApprover));
params.put("nodeTypes", JSON.toJSONString(nodeTypes));
return JSON.toJSONString(params);
}
public CustomApproveTaskCmd(BpmnTaskAuditDTO dto) {
this(dto, null);

View File

@ -3,10 +3,13 @@ package cn.axzo.workflow.core.engine.cmd;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
import cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper;
import com.alibaba.fastjson.JSON;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.task.api.Task;
@ -14,7 +17,9 @@ import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.util.CollectionUtils;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import static cn.axzo.workflow.common.constant.BpmnConstants.HIDDEN_ASSIGNEE_ID;
@ -22,8 +27,11 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_R
import static cn.axzo.workflow.common.constant.BpmnConstants.NO_ASSIGNEE;
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.DELETED;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING;
import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_ID_NOT_EXISTS;
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.ACTIVITY_BIZ_SET_ASSIGNEE_ERROR;
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.ACTIVITY_CANT_SET_ASSIGNEE;
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.PROCESS_CANT_SET_ASSIGNEE;
/**
* 自定的业务指定审批人命令实现
@ -31,7 +39,7 @@ import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.ACTIVITY_CANT_S
* @author wangli
* @since 2023/12/22 13:51
*/
public class CustomBizSpecifyAssigneeToTaskCmd implements Command<Boolean>, Serializable {
public class CustomBizSpecifyAssigneeToTaskCmd extends AbstractCommand<Boolean> implements Serializable {
private final String executionId;
private final List<BpmnTaskDelegateAssigner> addedAssigners;
@ -41,6 +49,14 @@ public class CustomBizSpecifyAssigneeToTaskCmd implements Command<Boolean>, Seri
this.addedAssigners = addedAssigners;
}
@Override
public String paramToJsonString() {
Map<String, Object> params = new HashMap<>();
params.put("executionId", executionId);
params.put("addedAssigners", addedAssigners);
return JSON.toJSONString(params);
}
@Override
public Boolean execute(CommandContext commandContext) {
ProcessEngineConfigurationImpl processEngineConfiguration =
@ -53,6 +69,8 @@ public class CustomBizSpecifyAssigneeToTaskCmd implements Command<Boolean>, Seri
validTask(task);
validProcessInstance(commandContext, task);
changeAssigneeSnapshot(commandContext, task);
addAssignee(commandContext, taskService, task);
@ -60,6 +78,20 @@ public class CustomBizSpecifyAssigneeToTaskCmd implements Command<Boolean>, Seri
return true;
}
private void validProcessInstance(CommandContext commandContext, Task task) {
ProcessEngineConfigurationImpl processEngineConfiguration =
CommandContextUtil.getProcessEngineConfiguration(commandContext);
HistoryService historyService = processEngineConfiguration.getHistoryService();
HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
if (Objects.isNull(processInstance)) {
throw new WorkflowEngineException(PROCESS_INSTANCE_ID_NOT_EXISTS, task.getProcessInstanceId());
}
if (!Objects.equals(PROCESSING.getStatus(), processInstance.getBusinessStatus())) {
throw new WorkflowEngineException(PROCESS_CANT_SET_ASSIGNEE);
}
}
private void changeAssigneeSnapshot(CommandContext commandContext, Task task) {
ProcessEngineConfigurationImpl processEngineConfiguration =
CommandContextUtil.getProcessEngineConfiguration(commandContext);
@ -85,9 +117,7 @@ public class CustomBizSpecifyAssigneeToTaskCmd implements Command<Boolean>, Seri
return;
}
addedAssigners.forEach(i -> {
CustomTaskHelper.addMultiTask(commandContext, (TaskEntity) task, i);
});
addedAssigners.forEach(i -> CustomTaskHelper.addMultiTask(commandContext, (TaskEntity) task, i));
taskService.setAssignee(task.getId(), HIDDEN_ASSIGNEE_ID);
((TaskEntity) task).setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + task.getId(), DELETED.getStatus());

View File

@ -5,7 +5,7 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
import cn.axzo.workflow.core.engine.job.AsyncCancelProcessInstanceHandler;
import cn.hutool.json.JSONUtil;
import org.flowable.common.engine.impl.interceptor.Command;
import com.alibaba.fastjson.JSON;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.HistoryService;
import org.flowable.engine.history.HistoricProcessInstance;
@ -23,7 +23,7 @@ import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INS
import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_CANT_CANCEL;
import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_NOT_EXISTS;
public class CustomCancelProcessInstanceAsyncCmd implements Command<Void>, Serializable {
public class CustomCancelProcessInstanceAsyncCmd extends AbstractCommand<Void> implements Serializable {
private final BpmnProcessInstanceCancelDTO dto;
@ -31,6 +31,11 @@ public class CustomCancelProcessInstanceAsyncCmd implements Command<Void>, Seria
this.dto = dto;
}
@Override
public String paramToJsonString() {
return JSON.toJSONString(dto);
}
@Override
public Void execute(CommandContext commandContext) {
String processInstanceId = dto.getProcessInstanceId(), tenantId = dto.getTenantId();
@ -81,4 +86,5 @@ public class CustomCancelProcessInstanceAsyncCmd implements Command<Void>, Seria
jobService.createAsyncJob(job, false);
jobService.scheduleAsyncJob(job);
}
}

View File

@ -1,9 +1,11 @@
package cn.axzo.workflow.core.engine.cmd;
import cn.axzo.framework.context.validation.SpringValidator;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
import cn.axzo.workflow.core.engine.operation.DeleteProcessInstanceOperation;
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
import com.alibaba.fastjson.JSON;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.HistoryService;
@ -12,6 +14,7 @@ import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.task.api.Task;
import org.springframework.util.StringUtils;
import java.io.Serializable;
import java.util.HashMap;
@ -41,7 +44,7 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.createVir
* @author wangli
* @since 2024/1/2 18:19
*/
public class CustomCancelProcessInstanceCmd implements Command<Void>, Serializable {
public class CustomCancelProcessInstanceCmd extends AbstractCommand<Void> implements Serializable {
private final String processInstanceId;
private final String tenantId;
private final String reason;
@ -58,6 +61,16 @@ public class CustomCancelProcessInstanceCmd implements Command<Void>, Serializab
this.extAxHiTaskInstService = extAxHiTaskInstService;
}
@Override
public String paramToJsonString() {
Map<String, Object> params = new HashMap<>();
params.put("processInstanceId", processInstanceId);
params.put("tenantId", tenantId);
params.put("reason", reason);
params.put("initiator", initiator);
return JSON.toJSONString(params);
}
@Override
public Void execute(CommandContext commandContext) {
ProcessEngineConfigurationImpl processEngineConfiguration =
@ -102,4 +115,5 @@ public class CustomCancelProcessInstanceCmd implements Command<Void>, Serializab
addComment(commandContext, task, COMMENT_TYPE_OPERATION_DESC, "已撤回");
return null;
}
}

View File

@ -10,6 +10,7 @@ import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.CustomProperty;
import org.flowable.bpmn.model.ServiceTask;
import org.flowable.common.engine.impl.interceptor.Command;
@ -27,12 +28,14 @@ import org.springframework.util.CollectionUtils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO;
import static cn.axzo.workflow.common.constant.BpmnConstants.NO_ASSIGNEE;
@ -45,7 +48,8 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.removeDup
* @author wangli
* @since 18/03/2024 11:33
*/
public class CustomCarbonCopyUserSelectorCmd implements Command<List<BpmnTaskDelegateAssigner>>, Serializable {
@Slf4j
public class CustomCarbonCopyUserSelectorCmd extends AbstractCommand<List<BpmnTaskDelegateAssigner>> implements Serializable {
private static final long serialVersionUID = 1L;
private final String processInstanceId;
@ -83,6 +87,15 @@ public class CustomCarbonCopyUserSelectorCmd implements Command<List<BpmnTaskDel
this.execution = execution;
}
@Override
public String paramToJsonString() {
Map<String, Object> params = new HashMap<>();
params.put("processInstanceId", processInstanceId);
params.put("carbons", carbons);
params.put("serviceVersion", serviceVersion);
return JSON.toJSONString(params);
}
@Override
public List<BpmnTaskDelegateAssigner> execute(CommandContext commandContext) {
if (CollectionUtils.isEmpty(carbons)) {
@ -97,6 +110,17 @@ public class CustomCarbonCopyUserSelectorCmd implements Command<List<BpmnTaskDel
} else {
executions.add((Execution) execution);
}
//流程为空表示已经执行完去历史版本获取
if (CollectionUtils.isEmpty(executions)) {
List<HistoricVariableInstance> hisVarInst = processEngineConfiguration.getHistoryService().createHistoricVariableInstanceQuery()
.processInstanceId(processInstanceId)
.variableName(INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + serviceTask.getId()).list();
if (!CollectionUtils.isEmpty(hisVarInst)) {
return (List<BpmnTaskDelegateAssigner>) hisVarInst.get(0).getValue();
}
log.warn("executions is empty,get historic task assigner list empty,processInstanceId: {},serviceTaskId: {}", processInstanceId, serviceTask.getId());
return Collections.emptyList();
}
List<BpmnTaskDelegateAssigner> assigners = new ArrayList<>();
carbons.forEach(carbon -> {
CarbonCopyObjectType carbonCopyObjectType = carbon.getCarbonCopyObjectType();
@ -108,6 +132,9 @@ public class CustomCarbonCopyUserSelectorCmd implements Command<List<BpmnTaskDel
case project_identity:
case project_position:
case government_role:
if (CollectionUtils.isEmpty(executions)) {
return;
}
CustomProperty property = new CustomProperty();
property.setName(carbonCopyObjectType.getType());
property.setSimpleValue(carbon.getSpecifyValue());
@ -116,6 +143,9 @@ public class CustomCarbonCopyUserSelectorCmd implements Command<List<BpmnTaskDel
serviceTask, (DelegateExecution) executions.get(0), false));
break;
case approver_relation:
if (CollectionUtils.isEmpty(executions)) {
return;
}
assigners.addAll(getApproverRelationUser(carbon, carbonCopyObjectType,
(DelegateExecution) executions.get(0), processEngineConfiguration, processInstanceId));
break;
@ -210,5 +240,4 @@ public class CustomCarbonCopyUserSelectorCmd implements Command<List<BpmnTaskDel
return assigners;
}
}

View File

@ -9,7 +9,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* TODO
* CommandContext 中的 WorkflowEngineException 进行日志降级
*
* @author wangli
* @since 2024/5/21 09:46

View File

@ -7,6 +7,7 @@ import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
import cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper;
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import org.flowable.common.engine.impl.cfg.IdGenerator;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.common.engine.impl.interceptor.Command;
@ -27,7 +28,9 @@ import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE;
@ -44,7 +47,7 @@ import static org.flowable.task.api.Task.DEFAULT_PRIORITY;
* @author wangli
* @since 2023/12/26 16:14
*/
public class CustomCommentTaskCmd implements Command<Void>, Serializable {
public class CustomCommentTaskCmd extends AbstractCommand<Void> implements Serializable {
private final String processInstanceId;
private final BpmnTaskDelegateAssigner operator;
private final String comment;
@ -63,6 +66,17 @@ public class CustomCommentTaskCmd implements Command<Void>, Serializable {
this.extAxHiTaskInstService = extAxHiTaskInstService;
}
@Override
public String paramToJsonString() {
Map<String, Object> params = new HashMap<>();
params.put("processInstanceId", processInstanceId);
params.put("operator", operator);
params.put("comment", comment);
params.put("commentExt", commentExt);
params.put("attachmentList", attachmentList);
return JSON.toJSONString(params);
}
@Override
public Void execute(CommandContext commandContext) {
ProcessEngineConfigurationImpl processEngineConfiguration =

View File

@ -5,6 +5,7 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
import cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper;
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
import com.alibaba.fastjson.JSON;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
@ -16,7 +17,9 @@ import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC;
@ -30,7 +33,7 @@ import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.DUMMY_TASK_NOT_
* @author wangli
* @since 2023/12/27 11:24
*/
public class CustomCompleteDummyTaskCmd implements Command<Void>, Serializable {
public class CustomCompleteDummyTaskCmd extends AbstractCommand<Void> implements Serializable {
private final String processInstanceId;
private final String taskId;
private final String flowNodeName;
@ -46,6 +49,16 @@ public class CustomCompleteDummyTaskCmd implements Command<Void>, Serializable {
this.extAxHiTaskInstService = extAxHiTaskInstService;
}
@Override
public String paramToJsonString() {
Map<String, Object> params = new HashMap<>();
params.put("processInstanceId", processInstanceId);
params.put("taskId", taskId);
params.put("flowNodeName", flowNodeName);
params.put("operationDesc", operationDesc);
return JSON.toJSONString(params);
}
@Override
public Void execute(CommandContext commandContext) {
ProcessEngineConfigurationImpl processEngineConfiguration =
@ -93,4 +106,5 @@ public class CustomCompleteDummyTaskCmd implements Command<Void>, Serializable {
taskService.setOwner(i.getId(), null);
});
}
}

View File

@ -3,6 +3,7 @@ package cn.axzo.workflow.core.engine.cmd;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO;
import cn.axzo.workflow.core.engine.job.AsyncCountersignUserTaskJobHandler;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.TaskService;
@ -16,17 +17,24 @@ import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTaskAssignerDuplicated;
public class CustomCountersignUserTaskAsyncCmd implements Command<Void>, Serializable {
public class CustomCountersignUserTaskAsyncCmd extends AbstractCommand<Void> implements Serializable {
private final BpmnTaskCountersignDTO dto;
public CustomCountersignUserTaskAsyncCmd(BpmnTaskCountersignDTO dto) {
this.dto = dto;
}
@Override
public String paramToJsonString() {
return JSON.toJSONString(dto);
}
@Override
public Void execute(CommandContext commandContext) {
ProcessEngineConfigurationImpl processEngineConfiguration =
@ -66,4 +74,5 @@ public class CustomCountersignUserTaskAsyncCmd implements Command<Void>, Seriali
jobService.createAsyncJob(job, false);
jobService.scheduleAsyncJob(job);
}
}

View File

@ -6,6 +6,7 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper;
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
@ -19,7 +20,9 @@ import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT;
@ -39,7 +42,7 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask
* @since 2023/12/25 14:05
*/
@Slf4j
public class CustomCountersignUserTaskCmd implements Command<Void>, Serializable {
public class CustomCountersignUserTaskCmd extends AbstractCommand<Void> implements Serializable {
private final BpmnCountersignTypeEnum countersignType;
private final String originTaskId;
@ -62,6 +65,18 @@ public class CustomCountersignUserTaskCmd implements Command<Void>, Serializable
this.extAxHiTaskInstService = extAxHiTaskInstService;
}
@Override
public String paramToJsonString() {
Map<String, Object> params = new HashMap<>();
params.put("countersignType", countersignType.getType());
params.put("originTaskId", originTaskId);
params.put("originTaskAssignee", originTaskAssignee);
params.put("advice", advice);
params.put("attachmentList", JSON.toJSONString(attachmentList));
params.put("targetTaskAssigneeList", JSON.toJSONString(targetTaskAssigneeList));
return JSON.toJSONString(params);
}
@Override
public Void execute(CommandContext commandContext) {
ProcessEngineConfigurationImpl processEngineConfiguration =
@ -139,4 +154,5 @@ public class CustomCountersignUserTaskCmd implements Command<Void>, Serializable
addComment(commandContext, virtualTask, COMMENT_TYPE_OPERATION_DESC, message.toString());
batchAddAttachment(commandContext, task.getProcessInstanceId(), task.getId(), attachmentList, originTaskAssignee);
}
}

View File

@ -5,6 +5,7 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
import cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper;
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
import com.alibaba.fastjson.JSON;
import org.flowable.common.engine.impl.cfg.IdGenerator;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.common.engine.impl.interceptor.Command;
@ -21,7 +22,9 @@ import org.springframework.util.CollectionUtils;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC;
@ -41,7 +44,7 @@ import static org.flowable.task.api.Task.DEFAULT_PRIORITY;
* @author wangli
* @since 2023/12/27 10:21
*/
public class CustomCreateDummyTaskCmd implements Command<String>, Serializable {
public class CustomCreateDummyTaskCmd extends AbstractCommand<String> implements Serializable {
private final String processInstanceId;
private final String flowNodeName;
private final String operationDesc;
@ -57,6 +60,16 @@ public class CustomCreateDummyTaskCmd implements Command<String>, Serializable {
this.extAxHiTaskInstService = extAxHiTaskInstService;
}
@Override
public String paramToJsonString() {
Map<String, Object> params = new HashMap<>();
params.put("processInstanceId", processInstanceId);
params.put("flowNodeName", flowNodeName);
params.put("operationDesc", operationDesc);
params.put("operator", operator);
return JSON.toJSONString(params);
}
/**
* 在同一个实例下,不允许创建多个执行中的虚拟任务节点
*
@ -139,4 +152,5 @@ public class CustomCreateDummyTaskCmd implements Command<String>, Serializable {
});
}
}
}

View File

@ -19,7 +19,9 @@ import org.springframework.util.CollectionUtils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverSpecify;
@ -30,7 +32,7 @@ import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApprove
* @since 2023/12/11 17:56
*/
@Slf4j
public class CustomForecastUserTaskAssigneeCmd implements Command<List<BpmnTaskDelegateAssigner>>, Serializable {
public class CustomForecastUserTaskAssigneeCmd extends AbstractCommand<List<BpmnTaskDelegateAssigner>> implements Serializable {
private final String processInstanceId;
private final UserTask userTask;
private final EngineExecutionStartListener engineExecutionStartListener;
@ -42,6 +44,13 @@ public class CustomForecastUserTaskAssigneeCmd implements Command<List<BpmnTaskD
this.engineExecutionStartListener = engineExecutionStartListener;
}
@Override
public String paramToJsonString() {
Map<String, Object> params = new HashMap<>();
params.put("processInstanceId", processInstanceId);
return JSON.toJSONString(params);
}
@Override
public List<BpmnTaskDelegateAssigner> execute(CommandContext commandContext) {
ProcessEngineConfigurationImpl processEngineConfiguration =
@ -81,4 +90,5 @@ public class CustomForecastUserTaskAssigneeCmd implements Command<List<BpmnTaskD
JSONUtil.toJsonStr(forecastAssigners));
return forecastAssigners;
}
}

View File

@ -23,6 +23,7 @@ import org.flowable.variable.api.history.HistoricVariableInstance;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@ -40,7 +41,7 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.removeDup
* @author wangli
* @since 2024/5/11 09:42
*/
public class CustomNoticeDestinationUserSelectorCmd implements Command<List<BpmnTaskDelegateAssigner>>, Serializable {
public class CustomNoticeDestinationUserSelectorCmd extends AbstractCommand<List<BpmnTaskDelegateAssigner>> implements Serializable {
private static final long serialVersionUID = 1L;
private final EngineExecutionStartListener engineExecutionStartListener;
private final BpmnHistoricTaskInstanceConverter historicTaskInstanceConverter;
@ -63,6 +64,17 @@ public class CustomNoticeDestinationUserSelectorCmd implements Command<List<Bpmn
this.initiator = initiator;
}
@Override
public String paramToJsonString() {
Map<String, Object> params = new HashMap<>();
params.put("serviceVersion", serviceVersion);
params.put("workspaceType", workspaceType);
params.put("noticeProperty", noticeProperty);
params.put("processInstanceId", processInstanceId);
params.put("initiator", initiator);
return JSON.toJSONString(params);
}
@Override
public List<BpmnTaskDelegateAssigner> execute(CommandContext commandContext) {
if (!noticeProperty.getSendMessage()) {
@ -170,5 +182,4 @@ public class CustomNoticeDestinationUserSelectorCmd implements Command<List<Bpmn
return noticeFlowElement;
}
}

View File

@ -1,9 +1,10 @@
package cn.axzo.workflow.core.engine.cmd;
import cn.axzo.framework.jackson.utility.JSON;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO;
import cn.axzo.workflow.core.engine.job.AsyncRejectTaskJobHandler;
import cn.hutool.json.JSONUtil;
import org.flowable.common.engine.impl.interceptor.Command;
import com.alibaba.fastjson.JSONObject;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.TaskService;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
@ -25,13 +26,18 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask
* @author wangli
* @since 2024/1/4 13:36
*/
public class CustomRejectionTaskAsyncCmd implements Command<Void>, Serializable {
public class CustomRejectionTaskAsyncCmd extends AbstractCommand<Void> implements Serializable {
private final BpmnTaskAuditDTO dto;
public CustomRejectionTaskAsyncCmd(BpmnTaskAuditDTO dto) {
this.dto = dto;
}
@Override
public String paramToJsonString() {
return JSON.toJSONString(dto);
}
@Override
public Void execute(CommandContext commandContext) {
ProcessEngineConfigurationImpl processEngineConfiguration =
@ -69,4 +75,5 @@ public class CustomRejectionTaskAsyncCmd implements Command<Void>, Serializable
jobService.createAsyncJob(job, false);
jobService.scheduleAsyncJob(job);
}
}

View File

@ -6,11 +6,12 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.core.engine.operation.DeleteProcessInstanceOperation;
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
import org.flowable.common.engine.impl.interceptor.Command;
import com.alibaba.fastjson.JSON;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.context.Context;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
@ -21,6 +22,7 @@ import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_DELETE_PROCESS_FLAG;
@ -42,7 +44,7 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask
* @author wangli
* @since 2024/1/4 13:36
*/
public class CustomRejectionTaskCmd implements Command<Void>, Serializable {
public class CustomRejectionTaskCmd extends AbstractCommand<Void> implements Serializable {
private final String taskId;
private final String advice;
@ -60,6 +62,17 @@ public class CustomRejectionTaskCmd implements Command<Void>, Serializable {
this.nodeTypes = dto.getNodeTypes();
}
@Override
public String paramToJsonString() {
Map<String, Object> params = new HashMap<>();
params.put("taskId", taskId);
params.put("advice", advice);
params.put("attachmentList", attachmentList);
params.put("approver", approver);
params.put("nodeTypes", nodeTypes);
return JSON.toJSONString(params);
}
@Override
public Void execute(CommandContext commandContext) {
ProcessEngineConfigurationImpl processEngineConfiguration =
@ -99,4 +112,5 @@ public class CustomRejectionTaskCmd implements Command<Void>, Serializable {
.planOperation(new DeleteProcessInstanceOperation(commandContext, task.getProcessInstanceId(),
extAxHiTaskInstService));
}
}

View File

@ -3,8 +3,8 @@ package cn.axzo.workflow.core.engine.cmd;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO;
import cn.axzo.workflow.core.engine.job.AsyncTransferUserTaskJobHandler;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.TaskService;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
@ -17,6 +17,8 @@ import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTaskAssignerDuplicated;
@ -24,7 +26,7 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask
/**
* 异步转交任务的命令执行器
*/
public class CustomTransferUserTaskAsyncCmd implements Command<Void>, Serializable {
public class CustomTransferUserTaskAsyncCmd extends AbstractCommand<Void> implements Serializable {
private final BpmnTaskTransferDTO dto;
@ -32,6 +34,11 @@ public class CustomTransferUserTaskAsyncCmd implements Command<Void>, Serializab
this.dto = dto;
}
@Override
public String paramToJsonString() {
return JSON.toJSONString(dto);
}
@Override
public Void execute(CommandContext commandContext) {
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
@ -65,4 +72,5 @@ public class CustomTransferUserTaskAsyncCmd implements Command<Void>, Serializab
jobService.createAsyncJob(job, false);
jobService.scheduleAsyncJob(job);
}
}

View File

@ -3,6 +3,7 @@ package cn.axzo.workflow.core.engine.cmd;
import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.common.engine.impl.interceptor.Command;
@ -18,7 +19,9 @@ import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.util.StringUtils;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
@ -43,7 +46,7 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask
* @author wangli
* @since 2023/12/22 10:22
*/
public class CustomTransferUserTaskCmd implements Command<Void>, Serializable {
public class CustomTransferUserTaskCmd extends AbstractCommand<Void> implements Serializable {
private final String originTaskId;
private final BpmnTaskDelegateAssigner originTaskAssignee;
@ -60,6 +63,16 @@ public class CustomTransferUserTaskCmd implements Command<Void>, Serializable {
this.targetTaskAssignee = targetTaskAssignee;
}
@Override
public String paramToJsonString() {
Map<String, Object> params = new HashMap<>();
params.put("originTaskId", originTaskId);
params.put("originTaskAssignee", originTaskAssignee);
params.put("advice", advice);
params.put("attachmentList", attachmentList);
params.put("targetTaskAssignee", targetTaskAssignee);
return JSON.toJSONString(params);
}
@Override
public Void execute(CommandContext commandContext) {
@ -125,4 +138,5 @@ public class CustomTransferUserTaskCmd implements Command<Void>, Serializable {
INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + task.getTaskDefinitionKey(),
originAssingeeList);
}
}

View File

@ -25,6 +25,8 @@ public interface MessagePushEvent extends FlowableEvent {
String getProcessDefinitionId();
String getProcessDefinitionKey();
String getCurrentTaskDefinitionKey();
String getTenantId();

View File

@ -26,21 +26,21 @@ import static cn.axzo.workflow.core.engine.event.MessagePushEventType.SMS;
public class MessagePushEventBuilder {
public static MessagePushEventImpl createEvent(MessagePushEventType type, List<BpmnTaskDelegateAssigner> assigners,
BpmnNoticeConf noticeConf, String processInstanceId,
BpmnNoticeConf noticeConf, String processInstanceId, String processDefinitionKey,
String tenantId, String taskId) {
switch (type) {
case NOTICE:
return createNoticeEvent(assigners, noticeConf, processInstanceId, tenantId, taskId);
return createNoticeEvent(assigners, noticeConf, processInstanceId, processDefinitionKey, tenantId, taskId);
case PENDING_PUSH:
throw new WorkflowEngineException(MESSAGE_PUSH_EVENT_BUILD_ERROR);
case PENDING_COMPLETE:
return createPendingCompleteEvent(assigners, noticeConf, processInstanceId, tenantId, taskId);
return createPendingCompleteEvent(assigners, noticeConf, processInstanceId, processDefinitionKey, tenantId, taskId);
case CARBON_COPY:
return createCarbonCopyEvent(assigners, noticeConf, processInstanceId, tenantId);
return createCarbonCopyEvent(assigners, noticeConf, processInstanceId, processDefinitionKey, tenantId);
case CARBON_COPY_COMPLETE:
return createCarbonCopyCompleteEvent(assigners, noticeConf, processInstanceId, tenantId);
return createCarbonCopyCompleteEvent(assigners, noticeConf, processInstanceId, processDefinitionKey, tenantId);
case SMS:
return createSmsEvent(assigners, noticeConf, processInstanceId, tenantId, taskId);
return createSmsEvent(assigners, noticeConf, processInstanceId, processDefinitionKey, tenantId, taskId);
default:
throw new WorkflowEngineException(MES_PUSH_OBJECT_BUILD_ERROR);
}
@ -48,9 +48,9 @@ public class MessagePushEventBuilder {
public static MessagePushEventImpl createNoticeEvent(List<BpmnTaskDelegateAssigner> assigners,
BpmnNoticeConf noticeConf
, String processInstanceId, String tenantId, String taskId) {
, String processInstanceId, String processDefinitionKey, String tenantId, String taskId) {
MessagePushEventImpl newEvent = new MessagePushEventImpl(NOTICE, assigners, noticeConf, processInstanceId,
tenantId, taskId);
processDefinitionKey, tenantId, taskId);
return newEvent;
}
@ -58,47 +58,54 @@ public class MessagePushEventBuilder {
BpmnNoticeConf noticeConf,
BpmnApproveConf processApproveConf,
String processInstanceId,
String processDefinitionId, String currentTaskDefinitionKey,
String processDefinitionId,
String processDefinitionKey,
String currentTaskDefinitionKey,
String tenantId, String taskId) {
MessagePushEventImpl newEvent = new MessagePushEventImpl(PENDING_PUSH, assigners, noticeConf, processApproveConf, processInstanceId,
processDefinitionId, currentTaskDefinitionKey, tenantId, taskId);
MessagePushEventImpl newEvent = new MessagePushEventImpl(PENDING_PUSH, assigners, noticeConf, processApproveConf,
processInstanceId, processDefinitionId, processDefinitionKey, currentTaskDefinitionKey, tenantId, taskId);
return newEvent;
}
public static MessagePushEventImpl createPendingCompleteEvent(List<BpmnTaskDelegateAssigner> assigners,
BpmnNoticeConf noticeConf, String processInstanceId,
String processDefinitionKey,
String tenantId, String taskId) {
MessagePushEventImpl newEvent = new MessagePushEventImpl(PENDING_COMPLETE, assigners, noticeConf,
processInstanceId,
tenantId, taskId);
processInstanceId, processDefinitionKey, tenantId, taskId);
return newEvent;
}
public static MessagePushEvent createPendingRollbackEvent(String processInstanceId, String tenantId, String taskId, BpmnNoticeConf noticeConf) {
return new MessagePushEventImpl(PENDING_ROLLBACK, null, noticeConf, processInstanceId, tenantId, taskId);
public static MessagePushEvent createPendingRollbackEvent(String processInstanceId, String processDefinitionKey,
String tenantId, String taskId, BpmnNoticeConf noticeConf) {
return new MessagePushEventImpl(PENDING_ROLLBACK, null, noticeConf, processInstanceId, processDefinitionKey, tenantId, taskId);
}
public static MessagePushEventImpl createCarbonCopyEvent(List<BpmnTaskDelegateAssigner> assigners,
BpmnNoticeConf noticeConf, String processInstanceId,
String processDefinitionKey,
String tenantId) {
MessagePushEventImpl newEvent = new MessagePushEventImpl(CARBON_COPY, assigners, noticeConf,
processInstanceId, tenantId, null);
processInstanceId, processDefinitionKey, tenantId, null);
return newEvent;
}
public static MessagePushEventImpl createCarbonCopyCompleteEvent(List<BpmnTaskDelegateAssigner> assigners,
BpmnNoticeConf noticeConf, String processInstanceId,
String processDefinitionKey,
String tenantId) {
MessagePushEventImpl newEvent = new MessagePushEventImpl(CARBON_COPY_COMPLETE, assigners, noticeConf,
processInstanceId, tenantId, null);
processInstanceId, processDefinitionKey, tenantId, null);
return newEvent;
}
public static MessagePushEventImpl createSmsEvent(List<BpmnTaskDelegateAssigner> assigners,
BpmnNoticeConf noticeConf,
String processInstanceId, String tenantId, String taskId) {
String processInstanceId,
String processDefinitionKey,
String tenantId, String taskId) {
MessagePushEventImpl newEvent = new MessagePushEventImpl(SMS, assigners, noticeConf, processInstanceId,
tenantId, taskId);
processDefinitionKey, tenantId, taskId);
return newEvent;
}
}

View File

@ -25,6 +25,7 @@ public class MessagePushEventImpl implements MessagePushEvent {
private BpmnApproveConf processApproveConfig;
private String processInstanceId;
private String processDefinitionId;
private String processDefinitionKey;
private String currentTaskDefinitionKey;
private String tenantId;
private String taskId;
@ -48,11 +49,13 @@ public class MessagePushEventImpl implements MessagePushEvent {
* @param tenantId
* @param taskId
*/
public MessagePushEventImpl(FlowableEventType type, List<BpmnTaskDelegateAssigner> assigners, BpmnNoticeConf noticeConfig, String processInstanceId, String tenantId, String taskId) {
public MessagePushEventImpl(FlowableEventType type, List<BpmnTaskDelegateAssigner> assigners, BpmnNoticeConf noticeConfig,
String processInstanceId, String processDefinitionKey, String tenantId, String taskId) {
this.type = type;
this.assigners = assigners;
this.noticeConfig = noticeConfig;
this.processInstanceId = processInstanceId;
this.processDefinitionKey = processDefinitionKey;
this.tenantId = tenantId;
this.taskId = taskId;
}
@ -75,7 +78,7 @@ public class MessagePushEventImpl implements MessagePushEvent {
public MessagePushEventImpl(FlowableEventType type, List<BpmnTaskDelegateAssigner> assigners,
BpmnNoticeConf noticeConfig,
BpmnApproveConf processApproveConfig,
String processInstanceId, String processDefinitionId,
String processInstanceId, String processDefinitionId, String processDefinitionKey,
String currentTaskDefinitionKey, String tenantId, String taskId) {
this.type = type;
this.assigners = assigners;
@ -141,6 +144,15 @@ public class MessagePushEventImpl implements MessagePushEvent {
this.processDefinitionId = processDefinitionId;
}
@Override
public String getProcessDefinitionKey() {
return processDefinitionKey;
}
public void setProcessDefinitionKey(String processDefinitionKey) {
this.processDefinitionKey = processDefinitionKey;
}
@Override
public String getCurrentTaskDefinitionKey() {
return currentTaskDefinitionKey;

View File

@ -0,0 +1,89 @@
package cn.axzo.workflow.core.engine.interceptor;
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
import cn.axzo.workflow.core.common.utils.TraceUtil;
import cn.axzo.workflow.core.engine.cmd.AbstractCommand;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.exceptions.PersistenceException;
import org.flowable.common.engine.impl.interceptor.AbstractCommandInterceptor;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandConfig;
import org.flowable.common.engine.impl.interceptor.CommandExecutor;
import static cn.axzo.workflow.core.common.code.FlowableEngineRespCode.ENGINE_ASYNC_COMMAND_EXECUTION_RETRY_GIVE_UP;
/**
* 基于 RetryInterceptor 的命令重试拦截器, 本意想用来处理多人同时操作同一个任务, 但会存在超过重试次数后,会丢弃原有的命令.
*
* @author wangli
* @since 2024/7/1 13:51
*/
@Slf4j
public class CustomRetryInterceptor extends AbstractCommandInterceptor {
protected int numOfRetries = 3;
protected int waitTimeInMs = 60;
protected int waitIncreaseFactor = 5;
@Override
public <T> T execute(CommandConfig config, Command<T> command, CommandExecutor commandExecutor) {
long waitTime = waitTimeInMs;
int failedAttempts = 0;
do {
if (failedAttempts > 0) {
log.warn("Waiting for {}ms before retrying the command.", waitTime);
waitBeforeRetry(waitTime);
waitTime *= waitIncreaseFactor;
}
try {
// try to execute the command
if (AbstractCommand.class.isAssignableFrom(command.getClass())) {
// 如果在以后,重试三次也不能解决的话, 可以利用这里的拿到的参数,重新自动构造CMD,并执行.
log.info("traceId:{} Executing command params: {}", TraceUtil.traceId(),
((AbstractCommand<T>) command).paramToJsonString());
}
return next.execute(config, command, commandExecutor);
} catch (PersistenceException e) {
log.warn("Caught persistence exception: {}", e.getMessage(), e);
}
failedAttempts++;
} while (failedAttempts <= numOfRetries);
throw new WorkflowEngineException(ENGINE_ASYNC_COMMAND_EXECUTION_RETRY_GIVE_UP, String.valueOf(numOfRetries));
}
protected void waitBeforeRetry(long waitTime) {
try {
Thread.sleep(waitTime);
} catch (InterruptedException e) {
log.warn("I am interrupted while waiting for a retry.");
}
}
public void setNumOfRetries(int numOfRetries) {
this.numOfRetries = numOfRetries;
}
public void setWaitIncreaseFactor(int waitIncreaseFactor) {
this.waitIncreaseFactor = waitIncreaseFactor;
}
public void setWaitTimeInMs(int waitTimeInMs) {
this.waitTimeInMs = waitTimeInMs;
}
public int getNumOfRetries() {
return numOfRetries;
}
public int getWaitIncreaseFactor() {
return waitIncreaseFactor;
}
public int getWaitTimeInMs() {
return waitTimeInMs;
}
}

View File

@ -19,15 +19,16 @@ public class CustomWorkflowEngineExceptionHandler implements AsyncRunnableExecut
@Override
public boolean handleException(JobServiceConfiguration jobServiceConfiguration, JobInfo job, Throwable e) {
Throwable rootCause = getRootCause(e);
if (rootCause.getClass().isAssignableFrom(WorkflowEngineException.class)) {
WorkflowEngineException workflowEngineException = (WorkflowEngineException) rootCause;
if (Objects.equals(workflowEngineException.getCode(), "99806020")) {
log.info("AsyncApproveTaskJobHandler execute exception code: {} info: {}",
workflowEngineException.getCode(), rootCause.getMessage(), rootCause);
return true;
}
}
return false;
// if (rootCause.getClass().isAssignableFrom(WorkflowEngineException.class)) {
// WorkflowEngineException workflowEngineException = (WorkflowEngineException) rootCause;
// if (Objects.equals(workflowEngineException.getCode(), "99806020")) {
// log.info("AsyncApproveTaskJobHandler execute exception code: {} info: {}",
// workflowEngineException.getCode(), rootCause.getMessage(), rootCause);
// return true;
// }
// }
log.warn("Async Runnable Execution Exception: {}", rootCause.getMessage(), e);
return WorkflowEngineException.class.isAssignableFrom(rootCause.getClass());
}
private Throwable getRootCause(Throwable throwable) {

View File

@ -38,6 +38,7 @@ import java.util.concurrent.atomic.AtomicReference;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT;
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getCarbonCopyConfigs;
import static cn.axzo.workflow.core.listener.AbstractBpmnEventListener.parseProcessDefinitionKey;
/**
* 抄送功能的具体实现
@ -110,6 +111,7 @@ public class EngineCarbonCopyEventListener implements JavaDelegate {
MessagePushEventImpl event = MessagePushEventBuilder.createEvent(MessagePushEventType.CARBON_COPY,
carbonUsers, bpmnNoticeConf, execution.getProcessInstanceId(),
parseProcessDefinitionKey(execution.getProcessDefinitionId()),
execution.getTenantId(), getCarbonTaskId(execution));
eventDispatcher.dispatchEvent(event, processEngineConfiguration.getEngineCfgKey());
}

View File

@ -8,7 +8,6 @@ import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper;
import cn.axzo.workflow.core.engine.cmd.CustomNoticeDestinationUserSelectorCmd;
import cn.axzo.workflow.core.engine.event.MessagePushEventBuilder;
import cn.axzo.workflow.core.engine.event.MessagePushEventImpl;
import cn.axzo.workflow.core.engine.event.MessagePushEventType;
import cn.axzo.workflow.core.listener.BpmnProcessEventListener;
import cn.axzo.workflow.core.service.converter.BpmnHistoricTaskInstanceConverter;
import cn.hutool.json.JSONUtil;
@ -48,6 +47,7 @@ import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROV
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.CANCELLED;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.DELETED;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.REJECTED;
import static cn.axzo.workflow.core.engine.event.MessagePushEventType.NOTICE;
/**
* 引擎全局的流程实例事件监听
@ -157,8 +157,9 @@ public class EngineProcessInstanceEventListener extends AbstractFlowableEngineEv
List<BpmnTaskDelegateAssigner> assigners = processEngineConfiguration.getCommandExecutor()
.execute(new CustomNoticeDestinationUserSelectorCmd(engineExecutionStartListener, historicTaskInstanceConverter,
serviceVersion, workspaceType, config.getNotice(), event.getProcessInstanceId(), assigner));
MessagePushEventImpl messagePushEvent = MessagePushEventBuilder.createEvent(MessagePushEventType.NOTICE,
assigners, config, processInstance.getProcessInstanceId(), processInstance.getTenantId(), null);
MessagePushEventImpl messagePushEvent = MessagePushEventBuilder.createEvent(NOTICE,
assigners, config, processInstance.getProcessInstanceId(), processInstance.getProcessDefinitionKey(),
processInstance.getTenantId(), null);
log.info("发送通知消息: {}", JSONUtil.toJsonStr(messagePushEvent));
eventDispatcher.dispatchEvent(messagePushEvent, processEngineConfiguration.getEngineCfgKey());
}

View File

@ -3,6 +3,7 @@ package cn.axzo.workflow.core.listener;
import cn.axzo.workflow.core.common.context.OperationContext;
import cn.hutool.json.JSONUtil;
import org.slf4j.MDC;
import org.springframework.util.StringUtils;
import static cn.azxo.framework.common.constatns.Constants.CTX_LOG_ID_MDC;
@ -33,4 +34,11 @@ public abstract class AbstractBpmnEventListener<T extends OperationContext> impl
protected String buildCacheKey(String apiUrl, Object request) {
return apiUrl + JSONUtil.toJsonStr(request);
}
public static String parseProcessDefinitionKey(String processDefinitionId) {
if (!StringUtils.hasText(processDefinitionId)) {
return "";
}
return processDefinitionId.split(":")[0];
}
}

View File

@ -17,7 +17,7 @@ import java.util.List;
import java.util.Optional;
import java.util.function.BiConsumer;
import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_APP;
import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_APPLICATION;
/**
* 默认的 RocketMQ 事件生产者的装饰器
@ -68,7 +68,9 @@ public class CustomRocketMQEventProducer extends RocketMQEventProducer {
newHeaders.put(TraceUtils.TRACE_ID, TraceUtils.getOrCreateTraceId());
newHeaders.put(TraceUtils.CTX_LOG_ID, TraceUtils.getOrCreateTraceId());
newHeaders.put(TraceUtils.TRACE_ID_IN_MDC, TraceUtils.getOrCreateTraceId());
newHeaders.put(MQ_OWNERSHIP_APP, applicationName);
// FIXME
// newHeaders.put(MQ_OWNERSHIP_APPLICATION, applicationName);
newHeaders.put(MQ_OWNERSHIP_APPLICATION, "senna");
final Context copiedContext = context.toBuilder().headers(newHeaders).build();
Runnable runnable = () -> {
@ -94,7 +96,7 @@ public class CustomRocketMQEventProducer extends RocketMQEventProducer {
} else {
// 并发会导致事件时序出现问题. 所以串行执行
log.info("runnable not transaction event={}", copiedEvent.toJsonString());
getAfterCommitExecutor().executeAndRollback(() -> runnable.run(), () -> rollbackRunnable.run());
getAfterCommitExecutor().executeAndRollback(runnable, rollbackRunnable);
}
List<Runnable> runnables = getAfterCommitExecutor().getRunnables();

View File

@ -34,5 +34,9 @@ public class ExtAxProperty extends BaseEntity<ExtAxProperty> {
@TableField("value")
private String value;
/**
* 接入方是否使用了 manageable
*/
@TableField("manageable")
private Boolean manageable;
}

View File

@ -86,9 +86,12 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.Nullable;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Collections;
@ -102,6 +105,7 @@ import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_SERVER_NAME;
import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION;
import static cn.axzo.workflow.common.constant.BpmnConstants.BIZ_ORG_RELATION;
import static cn.axzo.workflow.common.constant.BpmnConstants.BPM_MODEL_CATEGORY;
@ -112,6 +116,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_PROCESS_AG
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_PROCESS_WORKSPACE_TYPE;
import static cn.axzo.workflow.common.constant.BpmnConstants.OLD_INTERNAL_INITIATOR;
import static cn.axzo.workflow.common.constant.BpmnConstants.PENDING_TEMPLATE_VARIABLE;
import static cn.axzo.workflow.common.constant.BpmnConstants.PROCESS_OWNERSHIP_APPLICATION;
import static cn.axzo.workflow.common.constant.BpmnConstants.WORKFLOW_ENGINE_VERSION;
import static cn.axzo.workflow.common.enums.ApprovalMethodEnum.autoPassed;
import static cn.axzo.workflow.common.enums.ApprovalMethodEnum.autoRejection;
@ -320,6 +325,9 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
dto.getVariables().put(INTERNAL_PROCESS_AGENT, StringUtils.isNotBlank(definition.getTenantId()));
dto.getVariables().put(CREATE_INSTANCE_PARAMS, JSONUtil.toJsonStr(dto));
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
dto.getVariables().put(PROCESS_OWNERSHIP_APPLICATION, request.getHeader(HEADER_SERVER_NAME));
// dto.getVariables().put(MQ_OWNERSHIP_APPLICATION, );
// if (Objects.nonNull(dto.getNextApprover())) {
// BpmnTaskDelegateAssigner nextApprover = dto.getNextApprover();
// nextApprover.setTenantId(Objects.nonNull(nextApprover.getTenantId()) ? nextApprover.getTenantId

View File

@ -458,7 +458,7 @@ public class BpmnProcessModelServiceImpl implements BpmnProcessModelService {
if (CollectionUtils.isEmpty(list)) {
return Collections.emptyList();
}
return list.stream().map(Model::getTenantId).collect(Collectors.toList());
return list.stream().map(Model::getTenantId).distinct().collect(Collectors.toList());
}
private void updateProcessDefinitionSuspended(String deploymentId) {

View File

@ -628,6 +628,7 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService {
MessagePushEventImpl event = MessagePushEventBuilder.createEvent(MessagePushEventType.valueOf(type),
Lists.newArrayList(assigner), noticeConfig.orElse(null),
processInstance.getProcessInstanceId(),
processInstance.getProcessDefinitionKey(),
processInstance.getTenantId(), task.getId());
event.setProcessInstanceId(processInstance.getProcessInstanceId());
event.setTenantId(processInstance.getTenantId());

View File

@ -5,6 +5,9 @@ import cn.axzo.workflow.core.repository.mapper.ExtAxPropertyMapper;
import cn.axzo.workflow.core.service.ExtAxPropertyService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
@ -23,18 +26,21 @@ public class ExtAxPropertyServiceImpl implements ExtAxPropertyService {
@Resource
private ExtAxPropertyMapper mapper;
@CacheEvict(value = "property", key = "#property.name")
@Override
public ExtAxProperty add(ExtAxProperty property) {
mapper.insert(property);
return property;
}
@CachePut(value = "property", key = "#property.name")
@Override
public ExtAxProperty update(ExtAxProperty property) {
mapper.updateById(property);
return property;
}
@Cacheable(value = "property", key = "#name")
@Override
public Optional<ExtAxProperty> getByName(String name) {
if (!StringUtils.hasText(name)) {

View File

@ -1,7 +1,9 @@
package cn.axzo.workflow.core.service.support;
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
import cn.axzo.workflow.core.engine.cmd.AbstractCommand;
import cn.azxo.framework.common.utils.StringUtils;
import com.alibaba.fastjson.JSON;
import org.flowable.common.engine.api.delegate.Expression;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
@ -10,6 +12,8 @@ import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import static cn.axzo.workflow.core.common.code.FlowableEngineRespCode.ENGINE_EXECUTION_LOST_ID_ERROR;
@ -20,7 +24,7 @@ import static cn.axzo.workflow.core.common.code.FlowableEngineRespCode.ENGINE_EX
* @author wangli
* @since 2023/10/9 19:30
*/
public class ExpressionConditionCmd implements Command<Boolean>, Serializable {
public class ExpressionConditionCmd extends AbstractCommand<Boolean> implements Serializable {
protected final RuntimeService runtimeService;
protected final ProcessEngineConfigurationImpl processEngineConfiguration;
protected final String processInstanceId;
@ -35,6 +39,14 @@ public class ExpressionConditionCmd implements Command<Boolean>, Serializable {
this.exp = exp;
}
@Override
public String paramToJsonString() {
Map<String, Object> params = new HashMap<>();
params.put("processInstanceId", processInstanceId);
params.put("exp", exp);
return JSON.toJSONString(params);
}
@Override
public Boolean execute(CommandContext commandContext) {
Expression expression = processEngineConfiguration.getExpressionManager().createExpression(this.exp);

View File

@ -1,5 +1,8 @@
package org.flowable.engine.impl.cmd;
import cn.axzo.workflow.core.engine.cmd.AbstractCommand;
import com.alibaba.fastjson.JSON;
import liquibase.pro.packaged.M;
import org.flowable.common.engine.api.FlowableException;
import org.flowable.common.engine.api.FlowableObjectNotFoundException;
import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType;
@ -22,6 +25,9 @@ import org.flowable.task.api.Task;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import java.io.InputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/**
* 覆盖 Flowable 自带的 CreateAttachmentCmd, 由于 Flowable 5 的实现导致异常需要覆盖
@ -29,7 +35,7 @@ import java.io.InputStream;
* @author Tom Baeyens
* @author Joram Barrez
*/
public class CreateAttachmentCmd implements Command<Attachment> {
public class CreateAttachmentCmd extends AbstractCommand<Attachment> implements Serializable {
protected String attachmentType;
protected String taskId;
@ -50,6 +56,19 @@ public class CreateAttachmentCmd implements Command<Attachment> {
this.url = url;
}
@Override
public String paramToJsonString() {
Map<String, Object> params = new HashMap<>();
params.put("attachmentType", attachmentType);
params.put("taskId", taskId);
params.put("processInstanceId", processInstanceId);
params.put("attachmentName", attachmentName);
params.put("attachmentDescription", attachmentDescription);
// params.put("content", content);
params.put("url", url);
return JSON.toJSONString(params);
}
@Override
public Attachment execute(CommandContext commandContext) {

View File

@ -0,0 +1,3 @@
alter table ext_ax_property
add manageable boolean default false null comment '接入方是否使用了 manageable';

View File

@ -10,6 +10,7 @@
<modelVersion>4.0.0</modelVersion>
<artifactId>workflow-engine-server</artifactId>
<name>Workflow Engine Server</name>
<properties>
<maven.compiler.source>8</maven.compiler.source>
@ -20,6 +21,10 @@
<redisson.version>3.25.0</redisson.version>
</properties>
<dependencies>
<!--<dependency>
<groupId>cn.axzo.workflow</groupId>
<artifactId>workflow-engine-spring-boot-starter</artifactId>
</dependency>-->
<dependency>
<groupId>cn.axzo.framework</groupId>
<artifactId>axzo-web-spring-boot-starter</artifactId>
@ -95,10 +100,10 @@
<groupId>cn.axzo.maokai</groupId>
<artifactId>maokai-api</artifactId>
</dependency>
<dependency>
<groupId>cn.axzo.tyr</groupId>
<artifactId>tyr-api</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>cn.axzo.tyr</groupId>-->
<!-- <artifactId>tyr-api</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>cn.axzo.karma</groupId>
<artifactId>karma-api</artifactId>

View File

@ -1,9 +1,11 @@
package cn.axzo.workflow.server;
import liquibase.pro.packaged.E;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@ -12,6 +14,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
@ComponentScan({"cn.axzo.workflow", "cn.axzo.maokai"})
@SpringBootApplication(exclude = RabbitAutoConfiguration.class)
@EnableTransactionManagement
@EnableCaching
public class WorkflowEnginApplication {
public static void main(String[] args) {

View File

@ -2,6 +2,7 @@ package cn.axzo.workflow.server.advice;
import cn.axzo.framework.autoconfigure.web.exception.RespErrorCodeMappingProperties;
import cn.axzo.framework.autoconfigure.web.exception.handler.AbstractExceptionApiResultHandler;
import cn.axzo.framework.domain.web.code.BaseCode;
import cn.axzo.framework.domain.web.code.IRespCode;
import cn.axzo.framework.domain.web.code.RespCode;
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
@ -30,8 +31,8 @@ public class FlowableExceptionResultHandlerAdvice extends AbstractExceptionApiRe
protected IRespCode decode(FlowableException ex, IRespCode fallbackCode) {
log.warn("发现 FlowableException Error: ", ex);
if (Objects.nonNull(ex.getCause()) && ex.getCause() instanceof WorkflowEngineException) {
return new RespCode(UNAVAILABLE_FOR_LEGAL_REASONS.getCode(), ex.getCause().getMessage());
return new RespCode(BaseCode.SUCCESS.getCode(), ex.getCause().getMessage());
}
return new RespCode(UNAVAILABLE_FOR_LEGAL_REASONS.getCode(), ex.getMessage());
return new RespCode(BaseCode.SUCCESS.getCode(), ex.getMessage());
}
}

View File

@ -0,0 +1,31 @@
package cn.axzo.workflow.server.advice;
import cn.axzo.framework.autoconfigure.web.exception.RespErrorCodeMappingProperties;
import cn.axzo.framework.autoconfigure.web.exception.handler.AbstractExceptionApiResultHandler;
import cn.axzo.framework.domain.web.code.BaseCode;
import cn.axzo.framework.domain.web.code.IRespCode;
import cn.axzo.framework.domain.web.code.RespCode;
import org.flowable.common.engine.api.FlowableOptimisticLockingException;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.springframework.stereotype.Component;
import static cn.axzo.framework.domain.web.code.BaseCode.UNAVAILABLE_FOR_LEGAL_REASONS;
/**
* 降级 FlowableOptimisticLockingException 异常该异常在 Flowable 框架中是可以忽略的
*
* @author wangli
* @see CommandContext#logException()
* @since 2024/6/19 17:32
*/
@Component
public class FlowableOptimisticLockingExceptionHandlerAdvice extends AbstractExceptionApiResultHandler<FlowableOptimisticLockingException> {
public FlowableOptimisticLockingExceptionHandlerAdvice(RespErrorCodeMappingProperties properties) {
super(properties);
}
@Override
protected IRespCode decode(FlowableOptimisticLockingException ex, IRespCode fallbackCode) {
return new RespCode(BaseCode.SUCCESS.getCode(), ex.getMessage());
}
}

View File

@ -0,0 +1,36 @@
package cn.axzo.workflow.server.advice;
import cn.axzo.framework.autoconfigure.web.exception.RespErrorCodeMappingProperties;
import cn.axzo.framework.autoconfigure.web.exception.handler.AbstractExceptionApiResultHandler;
import cn.axzo.framework.domain.web.code.BaseCode;
import cn.axzo.framework.domain.web.code.IRespCode;
import cn.axzo.framework.domain.web.code.RespCode;
import cn.axzo.workflow.client.feign.bpmn.ProcessActivityApi;
import cn.axzo.workflow.client.feign.bpmn.ProcessInstanceApi;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO;
import org.springframework.stereotype.Component;
import java.sql.SQLIntegrityConstraintViolationException;
/**
* 处理多个接口同时操作一个流程实例时可能会抛出数据库的异常这种异常是可以被忽略的
* <p>
* 例如 {@link ProcessActivityApi#setAssignee(BpmnActivitySetAssigneeDTO)} {@link ProcessInstanceApi#abortProcessInstance(BpmnProcessInstanceAbortDTO)}
* 两个接口并发访问时由于 abort 先执行完并提交事务后setAssignee 方法内虽然有判断实例状态但最后事务提交时突然发现实例状态被中止了就会抛出异常
*
* @author wangli
* @since 2024/6/20 09:42
*/
@Component
public class SQLIntegrityConstraintViolationExceptionHandlerAdvice extends AbstractExceptionApiResultHandler<SQLIntegrityConstraintViolationException> {
public SQLIntegrityConstraintViolationExceptionHandlerAdvice(RespErrorCodeMappingProperties properties) {
super(properties);
}
@Override
protected IRespCode decode(SQLIntegrityConstraintViolationException ex, IRespCode fallbackCode) {
return new RespCode(BaseCode.SUCCESS.getCode(), ex.getMessage());
}
}

View File

@ -1,8 +1,6 @@
package cn.axzo.workflow.server.common.annotation;
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
import cn.axzo.workflow.server.common.util.DingTalkUtils;
import cn.azxo.framework.common.utils.LogUtil;
import lombok.extern.slf4j.Slf4j;
import static cn.axzo.workflow.server.common.aspectj.RepeatSubmitAspect.argsArrayToString;
@ -71,10 +69,11 @@ public enum ReporterType {
public abstract void executeAction(String profile, String title, Boolean sendDingTalk, Object[] args, String shortString, Throwable e, Boolean downgrade);
private static void logWarn(Throwable throwable, String shortString) {
if (throwable instanceof WorkflowEngineException) {
log.warn("引擎内部正常业务异常类型,日志降级: " + throwable.getMessage(), throwable);
} else {
LogUtil.error(LogUtil.ErrorType.ERROR_BUSINESS, shortString, throwable.getMessage(), throwable);
}
// 由于框架底层 AbstractExceptionApiResultHandler 默认会打印所以此处都只是降级打印
// if (throwable instanceof WorkflowEngineException) {
log.warn("引擎内部正常业务异常类型,日志降级: " + throwable.getMessage(), throwable);
// } else {
// LogUtil.error(LogUtil.ErrorType.ERROR_BUSINESS, shortString, throwable.getMessage(), throwable);
// }
}
}

View File

@ -4,6 +4,7 @@ import cn.axzo.workflow.core.common.event.ApiLogEvent;
import cn.axzo.workflow.server.common.annotation.EnvConfig;
import cn.axzo.workflow.server.common.annotation.ErrorReporter;
import cn.axzo.workflow.server.common.config.property.WorkflowProperties;
import com.google.common.collect.Lists;
import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
@ -26,6 +27,7 @@ import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_API_VERSION;
@ -50,6 +52,7 @@ public class ErrorReportAspect implements Ordered {
private ApplicationEventPublisher applicationEventPublisher;
@Resource
private WorkflowProperties workflowProperties;
private static List<String> methodNames = Lists.newArrayList("HealthCheckController.checkDeath()");
@Override
public int getOrder() {
@ -73,6 +76,10 @@ public class ErrorReportAspect implements Ordered {
watch.stop();
log.info("StopWatch '{}': running time = {} 's", watch.getLastTaskName(), watch.getTotalTimeSeconds());
if (!methodNames.contains(watch.getLastTaskName())) {
log.info("StopWatch '{}': running time = {} 's", watch.getLastTaskName(), watch.getTotalTimeSeconds());
}
if (!signature.toShortString().contains("ExtAxApiLogServiceImpl")) {
String type = getType(joinPoint);
ApiLogEvent event = new ApiLogEvent(MDC.get(CTX_LOG_ID_MDC),

View File

@ -1,6 +1,5 @@
package cn.axzo.workflow.server.common.filter;
import cn.azxo.framework.common.constatns.Constants;
import cn.hutool.core.util.IdUtil;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
@ -9,6 +8,7 @@ import org.apache.skywalking.apm.toolkit.trace.TraceContext;
import org.slf4j.MDC;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
@ -18,6 +18,7 @@ import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import static cn.axzo.workflow.common.constant.LogFieldConstants.X_REQUEST_ID;
import static cn.azxo.framework.common.constatns.Constants.CTX_LOG_ID_MDC;
/**
* Http接口日志记录
@ -44,18 +45,18 @@ public class HttpTraceLogFilter extends OncePerRequestFilter implements Ordered
} else {
MDC.put(X_REQUEST_ID, requestId);
}
String ctxLogId = request.getHeader(Constants.CTX_LOG_ID_MDC);
String ctxLogId = request.getHeader(CTX_LOG_ID_MDC);
if (Strings.isNullOrEmpty(ctxLogId)) {
MDC.put(Constants.CTX_LOG_ID_MDC, getTraceId());
MDC.put(CTX_LOG_ID_MDC, getTraceId());
} else {
MDC.put(Constants.CTX_LOG_ID_MDC, ctxLogId);
MDC.put(CTX_LOG_ID_MDC, ctxLogId);
}
try {
filterChain.doFilter(request, response);
} finally {
response.setHeader(Constants.CTX_LOG_ID_MDC, MDC.get(Constants.CTX_LOG_ID_MDC));
response.setHeader(X_REQUEST_ID, MDC.get(Constants.CTX_LOG_ID_MDC));
response.setHeader(CTX_LOG_ID_MDC, MDC.get(CTX_LOG_ID_MDC));
response.setHeader(X_REQUEST_ID, MDC.get(CTX_LOG_ID_MDC));
MDC.clear();
}
}
@ -64,4 +65,10 @@ public class HttpTraceLogFilter extends OncePerRequestFilter implements Ordered
String contextTraceId = TraceContext.traceId();
return Strings.isNullOrEmpty(contextTraceId) ? IdUtil.fastSimpleUUID() : contextTraceId;
}
public static String traceId() {
String xRequestId = MDC.get(X_REQUEST_ID);
return StringUtils.hasText(xRequestId) ? xRequestId : MDC.get(CTX_LOG_ID_MDC);
}
}

View File

@ -1,26 +0,0 @@
package cn.axzo.workflow.server.common.hook;
import org.springframework.context.SmartLifecycle;
/**
* TODO
*
* @author wangli
* @since 2024/6/6 14:35
*/
public class NacosShutdownHook implements SmartLifecycle {
@Override
public void start() {
}
@Override
public void stop() {
}
@Override
public boolean isRunning() {
return false;
}
}

View File

@ -3,6 +3,7 @@ package cn.axzo.workflow.server.common.interceptor;
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
import cn.axzo.workflow.core.repository.entity.ExtAxProperty;
import cn.axzo.workflow.core.service.ExtAxPropertyService;
import cn.axzo.workflow.server.common.util.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.springframework.beans.factory.annotation.Autowired;
@ -12,14 +13,17 @@ import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.Duration;
import java.util.Enumeration;
import java.util.Objects;
import java.util.Optional;
import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_API_VERSION;
import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT;
import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_HTTP_CLIENT_VALUE;
import static cn.axzo.workflow.client.config.WorkflowRequestInterceptor.HEADER_SERVER_NAME;
import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION_130;
import static cn.axzo.workflow.common.constant.StarterConstants.ENABLE_MANAGEABLE;
import static cn.axzo.workflow.core.common.code.OtherRespCode.CLIENT_VERSION_SUPPORT;
import static cn.axzo.workflow.core.common.code.OtherRespCode.MICRO_SERVER_NEED_REBUILD;
@ -36,6 +40,8 @@ public class RequestHeaderContextInterceptor implements HandlerInterceptor {
private String serviceVersion;
@Autowired
private ExtAxPropertyService extAxPropertyService;
private static final ThreadLocal<String> KEY_CACHE = new ThreadLocal<>();
private static final String REPEAT_KEY = "global:api_application:";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
@ -74,28 +80,52 @@ public class RequestHeaderContextInterceptor implements HandlerInterceptor {
private void recordClientInfo(HttpServletRequest request, String headerClientVersion,
DefaultArtifactVersion clientVersion) {
log.info("HEADER_SERVER_NAME : {}", request.getHeader(HEADER_SERVER_NAME));
if (!StringUtils.hasText(request.getHeader(HEADER_SERVER_NAME))) {
String applicationName = request.getHeader(HEADER_SERVER_NAME);
log.info("HEADER_SERVER_NAME : {}", applicationName);
if (!StringUtils.hasText(applicationName)) {
return;
}
ExtAxProperty property = extAxPropertyService.getByName(request.getHeader(HEADER_SERVER_NAME)).map(entity -> {
entity.setCreated(!Objects.equals(entity.getValue(), serviceVersion));
entity.setValue(headerClientVersion);
return entity;
}).orElseGet(() -> {
ExtAxProperty extAxProperty = new ExtAxProperty();
extAxProperty.setCreated(true);
extAxProperty.setName(request.getHeader(HEADER_SERVER_NAME));
extAxProperty.setValue(clientVersion.toString());
return extAxProperty;
});
String manageableStatus = request.getHeader(ENABLE_MANAGEABLE);
if (property.getCreated()) {
if (Objects.isNull(property.getId())) {
extAxPropertyService.add(property);
} else {
extAxPropertyService.update(property);
}
Optional<ExtAxProperty> extAxProperty = extAxPropertyService.getByName(applicationName);
String cacheRepeatKey = REPEAT_KEY + applicationName;
log.info("repeatApi key: {}", cacheRepeatKey);
//success为true表示key不存在,执行成功,false表示key存在,执行失败
Boolean success = RedisUtils.trySetObject(cacheRepeatKey, "", Duration.ofSeconds(5));
if (success) {
KEY_CACHE.set(cacheRepeatKey);
insert(extAxProperty, applicationName, clientVersion, manageableStatus);
}
}
private void update(Optional<ExtAxProperty> extAxProperty, String requestApplicationName, DefaultArtifactVersion clientVersion, String manageableStatus) {
if (!extAxProperty.isPresent()) {
return;
}
ExtAxProperty property = extAxProperty.get();
if (Objects.equals(property.getValue(), clientVersion.toString())
&& Objects.equals(property.getManageable().toString(), manageableStatus)) {
return;
}
property.setName(requestApplicationName);
property.setValue(clientVersion.toString());
property.setManageable(Boolean.valueOf(manageableStatus));
extAxPropertyService.update(property);
}
private void insert(Optional<ExtAxProperty> extAxProperty, String requestApplicationName, DefaultArtifactVersion clientVersion, String manageableStatus) {
if (extAxProperty.isPresent()) {
update(extAxProperty, requestApplicationName, clientVersion, manageableStatus);
} else {
extAxPropertyService.add(extAxProperty.orElseGet(() -> {
ExtAxProperty property = new ExtAxProperty();
property.setCreated(true);
property.setName(requestApplicationName);
property.setValue(clientVersion.toString());
property.setManageable(Boolean.valueOf(manageableStatus));
return property;
}));
}
}

View File

@ -7,6 +7,7 @@ import org.redisson.api.RAtomicLong;
import org.redisson.api.RBatch;
import org.redisson.api.RBucket;
import org.redisson.api.RBucketAsync;
import org.redisson.api.RFuture;
import org.redisson.api.RKeys;
import org.redisson.api.RList;
import org.redisson.api.RMap;
@ -23,6 +24,7 @@ import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -140,6 +142,16 @@ public class RedisUtils {
batch.execute();
}
public static <T> Boolean trySetObject(final String key, final T value, final Duration duration) {
RBatch batch = CLIENT.createBatch();
RBucketAsync<T> bucket = batch.getBucket(key);
RFuture<Boolean> future = bucket.trySetAsync(value, duration.toMillis(), TimeUnit.MILLISECONDS);
batch.execute();
return future.join();
}
/**
* 注册对象监听器
* <p>

View File

@ -25,15 +25,19 @@ import org.springframework.context.annotation.Scope;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION_121;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT;
import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_PROCESS_DEFINITION_KEY;
import static cn.axzo.workflow.common.constant.BpmnConstants.WORKFLOW_ENGINE_VERSION;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED;
import static cn.axzo.workflow.common.enums.ProcessActivityEventEnum.PROCESS_ACTIVITY_END;
@ -179,13 +183,18 @@ public class RocketMqBpmActivityEventListener extends AbstractBpmnEventListener<
if (!sendMQ) {
return;
}
Map<String, String> header = new HashMap<>();
if (StringUtils.hasText(dto.getProcessDefinitionKey())) {
log.warn("record process definition key: {}", dto.getProcessDefinitionKey());
header.put(MQ_OWNERSHIP_PROCESS_DEFINITION_KEY, dto.getProcessDefinitionKey());
}
eventProducer.send(Event.builder()
.shardingKey(dto.getProcessInstanceId())
.eventCode(eventEnum.getEventCode())
.targetId(dto.getProcessInstanceId())
.targetType(eventEnum.getTag())
.targetType(dto.getProcessDefinitionKey())
.data(dto)
.build());
.build(), header);
}
@Override

View File

@ -31,6 +31,7 @@ import java.util.Optional;
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF;
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.TASK_COMPLETE_FAIL_NOT_EXISTS;
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.TASK_HAS_BEEN_COMPLETE;
import static cn.axzo.workflow.core.listener.AbstractBpmnEventListener.parseProcessDefinitionKey;
import static org.flowable.common.engine.api.delegate.event.FlowableEngineEventType.JOB_MOVED_TO_DEADLETTER;
/**
@ -80,7 +81,9 @@ public class ApproveErrorReporterEventListener implements BpmnAsyncJobEventListe
Optional<BpmnNoticeConf> noticeConfig = BpmnMetaParserHelper.getNoticeConfig(process);
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration();
FlowableEventDispatcher eventDispatcher = processEngineConfiguration.getEventDispatcher();
MessagePushEvent event = MessagePushEventBuilder.createPendingRollbackEvent(jobEvent.getProcessInstanceId(), jobInfo.getTenantId(), dto.getTaskId(), noticeConfig.orElse(new BpmnNoticeConf()));
MessagePushEvent event = MessagePushEventBuilder.createPendingRollbackEvent(jobEvent.getProcessInstanceId(),
parseProcessDefinitionKey(jobEvent.getProcessDefinitionId()),
jobInfo.getTenantId(), dto.getTaskId(), noticeConfig.orElse(new BpmnNoticeConf()));
log.info("发送恢复待办的流程事件消息: taskDto:{},event:{}", JSONUtil.toJsonStr(dto), JSONUtil.toJsonStr(event));
eventDispatcher.dispatchEvent(event, processEngineConfiguration.getEngineCfgKey());
}

View File

@ -54,6 +54,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_PROCESS_TY
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_SPECIFY_NEXT_APPROVER;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO;
import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_PROCESS_DEFINITION_KEY;
import static cn.axzo.workflow.common.constant.BpmnConstants.MULTI_INSTANCE_LOOP_COUNTER;
import static cn.axzo.workflow.common.constant.BpmnConstants.NUMBER_OF_INSTANCES;
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE;
@ -244,6 +245,7 @@ public class RocketMqMessagePushEventListener extends AbstractBpmnEventListener<
|| !StringUtils.hasText(event.getNoticeConfig().getCarbonCopy().getCarbonCopyMessageId())) {
return;
}
// TODO 这里的抄送人,不建议使用一个 MQ 事件来承载,而是一个人一个事件
log.info("RocketMqMessagePushEventListener#onCarbonCopy... cc' templateId: {}, receivePerson: {}, processInstanceId: {}",
event.getNoticeConfig().getCarbonCopy().getCarbonCopyMessageId(),
JSONUtil.toJsonStr(event.getAssigners()), event.getProcessInstanceId());
@ -376,6 +378,7 @@ public class RocketMqMessagePushEventListener extends AbstractBpmnEventListener<
Object> variables) {
return new MessagePushDTO()
.setProcessInstanceId(event.getProcessInstanceId())
.setProcessDefinitionKey(event.getProcessDefinitionKey())
.setType(type)
.setTemplateId(templateId)
.setTaskId(event.getTaskId())
@ -389,13 +392,18 @@ public class RocketMqMessagePushEventListener extends AbstractBpmnEventListener<
if (!sendMQ) {
return;
}
Map<String, String> header = new HashMap<>();
if (StringUtils.hasText(dto.getProcessDefinitionKey())) {
log.warn("record process definition key: {}", dto.getProcessDefinitionKey());
header.put(MQ_OWNERSHIP_PROCESS_DEFINITION_KEY, dto.getProcessDefinitionKey());
}
eventProducer.send(Event.builder()
.shardingKey(dto.getProcessInstanceId())
.eventCode(eventEnum.getEventCode())
.targetId(dto.getProcessInstanceId())
.targetType(eventEnum.getTag())
.targetType(dto.getProcessDefinitionKey())
.data(dto)
.build());
.build(), header);
}
@Override

View File

@ -76,7 +76,7 @@ public class MessagePushProcessEventListener extends AbstractBpmnEventListener<P
optNoticeConfig.ifPresent(noticeConfig -> {
MessagePushEventImpl messagePushEvent =
MessagePushEventBuilder.createEvent(MessagePushEventType.PENDING_COMPLETE, null, noticeConfig,
event.getProcessInstanceId(), null, null);
event.getProcessInstanceId(), parseProcessDefinitionKey(event.getProcessDefinitionId()), null, null);
log.info("发送完成实例下所有待办的消息: {}", JSONUtil.toJsonStr(messagePushEvent));
@ -87,7 +87,7 @@ public class MessagePushProcessEventListener extends AbstractBpmnEventListener<P
}
MessagePushEventImpl carbonCopyCompleteEvent =
MessagePushEventBuilder.createEvent(MessagePushEventType.CARBON_COPY_COMPLETE, null, noticeConfig,
event.getProcessInstanceId(), null, null);
event.getProcessInstanceId(), parseProcessDefinitionKey(event.getProcessDefinitionId()), null, null);
eventDispatcher.dispatchEvent(carbonCopyCompleteEvent, processEngineConfiguration.getEngineCfgKey());
log.info("发送完成抄送的消息: {}", JSONUtil.toJsonStr(carbonCopyCompleteEvent));
}

Some files were not shown because too many files have changed in this diff Show More