mirror of
https://gitee.com/orangeform/orange-admin.git
synced 2026-01-17 18:46:36 +08:00
commit:流程支持自动化任务
This commit is contained in:
@@ -78,6 +78,10 @@ public final class ApplicationConstant {
|
|||||||
* 请求头跟踪id名。
|
* 请求头跟踪id名。
|
||||||
*/
|
*/
|
||||||
public static final String HTTP_HEADER_TRACE_ID = "traceId";
|
public static final String HTTP_HEADER_TRACE_ID = "traceId";
|
||||||
|
/**
|
||||||
|
* 请求头业务流水号id名。
|
||||||
|
*/
|
||||||
|
public static final String HTTP_HEADER_TRANS_ID = "transId";
|
||||||
/**
|
/**
|
||||||
* 请求头菜单Id。
|
* 请求头菜单Id。
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -434,6 +434,19 @@ public class MyCommonUtil {
|
|||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前请求的traceId。
|
||||||
|
*
|
||||||
|
* @return 当前请求的traceId。
|
||||||
|
*/
|
||||||
|
public static String getTraceId() {
|
||||||
|
HttpServletRequest request = ContextUtil.getHttpRequest();
|
||||||
|
if (request == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return request.getHeader(ApplicationConstant.HTTP_HEADER_TRACE_ID);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 私有构造函数,明确标识该常量类的作用。
|
* 私有构造函数,明确标识该常量类的作用。
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
package com.orangeforms.common.dbutil.util;
|
package com.orangeforms.common.dbutil.util;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.convert.Convert;
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
import cn.hutool.core.util.BooleanUtil;
|
import cn.hutool.core.util.BooleanUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.alibaba.druid.pool.DruidDataSource;
|
import com.alibaba.druid.pool.DruidDataSource;
|
||||||
import com.alibaba.druid.pool.DruidDataSourceFactory;
|
import com.alibaba.druid.pool.DruidDataSourceFactory;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONArray;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.orangeforms.common.core.constant.FieldFilterType;
|
import com.orangeforms.common.core.constant.FieldFilterType;
|
||||||
import com.orangeforms.common.core.exception.InvalidDblinkTypeException;
|
import com.orangeforms.common.core.exception.InvalidDblinkTypeException;
|
||||||
@@ -28,6 +31,7 @@ import net.sf.jsqlparser.statement.select.SelectItem;
|
|||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
|
import java.io.Serializable;
|
||||||
import java.sql.*;
|
import java.sql.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
@@ -48,12 +52,12 @@ public abstract class DataSourceUtil {
|
|||||||
private static final Map<Integer, DataSourceProvider> PROVIDER_MAP = new HashMap<>(5);
|
private static final Map<Integer, DataSourceProvider> PROVIDER_MAP = new HashMap<>(5);
|
||||||
protected final Map<Long, DataSourceProvider> dblinkProviderMap = new ConcurrentHashMap<>(4);
|
protected final Map<Long, DataSourceProvider> dblinkProviderMap = new ConcurrentHashMap<>(4);
|
||||||
|
|
||||||
private static final String SQL_SELECT = " SELECT ";
|
public static final String SQL_SELECT = " SELECT ";
|
||||||
private static final String SQL_SELECT_FROM = " SELECT * FROM (";
|
public static final String SQL_SELECT_FROM = " SELECT * FROM (";
|
||||||
private static final String SQL_AS_TMP = " ) tmp ";
|
public static final String SQL_AS_TMP = " ) tmp ";
|
||||||
private static final String SQL_ORDER_BY = " ORDER BY ";
|
public static final String SQL_ORDER_BY = " ORDER BY ";
|
||||||
private static final String SQL_AND = " AND ";
|
public static final String SQL_AND = " AND ";
|
||||||
private static final String SQL_WHERE = " WHERE ";
|
public static final String SQL_WHERE = " WHERE ";
|
||||||
private static final String LOG_PREPARING_FORMAT = "==> Preparing: {}";
|
private static final String LOG_PREPARING_FORMAT = "==> Preparing: {}";
|
||||||
private static final String LOG_PARMS_FORMAT = "==> Parameters: {}";
|
private static final String LOG_PARMS_FORMAT = "==> Parameters: {}";
|
||||||
private static final String LOG_TOTAL_FORMAT = "<== Total: {}";
|
private static final String LOG_TOTAL_FORMAT = "<== Total: {}";
|
||||||
@@ -354,6 +358,27 @@ public abstract class DataSourceUtil {
|
|||||||
return this.getDataListInternnally(dblinkId, provider, sqlCount, sql, datasetParam, paramList);
|
return this.getDataListInternnally(dblinkId, provider, sqlCount, sql, datasetParam, paramList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行包含参数变量的增删改操作。
|
||||||
|
*
|
||||||
|
* @param connection 数据库链接。
|
||||||
|
* @param sql SQL语句。
|
||||||
|
* @param paramList 参数列表。
|
||||||
|
* @return 影响的行数。
|
||||||
|
*/
|
||||||
|
public int execute(Connection connection, String sql, List<Object> paramList) {
|
||||||
|
try (PreparedStatement stat = connection.prepareStatement(sql)) {
|
||||||
|
for (int i = 0; i < paramList.size(); i++) {
|
||||||
|
stat.setObject(i + 1, paramList.get(i));
|
||||||
|
}
|
||||||
|
stat.execute();
|
||||||
|
return stat.getUpdateCount();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
throw new MyRuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在指定数据库链接上执行查询语句,并返回指定映射对象类型的单条数据对象。
|
* 在指定数据库链接上执行查询语句,并返回指定映射对象类型的单条数据对象。
|
||||||
*
|
*
|
||||||
@@ -414,6 +439,87 @@ public abstract class DataSourceUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据数据库链接的类型,将数据表字段类型转换为Java的字段属性类型。
|
||||||
|
*
|
||||||
|
* @param column 数据表字段对象。
|
||||||
|
* @param dblinkType 数据库链接类型。
|
||||||
|
* @return 返回与Java字段属性的类型名。
|
||||||
|
*/
|
||||||
|
public String convertToJavaType(SqlTableColumn column, int dblinkType) {
|
||||||
|
return this.convertToJavaType(
|
||||||
|
column.getColumnType(), column.getNumericPrecision(), column.getNumericScale(), dblinkType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据数据库链接的类型,将数据表字段类型转换为Java的字段属性类型。
|
||||||
|
*
|
||||||
|
* @param columnType 表字段类型。
|
||||||
|
* @param numericPrecision 数值的精度。
|
||||||
|
* @param numericScale 数值的刻度。
|
||||||
|
* @param dblinkType 数据库链接类型。
|
||||||
|
* @return 返回与Java字段属性的类型名。
|
||||||
|
*/
|
||||||
|
public String convertToJavaType(String columnType, Integer numericPrecision, Integer numericScale, int dblinkType) {
|
||||||
|
DataSourceProvider provider = this.getProvider(dblinkType);
|
||||||
|
if (provider == null) {
|
||||||
|
throw new MyRuntimeException("Unsupported Data Type");
|
||||||
|
}
|
||||||
|
return provider.convertColumnTypeToJavaType(columnType, numericPrecision, numericScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据Java字段属性的类型,转换参数中的values值到与fieldType匹配的值类型数据列表。
|
||||||
|
*
|
||||||
|
* @param fieldType Java字段属性值。
|
||||||
|
* @param values 字符串类型的参数值列表,该参数为JSON数组。
|
||||||
|
* @return 目标类型的参数值列表。
|
||||||
|
*/
|
||||||
|
public List<Serializable> convertToColumnValues(String fieldType, String values) {
|
||||||
|
List<Serializable> valueList = new LinkedList<>();
|
||||||
|
if (StrUtil.isBlank(values)) {
|
||||||
|
return valueList;
|
||||||
|
}
|
||||||
|
JSONArray valueArray = JSON.parseArray(values);
|
||||||
|
for (int i = 0; i < valueArray.size(); i++) {
|
||||||
|
String v = valueArray.getString(i);
|
||||||
|
valueList.add(this.convertToColumnValue(fieldType, v));
|
||||||
|
}
|
||||||
|
return valueList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据Java字段属性的类型,转换参数中的value值到与fieldType匹配的值类型。
|
||||||
|
*
|
||||||
|
* @param fieldType Java字段属性值。
|
||||||
|
* @param value 参数值。
|
||||||
|
* @return 目标类型的参数值。
|
||||||
|
*/
|
||||||
|
public Serializable convertToColumnValue(String fieldType, Serializable value) {
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
switch (fieldType) {
|
||||||
|
case "Long":
|
||||||
|
return Convert.toLong(value);
|
||||||
|
case "Integer":
|
||||||
|
return Convert.toInt(value);
|
||||||
|
case "BigDecimal":
|
||||||
|
return Convert.toBigDecimal(value);
|
||||||
|
case "Double":
|
||||||
|
return Convert.toDouble(value);
|
||||||
|
case "Boolean":
|
||||||
|
return Convert.toBool(value);
|
||||||
|
case "Date":
|
||||||
|
return value;
|
||||||
|
case "String":
|
||||||
|
return value.toString();
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算过滤从句和过滤参数。
|
* 计算过滤从句和过滤参数。
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -20,6 +20,11 @@
|
|||||||
<artifactId>common-satoken</artifactId>
|
<artifactId>common-satoken</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.orangeforms</groupId>
|
||||||
|
<artifactId>common-dbutil</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.orangeforms</groupId>
|
<groupId>com.orangeforms</groupId>
|
||||||
<artifactId>common-datafilter</artifactId>
|
<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 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_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 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.orangeforms.common.flow.controller;
|
package com.orangeforms.common.flow.controller;
|
||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
|
import com.orangeforms.common.core.exception.MyRuntimeException;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
@@ -35,6 +36,7 @@ import org.flowable.bpmn.model.BpmnModel;
|
|||||||
import org.flowable.bpmn.model.UserTask;
|
import org.flowable.bpmn.model.UserTask;
|
||||||
import org.flowable.engine.history.HistoricActivityInstance;
|
import org.flowable.engine.history.HistoricActivityInstance;
|
||||||
import org.flowable.engine.history.HistoricProcessInstance;
|
import org.flowable.engine.history.HistoricProcessInstance;
|
||||||
|
import org.flowable.engine.runtime.ProcessInstance;
|
||||||
import org.flowable.task.api.Task;
|
import org.flowable.task.api.Task;
|
||||||
import org.flowable.task.api.TaskInfo;
|
import org.flowable.task.api.TaskInfo;
|
||||||
import org.flowable.task.api.history.HistoricTaskInstance;
|
import org.flowable.task.api.history.HistoricTaskInstance;
|
||||||
@@ -113,6 +115,26 @@ public class FlowOperationController {
|
|||||||
return ResponseResult.success();
|
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="bpmn_xml" jdbcType="LONGVARCHAR" property="bpmnXml"/>
|
||||||
<result column="diagram_type" jdbcType="INTEGER" property="diagramType"/>
|
<result column="diagram_type" jdbcType="INTEGER" property="diagramType"/>
|
||||||
<result column="bind_form_type" jdbcType="INTEGER" property="bindFormType"/>
|
<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="page_id" jdbcType="BIGINT" property="pageId"/>
|
||||||
<result column="default_form_id" jdbcType="BIGINT" property="defaultFormId"/>
|
<result column="default_form_id" jdbcType="BIGINT" property="defaultFormId"/>
|
||||||
<result column="default_router_name" jdbcType="VARCHAR" property="defaultRouterName"/>
|
<result column="default_router_name" jdbcType="VARCHAR" property="defaultRouterName"/>
|
||||||
@@ -58,6 +59,9 @@
|
|||||||
<if test="flowEntryFilter.status != null">
|
<if test="flowEntryFilter.status != null">
|
||||||
AND zz_flow_entry.status = #{flowEntryFilter.status}
|
AND zz_flow_entry.status = #{flowEntryFilter.status}
|
||||||
</if>
|
</if>
|
||||||
|
<if test="flowEntryFilter.flowType != null">
|
||||||
|
AND zz_flow_entry.flow_type = #{flowEntryFilter.flowType}
|
||||||
|
</if>
|
||||||
</if>
|
</if>
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
@@ -73,6 +77,7 @@
|
|||||||
status,
|
status,
|
||||||
diagram_type,
|
diagram_type,
|
||||||
bind_form_type,
|
bind_form_type,
|
||||||
|
flow_type,
|
||||||
page_id,
|
page_id,
|
||||||
default_form_id,
|
default_form_id,
|
||||||
default_router_name,
|
default_router_name,
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
<result column="candidate_usernames" jdbcType="VARCHAR" property="candidateUsernames"/>
|
<result column="candidate_usernames" jdbcType="VARCHAR" property="candidateUsernames"/>
|
||||||
<result column="copy_list_json" jdbcType="VARCHAR" property="copyListJson"/>
|
<result column="copy_list_json" jdbcType="VARCHAR" property="copyListJson"/>
|
||||||
<result column="extra_data_json" jdbcType="VARCHAR" property="extraDataJson"/>
|
<result column="extra_data_json" jdbcType="VARCHAR" property="extraDataJson"/>
|
||||||
|
<result column="auto_config_json" jdbcType="VARCHAR" property="autoConfigJson"/>
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<insert id="insertList">
|
<insert id="insertList">
|
||||||
@@ -30,7 +31,8 @@
|
|||||||
#{item.deptIds},
|
#{item.deptIds},
|
||||||
#{item.candidateUsernames},
|
#{item.candidateUsernames},
|
||||||
#{item.copyListJson},
|
#{item.copyListJson},
|
||||||
#{item.extraDataJson})
|
#{item.extraDataJson},
|
||||||
|
#{item.autoConfigJson})
|
||||||
</foreach>
|
</foreach>
|
||||||
</insert>
|
</insert>
|
||||||
</mapper>
|
</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,52 @@
|
|||||||
|
package com.orangeforms.common.flow.dto;
|
||||||
|
|
||||||
|
import com.orangeforms.common.core.validator.UpdateGroup;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工作流自动化流程数据表所在数据库链接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,65 @@
|
|||||||
|
package com.orangeforms.common.flow.model;
|
||||||
|
|
||||||
|
import com.mybatisflex.annotation.*;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动化流程变量实体。
|
||||||
|
*
|
||||||
|
* @author Jerry
|
||||||
|
* @date 2024-07-02
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Table(value = "zz_flow_auto_variable_log")
|
||||||
|
public class FlowAutoVariableLog {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键Id。
|
||||||
|
*/
|
||||||
|
@Id(value = "id")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程实例Id。
|
||||||
|
*/
|
||||||
|
@Column(value = "process_instance_id")
|
||||||
|
private String processInstanceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行实例Id。
|
||||||
|
*/
|
||||||
|
@Column(value = "execution_id")
|
||||||
|
private String executionId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务Id。
|
||||||
|
*/
|
||||||
|
@Column(value = "task_id")
|
||||||
|
private String taskId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务标识。
|
||||||
|
*/
|
||||||
|
@Column(value = "task_key")
|
||||||
|
private String taskKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前请求的traceId。
|
||||||
|
*/
|
||||||
|
@Column(value = "trace_id")
|
||||||
|
private String traceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变量数据。
|
||||||
|
*/
|
||||||
|
@Column(value = "variable_data")
|
||||||
|
private String variableData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间。
|
||||||
|
*/
|
||||||
|
@Column(value = "create_time")
|
||||||
|
private Date createTime;
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package com.orangeforms.common.flow.model;
|
||||||
|
|
||||||
|
import com.mybatisflex.annotation.*;
|
||||||
|
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
|
||||||
|
@Table(value = "zz_flow_dblink")
|
||||||
|
public class FlowDblink {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键Id。
|
||||||
|
*/
|
||||||
|
@Id(value = "dblink_id")
|
||||||
|
private Long dblinkId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用编码。为空时,表示非第三方应用接入。
|
||||||
|
*/
|
||||||
|
@Column(value = "app_code")
|
||||||
|
private String appCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 链接中文名称。
|
||||||
|
*/
|
||||||
|
@Column(value = "dblink_name")
|
||||||
|
private String dblinkName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 链接描述。
|
||||||
|
*/
|
||||||
|
@Column(value = "dblink_description")
|
||||||
|
private String dblinkDescription;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置信息。
|
||||||
|
*/
|
||||||
|
private String configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据库链接类型。
|
||||||
|
*/
|
||||||
|
@Column(value = "dblink_type")
|
||||||
|
private Integer dblinkType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间。
|
||||||
|
*/
|
||||||
|
@Column(value = "create_time")
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建者。
|
||||||
|
*/
|
||||||
|
@Column(value = "create_user_id")
|
||||||
|
private Long createUserId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改时间。
|
||||||
|
*/
|
||||||
|
@Column(value = "update_time")
|
||||||
|
private Date updateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新者。
|
||||||
|
*/
|
||||||
|
@Column(value = "update_user_id")
|
||||||
|
private Long updateUserId;
|
||||||
|
|
||||||
|
@RelationConstDict(
|
||||||
|
masterIdField = "dblinkType",
|
||||||
|
constantDictClass = DblinkType.class)
|
||||||
|
@Column(ignore = true)
|
||||||
|
private Map<String, Object> dblinkTypeDictMap;
|
||||||
|
}
|
||||||
@@ -88,6 +88,12 @@ public class FlowEntry {
|
|||||||
@Column(value = "bind_form_type")
|
@Column(value = "bind_form_type")
|
||||||
private Integer bindFormType;
|
private Integer bindFormType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程类型。
|
||||||
|
*/
|
||||||
|
@Column(value = "flow_type")
|
||||||
|
private Integer flowType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在线表单的页面Id。
|
* 在线表单的页面Id。
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.orangeforms.common.flow.model;
|
package com.orangeforms.common.flow.model;
|
||||||
|
|
||||||
import com.mybatisflex.annotation.*;
|
import com.mybatisflex.annotation.*;
|
||||||
|
import com.orangeforms.common.flow.model.constant.FlowVariableType;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@@ -74,4 +75,13 @@ public class FlowEntryVariable {
|
|||||||
*/
|
*/
|
||||||
@Column(value = "create_time")
|
@Column(value = "create_time")
|
||||||
private Date createTime;
|
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 {
|
|||||||
*/
|
*/
|
||||||
@Column(value = "extra_data_json")
|
@Column(value = "extra_data_json")
|
||||||
private String extraDataJson;
|
private String extraDataJson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动化任务配置数据,存储为JSON的字符串格式。
|
||||||
|
*/
|
||||||
|
@Column(value = "auto_config_json")
|
||||||
|
private String autoConfigJson;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,131 @@
|
|||||||
|
package com.orangeforms.common.flow.model;
|
||||||
|
|
||||||
|
import com.mybatisflex.annotation.*;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程处理事务事件生产者流水实体。
|
||||||
|
*
|
||||||
|
* @author Jerry
|
||||||
|
* @date 2024-07-02
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Table(value = "zz_flow_trans_producer")
|
||||||
|
public class FlowTransProducer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流水Id。
|
||||||
|
*/
|
||||||
|
@Id(value = "trans_id")
|
||||||
|
private Long transId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用编码。为空时,表示非第三方应用接入。
|
||||||
|
*/
|
||||||
|
@Column(value = "app_code")
|
||||||
|
private String appCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务数据库链接Id。
|
||||||
|
*/
|
||||||
|
@Column(value = "dblink_id")
|
||||||
|
private Long dblinkId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程实例Id。
|
||||||
|
*/
|
||||||
|
@Column(value = "process_instance_id")
|
||||||
|
private String processInstanceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行实例Id。
|
||||||
|
*/
|
||||||
|
@Column(value = "execution_id")
|
||||||
|
private String executionId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务Id。
|
||||||
|
*/
|
||||||
|
@Column(value = "task_id")
|
||||||
|
private String taskId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务标识。
|
||||||
|
*/
|
||||||
|
@Column(value = "task_key")
|
||||||
|
private String taskKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务名称。
|
||||||
|
*/
|
||||||
|
@Column(value = "task_name")
|
||||||
|
private String taskName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审批批注。
|
||||||
|
*/
|
||||||
|
@Column(value = "task_comment")
|
||||||
|
private String taskComment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前请求的url。
|
||||||
|
*/
|
||||||
|
@Column(value = "url")
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建该事务性事件对象的初始方法。格式为:方法名(参数类型1,参数类型2)。
|
||||||
|
*/
|
||||||
|
@Column(value = "init_method")
|
||||||
|
private String initMethod;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前请求的traceId。
|
||||||
|
*/
|
||||||
|
@Column(value = "trace_id")
|
||||||
|
private String traceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 和SQL操作相关的数据。值类型为TransactionalBusinessData.BusinessSqlData对象。
|
||||||
|
*/
|
||||||
|
@Column(value = "sql_data")
|
||||||
|
private String sqlData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动化流程的任务配置。
|
||||||
|
*/
|
||||||
|
@Column(value = "auto_task_config")
|
||||||
|
private String autoTaskConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 尝试次数。默认的插入值为1。
|
||||||
|
*/
|
||||||
|
@Column(value = "try_times")
|
||||||
|
private Integer tryTimes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交业务数据时的错误信息。如果正常提交,该值为空。
|
||||||
|
*/
|
||||||
|
@Column(value = "error_reason")
|
||||||
|
private String errorReason;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建者登录名。
|
||||||
|
*/
|
||||||
|
@Column(value = "create_login_name")
|
||||||
|
private String createLoginName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建者中文用户名。
|
||||||
|
*/
|
||||||
|
@Column(value = "create_username")
|
||||||
|
private String createUsername;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间。
|
||||||
|
*/
|
||||||
|
@Column(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 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);
|
private static final Map<Object, String> DICT_MAP = new HashMap<>(2);
|
||||||
static {
|
static {
|
||||||
DICT_MAP.put(INSTANCE, "流程实例变量");
|
DICT_MAP.put(INSTANCE, "流程实例变量");
|
||||||
DICT_MAP.put(TASK, "任务变量");
|
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.TaskInfo;
|
||||||
import org.flowable.task.api.history.HistoricTaskInstance;
|
import org.flowable.task.api.history.HistoricTaskInstance;
|
||||||
|
|
||||||
import javax.xml.stream.XMLStreamException;
|
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -46,6 +45,15 @@ public interface FlowApiService {
|
|||||||
*/
|
*/
|
||||||
ProcessInstance start(String processDefinitionId, Object dataId);
|
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格式的流程模型字符串。
|
* @param bpmnXml xml格式的流程模型字符串。
|
||||||
* @return 转换后的标准的流程模型。
|
* @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(
|
Tuple2<Set<String>, Set<String>> getDeptPostIdAndPostIds(
|
||||||
FlowTaskExt flowTaskExt, String processInstanceId, boolean historic);
|
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,
|
String executionId,
|
||||||
FlowTaskExt flowTaskExt);
|
FlowTaskExt flowTaskExt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证自动化任务的配置,如果有问题直接抛出MyRuntimeException异常。
|
||||||
|
*
|
||||||
|
* @param taskExt 流程任务的扩展。
|
||||||
|
*/
|
||||||
|
void verifyAutoTaskConfig(FlowTaskExt taskExt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过UserTask对象中的扩展节点信息,构建FLowTaskExt对象。
|
* 通过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);
|
||||||
|
}
|
||||||
@@ -19,15 +19,14 @@ import com.orangeforms.common.core.util.MyCommonUtil;
|
|||||||
import com.orangeforms.common.core.util.DefaultDataSourceResolver;
|
import com.orangeforms.common.core.util.DefaultDataSourceResolver;
|
||||||
import com.orangeforms.common.flow.cmd.AddSequenceMultiInstanceCmd;
|
import com.orangeforms.common.flow.cmd.AddSequenceMultiInstanceCmd;
|
||||||
import com.orangeforms.common.flow.exception.FlowOperationException;
|
import com.orangeforms.common.flow.exception.FlowOperationException;
|
||||||
|
import com.orangeforms.common.flow.model.constant.FlowEntryType;
|
||||||
import com.orangeforms.common.flow.object.*;
|
import com.orangeforms.common.flow.object.*;
|
||||||
import com.orangeforms.common.flow.constant.FlowConstant;
|
import com.orangeforms.common.flow.constant.FlowConstant;
|
||||||
import com.orangeforms.common.flow.constant.FlowApprovalType;
|
import com.orangeforms.common.flow.constant.FlowApprovalType;
|
||||||
import com.orangeforms.common.flow.constant.FlowTaskStatus;
|
import com.orangeforms.common.flow.constant.FlowTaskStatus;
|
||||||
import com.orangeforms.common.flow.model.*;
|
import com.orangeforms.common.flow.model.*;
|
||||||
import com.orangeforms.common.flow.service.*;
|
import com.orangeforms.common.flow.service.*;
|
||||||
import com.orangeforms.common.flow.util.BaseFlowIdentityExtHelper;
|
import com.orangeforms.common.flow.util.*;
|
||||||
import com.orangeforms.common.flow.util.CustomChangeActivityStateBuilderImpl;
|
|
||||||
import com.orangeforms.common.flow.util.FlowCustomExtFactory;
|
|
||||||
import com.orangeforms.common.flow.vo.FlowTaskVo;
|
import com.orangeforms.common.flow.vo.FlowTaskVo;
|
||||||
import com.orangeforms.common.flow.vo.FlowUserInfoVo;
|
import com.orangeforms.common.flow.vo.FlowUserInfoVo;
|
||||||
import lombok.Cleanup;
|
import lombok.Cleanup;
|
||||||
@@ -107,6 +106,14 @@ public class FlowApiServiceImpl implements FlowApiService {
|
|||||||
private FlowCustomExtFactory flowCustomExtFactory;
|
private FlowCustomExtFactory flowCustomExtFactory;
|
||||||
@Autowired
|
@Autowired
|
||||||
private FlowMultiInstanceTransService flowMultiInstanceTransService;
|
private FlowMultiInstanceTransService flowMultiInstanceTransService;
|
||||||
|
@Autowired
|
||||||
|
private FlowTransProducerService flowTransProducerService;
|
||||||
|
@Autowired
|
||||||
|
private FlowAutoVariableLogService flowAutoVariableLogService;
|
||||||
|
@Autowired
|
||||||
|
private FlowOperationHelper flowOperationHelper;
|
||||||
|
@Autowired
|
||||||
|
private AutoFlowHelper autoFlowHelper;
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@Override
|
@Override
|
||||||
@@ -127,6 +134,45 @@ public class FlowApiServiceImpl implements FlowApiService {
|
|||||||
return builder.start();
|
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)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@Override
|
@Override
|
||||||
public Task takeFirstTask(String processInstanceId, FlowTaskComment flowTaskComment, JSONObject taskVariableData) {
|
public Task takeFirstTask(String processInstanceId, FlowTaskComment flowTaskComment, JSONObject taskVariableData) {
|
||||||
@@ -976,6 +1022,12 @@ public class FlowApiServiceImpl implements FlowApiService {
|
|||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@Override
|
@Override
|
||||||
public CallResult stopProcessInstance(String processInstanceId, String stopReason, int status) {
|
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();
|
List<Task> taskList = taskService.createTaskQuery().processInstanceId(processInstanceId).active().list();
|
||||||
if (CollUtil.isEmpty(taskList)) {
|
if (CollUtil.isEmpty(taskList)) {
|
||||||
return CallResult.error("数据验证失败,当前流程尚未开始或已经结束!");
|
return CallResult.error("数据验证失败,当前流程尚未开始或已经结束!");
|
||||||
@@ -1085,11 +1137,15 @@ public class FlowApiServiceImpl implements FlowApiService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BpmnModel convertToBpmnModel(String bpmnXml) throws XMLStreamException {
|
public BpmnModel convertToBpmnModel(String bpmnXml) {
|
||||||
|
try {
|
||||||
BpmnXMLConverter converter = new BpmnXMLConverter();
|
BpmnXMLConverter converter = new BpmnXMLConverter();
|
||||||
InputStream in = new ByteArrayInputStream(bpmnXml.getBytes(StandardCharsets.UTF_8));
|
InputStream in = new ByteArrayInputStream(bpmnXml.getBytes(StandardCharsets.UTF_8));
|
||||||
@Cleanup XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(in);
|
@Cleanup XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(in);
|
||||||
return converter.convertToBpmnModel(reader);
|
return converter.convertToBpmnModel(reader);
|
||||||
|
} catch (XMLStreamException e) {
|
||||||
|
throw new MyRuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@@ -1715,6 +1771,15 @@ public class FlowApiServiceImpl implements FlowApiService {
|
|||||||
return new Tuple2<>(deptPostIdSet, postIdSet);
|
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
|
@Override
|
||||||
public Map<String, UserTask> getAllUserTaskMap(String processDefinitionId) {
|
public Map<String, UserTask> getAllUserTaskMap(String processDefinitionId) {
|
||||||
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
|
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package com.orangeforms.common.flow.service.impl;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
|
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) {
|
||||||
|
QueryWrapper qw = new QueryWrapper();
|
||||||
|
qw.eq(FlowAutoVariableLog::getProcessInstanceId, processInstanceId);
|
||||||
|
return flowAutoVariableLogMapper.selectOneByQuery(qw);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
package com.orangeforms.common.flow.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
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());
|
||||||
|
return flowDblinkMapper.update(flowDblink, false) == 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ import com.orangeforms.common.core.object.MyRelationParam;
|
|||||||
import com.orangeforms.common.core.object.TokenData;
|
import com.orangeforms.common.core.object.TokenData;
|
||||||
import com.orangeforms.common.core.util.MyModelUtil;
|
import com.orangeforms.common.core.util.MyModelUtil;
|
||||||
import com.orangeforms.common.core.util.DefaultDataSourceResolver;
|
import com.orangeforms.common.core.util.DefaultDataSourceResolver;
|
||||||
|
import com.orangeforms.common.flow.model.constant.FlowEntryType;
|
||||||
import com.orangeforms.common.redis.util.CommonRedisUtil;
|
import com.orangeforms.common.redis.util.CommonRedisUtil;
|
||||||
import com.orangeforms.common.sequence.wrapper.IdGeneratorWrapper;
|
import com.orangeforms.common.sequence.wrapper.IdGeneratorWrapper;
|
||||||
import com.orangeforms.common.flow.listener.*;
|
import com.orangeforms.common.flow.listener.*;
|
||||||
@@ -29,9 +30,7 @@ import com.orangeforms.common.flow.model.*;
|
|||||||
import com.orangeforms.common.flow.service.*;
|
import com.orangeforms.common.flow.service.*;
|
||||||
import com.orangeforms.common.flow.model.constant.FlowEntryStatus;
|
import com.orangeforms.common.flow.model.constant.FlowEntryStatus;
|
||||||
import com.orangeforms.common.flow.model.constant.FlowVariableType;
|
import com.orangeforms.common.flow.model.constant.FlowVariableType;
|
||||||
import lombok.Cleanup;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.flowable.bpmn.converter.BpmnXMLConverter;
|
|
||||||
import org.flowable.bpmn.model.*;
|
import org.flowable.bpmn.model.*;
|
||||||
import org.flowable.engine.RepositoryService;
|
import org.flowable.engine.RepositoryService;
|
||||||
import org.flowable.engine.repository.Deployment;
|
import org.flowable.engine.repository.Deployment;
|
||||||
@@ -40,12 +39,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
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.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -111,19 +104,16 @@ public class FlowEntryServiceImpl extends BaseService<FlowEntry, Long> implement
|
|||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@Override
|
@Override
|
||||||
public void publish(FlowEntry flowEntry, String initTaskInfo) throws XMLStreamException {
|
public void publish(FlowEntry flowEntry, String initTaskInfo) {
|
||||||
commonRedisUtil.evictFormCache(
|
commonRedisUtil.evictFormCache(FlowRedisKeyUtil.makeFlowEntryKey(flowEntry.getProcessDefinitionKey()));
|
||||||
FlowRedisKeyUtil.makeFlowEntryKey(flowEntry.getProcessDefinitionKey()));
|
|
||||||
FlowCategory flowCategory = flowCategoryService.getById(flowEntry.getCategoryId());
|
FlowCategory flowCategory = flowCategoryService.getById(flowEntry.getCategoryId());
|
||||||
InputStream xmlStream = new ByteArrayInputStream(
|
BpmnModel bpmnModel = flowApiService.convertToBpmnModel(flowEntry.getBpmnXml());
|
||||||
flowEntry.getBpmnXml().getBytes(StandardCharsets.UTF_8));
|
|
||||||
@Cleanup XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(xmlStream);
|
|
||||||
BpmnXMLConverter converter = new BpmnXMLConverter();
|
|
||||||
BpmnModel bpmnModel = converter.convertToBpmnModel(reader);
|
|
||||||
bpmnModel.getMainProcess().setName(flowEntry.getProcessDefinitionName());
|
bpmnModel.getMainProcess().setName(flowEntry.getProcessDefinitionName());
|
||||||
bpmnModel.getMainProcess().setId(flowEntry.getProcessDefinitionKey());
|
bpmnModel.getMainProcess().setId(flowEntry.getProcessDefinitionKey());
|
||||||
|
this.processAutomaticTask(flowEntry, bpmnModel);
|
||||||
flowApiService.addProcessInstanceEndListener(bpmnModel, FlowFinishedListener.class);
|
flowApiService.addProcessInstanceEndListener(bpmnModel, FlowFinishedListener.class);
|
||||||
List<FlowTaskExt> flowTaskExtList = flowTaskExtService.buildTaskExtList(bpmnModel);
|
List<FlowTaskExt> flowTaskExtList = flowTaskExtService.buildTaskExtList(bpmnModel);
|
||||||
|
flowTaskExtList.forEach(t -> flowTaskExtService.verifyAutoTaskConfig(t));
|
||||||
if (StrUtil.isNotBlank(flowEntry.getExtensionData())) {
|
if (StrUtil.isNotBlank(flowEntry.getExtensionData())) {
|
||||||
FlowEntryExtensionData flowEntryExtensionData =
|
FlowEntryExtensionData flowEntryExtensionData =
|
||||||
JSON.parseObject(flowEntry.getExtensionData(), FlowEntryExtensionData.class);
|
JSON.parseObject(flowEntry.getExtensionData(), FlowEntryExtensionData.class);
|
||||||
@@ -338,6 +328,18 @@ public class FlowEntryServiceImpl extends BaseService<FlowEntry, Long> implement
|
|||||||
return CallResult.ok();
|
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) {
|
private void insertBuiltinEntryVariables(Long entryId) {
|
||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
FlowEntryVariable operationTypeVariable = new FlowEntryVariable();
|
FlowEntryVariable operationTypeVariable = new FlowEntryVariable();
|
||||||
@@ -442,6 +444,9 @@ public class FlowEntryServiceImpl extends BaseService<FlowEntry, Long> implement
|
|||||||
.filter(UserTask.class::isInstance).collect(Collectors.toMap(FlowElement::getId, c -> c));
|
.filter(UserTask.class::isInstance).collect(Collectors.toMap(FlowElement::getId, c -> c));
|
||||||
BaseFlowIdentityExtHelper flowIdentityExtHelper = flowCustomExtFactory.getFlowIdentityExtHelper();
|
BaseFlowIdentityExtHelper flowIdentityExtHelper = flowCustomExtFactory.getFlowIdentityExtHelper();
|
||||||
for (FlowTaskExt t : flowTaskExtList) {
|
for (FlowTaskExt t : flowTaskExtList) {
|
||||||
|
if (!elementMap.containsKey(t.getTaskId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
UserTask userTask = (UserTask) elementMap.get(t.getTaskId());
|
UserTask userTask = (UserTask) elementMap.get(t.getTaskId());
|
||||||
flowApiService.addTaskCreateListener(userTask, FlowUserTaskListener.class);
|
flowApiService.addTaskCreateListener(userTask, FlowUserTaskListener.class);
|
||||||
Map<String, List<ExtensionAttribute>> attributes = userTask.getAttributes();
|
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.collection.CollUtil;
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
|
import cn.hutool.core.text.StrFormatter;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.alibaba.fastjson.JSONArray;
|
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.object.Tuple2;
|
||||||
import com.orangeforms.common.core.util.DefaultDataSourceResolver;
|
import com.orangeforms.common.core.util.DefaultDataSourceResolver;
|
||||||
import com.orangeforms.common.flow.constant.FlowApprovalType;
|
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.constant.FlowConstant;
|
||||||
|
import com.orangeforms.common.flow.object.AutoTaskConfig;
|
||||||
import com.orangeforms.common.flow.object.FlowElementExtProperty;
|
import com.orangeforms.common.flow.object.FlowElementExtProperty;
|
||||||
import com.orangeforms.common.flow.object.FlowTaskMultiSignAssign;
|
import com.orangeforms.common.flow.object.FlowTaskMultiSignAssign;
|
||||||
import com.orangeforms.common.flow.object.FlowUserTaskExtData;
|
import com.orangeforms.common.flow.object.FlowUserTaskExtData;
|
||||||
@@ -221,16 +224,29 @@ public class FlowTaskExtServiceImpl extends BaseService<FlowTaskExt, String> imp
|
|||||||
return resultUserMapList;
|
return resultUserMapList;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void buildUserMapList(
|
@Override
|
||||||
List<FlowUserInfoVo> userInfoList, Set<String> loginNameSet, List<FlowUserInfoVo> userMapList) {
|
public void verifyAutoTaskConfig(FlowTaskExt taskExt) {
|
||||||
if (CollUtil.isEmpty(userInfoList)) {
|
if (StrUtil.isBlank(taskExt.getAutoConfigJson())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (FlowUserInfoVo userInfo : userInfoList) {
|
AutoTaskConfig taskConfig = JSON.parseObject(taskExt.getAutoConfigJson(), AutoTaskConfig.class);
|
||||||
if (!loginNameSet.contains(userInfo.getLoginName())) {
|
this.verifyDataOperationTask(taskConfig);
|
||||||
loginNameSet.add(userInfo.getLoginName());
|
String errorMessage;
|
||||||
userMapList.add(userInfo);
|
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;
|
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) {
|
private void doBuildTaskExtList(FlowElement element, List<FlowTaskExt> flowTaskExtList) {
|
||||||
if (element instanceof UserTask) {
|
if (element instanceof UserTask) {
|
||||||
FlowTaskExt flowTaskExt = this.buildTaskExtByUserTask((UserTask) element);
|
FlowTaskExt flowTaskExt = this.buildTaskExtByUserTask((UserTask) element);
|
||||||
flowTaskExtList.add(flowTaskExt);
|
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) {
|
} else if (element instanceof SubProcess) {
|
||||||
Collection<FlowElement> flowElements = ((SubProcess) element).getFlowElements();
|
Collection<FlowElement> flowElements = ((SubProcess) element).getFlowElements();
|
||||||
for (FlowElement element1 : flowElements) {
|
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().update(data, true) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@Override
|
||||||
|
public boolean removeById(Serializable transId) {
|
||||||
|
return mapper().deleteById(transId) != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,656 @@
|
|||||||
|
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.*;
|
||||||
|
|
||||||
|
@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 (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 (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;
|
||||||
|
}
|
||||||
BIN
OrangeFormsOpen-MybatisFlex/zz-resource/.DS_Store
vendored
Normal file
BIN
OrangeFormsOpen-MybatisFlex/zz-resource/.DS_Store
vendored
Normal file
Binary file not shown.
@@ -1290,6 +1290,7 @@ CREATE TABLE `zz_flow_entry` (
|
|||||||
`bpmn_xml` longtext COMMENT '流程定义的xml',
|
`bpmn_xml` longtext COMMENT '流程定义的xml',
|
||||||
`diagram_type` int NOT NULL COMMENT '流程图类型',
|
`diagram_type` int NOT NULL COMMENT '流程图类型',
|
||||||
`bind_form_type` int NOT NULL COMMENT '绑定表单类型',
|
`bind_form_type` int NOT NULL COMMENT '绑定表单类型',
|
||||||
|
`flow_type` int NOT NULL COMMENT '流程类型',
|
||||||
`page_id` bigint DEFAULT NULL COMMENT '在线表单的页面Id',
|
`page_id` bigint DEFAULT NULL COMMENT '在线表单的页面Id',
|
||||||
`default_form_id` bigint DEFAULT NULL COMMENT '在线表单Id',
|
`default_form_id` bigint DEFAULT NULL COMMENT '在线表单Id',
|
||||||
`default_router_name` varchar(255) DEFAULT NULL COMMENT '静态表单的缺省路由名称',
|
`default_router_name` varchar(255) DEFAULT NULL COMMENT '静态表单的缺省路由名称',
|
||||||
@@ -1517,6 +1518,7 @@ CREATE TABLE `zz_flow_task_ext` (
|
|||||||
`candidate_usernames` varchar(4000) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '保存候选组用户名数据',
|
`candidate_usernames` varchar(4000) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '保存候选组用户名数据',
|
||||||
`copy_list_json` varchar(4000) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '抄送相关的数据',
|
`copy_list_json` varchar(4000) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '抄送相关的数据',
|
||||||
`extra_data_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin COMMENT '用户任务的扩展属性,存储为JSON的字符串格式',
|
`extra_data_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin COMMENT '用户任务的扩展属性,存储为JSON的字符串格式',
|
||||||
|
`auto_config_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin COMMENT '自动化任务配置数据,存储为JSON的字符串格式',
|
||||||
PRIMARY KEY (`process_definition_id`,`task_id`) USING BTREE
|
PRIMARY KEY (`process_definition_id`,`task_id`) USING BTREE
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='流程流程图任务扩展表';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='流程流程图任务扩展表';
|
||||||
|
|
||||||
@@ -1579,6 +1581,72 @@ CREATE TABLE `zz_flow_work_order_ext` (
|
|||||||
KEY `idx_work_order_id` (`work_order_id`) USING BTREE
|
KEY `idx_work_order_id` (`work_order_id`) USING BTREE
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='流程工单扩展表';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='流程工单扩展表';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for zz_flow_auto_variable_log
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `zz_flow_auto_variable_log`;
|
||||||
|
CREATE TABLE `zz_flow_auto_variable_log` (
|
||||||
|
`id` bigint NOT NULL COMMENT '主键Id',
|
||||||
|
`process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '流程实例Id',
|
||||||
|
`execution_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '执行实例Id',
|
||||||
|
`task_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '任务Id',
|
||||||
|
`task_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '任务标识',
|
||||||
|
`trace_id` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '当前请求的traceId',
|
||||||
|
`variable_data` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin COMMENT '变量数据',
|
||||||
|
`create_time` datetime NOT NULL COMMENT '创建时间',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
KEY `idx_process_instance_id` (`process_instance_id`,`task_key`) USING BTREE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='流程变量日志表';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for zz_flow_dblink
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `zz_flow_dblink`;
|
||||||
|
CREATE TABLE `zz_flow_dblink` (
|
||||||
|
`dblink_id` bigint NOT NULL COMMENT '主键Id',
|
||||||
|
`app_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '应用编码',
|
||||||
|
`dblink_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '链接中文名称',
|
||||||
|
`dblink_description` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '链接描述',
|
||||||
|
`dblink_type` int NOT NULL COMMENT '数据源类型',
|
||||||
|
`configuration` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '配置信息',
|
||||||
|
`create_time` datetime NOT NULL COMMENT '创建时间',
|
||||||
|
`create_user_id` bigint NOT NULL COMMENT '创建者',
|
||||||
|
`update_time` datetime NOT NULL COMMENT '更新时间',
|
||||||
|
`update_user_id` bigint NOT NULL COMMENT '更新者',
|
||||||
|
PRIMARY KEY (`dblink_id`) USING BTREE,
|
||||||
|
KEY `idx_dblink_type` (`dblink_type`) USING BTREE,
|
||||||
|
KEY `idx_app_code` (`app_code`) USING BTREE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='在线表单数据库链接表';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for zz_flow_trans_producer
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `zz_flow_trans_producer`;
|
||||||
|
CREATE TABLE `zz_flow_trans_producer` (
|
||||||
|
`trans_id` bigint NOT NULL COMMENT '主键Id',
|
||||||
|
`app_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '应用Id',
|
||||||
|
`dblink_id` bigint DEFAULT NULL COMMENT '数据库链接Id',
|
||||||
|
`process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '流程实例Id',
|
||||||
|
`execution_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '执行实例Id',
|
||||||
|
`task_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '任务Id',
|
||||||
|
`task_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '任务标识',
|
||||||
|
`task_name` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '任务名称',
|
||||||
|
`task_comment` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '批注内容',
|
||||||
|
`url` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '当前请求的url',
|
||||||
|
`init_method` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '创建该事务性事件对象的初始方法',
|
||||||
|
`trace_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '当前请求的traceId',
|
||||||
|
`sql_data` text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin COMMENT '和SQL操作相关的数据',
|
||||||
|
`auto_task_config` text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin COMMENT '自动化任务需要执行的数据',
|
||||||
|
`try_times` int NOT NULL COMMENT '尝试次数',
|
||||||
|
`error_reason` text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin COMMENT '提交业务数据时的错误信息',
|
||||||
|
`create_login_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '创建者登录名',
|
||||||
|
`create_username` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '创建者中文用户名',
|
||||||
|
`create_time` datetime NOT NULL COMMENT '创建时间',
|
||||||
|
PRIMARY KEY (`trans_id`) USING BTREE,
|
||||||
|
KEY `idx_app_code` (`app_code`) USING BTREE,
|
||||||
|
KEY `idx_process_instance_id` (`process_instance_id`) USING BTREE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for zz_global_dict
|
-- Table structure for zz_global_dict
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user