mirror of
https://gitee.com/orangeform/orange-admin.git
synced 2026-01-17 10:36:31 +08:00
commit:流程支持自动化任务
This commit is contained in:
@@ -20,6 +20,11 @@
|
||||
<artifactId>common-satoken</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.orangeforms</groupId>
|
||||
<artifactId>common-dbutil</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.orangeforms</groupId>
|
||||
<artifactId>common-datafilter</artifactId>
|
||||
|
||||
@@ -96,6 +96,10 @@ public final class FlowApprovalType {
|
||||
* 空审批人自动退回。
|
||||
*/
|
||||
public static final String EMPTY_USER_AUTO_REJECT = "empty_user_auto_reject";
|
||||
/**
|
||||
* 自动化任务。
|
||||
*/
|
||||
public static final String AUTO_FLOW_TASK = "auto_flow_task";
|
||||
|
||||
/**
|
||||
* 私有构造函数,明确标识该常量类的作用。
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.orangeforms.common.flow.constant;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 工作流自动化任务的动作类型。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public class FlowAutoActionType {
|
||||
|
||||
/**
|
||||
* 添加新数据。
|
||||
*/
|
||||
public static final int ADD_NEW = 0;
|
||||
/**
|
||||
* 更新数据。
|
||||
*/
|
||||
public static final int UPDATE = 1;
|
||||
/**
|
||||
* 删除数据。
|
||||
*/
|
||||
public static final int DELETE = 2;
|
||||
/**
|
||||
* 查询单条数据。
|
||||
*/
|
||||
public static final int SELECT_ONE = 3;
|
||||
/**
|
||||
* 聚合计算。
|
||||
*/
|
||||
public static final int AGGREGATION_CALC = 5;
|
||||
/**
|
||||
* 数值计算。
|
||||
*/
|
||||
public static final int NUMBER_CALC = 6;
|
||||
/**
|
||||
* HTTP请求调用
|
||||
*/
|
||||
public static final int HTTP = 10;
|
||||
|
||||
private static final Map<Integer, String> DICT_MAP = new HashMap<>(2);
|
||||
static {
|
||||
DICT_MAP.put(ADD_NEW, "添加新数据");
|
||||
DICT_MAP.put(UPDATE, "更新数据");
|
||||
DICT_MAP.put(DELETE, "删除数据");
|
||||
DICT_MAP.put(SELECT_ONE, "查询单条数据");
|
||||
DICT_MAP.put(AGGREGATION_CALC, "聚合计算");
|
||||
DICT_MAP.put(NUMBER_CALC, "数值计算");
|
||||
DICT_MAP.put(HTTP, "HTTP请求调用");
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据类型值返回显示值。
|
||||
*
|
||||
* @param flowActionType 类型值。
|
||||
* @return 对应的显示名。
|
||||
*/
|
||||
public static String getShowNname(int flowActionType) {
|
||||
return DICT_MAP.get(flowActionType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 私有构造函数,明确标识该常量类的作用。
|
||||
*/
|
||||
private FlowAutoActionType() {
|
||||
}
|
||||
}
|
||||
@@ -153,6 +153,11 @@ public class FlowConstant {
|
||||
*/
|
||||
public static final String GROUP_TYPE_DEPT_POST_LEADER = "DEPT_POST_LEADER";
|
||||
|
||||
/**
|
||||
* 自动执行。
|
||||
*/
|
||||
public static final String GROUP_TYPE_AUTO_EXEC = "AUTO_EXEC";
|
||||
|
||||
/**
|
||||
* 本部门岗位前缀。
|
||||
*/
|
||||
@@ -258,6 +263,11 @@ public class FlowConstant {
|
||||
*/
|
||||
public static final String EMPTY_USER_TO_ASSIGNEE = "emptyUserToAssignee";
|
||||
|
||||
/**
|
||||
* 自动化任务中用于传递的生产者日志对象变量。
|
||||
*/
|
||||
public static final String AUTO_FLOW_TRANS_PRODUCER_VAR = "transProducer";
|
||||
|
||||
/**
|
||||
* 私有构造函数,明确标识该常量类的作用。
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,276 @@
|
||||
package com.orangeforms.common.flow.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.github.pagehelper.page.PageMethod;
|
||||
import com.orangeforms.common.core.annotation.MyRequestBody;
|
||||
import com.orangeforms.common.core.constant.ErrorCodeEnum;
|
||||
import com.orangeforms.common.core.object.*;
|
||||
import com.orangeforms.common.core.util.MyCommonUtil;
|
||||
import com.orangeforms.common.core.util.MyModelUtil;
|
||||
import com.orangeforms.common.core.util.MyPageUtil;
|
||||
import com.orangeforms.common.dbutil.object.SqlTable;
|
||||
import com.orangeforms.common.dbutil.object.SqlTableColumn;
|
||||
import com.orangeforms.common.flow.dto.FlowDblinkDto;
|
||||
import com.orangeforms.common.flow.model.FlowDblink;
|
||||
import com.orangeforms.common.flow.service.FlowDblinkService;
|
||||
import com.orangeforms.common.flow.util.FlowDataSourceUtil;
|
||||
import com.orangeforms.common.flow.vo.FlowDblinkVo;
|
||||
import com.orangeforms.common.log.annotation.OperationLog;
|
||||
import com.orangeforms.common.log.model.constant.SysOperationLogType;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springdoc.core.annotations.ParameterObject;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 工作流数据库链接接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Tag(name = "工作流数据库链接接口")
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("${common-flow.urlPrefix}/flowDblink")
|
||||
@ConditionalOnProperty(name = "common-flow.operationEnabled", havingValue = "true")
|
||||
public class FlowDblinkController {
|
||||
|
||||
@Autowired
|
||||
private FlowDblinkService flowDblinkService;
|
||||
@Autowired
|
||||
private FlowDataSourceUtil dataSourceUtil;
|
||||
|
||||
/**
|
||||
* 新增数据库链接数据。
|
||||
*
|
||||
* @param flowDblinkDto 新增对象。
|
||||
* @return 应答结果对象,包含新增对象主键Id。
|
||||
*/
|
||||
@SaCheckPermission("flowDblink.all")
|
||||
@OperationLog(type = SysOperationLogType.ADD)
|
||||
@PostMapping("/add")
|
||||
public ResponseResult<Long> add(@MyRequestBody FlowDblinkDto flowDblinkDto) {
|
||||
String errorMessage = MyCommonUtil.getModelValidationError(flowDblinkDto, false);
|
||||
if (errorMessage != null) {
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
FlowDblink flowDblink = MyModelUtil.copyTo(flowDblinkDto, FlowDblink.class);
|
||||
flowDblink = flowDblinkService.saveNew(flowDblink);
|
||||
return ResponseResult.success(flowDblink.getDblinkId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新数据库链接数据。
|
||||
*
|
||||
* @param flowDblinkDto 更新对象。
|
||||
* @return 应答结果对象。
|
||||
*/
|
||||
@SaCheckPermission("flowDblink.all")
|
||||
@OperationLog(type = SysOperationLogType.UPDATE)
|
||||
@PostMapping("/update")
|
||||
public ResponseResult<Void> update(@MyRequestBody FlowDblinkDto flowDblinkDto) {
|
||||
String errorMessage = MyCommonUtil.getModelValidationError(flowDblinkDto, true);
|
||||
if (errorMessage != null) {
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
FlowDblink flowDblink = MyModelUtil.copyTo(flowDblinkDto, FlowDblink.class);
|
||||
ResponseResult<FlowDblink> verifyResult = this.doVerifyAndGet(flowDblinkDto.getDblinkId());
|
||||
if (!verifyResult.isSuccess()) {
|
||||
return ResponseResult.errorFrom(verifyResult);
|
||||
}
|
||||
FlowDblink originalFlowDblink = verifyResult.getData();
|
||||
if (ObjectUtil.notEqual(flowDblink.getDblinkType(), originalFlowDblink.getDblinkType())) {
|
||||
errorMessage = "数据验证失败,不能修改数据库类型!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
|
||||
}
|
||||
String passwdKey = "password";
|
||||
JSONObject configJson = JSON.parseObject(flowDblink.getConfiguration());
|
||||
String password = configJson.getString(passwdKey);
|
||||
if (StrUtil.isNotBlank(password) && StrUtil.isAllCharMatch(password, c -> '*' == c)) {
|
||||
password = JSON.parseObject(originalFlowDblink.getConfiguration()).getString(passwdKey);
|
||||
configJson.put(passwdKey, password);
|
||||
flowDblink.setConfiguration(configJson.toJSONString());
|
||||
}
|
||||
if (!flowDblinkService.update(flowDblink, originalFlowDblink)) {
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
|
||||
}
|
||||
return ResponseResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除数据库链接数据。
|
||||
*
|
||||
* @param dblinkId 删除对象主键Id。
|
||||
* @return 应答结果对象。
|
||||
*/
|
||||
@SaCheckPermission("flowDblink.all")
|
||||
@OperationLog(type = SysOperationLogType.DELETE)
|
||||
@PostMapping("/delete")
|
||||
public ResponseResult<Void> delete(@MyRequestBody Long dblinkId) {
|
||||
String errorMessage;
|
||||
// 验证关联Id的数据合法性
|
||||
ResponseResult<FlowDblink> verifyResult = this.doVerifyAndGet(dblinkId);
|
||||
if (!verifyResult.isSuccess()) {
|
||||
return ResponseResult.errorFrom(verifyResult);
|
||||
}
|
||||
if (!flowDblinkService.remove(dblinkId)) {
|
||||
errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
|
||||
}
|
||||
return ResponseResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列出符合过滤条件的数据库链接列表。
|
||||
*
|
||||
* @param flowDblinkDtoFilter 过滤对象。
|
||||
* @param orderParam 排序参数。
|
||||
* @param pageParam 分页参数。
|
||||
* @return 应答结果对象,包含查询结果集。
|
||||
*/
|
||||
@SaCheckPermission("flowDblink.all")
|
||||
@PostMapping("/list")
|
||||
public ResponseResult<MyPageData<FlowDblinkVo>> list(
|
||||
@MyRequestBody FlowDblinkDto flowDblinkDtoFilter,
|
||||
@MyRequestBody MyOrderParam orderParam,
|
||||
@MyRequestBody MyPageParam pageParam) {
|
||||
if (pageParam != null) {
|
||||
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
|
||||
}
|
||||
FlowDblink flowDblinkFilter = MyModelUtil.copyTo(flowDblinkDtoFilter, FlowDblink.class);
|
||||
String orderBy = MyOrderParam.buildOrderBy(orderParam, FlowDblink.class);
|
||||
List<FlowDblink> flowDblinkList =
|
||||
flowDblinkService.getFlowDblinkListWithRelation(flowDblinkFilter, orderBy);
|
||||
for (FlowDblink dblink : flowDblinkList) {
|
||||
this.maskOffPassword(dblink);
|
||||
}
|
||||
return ResponseResult.success(MyPageUtil.makeResponseData(flowDblinkList, FlowDblinkVo.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看指定数据库链接对象详情。
|
||||
*
|
||||
* @param dblinkId 指定对象主键Id。
|
||||
* @return 应答结果对象,包含对象详情。
|
||||
*/
|
||||
@SaCheckPermission("flowDblink.all")
|
||||
@GetMapping("/view")
|
||||
public ResponseResult<FlowDblinkVo> view(@RequestParam Long dblinkId) {
|
||||
ResponseResult<FlowDblink> verifyResult = this.doVerifyAndGet(dblinkId);
|
||||
if (!verifyResult.isSuccess()) {
|
||||
return ResponseResult.errorFrom(verifyResult);
|
||||
}
|
||||
FlowDblink flowDblink = verifyResult.getData();
|
||||
flowDblinkService.buildRelationForData(flowDblink, MyRelationParam.full());
|
||||
if (!StrUtil.equals(flowDblink.getAppCode(), TokenData.takeFromRequest().getAppCode())) {
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, "数据验证失败,当前应用并不存在该数据库链接!");
|
||||
}
|
||||
this.maskOffPassword(flowDblink);
|
||||
return ResponseResult.success(flowDblink, FlowDblinkVo.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定数据库链接下的所有动态表单依赖的数据表列表。
|
||||
*
|
||||
* @param dblinkId 数据库链接Id。
|
||||
* @return 所有动态表单依赖的数据表列表
|
||||
*/
|
||||
@SaCheckPermission("flowDblink.all")
|
||||
@GetMapping("/listDblinkTables")
|
||||
public ResponseResult<List<SqlTable>> listDblinkTables(@RequestParam Long dblinkId) {
|
||||
FlowDblink dblink = flowDblinkService.getById(dblinkId);
|
||||
if (dblink == null) {
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
|
||||
}
|
||||
return ResponseResult.success(flowDblinkService.getDblinkTableList(dblink));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定数据库链接下,指定数据表的所有字段信息。
|
||||
*
|
||||
* @param dblinkId 数据库链接Id。
|
||||
* @param tableName 表名。
|
||||
* @return 该表的所有字段列表。
|
||||
*/
|
||||
@SaCheckPermission("flowDblink.all")
|
||||
@GetMapping("/listDblinkTableColumns")
|
||||
public ResponseResult<List<SqlTableColumn>> listDblinkTableColumns(
|
||||
@RequestParam Long dblinkId, @RequestParam String tableName) {
|
||||
FlowDblink dblink = flowDblinkService.getById(dblinkId);
|
||||
if (dblink == null) {
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
|
||||
}
|
||||
return ResponseResult.success(flowDblinkService.getDblinkTableColumnList(dblink, tableName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试数据库链接的接口。
|
||||
*
|
||||
* @return 应答结果。
|
||||
*/
|
||||
@GetMapping("/testConnection")
|
||||
public ResponseResult<Void> testConnection(@RequestParam Long dblinkId) {
|
||||
ResponseResult<FlowDblink> verifyAndGet = this.doVerifyAndGet(dblinkId);
|
||||
if (!verifyAndGet.isSuccess()) {
|
||||
return ResponseResult.errorFrom(verifyAndGet);
|
||||
}
|
||||
try {
|
||||
dataSourceUtil.testConnection(dblinkId);
|
||||
return ResponseResult.success();
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to test connection with FLOW_DBLINK_ID [" + dblinkId + "]!", e);
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_ACCESS_FAILED, "数据库连接失败!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 以字典形式返回全部数据库链接数据集合。字典的键值为[dblinkId, dblinkName]。
|
||||
* 白名单接口,登录用户均可访问。
|
||||
*
|
||||
* @param filter 过滤对象。
|
||||
* @return 应答结果对象,包含的数据为 List<Map<String, String>>,map中包含两条记录,key的值分别是id和name,value对应具体数据。
|
||||
*/
|
||||
@GetMapping("/listDict")
|
||||
public ResponseResult<List<Map<String, Object>>> listDict(@ParameterObject FlowDblinkDto filter) {
|
||||
List<FlowDblink> resultList =
|
||||
flowDblinkService.getFlowDblinkList(MyModelUtil.copyTo(filter, FlowDblink.class), null);
|
||||
return ResponseResult.success(
|
||||
MyCommonUtil.toDictDataList(resultList, FlowDblink::getDblinkId, FlowDblink::getDblinkName));
|
||||
}
|
||||
|
||||
private ResponseResult<FlowDblink> doVerifyAndGet(Long dblinkId) {
|
||||
if (MyCommonUtil.existBlankArgument(dblinkId)) {
|
||||
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
|
||||
}
|
||||
FlowDblink flowDblink = flowDblinkService.getById(dblinkId);
|
||||
if (flowDblink == null) {
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
|
||||
}
|
||||
if (!StrUtil.equals(flowDblink.getAppCode(), TokenData.takeFromRequest().getAppCode())) {
|
||||
return ResponseResult.error(
|
||||
ErrorCodeEnum.DATA_VALIDATED_FAILED, "数据验证失败,当前应用并不存在该数据库链接!");
|
||||
}
|
||||
return ResponseResult.success(flowDblink);
|
||||
}
|
||||
|
||||
private void maskOffPassword(FlowDblink dblink) {
|
||||
String passwdKey = "password";
|
||||
JSONObject configJson = JSON.parseObject(dblink.getConfiguration());
|
||||
if (configJson.containsKey(passwdKey)) {
|
||||
String password = configJson.getString(passwdKey);
|
||||
if (StrUtil.isNotBlank(password)) {
|
||||
configJson.put(passwdKey, StrUtil.repeat('*', password.length()));
|
||||
dblink.setConfiguration(configJson.toJSONString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import com.alibaba.fastjson.JSONObject;
|
||||
import com.orangeforms.common.core.annotation.DisableDataFilter;
|
||||
import com.orangeforms.common.core.annotation.MyRequestBody;
|
||||
import com.orangeforms.common.core.constant.ErrorCodeEnum;
|
||||
import com.orangeforms.common.core.exception.MyRuntimeException;
|
||||
import com.orangeforms.common.core.object.*;
|
||||
import com.orangeforms.common.core.util.MyModelUtil;
|
||||
import com.orangeforms.common.core.util.MyPageUtil;
|
||||
@@ -35,6 +36,7 @@ import org.flowable.bpmn.model.BpmnModel;
|
||||
import org.flowable.bpmn.model.UserTask;
|
||||
import org.flowable.engine.history.HistoricActivityInstance;
|
||||
import org.flowable.engine.history.HistoricProcessInstance;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.flowable.task.api.Task;
|
||||
import org.flowable.task.api.TaskInfo;
|
||||
import org.flowable.task.api.history.HistoricTaskInstance;
|
||||
@@ -113,6 +115,26 @@ public class FlowOperationController {
|
||||
return ResponseResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发起一个自动化流程实例。
|
||||
*
|
||||
* @param processDefinitionKey 流程标识。
|
||||
* @param variableData 变量数据。
|
||||
* @return 应答结果对象。
|
||||
*/
|
||||
@SaCheckPermission("flowOperation.all")
|
||||
@OperationLog(type = SysOperationLogType.START_FLOW)
|
||||
@PostMapping("/startAuto")
|
||||
public ResponseResult<String> startAuto(
|
||||
@MyRequestBody(required = true) String processDefinitionKey, @MyRequestBody JSONObject variableData) {
|
||||
try {
|
||||
ProcessInstance processInstance = flowApiService.startAuto(processDefinitionKey, variableData);
|
||||
return ResponseResult.success(processInstance.getProcessInstanceId());
|
||||
} catch (MyRuntimeException e) {
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取开始节点之后的第一个任务节点的数据。
|
||||
*
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.orangeforms.common.flow.dao;
|
||||
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.flow.model.FlowAutoVariableLog;
|
||||
|
||||
/**
|
||||
* 自动化流程变量访问接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowAutoVariableLogMapper extends BaseDaoMapper<FlowAutoVariableLog> {
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.orangeforms.common.flow.dao;
|
||||
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.flow.model.FlowDblink;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 数据库链接数据操作访问接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowDblinkMapper extends BaseDaoMapper<FlowDblink> {
|
||||
|
||||
/**
|
||||
* 获取过滤后的对象列表。
|
||||
*
|
||||
* @param flowDblinkFilter 主表过滤对象。
|
||||
* @param orderBy 排序字符串,order by从句的参数。
|
||||
* @return 对象列表。
|
||||
*/
|
||||
List<FlowDblink> getFlowDblinkList(
|
||||
@Param("flowDblinkFilter") FlowDblink flowDblinkFilter, @Param("orderBy") String orderBy);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.orangeforms.common.flow.dao;
|
||||
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.flow.model.FlowTransProducer;
|
||||
|
||||
/**
|
||||
* 事务性业务数据生产者访问接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowTransProducerMapper extends BaseDaoMapper<FlowTransProducer> {
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.orangeforms.common.flow.dao.FlowAutoVariableLogMapper">
|
||||
<resultMap id="BaseResultMap" type="com.orangeforms.common.flow.model.FlowAutoVariableLog">
|
||||
<id column="id" jdbcType="BIGINT" property="id"/>
|
||||
<result column="process_instance_id" jdbcType="VARCHAR" property="processInstanceId"/>
|
||||
<result column="execution_id" jdbcType="VARCHAR" property="executionId"/>
|
||||
<result column="task_id" jdbcType="VARCHAR" property="taskId"/>
|
||||
<result column="task_key" jdbcType="VARCHAR" property="taskKey"/>
|
||||
<result column="trace_id" jdbcType="VARCHAR" property="traceId"/>
|
||||
<result column="variable_data" jdbcType="LONGVARCHAR" property="variableData"/>
|
||||
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
|
||||
</resultMap>
|
||||
</mapper>
|
||||
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.orangeforms.common.flow.dao.FlowDblinkMapper">
|
||||
<resultMap id="BaseResultMap" type="com.orangeforms.common.flow.model.FlowDblink">
|
||||
<id column="dblink_id" jdbcType="BIGINT" property="dblinkId"/>
|
||||
<result column="app_code" jdbcType="VARCHAR" property="appCode"/>
|
||||
<result column="dblink_name" jdbcType="VARCHAR" property="dblinkName"/>
|
||||
<result column="dblink_description" jdbcType="VARCHAR" property="dblinkDescription"/>
|
||||
<result column="configuration" jdbcType="VARCHAR" property="configuration"/>
|
||||
<result column="dblink_type" jdbcType="INTEGER" property="dblinkType"/>
|
||||
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
|
||||
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
|
||||
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
|
||||
<result column="update_user_id" jdbcType="BIGINT" property="updateUserId"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 如果有逻辑删除字段过滤,请写到这里 -->
|
||||
<sql id="filterRef">
|
||||
<!-- 这里必须加上全包名,否则当filterRef被其他Mapper.xml包含引用的时候,就会调用Mapper.xml中的该SQL片段 -->
|
||||
<include refid="com.orangeforms.common.flow.dao.FlowDblinkMapper.inputFilterRef"/>
|
||||
</sql>
|
||||
|
||||
<!-- 这里仅包含调用接口输入的主表过滤条件 -->
|
||||
<sql id="inputFilterRef">
|
||||
<if test="flowDblinkFilter != null">
|
||||
<if test="flowDblinkFilter.appCode == null">
|
||||
AND zz_flow_dblink.app_code IS NULL
|
||||
</if>
|
||||
<if test="flowDblinkFilter.appCode != null">
|
||||
AND zz_flow_dblink.app_code = #{flowDblinkFilter.appCode}
|
||||
</if>
|
||||
<if test="flowDblinkFilter.dblinkType != null">
|
||||
AND zz_flow_dblink.dblink_type = #{flowDblinkFilter.dblinkType}
|
||||
</if>
|
||||
</if>
|
||||
</sql>
|
||||
|
||||
<select id="getFlowDblinkList" resultMap="BaseResultMap" parameterType="com.orangeforms.common.flow.model.FlowDblink">
|
||||
SELECT * FROM zz_flow_dblink
|
||||
<where>
|
||||
<include refid="filterRef"/>
|
||||
</where>
|
||||
<if test="orderBy != null and orderBy != ''">
|
||||
ORDER BY ${orderBy}
|
||||
</if>
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -14,6 +14,7 @@
|
||||
<result column="bpmn_xml" jdbcType="LONGVARCHAR" property="bpmnXml"/>
|
||||
<result column="diagram_type" jdbcType="INTEGER" property="diagramType"/>
|
||||
<result column="bind_form_type" jdbcType="INTEGER" property="bindFormType"/>
|
||||
<result column="flow_type" jdbcType="INTEGER" property="flowType"/>
|
||||
<result column="page_id" jdbcType="BIGINT" property="pageId"/>
|
||||
<result column="default_form_id" jdbcType="BIGINT" property="defaultFormId"/>
|
||||
<result column="default_router_name" jdbcType="VARCHAR" property="defaultRouterName"/>
|
||||
@@ -58,6 +59,9 @@
|
||||
<if test="flowEntryFilter.status != null">
|
||||
AND zz_flow_entry.status = #{flowEntryFilter.status}
|
||||
</if>
|
||||
<if test="flowEntryFilter.flowType != null">
|
||||
AND zz_flow_entry.flow_type = #{flowEntryFilter.flowType}
|
||||
</if>
|
||||
</if>
|
||||
</sql>
|
||||
|
||||
@@ -73,6 +77,7 @@
|
||||
status,
|
||||
diagram_type,
|
||||
bind_form_type,
|
||||
flow_type,
|
||||
page_id,
|
||||
default_form_id,
|
||||
default_router_name,
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
<result column="candidate_usernames" jdbcType="VARCHAR" property="candidateUsernames"/>
|
||||
<result column="copy_list_json" jdbcType="VARCHAR" property="copyListJson"/>
|
||||
<result column="extra_data_json" jdbcType="VARCHAR" property="extraDataJson"/>
|
||||
<result column="auto_config_json" jdbcType="VARCHAR" property="autoConfigJson"/>
|
||||
</resultMap>
|
||||
|
||||
<insert id="insertList">
|
||||
@@ -30,7 +31,8 @@
|
||||
#{item.deptIds},
|
||||
#{item.candidateUsernames},
|
||||
#{item.copyListJson},
|
||||
#{item.extraDataJson})
|
||||
#{item.extraDataJson},
|
||||
#{item.autoConfigJson})
|
||||
</foreach>
|
||||
</insert>
|
||||
</mapper>
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.orangeforms.common.flow.dao.FlowTransProducerMapper">
|
||||
<resultMap id="BaseResultMap" type="com.orangeforms.common.flow.model.FlowTransProducer">
|
||||
<id column="trans_id" jdbcType="BIGINT" property="transId"/>
|
||||
<result column="app_code" jdbcType="VARCHAR" property="appCode"/>
|
||||
<result column="dblink_id" jdbcType="BIGINT" property="dblinkId"/>
|
||||
<result column="process_instance_id" jdbcType="VARCHAR" property="processInstanceId"/>
|
||||
<result column="execution_id" jdbcType="VARCHAR" property="executionId"/>
|
||||
<result column="task_id" jdbcType="VARCHAR" property="taskId"/>
|
||||
<result column="task_key" jdbcType="VARCHAR" property="taskKey"/>
|
||||
<result column="task_name" jdbcType="VARCHAR" property="taskName"/>
|
||||
<result column="task_comment" jdbcType="VARCHAR" property="taskComment"/>
|
||||
<result column="url" jdbcType="VARCHAR" property="url"/>
|
||||
<result column="init_method" jdbcType="VARCHAR" property="initMethod"/>
|
||||
<result column="trace_id" jdbcType="VARCHAR" property="traceId"/>
|
||||
<result column="sql_data" jdbcType="LONGVARCHAR" property="sqlData"/>
|
||||
<result column="auto_task_config" jdbcType="LONGVARCHAR" property="autoTaskConfig"/>
|
||||
<result column="try_times" jdbcType="INTEGER" property="tryTimes"/>
|
||||
<result column="error_reason" jdbcType="LONGVARCHAR" property="errorReason"/>
|
||||
<result column="create_login_name" jdbcType="VARCHAR" property="createUsername"/>
|
||||
<result column="create_username" jdbcType="VARCHAR" property="createLoginName"/>
|
||||
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
|
||||
</resultMap>
|
||||
</mapper>
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.orangeforms.common.flow.dto;
|
||||
|
||||
import com.orangeforms.common.core.validator.UpdateGroup;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 工作流自动化流程数据表所在数据库链接Dto对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Schema(description = "工作流自动化流程数据表所在数据库链接Dto对象")
|
||||
@Data
|
||||
public class FlowDblinkDto {
|
||||
|
||||
/**
|
||||
* 主键Id。
|
||||
*/
|
||||
@Schema(description = "主键Id")
|
||||
@NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class})
|
||||
private Long dblinkId;
|
||||
|
||||
/**
|
||||
* 链接中文名称。
|
||||
*/
|
||||
@Schema(description = "链接中文名称")
|
||||
@NotBlank(message = "数据验证失败,链接中文名称不能为空!")
|
||||
private String dblinkName;
|
||||
|
||||
/**
|
||||
* 链接描述。
|
||||
*/
|
||||
@Schema(description = "链接中文名称")
|
||||
private String dblinkDescription;
|
||||
|
||||
/**
|
||||
* 配置信息。
|
||||
*/
|
||||
@Schema(description = "配置信息")
|
||||
@NotBlank(message = "数据验证失败,配置信息不能为空!")
|
||||
private String configuration;
|
||||
|
||||
/**
|
||||
* 数据库链接类型。
|
||||
*/
|
||||
@Schema(description = "数据库链接类型")
|
||||
@NotNull(message = "数据验证失败,数据库链接类型不能为空!")
|
||||
private Integer dblinkType;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.orangeforms.common.flow.listener;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.text.StrFormatter;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.orangeforms.common.core.util.ApplicationContextHolder;
|
||||
import com.orangeforms.common.flow.constant.FlowApprovalType;
|
||||
import com.orangeforms.common.flow.constant.FlowAutoActionType;
|
||||
import com.orangeforms.common.flow.constant.FlowConstant;
|
||||
import com.orangeforms.common.flow.model.FlowTaskComment;
|
||||
import com.orangeforms.common.flow.model.FlowTransProducer;
|
||||
import com.orangeforms.common.flow.object.AutoTaskConfig;
|
||||
import com.orangeforms.common.flow.service.FlowApiService;
|
||||
import com.orangeforms.common.flow.service.FlowTaskCommentService;
|
||||
import com.orangeforms.common.flow.service.FlowTransProducerService;
|
||||
import com.orangeforms.common.flow.util.AutoFlowHelper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.engine.delegate.DelegateExecution;
|
||||
import org.flowable.engine.delegate.ExecutionListener;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 空审批人审批人检测监听器。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Slf4j
|
||||
public class ReceiveTaskEndListener implements ExecutionListener {
|
||||
|
||||
private final transient FlowApiService flowApiService =
|
||||
ApplicationContextHolder.getBean(FlowApiService.class);
|
||||
private final transient FlowTransProducerService flowTransProducerService =
|
||||
ApplicationContextHolder.getBean(FlowTransProducerService.class);
|
||||
private final transient FlowTaskCommentService flowTaskCommentService =
|
||||
ApplicationContextHolder.getBean(FlowTaskCommentService.class);
|
||||
private final transient AutoFlowHelper autoFlowHelper =
|
||||
ApplicationContextHolder.getBean(AutoFlowHelper.class);
|
||||
|
||||
@Override
|
||||
public void notify(DelegateExecution d) {
|
||||
//先从内存中的临时变量中获取,以便提升正常运行情况下的运行时效率。
|
||||
FlowTransProducer transProducer =
|
||||
(FlowTransProducer) d.getTransientVariable(FlowConstant.AUTO_FLOW_TRANS_PRODUCER_VAR);
|
||||
//如果临时变量中没有存在,则从流程执行实例中查询该变量。
|
||||
if (transProducer == null) {
|
||||
transProducer = (FlowTransProducer)
|
||||
flowApiService.getExecutionVariable(d.getId(), FlowConstant.AUTO_FLOW_TRANS_PRODUCER_VAR);
|
||||
}
|
||||
if (transProducer == null) {
|
||||
FlowTransProducer filter = new FlowTransProducer();
|
||||
filter.setProcessInstanceId(d.getProcessInstanceId());
|
||||
filter.setExecutionId(d.getId());
|
||||
filter.setTaskKey(d.getCurrentActivityId());
|
||||
List<FlowTransProducer> transProducers = flowTransProducerService.getListByFilter(filter);
|
||||
if (CollUtil.isNotEmpty(transProducers)) {
|
||||
transProducers = transProducers.stream()
|
||||
.sorted(Comparator.comparing(FlowTransProducer::getTransId, Comparator.reverseOrder()))
|
||||
.collect(Collectors.toList());
|
||||
transProducer = transProducers.get(0);
|
||||
}
|
||||
}
|
||||
if (transProducer == null) {
|
||||
return;
|
||||
}
|
||||
if (StrUtil.isNotBlank(transProducer.getAutoTaskConfig())) {
|
||||
AutoTaskConfig taskConfig = JSON.parseObject(transProducer.getAutoTaskConfig(), AutoTaskConfig.class);
|
||||
autoFlowHelper.executeTask(transProducer.getTransId(), taskConfig, d);
|
||||
FlowTaskComment comment = new FlowTaskComment();
|
||||
comment.setTaskKey(d.getCurrentActivityId());
|
||||
comment.setTaskName(taskConfig.getTaskName());
|
||||
comment.setProcessInstanceId(d.getProcessInstanceId());
|
||||
comment.setExecutionId(d.getId());
|
||||
comment.setApprovalType(FlowApprovalType.AUTO_FLOW_TASK);
|
||||
String s = StrFormatter.format("执行任务 [{}] 成功,任务类型 [{}]",
|
||||
taskConfig.getTaskName(), FlowAutoActionType.getShowNname(taskConfig.getActionType()));
|
||||
comment.setTaskComment(s);
|
||||
flowTaskCommentService.saveNew(comment);
|
||||
}
|
||||
flowTransProducerService.removeById(transProducer.getTransId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.orangeforms.common.flow.listener;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import com.orangeforms.common.core.util.ApplicationContextHolder;
|
||||
import com.orangeforms.common.flow.model.FlowTransProducer;
|
||||
import com.orangeforms.common.flow.object.AutoTaskConfig;
|
||||
import com.orangeforms.common.flow.service.FlowTransProducerService;
|
||||
import com.orangeforms.common.flow.util.AutoFlowHelper;
|
||||
import com.orangeforms.common.flow.util.ListenerEventPublishHelper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.engine.delegate.DelegateExecution;
|
||||
import org.flowable.engine.delegate.ExecutionListener;
|
||||
|
||||
/**
|
||||
* 空审批人审批人检测监听器。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Slf4j
|
||||
public class ReceiveTaskStartListener implements ExecutionListener {
|
||||
|
||||
private final transient AutoFlowHelper autoFlowHelper =
|
||||
ApplicationContextHolder.getBean(AutoFlowHelper.class);
|
||||
private final transient FlowTransProducerService flowTransProducerService =
|
||||
ApplicationContextHolder.getBean(FlowTransProducerService.class);
|
||||
private final transient ListenerEventPublishHelper eventPublishHelper =
|
||||
ApplicationContextHolder.getBean(ListenerEventPublishHelper.class);
|
||||
|
||||
@Override
|
||||
public void notify(DelegateExecution d) {
|
||||
//TODO 在目标表所在数据库也要创建业务执行的流水表,基于TransProduer的TransId做唯一性校验。
|
||||
AutoTaskConfig taskConfig = autoFlowHelper.parseAutoTaskConfig(d.getProcessDefinitionId(), d.getCurrentActivityId());
|
||||
FlowTransProducer producerData = new FlowTransProducer();
|
||||
producerData.setProcessInstanceId(d.getProcessInstanceId());
|
||||
producerData.setExecutionId(d.getId());
|
||||
producerData.setTaskKey(d.getCurrentActivityId());
|
||||
producerData.setDblinkId(taskConfig.getDestDblinkId());
|
||||
producerData.setInitMethod("ReceiveTaskStartListener.notify");
|
||||
producerData.setTryTimes(1);
|
||||
producerData.setAutoTaskConfig(JSON.toJSONString(taskConfig, SerializerFeature.WriteDateUseDateFormat));
|
||||
flowTransProducerService.saveNew(producerData);
|
||||
eventPublishHelper.publishEvent(producerData);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.orangeforms.common.flow.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 自动化流程变量实体。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
@TableName(value = "zz_flow_auto_variable_log")
|
||||
public class FlowAutoVariableLog {
|
||||
|
||||
/**
|
||||
* 主键Id。
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 流程实例Id。
|
||||
*/
|
||||
@TableField(value = "process_instance_id")
|
||||
private String processInstanceId;
|
||||
|
||||
/**
|
||||
* 执行实例Id。
|
||||
*/
|
||||
@TableField(value = "execution_id")
|
||||
private String executionId;
|
||||
|
||||
/**
|
||||
* 任务Id。
|
||||
*/
|
||||
@TableField(value = "task_id")
|
||||
private String taskId;
|
||||
|
||||
/**
|
||||
* 任务标识。
|
||||
*/
|
||||
@TableField(value = "task_key")
|
||||
private String taskKey;
|
||||
|
||||
/**
|
||||
* 当前请求的traceId。
|
||||
*/
|
||||
@TableField(value = "trace_id")
|
||||
private String traceId;
|
||||
|
||||
/**
|
||||
* 变量数据。
|
||||
*/
|
||||
@TableField(value = "variable_data")
|
||||
private String variableData;
|
||||
|
||||
/**
|
||||
* 创建时间。
|
||||
*/
|
||||
@TableField(value = "create_time")
|
||||
private Date createTime;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.orangeforms.common.flow.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.orangeforms.common.core.annotation.RelationConstDict;
|
||||
import com.orangeforms.common.dbutil.constant.DblinkType;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 在线表单数据表所在数据库链接实体对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
@TableName(value = "zz_flow_dblink")
|
||||
public class FlowDblink {
|
||||
|
||||
/**
|
||||
* 主键Id。
|
||||
*/
|
||||
@TableId(value = "dblink_id")
|
||||
private Long dblinkId;
|
||||
|
||||
/**
|
||||
* 应用编码。为空时,表示非第三方应用接入。
|
||||
*/
|
||||
@TableField(value = "app_code")
|
||||
private String appCode;
|
||||
|
||||
/**
|
||||
* 链接中文名称。
|
||||
*/
|
||||
@TableField(value = "dblink_name")
|
||||
private String dblinkName;
|
||||
|
||||
/**
|
||||
* 链接描述。
|
||||
*/
|
||||
@TableField(value = "dblink_description")
|
||||
private String dblinkDescription;
|
||||
|
||||
/**
|
||||
* 配置信息。
|
||||
*/
|
||||
private String configuration;
|
||||
|
||||
/**
|
||||
* 数据库链接类型。
|
||||
*/
|
||||
@TableField(value = "dblink_type")
|
||||
private Integer dblinkType;
|
||||
|
||||
/**
|
||||
* 创建时间。
|
||||
*/
|
||||
@TableField(value = "create_time")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 创建者。
|
||||
*/
|
||||
@TableField(value = "create_user_id")
|
||||
private Long createUserId;
|
||||
|
||||
/**
|
||||
* 修改时间。
|
||||
*/
|
||||
@TableField(value = "update_time")
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 更新者。
|
||||
*/
|
||||
@TableField(value = "update_user_id")
|
||||
private Long updateUserId;
|
||||
|
||||
@RelationConstDict(
|
||||
masterIdField = "dblinkType",
|
||||
constantDictClass = DblinkType.class)
|
||||
@TableField(exist = false)
|
||||
private Map<String, Object> dblinkTypeDictMap;
|
||||
}
|
||||
@@ -88,6 +88,12 @@ public class FlowEntry {
|
||||
@TableField(value = "bind_form_type")
|
||||
private Integer bindFormType;
|
||||
|
||||
/**
|
||||
* 流程类型。
|
||||
*/
|
||||
@TableField(value = "flow_type")
|
||||
private Integer flowType;
|
||||
|
||||
/**
|
||||
* 在线表单的页面Id。
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.orangeforms.common.flow.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.orangeforms.common.flow.model.constant.FlowVariableType;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
@@ -74,4 +75,13 @@ public class FlowEntryVariable {
|
||||
*/
|
||||
@TableField(value = "create_time")
|
||||
private Date createTime;
|
||||
|
||||
public static FlowEntryVariable createSystemVariable(String variableName, String showName) {
|
||||
FlowEntryVariable variable = new FlowEntryVariable();
|
||||
variable.variableName = variableName;
|
||||
variable.showName = showName;
|
||||
variable.variableType = FlowVariableType.SYSTEM;
|
||||
variable.builtin = true;
|
||||
return variable;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,4 +84,10 @@ public class FlowTaskExt {
|
||||
*/
|
||||
@TableField(value = "extra_data_json")
|
||||
private String extraDataJson;
|
||||
|
||||
/**
|
||||
* 自动化任务配置数据,存储为JSON的字符串格式。
|
||||
*/
|
||||
@TableField(value = "auto_config_json")
|
||||
private String autoConfigJson;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
package com.orangeforms.common.flow.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 流程处理事务事件生产者流水实体。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
@TableName(value = "zz_flow_trans_producer")
|
||||
public class FlowTransProducer {
|
||||
|
||||
/**
|
||||
* 流水Id。
|
||||
*/
|
||||
@TableId(value = "trans_id")
|
||||
private Long transId;
|
||||
|
||||
/**
|
||||
* 应用编码。为空时,表示非第三方应用接入。
|
||||
*/
|
||||
@TableField(value = "app_code")
|
||||
private String appCode;
|
||||
|
||||
/**
|
||||
* 业务数据库链接Id。
|
||||
*/
|
||||
@TableField(value = "dblink_id")
|
||||
private Long dblinkId;
|
||||
|
||||
/**
|
||||
* 流程实例Id。
|
||||
*/
|
||||
@TableField(value = "process_instance_id")
|
||||
private String processInstanceId;
|
||||
|
||||
/**
|
||||
* 执行实例Id。
|
||||
*/
|
||||
@TableField(value = "execution_id")
|
||||
private String executionId;
|
||||
|
||||
/**
|
||||
* 任务Id。
|
||||
*/
|
||||
@TableField(value = "task_id")
|
||||
private String taskId;
|
||||
|
||||
/**
|
||||
* 任务标识。
|
||||
*/
|
||||
@TableField(value = "task_key")
|
||||
private String taskKey;
|
||||
|
||||
/**
|
||||
* 任务名称。
|
||||
*/
|
||||
@TableField(value = "task_name")
|
||||
private String taskName;
|
||||
|
||||
/**
|
||||
* 审批批注。
|
||||
*/
|
||||
@TableField(value = "task_comment")
|
||||
private String taskComment;
|
||||
|
||||
/**
|
||||
* 当前请求的url。
|
||||
*/
|
||||
@TableField(value = "url")
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 创建该事务性事件对象的初始方法。格式为:方法名(参数类型1,参数类型2)。
|
||||
*/
|
||||
@TableField(value = "init_method")
|
||||
private String initMethod;
|
||||
|
||||
/**
|
||||
* 当前请求的traceId。
|
||||
*/
|
||||
@TableField(value = "trace_id")
|
||||
private String traceId;
|
||||
|
||||
/**
|
||||
* 和SQL操作相关的数据。值类型为TransactionalBusinessData.BusinessSqlData对象。
|
||||
*/
|
||||
@TableField(value = "sql_data")
|
||||
private String sqlData;
|
||||
|
||||
/**
|
||||
* 自动化流程的任务配置。
|
||||
*/
|
||||
@TableField(value = "auto_task_config")
|
||||
private String autoTaskConfig;
|
||||
|
||||
/**
|
||||
* 尝试次数。默认的插入值为1。
|
||||
*/
|
||||
@TableField(value = "try_times")
|
||||
private Integer tryTimes;
|
||||
|
||||
/**
|
||||
* 提交业务数据时的错误信息。如果正常提交,该值为空。
|
||||
*/
|
||||
@TableField(value = "error_reason")
|
||||
private String errorReason;
|
||||
|
||||
/**
|
||||
* 创建者登录名。
|
||||
*/
|
||||
@TableField(value = "create_login_name")
|
||||
private String createLoginName;
|
||||
|
||||
/**
|
||||
* 创建者中文用户名。
|
||||
*/
|
||||
@TableField(value = "create_username")
|
||||
private String createUsername;
|
||||
|
||||
/**
|
||||
* 创建时间。
|
||||
*/
|
||||
@TableField(value = "create_time")
|
||||
private Date createTime;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.orangeforms.common.flow.model.constant;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 流程类型。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public final class FlowEntryType {
|
||||
|
||||
/**
|
||||
* 普通审批。
|
||||
*/
|
||||
public static final int NORMAL_TYPE = 0;
|
||||
/**
|
||||
* 自动化流程。
|
||||
*/
|
||||
public static final int AUTO_TYPE = 1;
|
||||
|
||||
private static final Map<Object, String> DICT_MAP = new HashMap<>(2);
|
||||
static {
|
||||
DICT_MAP.put(NORMAL_TYPE, "普通审批");
|
||||
DICT_MAP.put(AUTO_TYPE, "自动化流程");
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断参数是否为当前常量字典的合法值。
|
||||
*
|
||||
* @param value 待验证的参数值。
|
||||
* @return 合法返回true,否则false。
|
||||
*/
|
||||
public static boolean isValid(Integer value) {
|
||||
return value != null && DICT_MAP.containsKey(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 私有构造函数,明确标识该常量类的作用。
|
||||
*/
|
||||
private FlowEntryType() {
|
||||
}
|
||||
}
|
||||
@@ -19,11 +19,21 @@ public final class FlowVariableType {
|
||||
* 任务变量。
|
||||
*/
|
||||
public static final int TASK = 1;
|
||||
/**
|
||||
* 系统内置变量。
|
||||
*/
|
||||
public static final int SYSTEM = 2;
|
||||
/**
|
||||
* 自定义变量。
|
||||
*/
|
||||
public static final int CUSTOM = 4;
|
||||
|
||||
private static final Map<Object, String> DICT_MAP = new HashMap<>(2);
|
||||
static {
|
||||
DICT_MAP.put(INSTANCE, "流程实例变量");
|
||||
DICT_MAP.put(TASK, "任务变量");
|
||||
DICT_MAP.put(SYSTEM, "系统内置变量");
|
||||
DICT_MAP.put(CUSTOM, "自定义变量");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.orangeforms.common.flow.object;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 自动化任务的执行数据。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
public class AutoExecData {
|
||||
|
||||
/**
|
||||
* 数据库链接ID。
|
||||
*/
|
||||
private Long dblinkId;
|
||||
/**
|
||||
* 执行sql。
|
||||
*/
|
||||
private String sql;
|
||||
/**
|
||||
* sql参数列表。
|
||||
*/
|
||||
private List<Object> params;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.orangeforms.common.flow.object;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 自动化任务调用HTTP请求的对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
public class AutoHttpRequestInfo {
|
||||
|
||||
public static final String BODY_TYPE_FORMDATA = "formData";
|
||||
public static final String BODY_TYPE_RAW = "raw";
|
||||
public static final String RAW_TYPE_TEXT = "text";
|
||||
public static final String RAW_TYPE_JSON = "json";
|
||||
|
||||
/**
|
||||
* 请求地址。
|
||||
*/
|
||||
private String url;
|
||||
/**
|
||||
* POST/GET/PUT ...
|
||||
*/
|
||||
private String httpMethod;
|
||||
/**
|
||||
* 请求body的类型。
|
||||
*/
|
||||
private String bodyType;
|
||||
/**
|
||||
* 仅当bodyType为raw的时候可用。
|
||||
*/
|
||||
private String rawType;
|
||||
/**
|
||||
* 当bodyType为raw的时候,请求体的数据。
|
||||
*/
|
||||
private String bodyData;
|
||||
/**
|
||||
* HTTP请求头列表。
|
||||
*/
|
||||
private List<AutoTaskConfig.ValueInfo> headerList;
|
||||
/**
|
||||
* 仅当bodyType为formData时可用。
|
||||
*/
|
||||
private List<AutoTaskConfig.ValueInfo> formDataList;
|
||||
/**
|
||||
* url参数。
|
||||
*/
|
||||
private List<AutoTaskConfig.ValueInfo> urlParamList;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.orangeforms.common.flow.object;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 自动化任务调用HTTP的应答对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
public class AutoHttpResponseData {
|
||||
|
||||
public static final String STOP_ON_FAIL = "stop";
|
||||
public static final String CONTINUE_ON_FAIL = "continue";
|
||||
|
||||
/**
|
||||
* 应答成功的HTTP状态码,多个状态码之间逗号分隔。
|
||||
*/
|
||||
private String successStatusCode;
|
||||
/**
|
||||
* 如果请求状态码为成功,还需要进一步根据应答体中的指定字段,进一步判断是否成功。
|
||||
* 如:data.isSuccess。
|
||||
*/
|
||||
private String successBodyField = "success";
|
||||
/**
|
||||
* 请求体中错误信息字段。
|
||||
*/
|
||||
private String errorMessageBodyField = "errorMessage";
|
||||
/**
|
||||
* 失败处理类型。
|
||||
*/
|
||||
private String failHandleType;
|
||||
/**
|
||||
* HTTP请求的应答体定义。
|
||||
*/
|
||||
private String httpResponseBody;
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
package com.orangeforms.common.flow.object;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 自动化任务的执行配置数据。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
public class AutoTaskConfig {
|
||||
|
||||
public static final String SRC_FILTER_SQL = "sql";
|
||||
public static final String SRC_FILTER_FIELD = "field";
|
||||
/**
|
||||
* 固定值。
|
||||
*/
|
||||
public static final int FIXED_VALUE = 0;
|
||||
/**
|
||||
* 表字段值。
|
||||
*/
|
||||
public static final int COLUMN_VALUE = 1;
|
||||
/**
|
||||
* 流程变量。
|
||||
*/
|
||||
public static final int VARIABLE_VALUE = 2;
|
||||
|
||||
/**
|
||||
* 任务标识,同时也是当前任务的输出变量名。
|
||||
*/
|
||||
private String taskKey;
|
||||
/**
|
||||
* 任务名称。
|
||||
*/
|
||||
private String taskName;
|
||||
/**
|
||||
* 执行动作的类型。
|
||||
*/
|
||||
private Integer actionType;
|
||||
/**
|
||||
* 数据库链接Id。
|
||||
*/
|
||||
private Long srcDblinkId;
|
||||
/**
|
||||
* 源数据库类型。
|
||||
*/
|
||||
private Integer srcDblinkType;
|
||||
/**
|
||||
* 源表名称。
|
||||
*/
|
||||
private String srcTableName;
|
||||
/**
|
||||
* 源数据的过滤类型,可能值为sql/field。
|
||||
*/
|
||||
private String srcFilterType;
|
||||
/**
|
||||
* 源数据过滤条件列表。
|
||||
*/
|
||||
private List<FilterInfo> srcFilterList;
|
||||
/**
|
||||
* 源数据过滤sql。
|
||||
*/
|
||||
private String srcFilterSql;
|
||||
/**
|
||||
* 目标数据库链接Id。
|
||||
*/
|
||||
private Long destDblinkId;
|
||||
/**
|
||||
* 目标数据库类型。
|
||||
*/
|
||||
private Integer destDblinkType;
|
||||
/**
|
||||
* 目标表名称。
|
||||
*/
|
||||
private String destTableName;
|
||||
/**
|
||||
* 目标数据的过滤类型,可能值为sql/field。
|
||||
*/
|
||||
private String destFilterType;
|
||||
/**
|
||||
* 目标数据过滤条件列表。
|
||||
*/
|
||||
private List<FilterInfo> destFilterList;
|
||||
/**
|
||||
* 目标数据过滤sql。
|
||||
*/
|
||||
private String destFilterSql;
|
||||
/**
|
||||
* 逻辑删除字段。
|
||||
*/
|
||||
private String logicDeleteField;
|
||||
/**
|
||||
* 数据插入对象
|
||||
*/
|
||||
private List<ValueInfo> insertDataList;
|
||||
/**
|
||||
* 数据插入对象
|
||||
*/
|
||||
private List<ValueInfo> updateDataList;
|
||||
/**
|
||||
* SELECT查询的字段。
|
||||
*/
|
||||
private List<String> selectFieldList;
|
||||
/**
|
||||
* 聚合数据列表。
|
||||
*/
|
||||
private List<AggregationInfo> aggregationDataList;
|
||||
/**
|
||||
* 数值计算表达式。
|
||||
*/
|
||||
private String calculateFormula;
|
||||
/**
|
||||
* HTTP请求信息。
|
||||
*/
|
||||
private AutoHttpRequestInfo httpRequestInfo;
|
||||
/**
|
||||
* HTTP应答数据。
|
||||
*/
|
||||
private AutoHttpResponseData httpResponnseData;
|
||||
|
||||
@Data
|
||||
public static class ValueInfo {
|
||||
|
||||
/**
|
||||
* HTTP任务中使用。
|
||||
*/
|
||||
private String key;
|
||||
/**
|
||||
* 目标字段名。
|
||||
*/
|
||||
private String destColumnName;
|
||||
/**
|
||||
* 值的类型,参考当前对象的常量。
|
||||
*/
|
||||
private Integer type;
|
||||
/**
|
||||
* 值。
|
||||
*/
|
||||
private String srcValue;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class FilterInfo {
|
||||
/**
|
||||
* 过滤字段名。
|
||||
*/
|
||||
private String filterColumnName;
|
||||
/**
|
||||
* 过滤类型。
|
||||
*/
|
||||
private Integer filterType;
|
||||
/**
|
||||
* 过滤值类型。
|
||||
*/
|
||||
private Integer valueType;
|
||||
/**
|
||||
* 过滤值。
|
||||
*/
|
||||
private String filterValue;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class AggregationInfo {
|
||||
/**
|
||||
* 聚合函数,如SUM/COUNT/AVERAGE/MIN/MAX。
|
||||
*/
|
||||
private String aggregationFunction;
|
||||
/**
|
||||
* 聚合字段。
|
||||
*/
|
||||
private String aggregationColumn;
|
||||
/**
|
||||
* 别名。
|
||||
*/
|
||||
private String alias;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.orangeforms.common.flow.object;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 自动化任务的变量对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
public class AutoTaskVariable {
|
||||
/**
|
||||
* 流程任务定义。
|
||||
*/
|
||||
private String taskKey;
|
||||
/**
|
||||
* 流程名称。
|
||||
*/
|
||||
private String taskName;
|
||||
/**
|
||||
* 执行动作的类型。
|
||||
*/
|
||||
private Integer actionType;
|
||||
/**
|
||||
* 输出变量名。
|
||||
*/
|
||||
private String outputVariableName;
|
||||
/**
|
||||
* 输出变量的显示名。
|
||||
*/
|
||||
private String outputVariableShowName;
|
||||
/**
|
||||
* 选择的字段列表。
|
||||
*/
|
||||
private List<String> fieldList;
|
||||
/**
|
||||
* HTTP请求的应答体定义。
|
||||
*/
|
||||
private String httpResponseBody;
|
||||
}
|
||||
@@ -22,7 +22,6 @@ import org.flowable.task.api.Task;
|
||||
import org.flowable.task.api.TaskInfo;
|
||||
import org.flowable.task.api.history.HistoricTaskInstance;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import java.text.ParseException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -46,6 +45,15 @@ public interface FlowApiService {
|
||||
*/
|
||||
ProcessInstance start(String processDefinitionId, Object dataId);
|
||||
|
||||
/**
|
||||
* 启动自动化流程实例。
|
||||
*
|
||||
* @param processDefinitionKey 流程定义标识。
|
||||
* @param variableData 变量参数数据。
|
||||
* @return 新启动的流程实例。
|
||||
*/
|
||||
ProcessInstance startAuto(String processDefinitionKey, JSONObject variableData);
|
||||
|
||||
/**
|
||||
* 完成第一个用户任务。
|
||||
*
|
||||
@@ -515,9 +523,8 @@ public interface FlowApiService {
|
||||
*
|
||||
* @param bpmnXml xml格式的流程模型字符串。
|
||||
* @return 转换后的标准的流程模型。
|
||||
* @throws XMLStreamException XML流处理异常
|
||||
*/
|
||||
BpmnModel convertToBpmnModel(String bpmnXml) throws XMLStreamException;
|
||||
BpmnModel convertToBpmnModel(String bpmnXml);
|
||||
|
||||
/**
|
||||
* 回退到上一个用户任务节点。如果没有指定,则回退到上一个任务。
|
||||
@@ -558,6 +565,14 @@ public interface FlowApiService {
|
||||
Tuple2<Set<String>, Set<String>> getDeptPostIdAndPostIds(
|
||||
FlowTaskExt flowTaskExt, String processInstanceId, boolean historic);
|
||||
|
||||
/**
|
||||
* 获取指定流程实例中正在运行是的任务Id列表。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @return 指定流程实例中正在运行是的任务Id列表。
|
||||
*/
|
||||
List<String> getCurrentActivityIds(String processInstanceId);
|
||||
|
||||
/**
|
||||
* 获取流程图中所有用户任务的映射。
|
||||
*
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.orangeforms.common.flow.service;
|
||||
|
||||
import com.orangeforms.common.core.base.service.IBaseService;
|
||||
import com.orangeforms.common.flow.model.FlowAutoVariableLog;
|
||||
|
||||
/**
|
||||
* 自动化流程变量操作服务接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowAutoVariableLogService extends IBaseService<FlowAutoVariableLog, Long> {
|
||||
|
||||
/**
|
||||
* 保存数据对象。
|
||||
*
|
||||
* @param flowAutoVariableLog 数据对象。
|
||||
*/
|
||||
void saveNew(FlowAutoVariableLog flowAutoVariableLog);
|
||||
|
||||
/**
|
||||
* 获取指定自动化流程实例的最新变量对象。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @return 自动化流程实例的最新变量对象。
|
||||
*/
|
||||
FlowAutoVariableLog getAutoVariableByProcessInstanceId(String processInstanceId);
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.orangeforms.common.flow.service;
|
||||
|
||||
import com.orangeforms.common.core.base.service.IBaseService;
|
||||
import com.orangeforms.common.dbutil.object.SqlTable;
|
||||
import com.orangeforms.common.dbutil.object.SqlTableColumn;
|
||||
import com.orangeforms.common.flow.model.FlowDblink;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 数据库链接数据操作服务接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowDblinkService extends IBaseService<FlowDblink, Long> {
|
||||
|
||||
/**
|
||||
* 保存新增对象。
|
||||
*
|
||||
* @param flowDblink 新增对象。
|
||||
* @return 返回新增对象。
|
||||
*/
|
||||
FlowDblink saveNew(FlowDblink flowDblink);
|
||||
|
||||
/**
|
||||
* 更新数据对象。
|
||||
*
|
||||
* @param flowDblink 更新的对象。
|
||||
* @param originalFlowDblink 原有数据对象。
|
||||
* @return 成功返回true,否则false。
|
||||
*/
|
||||
boolean update(FlowDblink flowDblink, FlowDblink originalFlowDblink);
|
||||
|
||||
/**
|
||||
* 删除指定数据。
|
||||
*
|
||||
* @param dblinkId 主键Id。
|
||||
* @return 成功返回true,否则false。
|
||||
*/
|
||||
boolean remove(Long dblinkId);
|
||||
|
||||
/**
|
||||
* 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。
|
||||
* 如果需要同时获取关联数据,请移步(getOnlineDblinkListWithRelation)方法。
|
||||
*
|
||||
* @param filter 过滤对象。
|
||||
* @param orderBy 排序参数。
|
||||
* @return 查询结果集。
|
||||
*/
|
||||
List<FlowDblink> getFlowDblinkList(FlowDblink filter, String orderBy);
|
||||
|
||||
/**
|
||||
* 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。
|
||||
* 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。
|
||||
* 如果仅仅需要获取主表数据,请移步(getOnlineDblinkList),以便获取更好的查询性能。
|
||||
*
|
||||
* @param filter 主表过滤对象。
|
||||
* @param orderBy 排序参数。
|
||||
* @return 查询结果集。
|
||||
*/
|
||||
List<FlowDblink> getFlowDblinkListWithRelation(FlowDblink filter, String orderBy);
|
||||
|
||||
/**
|
||||
* 获取指定DBLink下面的全部数据表。
|
||||
*
|
||||
* @param dblink 数据库链接对象。
|
||||
* @return 全部数据表列表。
|
||||
*/
|
||||
List<SqlTable> getDblinkTableList(FlowDblink dblink);
|
||||
|
||||
/**
|
||||
* 获取指定DBLink下,指定表名的数据表对象,及其关联字段列表。
|
||||
*
|
||||
* @param dblink 数据库链接对象。
|
||||
* @param tableName 数据库中的数据表名。
|
||||
* @return 数据表对象。
|
||||
*/
|
||||
SqlTable getDblinkTable(FlowDblink dblink, String tableName);
|
||||
|
||||
/**
|
||||
* 获取指定DBLink下,指定表名的字段列表。
|
||||
*
|
||||
* @param dblink 数据库链接对象。
|
||||
* @param tableName 数据库中的数据表名。
|
||||
* @return 表的字段列表。
|
||||
*/
|
||||
List<SqlTableColumn> getDblinkTableColumnList(FlowDblink dblink, String tableName);
|
||||
}
|
||||
@@ -76,6 +76,13 @@ public interface FlowTaskExtService extends IBaseService<FlowTaskExt, String> {
|
||||
String executionId,
|
||||
FlowTaskExt flowTaskExt);
|
||||
|
||||
/**
|
||||
* 验证自动化任务的配置,如果有问题直接抛出MyRuntimeException异常。
|
||||
*
|
||||
* @param taskExt 流程任务的扩展。
|
||||
*/
|
||||
void verifyAutoTaskConfig(FlowTaskExt taskExt);
|
||||
|
||||
/**
|
||||
* 通过UserTask对象中的扩展节点信息,构建FLowTaskExt对象。
|
||||
*
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.orangeforms.common.flow.service;
|
||||
|
||||
import com.orangeforms.common.core.base.service.IBaseService;
|
||||
import com.orangeforms.common.flow.model.FlowTransProducer;
|
||||
|
||||
/**
|
||||
* 流程引擎审批操作的生产者流水服务接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowTransProducerService extends IBaseService<FlowTransProducer, Long> {
|
||||
|
||||
/**
|
||||
* 保存新数据。
|
||||
*
|
||||
* @param data 数据对象。
|
||||
* @return 更新后的对象。
|
||||
*/
|
||||
FlowTransProducer saveNew(FlowTransProducer data);
|
||||
}
|
||||
@@ -25,14 +25,13 @@ import com.orangeforms.common.flow.constant.FlowConstant;
|
||||
import com.orangeforms.common.flow.constant.FlowTaskStatus;
|
||||
import com.orangeforms.common.flow.exception.FlowOperationException;
|
||||
import com.orangeforms.common.flow.model.*;
|
||||
import com.orangeforms.common.flow.model.constant.FlowEntryType;
|
||||
import com.orangeforms.common.flow.object.FlowEntryExtensionData;
|
||||
import com.orangeforms.common.flow.object.FlowTaskMultiSignAssign;
|
||||
import com.orangeforms.common.flow.object.FlowTaskOperation;
|
||||
import com.orangeforms.common.flow.object.FlowTaskPostCandidateGroup;
|
||||
import com.orangeforms.common.flow.service.*;
|
||||
import com.orangeforms.common.flow.util.BaseFlowIdentityExtHelper;
|
||||
import com.orangeforms.common.flow.util.CustomChangeActivityStateBuilderImpl;
|
||||
import com.orangeforms.common.flow.util.FlowCustomExtFactory;
|
||||
import com.orangeforms.common.flow.util.*;
|
||||
import com.orangeforms.common.flow.vo.FlowTaskVo;
|
||||
import com.orangeforms.common.flow.vo.FlowUserInfoVo;
|
||||
import lombok.Cleanup;
|
||||
@@ -114,6 +113,14 @@ public class FlowApiServiceImpl implements FlowApiService {
|
||||
private FlowCustomExtFactory flowCustomExtFactory;
|
||||
@Autowired
|
||||
private FlowMultiInstanceTransService flowMultiInstanceTransService;
|
||||
@Autowired
|
||||
private FlowTransProducerService flowTransProducerService;
|
||||
@Autowired
|
||||
private FlowAutoVariableLogService flowAutoVariableLogService;
|
||||
@Autowired
|
||||
private FlowOperationHelper flowOperationHelper;
|
||||
@Autowired
|
||||
private AutoFlowHelper autoFlowHelper;
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
@@ -134,6 +141,45 @@ public class FlowApiServiceImpl implements FlowApiService {
|
||||
return builder.start();
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public ProcessInstance startAuto(String processDefinitionKey, JSONObject variableData) {
|
||||
ResponseResult<FlowEntry> flowEntryResult = flowOperationHelper.verifyAndGetFlowEntry(processDefinitionKey);
|
||||
if (!flowEntryResult.isSuccess()) {
|
||||
throw new MyRuntimeException(flowEntryResult.getErrorMessage());
|
||||
}
|
||||
FlowEntry flowEntry = flowEntryResult.getData();
|
||||
if (!flowEntry.getFlowType().equals(FlowEntryType.AUTO_TYPE)) {
|
||||
throw new MyRuntimeException("数据验证失败,该接口只能启动自动化流程!");
|
||||
}
|
||||
JSONObject systemVariables = autoFlowHelper.getNonRealtimeSystemVariables();
|
||||
if (variableData == null) {
|
||||
variableData = new JSONObject();
|
||||
}
|
||||
variableData.putAll(systemVariables);
|
||||
AutoFlowHelper.setStartAutoInitVariables(variableData);
|
||||
TokenData tokenData = TokenData.takeFromRequest();
|
||||
Authentication.setAuthenticatedUserId(tokenData.getLoginName());
|
||||
String businessKey = variableData.getString("businessKey");
|
||||
String processDefinitionId = flowEntry.getMainFlowEntryPublish().getProcessDefinitionId();
|
||||
ProcessInstanceBuilder builder =
|
||||
runtimeService.createProcessInstanceBuilder()
|
||||
.processDefinitionId(processDefinitionId).businessKey(businessKey);
|
||||
if (tokenData.getTenantId() != null) {
|
||||
builder.tenantId(tokenData.getTenantId().toString());
|
||||
} else {
|
||||
if (tokenData.getAppCode() != null) {
|
||||
builder.tenantId(tokenData.getAppCode());
|
||||
}
|
||||
}
|
||||
ProcessInstance instance = builder.start();
|
||||
FlowAutoVariableLog data = new FlowAutoVariableLog();
|
||||
data.setProcessInstanceId(instance.getProcessInstanceId());
|
||||
data.setVariableData(variableData.toJSONString());
|
||||
flowAutoVariableLogService.saveNew(data);
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public Task takeFirstTask(String processInstanceId, FlowTaskComment flowTaskComment, JSONObject taskVariableData) {
|
||||
@@ -983,6 +1029,12 @@ public class FlowApiServiceImpl implements FlowApiService {
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public CallResult stopProcessInstance(String processInstanceId, String stopReason, int status) {
|
||||
ProcessInstance instance = this.getProcessInstance(processInstanceId);
|
||||
FlowEntry flowEntry = flowEntryService.getFlowEntryFromCache(instance.getProcessDefinitionKey());
|
||||
if (flowEntry.getFlowType().equals(FlowEntryType.AUTO_TYPE)) {
|
||||
runtimeService.deleteProcessInstance(processInstanceId, stopReason);
|
||||
return CallResult.ok();
|
||||
}
|
||||
List<Task> taskList = taskService.createTaskQuery().processInstanceId(processInstanceId).active().list();
|
||||
if (CollUtil.isEmpty(taskList)) {
|
||||
return CallResult.error("数据验证失败,当前流程尚未开始或已经结束!");
|
||||
@@ -1092,11 +1144,15 @@ public class FlowApiServiceImpl implements FlowApiService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BpmnModel convertToBpmnModel(String bpmnXml) throws XMLStreamException {
|
||||
BpmnXMLConverter converter = new BpmnXMLConverter();
|
||||
InputStream in = new ByteArrayInputStream(bpmnXml.getBytes(StandardCharsets.UTF_8));
|
||||
@Cleanup XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(in);
|
||||
return converter.convertToBpmnModel(reader);
|
||||
public BpmnModel convertToBpmnModel(String bpmnXml) {
|
||||
try {
|
||||
BpmnXMLConverter converter = new BpmnXMLConverter();
|
||||
InputStream in = new ByteArrayInputStream(bpmnXml.getBytes(StandardCharsets.UTF_8));
|
||||
@Cleanup XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(in);
|
||||
return converter.convertToBpmnModel(reader);
|
||||
} catch (XMLStreamException e) {
|
||||
throw new MyRuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -1722,6 +1778,15 @@ public class FlowApiServiceImpl implements FlowApiService {
|
||||
return new Tuple2<>(deptPostIdSet, postIdSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getCurrentActivityIds(String processInstanceId) {
|
||||
List<Execution> runExecutionList =
|
||||
runtimeService.createExecutionQuery().processInstanceId(processInstanceId).list();
|
||||
return runExecutionList.stream()
|
||||
.map(Execution::getActivityId)
|
||||
.filter(StrUtil::isNotBlank).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, UserTask> getAllUserTaskMap(String processDefinitionId) {
|
||||
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.orangeforms.common.flow.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.orangeforms.common.core.annotation.MyDataSourceResolver;
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.core.base.service.BaseService;
|
||||
import com.orangeforms.common.core.constant.ApplicationConstant;
|
||||
import com.orangeforms.common.core.util.DefaultDataSourceResolver;
|
||||
import com.orangeforms.common.core.util.MyCommonUtil;
|
||||
import com.orangeforms.common.flow.dao.FlowAutoVariableLogMapper;
|
||||
import com.orangeforms.common.flow.model.FlowAutoVariableLog;
|
||||
import com.orangeforms.common.flow.service.FlowAutoVariableLogService;
|
||||
import com.orangeforms.common.sequence.wrapper.IdGeneratorWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Slf4j
|
||||
@MyDataSourceResolver(
|
||||
resolver = DefaultDataSourceResolver.class,
|
||||
intArg = ApplicationConstant.COMMON_FLOW_AND_ONLINE_DATASOURCE_TYPE)
|
||||
@Service("flowAutoVariableLogService")
|
||||
public class FlowAutoVariableLogServiceImpl extends BaseService<FlowAutoVariableLog, Long> implements FlowAutoVariableLogService {
|
||||
|
||||
@Autowired
|
||||
private FlowAutoVariableLogMapper flowAutoVariableLogMapper;
|
||||
@Autowired
|
||||
private IdGeneratorWrapper idGenerator;
|
||||
|
||||
@Override
|
||||
protected BaseDaoMapper<FlowAutoVariableLog> mapper() {
|
||||
return flowAutoVariableLogMapper;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void saveNew(FlowAutoVariableLog o) {
|
||||
o.setId(idGenerator.nextLongId());
|
||||
o.setTraceId(MyCommonUtil.getTraceId());
|
||||
o.setCreateTime(new Date());
|
||||
flowAutoVariableLogMapper.insert(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlowAutoVariableLog getAutoVariableByProcessInstanceId(String processInstanceId) {
|
||||
LambdaQueryWrapper<FlowAutoVariableLog> qw = new LambdaQueryWrapper<>();
|
||||
qw.eq(FlowAutoVariableLog::getProcessInstanceId, processInstanceId);
|
||||
return flowAutoVariableLogMapper.selectOne(qw);
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Slf4j
|
||||
@MyDataSourceResolver(
|
||||
resolver = DefaultDataSourceResolver.class,
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
package com.orangeforms.common.flow.service.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||
import com.github.pagehelper.Page;
|
||||
import com.orangeforms.common.core.annotation.MyDataSourceResolver;
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.core.base.service.BaseService;
|
||||
import com.orangeforms.common.core.constant.ApplicationConstant;
|
||||
import com.orangeforms.common.core.object.MyRelationParam;
|
||||
import com.orangeforms.common.core.object.TokenData;
|
||||
import com.orangeforms.common.core.util.DefaultDataSourceResolver;
|
||||
import com.orangeforms.common.dbutil.object.SqlTable;
|
||||
import com.orangeforms.common.dbutil.object.SqlTableColumn;
|
||||
import com.orangeforms.common.flow.dao.FlowDblinkMapper;
|
||||
import com.orangeforms.common.flow.model.FlowDblink;
|
||||
import com.orangeforms.common.flow.service.FlowDblinkService;
|
||||
import com.orangeforms.common.flow.util.FlowDataSourceUtil;
|
||||
import com.orangeforms.common.sequence.wrapper.IdGeneratorWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@MyDataSourceResolver(
|
||||
resolver = DefaultDataSourceResolver.class,
|
||||
intArg = ApplicationConstant.COMMON_FLOW_AND_ONLINE_DATASOURCE_TYPE)
|
||||
@Service("flowDblinkService")
|
||||
public class FlowDblinkServiceImpl extends BaseService<FlowDblink, Long> implements FlowDblinkService {
|
||||
|
||||
@Autowired
|
||||
private FlowDblinkMapper flowDblinkMapper;
|
||||
@Autowired
|
||||
private IdGeneratorWrapper idGenerator;
|
||||
@Autowired
|
||||
private FlowDataSourceUtil dataSourceUtil;
|
||||
|
||||
/**
|
||||
* 返回当前Service的主表Mapper对象。
|
||||
*
|
||||
* @return 主表Mapper对象。
|
||||
*/
|
||||
@Override
|
||||
protected BaseDaoMapper<FlowDblink> mapper() {
|
||||
return flowDblinkMapper;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public FlowDblink saveNew(FlowDblink flowDblink) {
|
||||
flowDblinkMapper.insert(this.buildDefaultValue(flowDblink));
|
||||
return flowDblink;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public boolean update(FlowDblink flowDblink, FlowDblink originalFlowDblink) {
|
||||
if (!StrUtil.equals(flowDblink.getConfiguration(), originalFlowDblink.getConfiguration())) {
|
||||
dataSourceUtil.removeDataSource(flowDblink.getDblinkId());
|
||||
}
|
||||
flowDblink.setAppCode(TokenData.takeFromRequest().getAppCode());
|
||||
flowDblink.setCreateUserId(originalFlowDblink.getCreateUserId());
|
||||
flowDblink.setUpdateUserId(TokenData.takeFromRequest().getUserId());
|
||||
flowDblink.setCreateTime(originalFlowDblink.getCreateTime());
|
||||
flowDblink.setUpdateTime(new Date());
|
||||
// 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。
|
||||
UpdateWrapper<FlowDblink> uw = this.createUpdateQueryForNullValue(flowDblink, flowDblink.getDblinkId());
|
||||
return flowDblinkMapper.update(flowDblink, uw) == 1;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public boolean remove(Long dblinkId) {
|
||||
dataSourceUtil.removeDataSource(dblinkId);
|
||||
return flowDblinkMapper.deleteById(dblinkId) == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowDblink> getFlowDblinkList(FlowDblink filter, String orderBy) {
|
||||
if (filter == null) {
|
||||
filter = new FlowDblink();
|
||||
}
|
||||
filter.setAppCode(TokenData.takeFromRequest().getAppCode());
|
||||
return flowDblinkMapper.getFlowDblinkList(filter, orderBy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowDblink> getFlowDblinkListWithRelation(FlowDblink filter, String orderBy) {
|
||||
List<FlowDblink> resultList = this.getFlowDblinkList(filter, orderBy);
|
||||
// 在缺省生成的代码中,如果查询结果resultList不是Page对象,说明没有分页,那么就很可能是数据导出接口调用了当前方法。
|
||||
// 为了避免一次性的大量数据关联,规避因此而造成的系统运行性能冲击,这里手动进行了分批次读取,开发者可按需修改该值。
|
||||
int batchSize = resultList instanceof Page ? 0 : 1000;
|
||||
this.buildRelationForDataList(resultList, MyRelationParam.normal(), batchSize);
|
||||
return resultList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SqlTable> getDblinkTableList(FlowDblink dblink) {
|
||||
List<SqlTable> resultList = dataSourceUtil.getTableList(dblink.getDblinkId(), null);
|
||||
resultList.forEach(t -> t.setDblinkId(dblink.getDblinkId()));
|
||||
return resultList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlTable getDblinkTable(FlowDblink dblink, String tableName) {
|
||||
if (dblink.getDblinkId() == null || StrUtil.isBlank(tableName)) {
|
||||
return null;
|
||||
}
|
||||
SqlTable sqlTable = dataSourceUtil.getTable(dblink.getDblinkId(), tableName);
|
||||
sqlTable.setDblinkId(dblink.getDblinkId());
|
||||
sqlTable.setColumnList(getDblinkTableColumnList(dblink, tableName));
|
||||
return sqlTable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SqlTableColumn> getDblinkTableColumnList(FlowDblink dblink, String tableName) {
|
||||
List<SqlTableColumn> columnList = dataSourceUtil.getTableColumnList(dblink.getDblinkId(), tableName);
|
||||
columnList.forEach(c -> this.makeupSqlTableColumn(c, dblink.getDblinkType()));
|
||||
return columnList;
|
||||
}
|
||||
|
||||
private void makeupSqlTableColumn(SqlTableColumn sqlTableColumn, int dblinkType) {
|
||||
sqlTableColumn.setDblinkType(dblinkType);
|
||||
sqlTableColumn.setAutoIncrement("auto_increment".equals(sqlTableColumn.getExtra()));
|
||||
}
|
||||
|
||||
private FlowDblink buildDefaultValue(FlowDblink flowDblink) {
|
||||
flowDblink.setDblinkId(idGenerator.nextLongId());
|
||||
TokenData tokenData = TokenData.takeFromRequest();
|
||||
flowDblink.setCreateUserId(tokenData.getUserId());
|
||||
flowDblink.setUpdateUserId(tokenData.getUserId());
|
||||
Date now = new Date();
|
||||
flowDblink.setCreateTime(now);
|
||||
flowDblink.setUpdateTime(now);
|
||||
flowDblink.setAppCode(tokenData.getAppCode());
|
||||
return flowDblink;
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import com.orangeforms.common.flow.dao.FlowEntryPublishVariableMapper;
|
||||
import com.orangeforms.common.flow.listener.*;
|
||||
import com.orangeforms.common.flow.model.*;
|
||||
import com.orangeforms.common.flow.model.constant.FlowEntryStatus;
|
||||
import com.orangeforms.common.flow.model.constant.FlowEntryType;
|
||||
import com.orangeforms.common.flow.model.constant.FlowVariableType;
|
||||
import com.orangeforms.common.flow.object.FlowElementExtProperty;
|
||||
import com.orangeforms.common.flow.object.FlowEntryExtensionData;
|
||||
@@ -34,9 +35,7 @@ import com.orangeforms.common.flow.util.FlowCustomExtFactory;
|
||||
import com.orangeforms.common.flow.util.FlowRedisKeyUtil;
|
||||
import com.orangeforms.common.redis.util.CommonRedisUtil;
|
||||
import com.orangeforms.common.sequence.wrapper.IdGeneratorWrapper;
|
||||
import lombok.Cleanup;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.bpmn.converter.BpmnXMLConverter;
|
||||
import org.flowable.bpmn.model.*;
|
||||
import org.flowable.engine.RepositoryService;
|
||||
import org.flowable.engine.repository.Deployment;
|
||||
@@ -45,12 +44,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.xml.stream.XMLInputFactory;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -116,19 +109,16 @@ public class FlowEntryServiceImpl extends BaseService<FlowEntry, Long> implement
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void publish(FlowEntry flowEntry, String initTaskInfo) throws XMLStreamException {
|
||||
commonRedisUtil.evictFormCache(
|
||||
FlowRedisKeyUtil.makeFlowEntryKey(flowEntry.getProcessDefinitionKey()));
|
||||
public void publish(FlowEntry flowEntry, String initTaskInfo) {
|
||||
commonRedisUtil.evictFormCache(FlowRedisKeyUtil.makeFlowEntryKey(flowEntry.getProcessDefinitionKey()));
|
||||
FlowCategory flowCategory = flowCategoryService.getById(flowEntry.getCategoryId());
|
||||
InputStream xmlStream = new ByteArrayInputStream(
|
||||
flowEntry.getBpmnXml().getBytes(StandardCharsets.UTF_8));
|
||||
@Cleanup XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(xmlStream);
|
||||
BpmnXMLConverter converter = new BpmnXMLConverter();
|
||||
BpmnModel bpmnModel = converter.convertToBpmnModel(reader);
|
||||
BpmnModel bpmnModel = flowApiService.convertToBpmnModel(flowEntry.getBpmnXml());
|
||||
bpmnModel.getMainProcess().setName(flowEntry.getProcessDefinitionName());
|
||||
bpmnModel.getMainProcess().setId(flowEntry.getProcessDefinitionKey());
|
||||
this.processAutomaticTask(flowEntry, bpmnModel);
|
||||
flowApiService.addProcessInstanceEndListener(bpmnModel, FlowFinishedListener.class);
|
||||
List<FlowTaskExt> flowTaskExtList = flowTaskExtService.buildTaskExtList(bpmnModel);
|
||||
flowTaskExtList.forEach(t -> flowTaskExtService.verifyAutoTaskConfig(t));
|
||||
if (StrUtil.isNotBlank(flowEntry.getExtensionData())) {
|
||||
FlowEntryExtensionData flowEntryExtensionData =
|
||||
JSON.parseObject(flowEntry.getExtensionData(), FlowEntryExtensionData.class);
|
||||
@@ -343,6 +333,18 @@ public class FlowEntryServiceImpl extends BaseService<FlowEntry, Long> implement
|
||||
return CallResult.ok();
|
||||
}
|
||||
|
||||
private void processAutomaticTask(FlowEntry flowEntry, BpmnModel bpmnModel) {
|
||||
if (flowEntry.getFlowType().equals(FlowEntryType.NORMAL_TYPE)) {
|
||||
return;
|
||||
}
|
||||
List<ReceiveTask> receiveTasks = bpmnModel.getMainProcess().getFlowElements()
|
||||
.stream().filter(ReceiveTask.class::isInstance).map(ReceiveTask.class::cast).toList();
|
||||
receiveTasks.forEach(r -> {
|
||||
flowApiService.addExecutionListener(r, ReceiveTaskStartListener.class, "start", null);
|
||||
flowApiService.addExecutionListener(r, ReceiveTaskEndListener.class, "end", null);
|
||||
});
|
||||
}
|
||||
|
||||
private void insertBuiltinEntryVariables(Long entryId) {
|
||||
Date now = new Date();
|
||||
FlowEntryVariable operationTypeVariable = new FlowEntryVariable();
|
||||
@@ -447,6 +449,9 @@ public class FlowEntryServiceImpl extends BaseService<FlowEntry, Long> implement
|
||||
.filter(UserTask.class::isInstance).collect(Collectors.toMap(FlowElement::getId, c -> c));
|
||||
BaseFlowIdentityExtHelper flowIdentityExtHelper = flowCustomExtFactory.getFlowIdentityExtHelper();
|
||||
for (FlowTaskExt t : flowTaskExtList) {
|
||||
if (!elementMap.containsKey(t.getTaskId())) {
|
||||
continue;
|
||||
}
|
||||
UserTask userTask = (UserTask) elementMap.get(t.getTaskId());
|
||||
flowApiService.addTaskCreateListener(userTask, FlowUserTaskListener.class);
|
||||
Map<String, List<ExtensionAttribute>> attributes = userTask.getAttributes();
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.orangeforms.common.flow.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.text.StrFormatter;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
@@ -15,7 +16,9 @@ import com.orangeforms.common.core.exception.MyRuntimeException;
|
||||
import com.orangeforms.common.core.object.Tuple2;
|
||||
import com.orangeforms.common.core.util.DefaultDataSourceResolver;
|
||||
import com.orangeforms.common.flow.constant.FlowApprovalType;
|
||||
import com.orangeforms.common.flow.constant.FlowAutoActionType;
|
||||
import com.orangeforms.common.flow.constant.FlowConstant;
|
||||
import com.orangeforms.common.flow.object.AutoTaskConfig;
|
||||
import com.orangeforms.common.flow.object.FlowElementExtProperty;
|
||||
import com.orangeforms.common.flow.object.FlowTaskMultiSignAssign;
|
||||
import com.orangeforms.common.flow.object.FlowUserTaskExtData;
|
||||
@@ -221,16 +224,29 @@ public class FlowTaskExtServiceImpl extends BaseService<FlowTaskExt, String> imp
|
||||
return resultUserMapList;
|
||||
}
|
||||
|
||||
private void buildUserMapList(
|
||||
List<FlowUserInfoVo> userInfoList, Set<String> loginNameSet, List<FlowUserInfoVo> userMapList) {
|
||||
if (CollUtil.isEmpty(userInfoList)) {
|
||||
@Override
|
||||
public void verifyAutoTaskConfig(FlowTaskExt taskExt) {
|
||||
if (StrUtil.isBlank(taskExt.getAutoConfigJson())) {
|
||||
return;
|
||||
}
|
||||
for (FlowUserInfoVo userInfo : userInfoList) {
|
||||
if (!loginNameSet.contains(userInfo.getLoginName())) {
|
||||
loginNameSet.add(userInfo.getLoginName());
|
||||
userMapList.add(userInfo);
|
||||
AutoTaskConfig taskConfig = JSON.parseObject(taskExt.getAutoConfigJson(), AutoTaskConfig.class);
|
||||
this.verifyDataOperationTask(taskConfig);
|
||||
String errorMessage;
|
||||
if (taskConfig.getActionType().equals(FlowAutoActionType.SELECT_ONE)) {
|
||||
this.verifySrcTableNameEmpty(taskConfig);
|
||||
} else if (taskConfig.getActionType().equals(FlowAutoActionType.AGGREGATION_CALC)) {
|
||||
this.verifySrcTableNameEmpty(taskConfig);
|
||||
if (CollUtil.isEmpty(taskConfig.getAggregationDataList())) {
|
||||
errorMessage = StrFormatter.format("任务 [{}] 的聚合计算配置不能为空!", taskConfig.getTaskName());
|
||||
throw new MyRuntimeException(errorMessage);
|
||||
}
|
||||
} else if (taskConfig.getActionType().equals(FlowAutoActionType.NUMBER_CALC)) {
|
||||
if (StrUtil.isBlank(taskConfig.getCalculateFormula())) {
|
||||
errorMessage = StrFormatter.format("任务 [{}] 的数值计算公式不能为空!", taskConfig.getTaskName());
|
||||
throw new MyRuntimeException(errorMessage);
|
||||
}
|
||||
} else if (taskConfig.getActionType().equals(FlowAutoActionType.HTTP)) {
|
||||
this.verifyHttpConfig(taskConfig);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,10 +388,93 @@ public class FlowTaskExtServiceImpl extends BaseService<FlowTaskExt, String> imp
|
||||
return propertiesData;
|
||||
}
|
||||
|
||||
private void verifyDataOperationTask(AutoTaskConfig taskConfig) {
|
||||
String errorMessage;
|
||||
if (taskConfig.getActionType().equals(FlowAutoActionType.ADD_NEW)) {
|
||||
this.verifyDestTableNameEmpty(taskConfig);
|
||||
if (CollUtil.isEmpty(taskConfig.getInsertDataList())) {
|
||||
errorMessage = StrFormatter.format("任务 [{}] 的数据新增配置不能为空!", taskConfig.getTaskName());
|
||||
throw new MyRuntimeException(errorMessage);
|
||||
}
|
||||
} else if (taskConfig.getActionType().equals(FlowAutoActionType.UPDATE)) {
|
||||
this.verifyDestTableNameEmpty(taskConfig);
|
||||
if (CollUtil.isEmpty(taskConfig.getUpdateDataList())) {
|
||||
errorMessage = StrFormatter.format("任务 [{}] 的数据更新配置不能为空!", taskConfig.getTaskName());
|
||||
throw new MyRuntimeException(errorMessage);
|
||||
}
|
||||
} else if (taskConfig.getActionType().equals(FlowAutoActionType.DELETE)) {
|
||||
this.verifyDestTableNameEmpty(taskConfig);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyDestTableNameEmpty(AutoTaskConfig taskConfig) {
|
||||
if (StrUtil.isBlank(taskConfig.getDestTableName())) {
|
||||
String errorMessage = StrFormatter.format("任务 [{}] 的目标表不能为空!", taskConfig.getTaskName());
|
||||
throw new MyRuntimeException(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private void verifySrcTableNameEmpty(AutoTaskConfig taskConfig) {
|
||||
if (StrUtil.isBlank(taskConfig.getSrcTableName())) {
|
||||
String errorMessage = StrFormatter.format("任务 [{}] 的源表不能为空!", taskConfig.getTaskName());
|
||||
throw new MyRuntimeException(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyHttpConfig(AutoTaskConfig taskConfig) {
|
||||
if (StrUtil.isBlank(taskConfig.getHttpRequestInfo().getUrl())) {
|
||||
String errorMessage = StrFormatter.format("任务 [{}] 的URL不能为空!", taskConfig.getTaskName());
|
||||
throw new MyRuntimeException(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private void buildUserMapList(
|
||||
List<FlowUserInfoVo> userInfoList, Set<String> loginNameSet, List<FlowUserInfoVo> userMapList) {
|
||||
if (CollUtil.isEmpty(userInfoList)) {
|
||||
return;
|
||||
}
|
||||
for (FlowUserInfoVo userInfo : userInfoList) {
|
||||
if (!loginNameSet.contains(userInfo.getLoginName())) {
|
||||
loginNameSet.add(userInfo.getLoginName());
|
||||
userMapList.add(userInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private FlowTaskExt buildTaskExtByAutoTask(Task task) {
|
||||
FlowTaskExt flowTaskExt = new FlowTaskExt();
|
||||
flowTaskExt.setTaskId(task.getId());
|
||||
flowTaskExt.setGroupType(FlowConstant.GROUP_TYPE_AUTO_EXEC);
|
||||
Map<String, List<ExtensionElement>> extensionMap = task.getExtensionElements();
|
||||
List<ExtensionElement> autoConfigElements = extensionMap.get("taskInfo");
|
||||
if (CollUtil.isEmpty(autoConfigElements)) {
|
||||
return flowTaskExt;
|
||||
}
|
||||
ExtensionElement autoConfigElement = autoConfigElements.get(0);
|
||||
Map<String, List<ExtensionAttribute>> attributesMap = autoConfigElement.getAttributes();
|
||||
if (attributesMap != null) {
|
||||
List<ExtensionAttribute> attributes = attributesMap.get("data");
|
||||
if (CollUtil.isNotEmpty(attributes)) {
|
||||
ExtensionAttribute attribute = attributes.get(0);
|
||||
if (StrUtil.isNotBlank(attribute.getValue())) {
|
||||
AutoTaskConfig taskConfig = JSONObject.parseObject(attribute.getValue(), AutoTaskConfig.class);
|
||||
taskConfig.setTaskKey(task.getId());
|
||||
taskConfig.setTaskName(task.getName());
|
||||
flowTaskExt.setAutoConfigJson(JSON.toJSONString(taskConfig));
|
||||
}
|
||||
}
|
||||
}
|
||||
return flowTaskExt;
|
||||
}
|
||||
|
||||
private void doBuildTaskExtList(FlowElement element, List<FlowTaskExt> flowTaskExtList) {
|
||||
if (element instanceof UserTask) {
|
||||
FlowTaskExt flowTaskExt = this.buildTaskExtByUserTask((UserTask) element);
|
||||
flowTaskExtList.add(flowTaskExt);
|
||||
} else if (element instanceof ServiceTask || element instanceof ReceiveTask) {
|
||||
FlowTaskExt flowTaskExt = this.buildTaskExtByAutoTask((Task) element);
|
||||
flowTaskExtList.add(flowTaskExt);
|
||||
} else if (element instanceof SubProcess) {
|
||||
Collection<FlowElement> flowElements = ((SubProcess) element).getFlowElements();
|
||||
for (FlowElement element1 : flowElements) {
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.orangeforms.common.flow.service.impl;
|
||||
|
||||
import com.orangeforms.common.core.annotation.MyDataSourceResolver;
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.core.base.service.BaseService;
|
||||
import com.orangeforms.common.core.constant.ApplicationConstant;
|
||||
import com.orangeforms.common.core.object.TokenData;
|
||||
import com.orangeforms.common.core.util.DefaultDataSourceResolver;
|
||||
import com.orangeforms.common.core.util.MyCommonUtil;
|
||||
import com.orangeforms.common.flow.dao.FlowTransProducerMapper;
|
||||
import com.orangeforms.common.flow.model.FlowTransProducer;
|
||||
import com.orangeforms.common.flow.service.FlowTransProducerService;
|
||||
import com.orangeforms.common.sequence.wrapper.IdGeneratorWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
@Slf4j
|
||||
@MyDataSourceResolver(
|
||||
resolver = DefaultDataSourceResolver.class,
|
||||
intArg = ApplicationConstant.COMMON_FLOW_AND_ONLINE_DATASOURCE_TYPE)
|
||||
@Service("flowTransProducerService")
|
||||
public class FlowTransProducerServiceImpl extends BaseService<FlowTransProducer, Long> implements FlowTransProducerService {
|
||||
|
||||
@Autowired
|
||||
private FlowTransProducerMapper flowTransProducerMapper;
|
||||
@Autowired
|
||||
private IdGeneratorWrapper idGenerator;
|
||||
|
||||
@Override
|
||||
protected BaseDaoMapper<FlowTransProducer> mapper() {
|
||||
return flowTransProducerMapper;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public FlowTransProducer saveNew(FlowTransProducer data) {
|
||||
if (data.getTransId() == null) {
|
||||
data.setTransId(idGenerator.nextLongId());
|
||||
}
|
||||
TokenData tokenData = TokenData.takeFromRequest();
|
||||
if (tokenData != null) {
|
||||
data.setAppCode(tokenData.getAppCode());
|
||||
data.setCreateLoginName(tokenData.getLoginName());
|
||||
data.setCreateUsername(tokenData.getShowName());
|
||||
}
|
||||
data.setCreateTime(new Date());
|
||||
data.setTraceId(MyCommonUtil.getTraceId());
|
||||
flowTransProducerMapper.insert(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public boolean updateById(FlowTransProducer data) {
|
||||
return mapper().updateById(data) != 0;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public boolean removeById(Serializable transId) {
|
||||
return mapper().deleteById(transId) != 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,657 @@
|
||||
package com.orangeforms.common.flow.util;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.text.StrFormatter;
|
||||
import cn.hutool.core.util.BooleanUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.ReUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpStatus;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.JSONPath;
|
||||
import com.orangeforms.common.core.constant.ApplicationConstant;
|
||||
import com.orangeforms.common.core.constant.FieldFilterType;
|
||||
import com.orangeforms.common.core.constant.GlobalDeletedFlag;
|
||||
import com.orangeforms.common.core.exception.MyRuntimeException;
|
||||
import com.orangeforms.common.core.object.TokenData;
|
||||
import com.orangeforms.common.core.object.Tuple2;
|
||||
import com.orangeforms.common.dbutil.object.DatasetFilter;
|
||||
import com.orangeforms.common.dbutil.object.SqlTable;
|
||||
import com.orangeforms.common.dbutil.object.SqlTableColumn;
|
||||
import com.orangeforms.common.dbutil.util.DataSourceUtil;
|
||||
import com.orangeforms.common.flow.constant.FlowAutoActionType;
|
||||
import com.orangeforms.common.flow.model.FlowAutoVariableLog;
|
||||
import com.orangeforms.common.flow.model.FlowDblink;
|
||||
import com.orangeforms.common.flow.model.FlowEntryVariable;
|
||||
import com.orangeforms.common.flow.model.FlowTaskExt;
|
||||
import com.orangeforms.common.flow.object.*;
|
||||
import com.orangeforms.common.flow.service.FlowApiService;
|
||||
import com.orangeforms.common.flow.service.FlowAutoVariableLogService;
|
||||
import com.orangeforms.common.flow.service.FlowDblinkService;
|
||||
import com.orangeforms.common.flow.service.FlowTaskExtService;
|
||||
import com.orangeforms.common.sequence.wrapper.IdGeneratorWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.delegate.DelegateExecution;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.orangeforms.common.flow.object.AutoTaskConfig.*;
|
||||
import static com.orangeforms.common.flow.object.AutoTaskConfig.SRC_FILTER_SQL;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class AutoFlowHelper {
|
||||
|
||||
@Autowired
|
||||
private FlowApiService flowApiService;
|
||||
@Autowired
|
||||
private FlowDblinkService flowDblinkService;
|
||||
@Autowired
|
||||
private FlowTaskExtService flowTaskExtService;
|
||||
@Autowired
|
||||
private FlowAutoVariableLogService flowAutoVariableLogService;
|
||||
@Autowired
|
||||
private FlowDataSourceUtil flowDataSourceUtil;
|
||||
@Autowired
|
||||
private IdGeneratorWrapper idGenerator;
|
||||
@Autowired
|
||||
private RuntimeService runtimeService;
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
private static final String REGEX_VAR = "\\$\\{(.+?)\\}";
|
||||
private static final ThreadLocal<JSONObject> START_AUTO_INIT_VARIABLES = ThreadLocal.withInitial(() -> null);
|
||||
private static final List<FlowEntryVariable> SYSTEM_VARIABLES = CollUtil.newLinkedList();
|
||||
|
||||
static {
|
||||
SYSTEM_VARIABLES.add(FlowEntryVariable.createSystemVariable("currentTime", "当前时间"));
|
||||
SYSTEM_VARIABLES.add(FlowEntryVariable.createSystemVariable("initialUserId", "发起用户ID"));
|
||||
SYSTEM_VARIABLES.add(FlowEntryVariable.createSystemVariable("initialLoginName", "发起用户登录名"));
|
||||
SYSTEM_VARIABLES.add(FlowEntryVariable.createSystemVariable("initialShowName", "发起用户显示名"));
|
||||
SYSTEM_VARIABLES.add(FlowEntryVariable.createSystemVariable("initialDeptId", "发起用户部门ID"));
|
||||
SYSTEM_VARIABLES.add(FlowEntryVariable.createSystemVariable("tokenData", "Token令牌数据"));
|
||||
SYSTEM_VARIABLES.add(FlowEntryVariable.createSystemVariable("logicNormal", "逻辑删除正常值"));
|
||||
SYSTEM_VARIABLES.add(FlowEntryVariable.createSystemVariable("logicDelete", "逻辑删除删除值"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置初始化变量,仅在启动自动化流程的时候存入。临时存入变量参数到线程本地化存储,以后任务监听器的读取。
|
||||
*
|
||||
* @param variables 自动化流程启动时的初始变量对象。
|
||||
*/
|
||||
public static void setStartAutoInitVariables(JSONObject variables) {
|
||||
START_AUTO_INIT_VARIABLES.set(variables);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取自动化流程启动时传入的初始变量数据。
|
||||
*
|
||||
* @return 自动化流程启动时传入的初始变量数据。
|
||||
*/
|
||||
public static JSONObject getStartAutoInitVariables() {
|
||||
return START_AUTO_INIT_VARIABLES.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空该存储数据,主动释放线程本地化存储资源。
|
||||
*/
|
||||
public static void clearStartAutoInitVariables() {
|
||||
START_AUTO_INIT_VARIABLES.remove();
|
||||
}
|
||||
|
||||
public static List<FlowEntryVariable> systemFlowEntryVariables() {
|
||||
return SYSTEM_VARIABLES;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实时的系统变量。
|
||||
*
|
||||
* @return 系统变量键值对对象。
|
||||
*/
|
||||
public JSONObject getRealtimeSystemVariables() {
|
||||
JSONObject systemVariables = new JSONObject();
|
||||
systemVariables.put("currentTime", new Date());
|
||||
return systemVariables;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取非实时的系统变量。
|
||||
*
|
||||
* @return 系统变量键值对对象。
|
||||
*/
|
||||
public JSONObject getNonRealtimeSystemVariables() {
|
||||
JSONObject systemVariables = this.getRealtimeSystemVariables();
|
||||
TokenData tokenData = TokenData.takeFromRequest();
|
||||
systemVariables.put("initialUserId", tokenData != null ? tokenData.getUserId() : null);
|
||||
systemVariables.put("initialLoginName", tokenData != null ? tokenData.getLoginName() : null);
|
||||
systemVariables.put("initialShowName", tokenData != null ? tokenData.getShowName() : null);
|
||||
systemVariables.put("initialDeptId", tokenData != null ? tokenData.getDeptId() : null);
|
||||
systemVariables.put("tokenData", tokenData != null ? tokenData.getToken() : null);
|
||||
systemVariables.put("logicNormal", GlobalDeletedFlag.NORMAL);
|
||||
systemVariables.put("logicDelete", GlobalDeletedFlag.DELETED);
|
||||
return systemVariables;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析自动化任务配置对象。
|
||||
*
|
||||
* @param processDefinitionId 流程定义Id。
|
||||
* @param taskKey 流程任务定义标识。
|
||||
* @return 自动化任务的配置对象。
|
||||
*/
|
||||
public AutoTaskConfig parseAutoTaskConfig(String processDefinitionId, String taskKey) {
|
||||
FlowTaskExt taskExt = flowTaskExtService.getByProcessDefinitionIdAndTaskId(processDefinitionId, taskKey);
|
||||
return JSON.parseObject(taskExt.getAutoConfigJson(), AutoTaskConfig.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定指定的任务。
|
||||
*
|
||||
* @param transId 自动化任务执行时的生产者流水号Id。
|
||||
* @param taskConfig 自动化任务配置对象。
|
||||
* @param d 当前的执行委托对象。
|
||||
*/
|
||||
public void executeTask(Long transId, AutoTaskConfig taskConfig, DelegateExecution d) {
|
||||
JSONObject variableData = this.getAutomaticVariable(d.getProcessInstanceId());
|
||||
FlowDblink destDblink = new FlowDblink();
|
||||
destDblink.setDblinkId(taskConfig.getDestDblinkId());
|
||||
destDblink.setDblinkType(taskConfig.getDestDblinkType());
|
||||
SqlTable destTable = flowDblinkService.getDblinkTable(destDblink, taskConfig.getDestTableName());
|
||||
if (taskConfig.getActionType().equals(FlowAutoActionType.ADD_NEW)) {
|
||||
List<AutoExecData> execDataList = this.makeInsertAutoExecData(taskConfig, destTable, variableData);
|
||||
this.doExecuteSql(execDataList);
|
||||
} else if (taskConfig.getActionType().equals(FlowAutoActionType.UPDATE)) {
|
||||
AutoExecData execData = this.makeUpdateAutoExecData(taskConfig, destTable, variableData);
|
||||
this.doExecuteSql(CollUtil.newArrayList(execData));
|
||||
} else if (taskConfig.getActionType().equals(FlowAutoActionType.DELETE)) {
|
||||
AutoExecData execData = this.makeDeleteAutoExecData(taskConfig, destTable, variableData);
|
||||
this.doExecuteSql(CollUtil.newArrayList(execData));
|
||||
} else if (taskConfig.getActionType().equals(FlowAutoActionType.SELECT_ONE)) {
|
||||
this.doQueryOne(taskConfig, variableData, d);
|
||||
} else if (taskConfig.getActionType().equals(FlowAutoActionType.HTTP)) {
|
||||
this.doHttpRequest(transId, taskConfig, variableData, d);
|
||||
}
|
||||
}
|
||||
|
||||
private void doExecuteSql(List<AutoExecData> autoExecDataList) {
|
||||
if (CollUtil.isEmpty(autoExecDataList)) {
|
||||
return;
|
||||
}
|
||||
Connection connection = null;
|
||||
try {
|
||||
connection = flowDataSourceUtil.getConnection(autoExecDataList.get(0).getDblinkId());
|
||||
connection.setAutoCommit(false);
|
||||
for (AutoExecData autoExecData : autoExecDataList) {
|
||||
flowDataSourceUtil.execute(connection, autoExecData.getSql(), autoExecData.getParams());
|
||||
}
|
||||
connection.commit();
|
||||
} catch (Exception e) {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.rollback();
|
||||
} catch (SQLException ex) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
log.error(e.getMessage(), e);
|
||||
throw new MyRuntimeException(e);
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<AutoExecData> makeInsertAutoExecData(
|
||||
AutoTaskConfig taskConfig, SqlTable destTable, JSONObject variableData) {
|
||||
List<AutoExecData> resultList = new LinkedList<>();
|
||||
SqlTableColumn primaryKeyColumn = destTable.getColumnList().stream()
|
||||
.filter(c -> BooleanUtil.isTrue(c.getPrimaryKey())).findFirst().orElse(null);
|
||||
Map<String, SqlTableColumn> destColumnMap =
|
||||
destTable.getColumnList().stream().collect(Collectors.toMap(SqlTableColumn::getColumnName, c -> c));
|
||||
ValueInfo pkValueInfo = null;
|
||||
if (primaryKeyColumn != null) {
|
||||
pkValueInfo = taskConfig.getInsertDataList().stream()
|
||||
.filter(valueInfo -> valueInfo.getDestColumnName().equals(primaryKeyColumn.getColumnName()))
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
//查询源数据。
|
||||
List<Map<String, Object>> srcResultList = this.getSrcTableDataList(taskConfig, variableData);
|
||||
if (CollUtil.isEmpty(srcResultList)) {
|
||||
srcResultList.add(new HashMap<>(1));
|
||||
}
|
||||
for (Map<String, Object> srcResult : srcResultList) {
|
||||
List<Object> params = new LinkedList<>();
|
||||
StringBuilder sqlBuilder = new StringBuilder(1024);
|
||||
sqlBuilder.append("INSERT INTO ").append(taskConfig.getDestTableName()).append("(");
|
||||
if (primaryKeyColumn != null) {
|
||||
Object param = this.calculatePrimaryKeyParam(primaryKeyColumn, pkValueInfo, srcResult);
|
||||
if (param != null) {
|
||||
sqlBuilder.append(primaryKeyColumn.getColumnName()).append(",");
|
||||
params.add(param);
|
||||
}
|
||||
}
|
||||
for (ValueInfo valueInfo : taskConfig.getInsertDataList()) {
|
||||
if (pkValueInfo == null || !pkValueInfo.equals(valueInfo)) {
|
||||
sqlBuilder.append(valueInfo.getDestColumnName()).append(",");
|
||||
SqlTableColumn column = destColumnMap.get(valueInfo.getDestColumnName());
|
||||
String destFieldType = flowDataSourceUtil.convertToJavaType(column, taskConfig.getDestDblinkType());
|
||||
Object value = this.calculateValue(
|
||||
valueInfo.getType(), valueInfo.getSrcValue(), destFieldType, srcResult, variableData);
|
||||
params.add(value);
|
||||
}
|
||||
}
|
||||
sqlBuilder.setCharAt(sqlBuilder.length() - 1, ')');
|
||||
sqlBuilder.append(" VALUES(");
|
||||
params.forEach(p -> sqlBuilder.append("?,"));
|
||||
sqlBuilder.setCharAt(sqlBuilder.length() - 1, ')');
|
||||
AutoExecData execData = new AutoExecData();
|
||||
execData.setDblinkId(taskConfig.getDestDblinkId());
|
||||
execData.setSql(sqlBuilder.toString());
|
||||
execData.setParams(params);
|
||||
resultList.add(execData);
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
private AutoExecData makeUpdateAutoExecData(AutoTaskConfig taskConfig, SqlTable destTable, JSONObject variableData) {
|
||||
Map<String, SqlTableColumn> destColumnMap =
|
||||
destTable.getColumnList().stream().collect(Collectors.toMap(SqlTableColumn::getColumnName, c -> c));
|
||||
List<Object> params = new LinkedList<>();
|
||||
StringBuilder sqlBuilder = new StringBuilder(1024);
|
||||
sqlBuilder.append("UPDATE ").append(taskConfig.getDestTableName()).append(" SET ");
|
||||
for (ValueInfo valueInfo : taskConfig.getUpdateDataList()) {
|
||||
sqlBuilder.append(valueInfo.getDestColumnName()).append(" = ?,");
|
||||
SqlTableColumn column = destColumnMap.get(valueInfo.getDestColumnName());
|
||||
String destFieldType = flowDataSourceUtil.convertToJavaType(column, taskConfig.getDestDblinkType());
|
||||
Object value = this.calculateValue(
|
||||
valueInfo.getType(), valueInfo.getSrcValue(), destFieldType, null, variableData);
|
||||
params.add(value);
|
||||
}
|
||||
sqlBuilder.setCharAt(sqlBuilder.length() - 1, ' ');
|
||||
Tuple2<String, List<Object>> result = this.calculateWhereClause(taskConfig, destTable, variableData);
|
||||
sqlBuilder.append(result.getFirst());
|
||||
CollUtil.addAll(params, result.getSecond());
|
||||
AutoExecData execData = new AutoExecData();
|
||||
execData.setDblinkId(taskConfig.getDestDblinkId());
|
||||
execData.setSql(sqlBuilder.toString());
|
||||
execData.setParams(params);
|
||||
return execData;
|
||||
}
|
||||
|
||||
private AutoExecData makeDeleteAutoExecData(AutoTaskConfig taskConfig, SqlTable destTable, JSONObject variableData) {
|
||||
if (StrUtil.isNotBlank(taskConfig.getLogicDeleteField())) {
|
||||
List<ValueInfo> updateDataList = new LinkedList<>();
|
||||
ValueInfo logicDeleteValueInfo = new ValueInfo();
|
||||
logicDeleteValueInfo.setDestColumnName(taskConfig.getLogicDeleteField());
|
||||
logicDeleteValueInfo.setType(AutoTaskConfig.FIXED_VALUE);
|
||||
logicDeleteValueInfo.setSrcValue(String.valueOf(GlobalDeletedFlag.DELETED));
|
||||
updateDataList.add(logicDeleteValueInfo);
|
||||
taskConfig.setUpdateDataList(updateDataList);
|
||||
return this.makeUpdateAutoExecData(taskConfig, destTable, variableData);
|
||||
}
|
||||
StringBuilder sqlBuilder = new StringBuilder(1024);
|
||||
sqlBuilder.append("DELETE FROM ").append(taskConfig.getDestTableName());
|
||||
Tuple2<String, List<Object>> result = this.calculateWhereClause(taskConfig, destTable, variableData);
|
||||
sqlBuilder.append(result.getFirst());
|
||||
AutoExecData execData = new AutoExecData();
|
||||
execData.setDblinkId(taskConfig.getDestDblinkId());
|
||||
execData.setSql(sqlBuilder.toString());
|
||||
execData.setParams(result.getSecond());
|
||||
return execData;
|
||||
}
|
||||
|
||||
private void doQueryOne(AutoTaskConfig taskConfig, JSONObject variableData, DelegateExecution d) {
|
||||
List<Map<String, Object>> srcResultList = this.getSrcTableDataList(taskConfig, variableData);
|
||||
Map<String, Object> srcResult = null;
|
||||
if (CollUtil.isNotEmpty(srcResultList)) {
|
||||
srcResult = srcResultList.get(0);
|
||||
}
|
||||
this.refreshAutoVariableLog(d, taskConfig.getTaskKey(), srcResult);
|
||||
}
|
||||
|
||||
private void doHttpRequest(Long transId, AutoTaskConfig taskConfig, JSONObject variableData, DelegateExecution d) {
|
||||
AutoHttpRequestInfo req = taskConfig.getHttpRequestInfo();
|
||||
AutoHttpResponseData resp = taskConfig.getHttpResponnseData();
|
||||
String body = this.buildRequestBody(req, variableData);
|
||||
HttpHeaders headers = this.buildHttpHeaders(req, variableData);
|
||||
headers.add(ApplicationConstant.HTTP_HEADER_TRANS_ID, transId.toString());
|
||||
HttpEntity<String> httpEntity = new HttpEntity<>(body, headers);
|
||||
UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(req.getUrl());
|
||||
if (CollUtil.isNotEmpty(req.getUrlParamList())) {
|
||||
for (AutoTaskConfig.ValueInfo valueInfo : req.getUrlParamList()) {
|
||||
String paramValue = this.calculateValue(valueInfo.getType(), valueInfo.getSrcValue(), variableData);
|
||||
uriBuilder.queryParam(valueInfo.getKey(), paramValue);
|
||||
}
|
||||
}
|
||||
ResponseEntity<JSONObject> responseEntity = restTemplate.exchange(
|
||||
uriBuilder.encode().toUriString(), HttpMethod.valueOf(req.getHttpMethod()), httpEntity, JSONObject.class);
|
||||
try {
|
||||
this.handleHttpResponseFail(req, resp, responseEntity);
|
||||
this.refreshAutoVariableLog(d, taskConfig.getTaskKey(), responseEntity.getBody());
|
||||
} catch (MyRuntimeException e) {
|
||||
if (!resp.getFailHandleType().equals(AutoHttpResponseData.CONTINUE_ON_FAIL)) {
|
||||
throw e;
|
||||
}
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private Object calculatePrimaryKeyParam(
|
||||
SqlTableColumn primaryKeyColumn, ValueInfo pkValueInfo, Map<String, Object> srcResult) {
|
||||
// 说明目标表的主键值来自于源表的字段值。
|
||||
if (pkValueInfo != null) {
|
||||
return srcResult.get(pkValueInfo.getSrcValue());
|
||||
}
|
||||
if (BooleanUtil.isFalse(primaryKeyColumn.getAutoIncrement())) {
|
||||
return primaryKeyColumn.getStringPrecision() == null ? idGenerator.nextLongId() : idGenerator.nextStringId();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> getSrcTableDataList(AutoTaskConfig taskConfig, JSONObject variableData) {
|
||||
if (ObjectUtil.isEmpty(taskConfig.getSrcDblinkId()) || StrUtil.isBlank(taskConfig.getSrcTableName())) {
|
||||
return new LinkedList<>();
|
||||
}
|
||||
this.appendLogicDeleteFilter(taskConfig);
|
||||
FlowDblink srcDblink = new FlowDblink();
|
||||
srcDblink.setDblinkId(taskConfig.getSrcDblinkId());
|
||||
srcDblink.setDblinkType(taskConfig.getSrcDblinkType());
|
||||
SqlTable srcTable = flowDblinkService.getDblinkTable(srcDblink, taskConfig.getSrcTableName());
|
||||
StringBuilder sqlBuilder = new StringBuilder(256);
|
||||
String selectFields = CollUtil.isEmpty(taskConfig.getSelectFieldList())
|
||||
? "*" : CollUtil.join(taskConfig.getSelectFieldList(), ",");
|
||||
sqlBuilder.append("SELECT ").append(selectFields).append(" FROM ").append(srcTable.getTableName());
|
||||
if (taskConfig.getSrcFilterType().equals(AutoTaskConfig.SRC_FILTER_SQL)) {
|
||||
Tuple2<String, List<Object>> result = this.calcualteCustomSqlFilter(taskConfig.getSrcFilterSql(), variableData);
|
||||
if (StrUtil.isNotBlank(result.getFirst())) {
|
||||
sqlBuilder.append(result.getFirst());
|
||||
}
|
||||
try {
|
||||
return flowDataSourceUtil.query(taskConfig.getSrcDblinkId(), sqlBuilder.toString(), result.getSecond());
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
throw new MyRuntimeException(e);
|
||||
}
|
||||
}
|
||||
DatasetFilter dataFilter = null;
|
||||
if (CollUtil.isNotEmpty(taskConfig.getSrcFilterList())) {
|
||||
dataFilter = this.calculateDatasetFilter(
|
||||
srcTable, taskConfig.getSrcDblinkType(), taskConfig.getSrcFilterList(), variableData);
|
||||
}
|
||||
try {
|
||||
Tuple2<String, List<Object>> result =
|
||||
flowDataSourceUtil.buildWhereClauseByFilters(taskConfig.getSrcDblinkId(), dataFilter);
|
||||
sqlBuilder.append(result.getFirst());
|
||||
return flowDataSourceUtil.query(taskConfig.getSrcDblinkId(), sqlBuilder.toString(), result.getSecond());
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
throw new MyRuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshAutoVariableLog(DelegateExecution d, String outputVariableName, Map<String, Object> newResult) {
|
||||
if (StrUtil.isBlank(outputVariableName)) {
|
||||
return;
|
||||
}
|
||||
runtimeService.setVariable(d.getId(), outputVariableName, newResult);
|
||||
FlowAutoVariableLog autoVariableLog =
|
||||
flowAutoVariableLogService.getAutoVariableByProcessInstanceId(d.getProcessInstanceId());
|
||||
JSONObject latestVariableData = JSON.parseObject(autoVariableLog.getVariableData());
|
||||
latestVariableData.put(outputVariableName, newResult);
|
||||
autoVariableLog.setVariableData(JSON.toJSONString(latestVariableData));
|
||||
flowAutoVariableLogService.updateById(autoVariableLog);
|
||||
}
|
||||
|
||||
private Tuple2<String, List<Object>> calculateWhereClause(AutoTaskConfig taskConfig, SqlTable destTable, JSONObject variableData) {
|
||||
if (taskConfig.getDestFilterType().equals(AutoTaskConfig.SRC_FILTER_SQL)) {
|
||||
return this.calcualteCustomSqlFilter(taskConfig.getDestFilterSql(), variableData);
|
||||
}
|
||||
if (CollUtil.isNotEmpty(taskConfig.getDestFilterList())) {
|
||||
DatasetFilter dataFilter = this.calculateDatasetFilter(
|
||||
destTable, taskConfig.getDestDblinkType(), taskConfig.getDestFilterList(), variableData);
|
||||
return flowDataSourceUtil.buildWhereClauseByFilters(taskConfig.getDestDblinkId(), dataFilter);
|
||||
}
|
||||
return new Tuple2<>(StrUtil.EMPTY, new LinkedList<>());
|
||||
}
|
||||
|
||||
private Tuple2<String, List<Object>> calcualteCustomSqlFilter(String filterSql, JSONObject variableData) {
|
||||
Tuple2<String, List<String>> result = this.findAndReplaceAllVariables(filterSql);
|
||||
String whereClause = result.getFirst();
|
||||
if (StrUtil.isNotBlank(whereClause)) {
|
||||
whereClause = DataSourceUtil.SQL_WHERE + whereClause;
|
||||
}
|
||||
List<Object> params = this.extractVariableParamsByVariable(result.getSecond(), variableData);
|
||||
return new Tuple2<>(whereClause, params);
|
||||
}
|
||||
|
||||
private DatasetFilter calculateDatasetFilter(
|
||||
SqlTable table, Integer dblinkType, List<FilterInfo> filterInfoList, JSONObject variableData) {
|
||||
Map<String, SqlTableColumn> columnMap = table.getColumnList()
|
||||
.stream().collect(Collectors.toMap(SqlTableColumn::getColumnName, c -> c));
|
||||
DatasetFilter dataFilter = new DatasetFilter();
|
||||
filterInfoList.forEach(filterInfo -> {
|
||||
DatasetFilter.FilterInfo filter = new DatasetFilter.FilterInfo();
|
||||
filter.setFilterType(filterInfo.getFilterType());
|
||||
filter.setParamName(filterInfo.getFilterColumnName());
|
||||
SqlTableColumn column = columnMap.get(filterInfo.getFilterColumnName());
|
||||
String fieldType = flowDataSourceUtil.convertToJavaType(column, dblinkType);
|
||||
if (filterInfo.getFilterType().equals(FieldFilterType.IN)) {
|
||||
filter.setParamValueList(flowDataSourceUtil.convertToColumnValues(fieldType, filterInfo.getFilterValue()));
|
||||
} else {
|
||||
Object convertedValue = calculateValue(
|
||||
filterInfo.getValueType(), filterInfo.getFilterValue(), fieldType, null, variableData);
|
||||
filter.setParamValue(convertedValue);
|
||||
}
|
||||
dataFilter.add(filter);
|
||||
});
|
||||
return dataFilter;
|
||||
}
|
||||
|
||||
private void appendLogicDeleteFilter(AutoTaskConfig taskConfig) {
|
||||
if (StrUtil.isBlank(taskConfig.getLogicDeleteField())) {
|
||||
return;
|
||||
}
|
||||
if (taskConfig.getSrcFilterType().equals(SRC_FILTER_SQL)) {
|
||||
StringBuilder sb = new StringBuilder(512);
|
||||
if (StrUtil.isNotBlank(taskConfig.getSrcFilterSql())) {
|
||||
sb.append("(").append(taskConfig.getSrcFilterSql())
|
||||
.append(") AND ")
|
||||
.append(taskConfig.getLogicDeleteField())
|
||||
.append("=")
|
||||
.append(GlobalDeletedFlag.NORMAL);
|
||||
} else {
|
||||
sb.append(taskConfig.getLogicDeleteField()).append("=").append(GlobalDeletedFlag.NORMAL);
|
||||
}
|
||||
taskConfig.setSrcFilterSql(sb.toString());
|
||||
} else {
|
||||
List<FilterInfo> filterInfoList = taskConfig.getSrcFilterList();
|
||||
if (filterInfoList == null) {
|
||||
filterInfoList = new LinkedList<>();
|
||||
}
|
||||
FilterInfo logicDeleteFilter = new FilterInfo();
|
||||
logicDeleteFilter.setFilterColumnName(taskConfig.getLogicDeleteField());
|
||||
logicDeleteFilter.setFilterType(FieldFilterType.EQUAL);
|
||||
logicDeleteFilter.setValueType(AutoTaskConfig.FIXED_VALUE);
|
||||
logicDeleteFilter.setFilterValue(String.valueOf(GlobalDeletedFlag.NORMAL));
|
||||
filterInfoList.add(logicDeleteFilter);
|
||||
taskConfig.setSrcFilterList(filterInfoList);
|
||||
}
|
||||
}
|
||||
|
||||
private String buildRequestBody(AutoHttpRequestInfo req, JSONObject variableData) {
|
||||
String body = null;
|
||||
if (StrUtil.equals(req.getBodyType(), AutoHttpRequestInfo.BODY_TYPE_RAW)) {
|
||||
body = this.replaceAllVariables(req.getBodyData(), variableData);
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder(256);
|
||||
if (CollUtil.isNotEmpty(req.getFormDataList())) {
|
||||
for (ValueInfo valueInfo : req.getFormDataList()) {
|
||||
String value = this.calculateValue(valueInfo.getType(), valueInfo.getSrcValue(), variableData);
|
||||
sb.append(valueInfo.getKey()).append("=").append(value).append("&");
|
||||
}
|
||||
body = sb.substring(0, sb.length() - 1);
|
||||
}
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
private HttpHeaders buildHttpHeaders(AutoHttpRequestInfo req, JSONObject variableData) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
if (CollUtil.isNotEmpty(req.getHeaderList())) {
|
||||
for (AutoTaskConfig.ValueInfo valueInfo : req.getHeaderList()) {
|
||||
String value = this.calculateValue(valueInfo.getType(), valueInfo.getSrcValue(), variableData);
|
||||
headers.add(valueInfo.getKey(), value);
|
||||
}
|
||||
}
|
||||
if (StrUtil.equals(req.getBodyType(), AutoHttpRequestInfo.BODY_TYPE_RAW)) {
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
} else {
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
private void handleHttpResponseFail(
|
||||
AutoHttpRequestInfo req, AutoHttpResponseData resp, ResponseEntity<JSONObject> responseEntity) {
|
||||
Set<Integer> successStatusCodes = CollUtil.newHashSet(HttpStatus.HTTP_OK);
|
||||
if (StrUtil.isNotBlank(resp.getSuccessStatusCode())) {
|
||||
successStatusCodes = StrUtil.split(resp.getSuccessStatusCode(), StrUtil.COMMA)
|
||||
.stream().map(Integer::valueOf).collect(Collectors.toSet());
|
||||
}
|
||||
// 先判断HttpStatus是否正确。
|
||||
if (!CollUtil.contains(successStatusCodes, responseEntity.getStatusCode().value())) {
|
||||
String cancelReason = StrFormatter.format(
|
||||
"Failed to Rquest Url [{}] with StatusCode [{}]", req.getUrl(), responseEntity.getStatusCode().value());
|
||||
throw new MyRuntimeException(cancelReason);
|
||||
}
|
||||
// 如果没有配置应答体中标记是否成功的字段,则视为成功。
|
||||
if (StrUtil.isBlank(resp.getSuccessBodyField())) {
|
||||
return;
|
||||
}
|
||||
JSONObject responseData = responseEntity.getBody();
|
||||
String successFlagField = JSONPath.compile(resp.getSuccessBodyField()).eval(responseData, String.class);
|
||||
// 如果应答体中标记是否成功的字段你不存在,或者是应答体中标记为成功的字段值为true,则视为成功。
|
||||
if (StrUtil.isBlank(successFlagField)
|
||||
|| StrUtil.equals(successFlagField, "[]")
|
||||
|| BooleanUtil.toBooleanObject(successFlagField).equals(Boolean.TRUE)) {
|
||||
return;
|
||||
}
|
||||
// 开始处理失败场景。
|
||||
String cancelReason;
|
||||
if (StrUtil.isNotBlank(resp.getErrorMessageBodyField())) {
|
||||
String errorMsgPath = "$." + resp.getErrorMessageBodyField();
|
||||
String errorMsg = JSONPath.compile(errorMsgPath).eval(responseData, String.class);
|
||||
cancelReason = StrFormatter.format(
|
||||
"Failed to Rquest Url [{}] with errorMsg [{}]", req.getUrl(), errorMsg);
|
||||
} else {
|
||||
cancelReason = StrFormatter.format("Failed to Rquest Url [{}]", req.getUrl());
|
||||
}
|
||||
throw new MyRuntimeException(cancelReason);
|
||||
}
|
||||
|
||||
private Tuple2<String, List<String>> findAndReplaceAllVariables(String s) {
|
||||
List<String> variables = ReUtil.findAll(REGEX_VAR, s, 0);
|
||||
if (CollUtil.isNotEmpty(variables)) {
|
||||
s = s.replaceAll(REGEX_VAR, "?");
|
||||
variables = variables.stream().map(v -> v.substring(2, v.length() - 1)).collect(Collectors.toList());
|
||||
}
|
||||
return new Tuple2<>(s, variables);
|
||||
}
|
||||
|
||||
private String replaceAllVariables(String s, JSONObject variableData) {
|
||||
if (StrUtil.isNotBlank(s)) {
|
||||
List<String> variables = ReUtil.findAll(REGEX_VAR, s, 0);
|
||||
if (CollUtil.isNotEmpty(variables)) {
|
||||
for (String v : variables) {
|
||||
s = StrUtil.replace(s, v, variableData.getString(v.substring(2, v.length() - 1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
private JSONObject getAutomaticVariable(String processInstanceId) {
|
||||
JSONObject variableData = getStartAutoInitVariables();
|
||||
if (variableData == null) {
|
||||
FlowAutoVariableLog v = flowAutoVariableLogService.getAutoVariableByProcessInstanceId(processInstanceId);
|
||||
if (v != null) {
|
||||
variableData = JSON.parseObject(v.getVariableData());
|
||||
}
|
||||
}
|
||||
JSONObject systemVariables = this.getRealtimeSystemVariables();
|
||||
if (variableData == null) {
|
||||
return systemVariables;
|
||||
}
|
||||
variableData.putAll(systemVariables);
|
||||
return variableData;
|
||||
}
|
||||
|
||||
private List<Object> extractVariableParamsByVariable(List<String> variableNames, JSONObject variableData) {
|
||||
List<Object> resultList = new LinkedList<>();
|
||||
if (CollUtil.isEmpty(variableNames) || MapUtil.isEmpty(variableData)) {
|
||||
return resultList;
|
||||
}
|
||||
for (String name : variableNames) {
|
||||
Object value = this.verifyAndGetVariableExist(name, variableData);
|
||||
if (value != null) {
|
||||
resultList.add(value);
|
||||
}
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
private Object calculateValue(
|
||||
Integer valueType, String value, String fieldType, Map<String, Object> srcResult, JSONObject variableData) {
|
||||
if (valueType.equals(AutoTaskConfig.FIXED_VALUE)) {
|
||||
return flowDataSourceUtil.convertToColumnValue(fieldType, value);
|
||||
} else if (valueType.equals(AutoTaskConfig.COLUMN_VALUE)) {
|
||||
return srcResult.get(value);
|
||||
}
|
||||
Object variableValue = this.verifyAndGetVariableExist(value, variableData);
|
||||
return flowDataSourceUtil.convertToColumnValue(fieldType, (Serializable) variableValue);
|
||||
}
|
||||
|
||||
private String calculateValue(Integer valueType, String value, JSONObject variableData) {
|
||||
if (valueType.equals(AutoTaskConfig.FIXED_VALUE)) {
|
||||
return value;
|
||||
}
|
||||
Object variableValue = this.verifyAndGetVariableExist(value, variableData);
|
||||
return variableValue == null ? null : variableValue.toString();
|
||||
}
|
||||
|
||||
private Object verifyAndGetVariableExist(String name, JSONObject variableData) {
|
||||
String variableName = name;
|
||||
if (StrUtil.contains(name, StrUtil.DOT)) {
|
||||
variableName = StrUtil.subBefore(name, StrUtil.DOT, false);
|
||||
}
|
||||
if (!variableData.containsKey(variableName)) {
|
||||
throw new MyRuntimeException(StrFormatter.format("变量值 [{}] 不存在!", name));
|
||||
}
|
||||
if (!StrUtil.contains(name, StrUtil.DOT)) {
|
||||
return variableData.get(variableName);
|
||||
}
|
||||
JSONObject variableObject = variableData.getJSONObject(variableName);
|
||||
if (variableObject == null) {
|
||||
return null;
|
||||
}
|
||||
String variablePath = StrUtil.subAfter(name, StrUtil.DOT, false);
|
||||
return JSONPath.compile(variablePath).eval(variableObject);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.orangeforms.common.flow.util;
|
||||
|
||||
import com.orangeforms.common.core.exception.MyRuntimeException;
|
||||
import com.orangeforms.common.dbutil.provider.DataSourceProvider;
|
||||
import com.orangeforms.common.dbutil.util.DataSourceUtil;
|
||||
import com.orangeforms.common.flow.model.FlowDblink;
|
||||
import com.orangeforms.common.flow.service.FlowDblinkService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 工作流模块动态加载的数据源工具类。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class FlowDataSourceUtil extends DataSourceUtil {
|
||||
|
||||
@Autowired
|
||||
private FlowDblinkService dblinkService;
|
||||
|
||||
@Override
|
||||
protected int getDblinkTypeByDblinkId(Long dblinkId) {
|
||||
DataSourceProvider provider = this.dblinkProviderMap.get(dblinkId);
|
||||
if (provider != null) {
|
||||
return provider.getDblinkType();
|
||||
}
|
||||
FlowDblink dblink = dblinkService.getById(dblinkId);
|
||||
if (dblink == null) {
|
||||
throw new MyRuntimeException("Flow DblinkId [" + dblinkId + "] doesn't exist!");
|
||||
}
|
||||
this.dblinkProviderMap.put(dblinkId, this.getProvider(dblink.getDblinkType()));
|
||||
return dblink.getDblinkType();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDblinkConfigurationByDblinkId(Long dblinkId) {
|
||||
FlowDblink dblink = dblinkService.getById(dblinkId);
|
||||
if (dblink == null) {
|
||||
throw new MyRuntimeException("Flow DblinkId [" + dblinkId + "] doesn't exist!");
|
||||
}
|
||||
return dblink.getConfiguration();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.orangeforms.common.flow.util;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.orangeforms.common.core.exception.MyRuntimeException;
|
||||
import com.orangeforms.common.flow.constant.FlowConstant;
|
||||
import com.orangeforms.common.flow.model.FlowTransProducer;
|
||||
import com.orangeforms.common.flow.service.FlowTransProducerService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.event.TransactionPhase;
|
||||
import org.springframework.transaction.event.TransactionalEventListener;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
/**
|
||||
* 流程监听器发送spring事件的帮助类。
|
||||
* 注意:流程的监听器不是bean对象,不能发送和捕捉事件,因此需要借助该类完成。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class ListenerEventPublishHelper {
|
||||
|
||||
@Autowired
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
@Autowired
|
||||
private RuntimeService runtimeService;
|
||||
@Autowired
|
||||
private FlowTransProducerService flowTransProducerService;
|
||||
|
||||
public <T> void publishEvent(T data) {
|
||||
eventPublisher.publishEvent(data);
|
||||
}
|
||||
|
||||
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
|
||||
public void doHandle(FlowTransProducer producerData) {
|
||||
Map<String, Object> transVariableMap = new HashMap<>(1);
|
||||
transVariableMap.put(FlowConstant.AUTO_FLOW_TRANS_PRODUCER_VAR, producerData);
|
||||
Executors.newSingleThreadExecutor().submit(() -> this.triggerReceiveTask(producerData, transVariableMap));
|
||||
}
|
||||
|
||||
private void triggerReceiveTask(FlowTransProducer producerData, Map<String, Object> transVariableMap) {
|
||||
try {
|
||||
runtimeService.trigger(producerData.getExecutionId(), null, transVariableMap);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to commit automatic business data [** " + JSON.toJSONString(producerData) + " **]", e);
|
||||
producerData.setErrorReason(e.getMessage());
|
||||
flowTransProducerService.updateById(producerData);
|
||||
throw new MyRuntimeException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.orangeforms.common.flow.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 工作流数据表所在数据库链接VO对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Schema(description = "工作流数据表所在数据库链接VO对象")
|
||||
@Data
|
||||
public class FlowDblinkVo {
|
||||
|
||||
/**
|
||||
* 主键Id。
|
||||
*/
|
||||
@Schema(description = "主键Id")
|
||||
private Long dblinkId;
|
||||
|
||||
/**
|
||||
* 应用编码。为空时,表示非第三方应用接入。
|
||||
*/
|
||||
@Schema(description = "应用编码。为空时,表示非第三方应用接入")
|
||||
private String appCode;
|
||||
|
||||
/**
|
||||
* 链接中文名称。
|
||||
*/
|
||||
@Schema(description = "链接中文名称")
|
||||
private String dblinkName;
|
||||
|
||||
/**
|
||||
* 链接描述。
|
||||
*/
|
||||
@Schema(description = "链接描述")
|
||||
private String dblinkDescription;
|
||||
|
||||
/**
|
||||
* 配置信息。
|
||||
*/
|
||||
@Schema(description = "配置信息")
|
||||
private String configuration;
|
||||
|
||||
/**
|
||||
* 数据库链接类型。
|
||||
*/
|
||||
@Schema(description = "数据库链接类型")
|
||||
private Integer dblinkType;
|
||||
|
||||
/**
|
||||
* 更新者。
|
||||
*/
|
||||
@Schema(description = "更新者")
|
||||
private Long updateUserId;
|
||||
|
||||
/**
|
||||
* 更新时间。
|
||||
*/
|
||||
@Schema(description = "更新时间")
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 创建者。
|
||||
*/
|
||||
@Schema(description = "创建者")
|
||||
private Long createUserId;
|
||||
|
||||
/**
|
||||
* 创建时间。
|
||||
*/
|
||||
@Schema(description = "创建时间")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 数据库链接类型常量字典关联数据。
|
||||
*/
|
||||
@Schema(description = "数据库链接类型常量字典关联数据")
|
||||
private Map<String, Object> dblinkTypeDictMap;
|
||||
}
|
||||
Reference in New Issue
Block a user