15 changed files with 2859 additions and 0 deletions
@ -0,0 +1,34 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||||
|
<parent> |
||||||
|
<artifactId>common</artifactId> |
||||||
|
<groupId>apelet</groupId> |
||||||
|
<version>1.0.0</version> |
||||||
|
</parent> |
||||||
|
<modelVersion>4.0.0</modelVersion> |
||||||
|
|
||||||
|
<artifactId>common-flow-online</artifactId> |
||||||
|
<version>1.0.0</version> |
||||||
|
<name>common-flow-online</name> |
||||||
|
<packaging>jar</packaging> |
||||||
|
|
||||||
|
<dependencies> |
||||||
|
<dependency> |
||||||
|
<groupId>apelet</groupId> |
||||||
|
<artifactId>common-flow</artifactId> |
||||||
|
<version>1.0.0</version> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>apelet</groupId> |
||||||
|
<artifactId>common-online</artifactId> |
||||||
|
<version>1.0.0</version> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>apelet</groupId> |
||||||
|
<artifactId>common-orm</artifactId> |
||||||
|
<version>1.0.0</version> |
||||||
|
</dependency> |
||||||
|
</dependencies> |
||||||
|
</project> |
||||||
@ -0,0 +1,88 @@ |
|||||||
|
package apelet.common.flow.online.aop; |
||||||
|
|
||||||
|
import apelet.common.core.object.TokenData; |
||||||
|
import apelet.common.core.util.AopTargetUtil; |
||||||
|
import apelet.common.core.util.MyDateUtil; |
||||||
|
import apelet.common.flow.dao.FlowTransProducerMapper; |
||||||
|
import apelet.common.flow.model.FlowTaskComment; |
||||||
|
import apelet.common.flow.model.FlowTransProducer; |
||||||
|
import apelet.common.flow.online.object.TransactionalFlowBusinessData; |
||||||
|
import cn.hutool.core.bean.BeanUtil; |
||||||
|
import cn.hutool.core.collection.CollUtil; |
||||||
|
import cn.hutool.core.util.StrUtil; |
||||||
|
import com.alibaba.fastjson.JSON; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.aspectj.lang.ProceedingJoinPoint; |
||||||
|
import org.aspectj.lang.annotation.Around; |
||||||
|
import org.aspectj.lang.annotation.Aspect; |
||||||
|
import org.aspectj.lang.annotation.Pointcut; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.context.ApplicationEventPublisher; |
||||||
|
import org.springframework.stereotype.Component; |
||||||
|
|
||||||
|
/** |
||||||
|
* 拦截流程业务多数据库数据写入的AOP对象。 |
||||||
|
* |
||||||
|
* @author guifc |
||||||
|
* @date 2023-08-04 |
||||||
|
*/ |
||||||
|
@Aspect |
||||||
|
@Component |
||||||
|
@Slf4j |
||||||
|
public class FlowMultiDatabaseWriteAspect { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private ApplicationEventPublisher eventPublisher; |
||||||
|
@Autowired |
||||||
|
private FlowTransProducerMapper flowTransProducerMapper; |
||||||
|
|
||||||
|
@Pointcut("execution(public * apelet.common.flow..service.impl..*(..)) " + |
||||||
|
"&& @annotation(apelet.common.core.annotation.MultiDatabaseWriteMethod)") |
||||||
|
public void multiDatabaseWriteMethodPointCut() { |
||||||
|
// 空注释,避免sonar警告
|
||||||
|
} |
||||||
|
|
||||||
|
@Around("multiDatabaseWriteMethodPointCut()") |
||||||
|
public Object around(ProceedingJoinPoint joinPoint) throws Throwable { |
||||||
|
String initMethod = AopTargetUtil.getFullMethodName(joinPoint); |
||||||
|
TransactionalFlowBusinessData data = TransactionalFlowBusinessData.getOrCreateFromRequestAttribute(); |
||||||
|
if (data.getInitMethod() == null) { |
||||||
|
data.setInitMethod(initMethod); |
||||||
|
} |
||||||
|
try { |
||||||
|
// 调用原来的方法
|
||||||
|
Object result = joinPoint.proceed(); |
||||||
|
if (StrUtil.equals(initMethod, data.getInitMethod()) && CollUtil.isNotEmpty(data.getSqlDataList())) { |
||||||
|
this.fillupTransactionalBusinessData(); |
||||||
|
FlowTransProducer producerData = BeanUtil.copyProperties(data, FlowTransProducer.class); |
||||||
|
producerData.setAppCode(TokenData.takeFromRequest().getAppCode()); |
||||||
|
producerData.setTryTimes(1); |
||||||
|
String sqlData = JSON.toJSONStringWithDateFormat( |
||||||
|
data.getSqlDataList(), MyDateUtil.COMMON_SHORT_DATETIME_FORMAT); |
||||||
|
producerData.setSqlData(sqlData); |
||||||
|
flowTransProducerMapper.insert(producerData); |
||||||
|
eventPublisher.publishEvent(data); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} catch (Exception e) { |
||||||
|
TransactionalFlowBusinessData.removeFromRequestAttribute(); |
||||||
|
throw e; |
||||||
|
} finally { |
||||||
|
if (StrUtil.equals(initMethod, data.getInitMethod())) { |
||||||
|
TransactionalFlowBusinessData.removeFromRequestAttribute(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void fillupTransactionalBusinessData() { |
||||||
|
FlowTaskComment comment = FlowTaskComment.getFromRequest(); |
||||||
|
TransactionalFlowBusinessData data = TransactionalFlowBusinessData.getFromRequestAttribute(); |
||||||
|
if (comment != null) { |
||||||
|
data.setProcessInstanceId(comment.getProcessInstanceId()); |
||||||
|
data.setTaskId(comment.getTaskId()); |
||||||
|
data.setTaskKey(comment.getTaskKey()); |
||||||
|
data.setTaskName(comment.getTaskName()); |
||||||
|
data.setTaskComment(comment.getTaskComment()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,38 @@ |
|||||||
|
package apelet.common.flow.online.aop; |
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.aspectj.lang.ProceedingJoinPoint; |
||||||
|
import org.aspectj.lang.annotation.Around; |
||||||
|
import org.aspectj.lang.annotation.Aspect; |
||||||
|
import org.aspectj.lang.annotation.Pointcut; |
||||||
|
import org.springframework.core.annotation.Order; |
||||||
|
import org.springframework.stereotype.Component; |
||||||
|
|
||||||
|
/** |
||||||
|
* 主要用于拦截FlowTransactionBusinessDataListener监听器类抛出的异常。 |
||||||
|
* |
||||||
|
* @author guifc |
||||||
|
* @date 2023-08-04 |
||||||
|
*/ |
||||||
|
@Aspect |
||||||
|
@Component |
||||||
|
@Order(1) |
||||||
|
@Slf4j |
||||||
|
public class FlowMultiDatabaseWriteExAspect { |
||||||
|
|
||||||
|
@Pointcut("execution(public * apelet.common.flow.online.service.impl..*(..)) " + |
||||||
|
"&& @annotation(apelet.common.core.annotation.MultiDatabaseWriteMethod)") |
||||||
|
public void multiDatabaseWriteMethodPointCut() { |
||||||
|
// 空注释,避免sonar警告
|
||||||
|
} |
||||||
|
|
||||||
|
@Around("multiDatabaseWriteMethodPointCut()") |
||||||
|
public Object around(ProceedingJoinPoint joinPoint) throws Throwable { |
||||||
|
try { |
||||||
|
return joinPoint.proceed(); |
||||||
|
} catch (Exception e) { |
||||||
|
log.error("FlowMultiDatabaseWriteExAspect throw", e); |
||||||
|
throw e; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,13 @@ |
|||||||
|
package apelet.common.flow.online.config; |
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties; |
||||||
|
|
||||||
|
/** |
||||||
|
* common-flow-online模块的自动配置引导类。 |
||||||
|
* |
||||||
|
* @author guifc |
||||||
|
* @date 2023-08-04 |
||||||
|
*/ |
||||||
|
@EnableConfigurationProperties({FlowOnlineProperties.class}) |
||||||
|
public class FlowOnlineAutoConfig { |
||||||
|
} |
||||||
@ -0,0 +1,20 @@ |
|||||||
|
package apelet.common.flow.online.config; |
||||||
|
|
||||||
|
import lombok.Data; |
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||||
|
|
||||||
|
/** |
||||||
|
* 在线表单工作流模块的配置对象。 |
||||||
|
* |
||||||
|
* @author guifc |
||||||
|
* @date 2023-08-04 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
@ConfigurationProperties(prefix = "common-flow-online") |
||||||
|
public class FlowOnlineProperties { |
||||||
|
|
||||||
|
/** |
||||||
|
* 在线表单的URL前缀。 |
||||||
|
*/ |
||||||
|
private String urlPrefix; |
||||||
|
} |
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,94 @@ |
|||||||
|
package apelet.common.flow.online.listener; |
||||||
|
|
||||||
|
import apelet.common.core.util.ApplicationContextHolder; |
||||||
|
import apelet.common.flow.model.FlowEntry; |
||||||
|
import apelet.common.flow.model.FlowNodeTasks; |
||||||
|
import apelet.common.flow.model.FlowWorkOrder; |
||||||
|
import apelet.common.flow.service.FlowEntryService; |
||||||
|
import apelet.common.flow.service.FlowNodeTasksService; |
||||||
|
import apelet.common.flow.service.FlowWorkOrderService; |
||||||
|
import apelet.common.online.dto.OnlinePluginExecuteDto; |
||||||
|
import apelet.common.online.model.OnlineForm; |
||||||
|
import apelet.common.online.service.OnlineFormService; |
||||||
|
import apelet.common.online.service.OnlineOperationService; |
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
||||||
|
import org.flowable.engine.RuntimeService; |
||||||
|
import org.flowable.engine.delegate.TaskListener; |
||||||
|
import org.flowable.engine.runtime.ProcessInstance; |
||||||
|
import org.flowable.task.service.delegate.DelegateTask; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* 审批设置插件by创建事件 |
||||||
|
*/ |
||||||
|
public class ApprovalSettingsByCreateListener implements TaskListener { |
||||||
|
|
||||||
|
private final transient FlowNodeTasksService flowNodeTasksService = |
||||||
|
ApplicationContextHolder.getBean(FlowNodeTasksService.class); |
||||||
|
private final transient FlowEntryService flowEntryService = |
||||||
|
ApplicationContextHolder.getBean(FlowEntryService.class); |
||||||
|
private final transient OnlineFormService onlineFormService = |
||||||
|
ApplicationContextHolder.getBean(OnlineFormService.class); |
||||||
|
private final transient FlowWorkOrderService flowWorkOrderService = |
||||||
|
ApplicationContextHolder.getBean(FlowWorkOrderService.class); |
||||||
|
private final transient OnlineOperationService onlineOperationService = |
||||||
|
ApplicationContextHolder.getBean(OnlineOperationService.class); |
||||||
|
|
||||||
|
private final transient RuntimeService runtimeService = |
||||||
|
ApplicationContextHolder.getBean(RuntimeService.class); |
||||||
|
@Override |
||||||
|
public void notify(DelegateTask delegateTask) { |
||||||
|
|
||||||
|
String eventName = delegateTask.getEventName(); |
||||||
|
List<Integer> setList = new ArrayList<>(); |
||||||
|
if (eventName.equals("create")) { |
||||||
|
setList.add(1); |
||||||
|
} else if (eventName.equals("assignment")) { |
||||||
|
setList.add(2); |
||||||
|
} else if (eventName.equals("complete")) { |
||||||
|
String operationType = (String)delegateTask.getVariable("operationType"); |
||||||
|
if(operationType != null){ |
||||||
|
if(operationType.equals("agree")){ |
||||||
|
setList.add(5); |
||||||
|
}else if(operationType.equals("reject")) { |
||||||
|
setList.add(6); |
||||||
|
}else if(operationType.equals("refuse")){ |
||||||
|
} |
||||||
|
} |
||||||
|
setList.add(3); |
||||||
|
} else if (eventName.equals("delete")) { |
||||||
|
setList.add(4); |
||||||
|
} |
||||||
|
String taskKey = delegateTask.getTaskDefinitionKey(); |
||||||
|
String processDefinitionId = delegateTask.getProcessDefinitionId(); |
||||||
|
LambdaQueryWrapper<FlowNodeTasks> wrapper = new LambdaQueryWrapper<>(); |
||||||
|
// wrapper.eq(FlowNodeTasks::getFlowId, processDefinitionId);
|
||||||
|
wrapper.eq(FlowNodeTasks::getTaskKey, taskKey); |
||||||
|
wrapper.in(FlowNodeTasks::getExecutionTiming, setList); |
||||||
|
List<FlowNodeTasks> list = flowNodeTasksService.list(wrapper); |
||||||
|
if (list != null && list.size() > 0) { |
||||||
|
for (FlowNodeTasks flowNodeTasks : list) { |
||||||
|
LambdaQueryWrapper<FlowEntry> wrapperFlowEntry = new LambdaQueryWrapper<>(); |
||||||
|
wrapperFlowEntry.eq(FlowEntry::getEntryId, flowNodeTasks.getFlowId()); |
||||||
|
FlowEntry flowEntry = flowEntryService.getById(flowNodeTasks.getFlowId()); |
||||||
|
OnlineForm form = onlineFormService.getOnlineFormFromCache(flowEntry.getDefaultFormId()); |
||||||
|
Long formId = form.getFormId(); |
||||||
|
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery() |
||||||
|
.processInstanceId(delegateTask.getProcessInstanceId()) |
||||||
|
.singleResult(); |
||||||
|
String billId = processInstance.getBusinessKey(); |
||||||
|
if (billId != null && formId > 0) { |
||||||
|
OnlinePluginExecuteDto onlinePluginExecuteDto = new OnlinePluginExecuteDto(); |
||||||
|
onlinePluginExecuteDto.setBillId(String.valueOf(billId)); |
||||||
|
onlinePluginExecuteDto.setFormId(formId); |
||||||
|
onlinePluginExecuteDto.setButtonName(flowNodeTasks.getOperation()); |
||||||
|
onlineOperationService.executePlugin(onlinePluginExecuteDto, null, null); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,101 @@ |
|||||||
|
package apelet.common.flow.online.object; |
||||||
|
|
||||||
|
import apelet.common.core.util.ContextUtil; |
||||||
|
import apelet.common.online.object.TransactionalBusinessData; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.EqualsAndHashCode; |
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest; |
||||||
|
|
||||||
|
/** |
||||||
|
* 跨库存储工作流的业务数据的事物性事件数据。 |
||||||
|
* |
||||||
|
* @author guifc |
||||||
|
* @date 2023-08-04 |
||||||
|
*/ |
||||||
|
@EqualsAndHashCode(callSuper = true) |
||||||
|
@Data |
||||||
|
public class TransactionalFlowBusinessData extends TransactionalBusinessData { |
||||||
|
|
||||||
|
/** |
||||||
|
* 流程实例Id。 |
||||||
|
*/ |
||||||
|
private String processInstanceId; |
||||||
|
/** |
||||||
|
* 流程任务Id。 |
||||||
|
*/ |
||||||
|
private String taskId; |
||||||
|
/** |
||||||
|
* 流程任务定义标识。 |
||||||
|
*/ |
||||||
|
private String taskKey; |
||||||
|
/** |
||||||
|
* 流程任务定义名称。 |
||||||
|
*/ |
||||||
|
private String taskName; |
||||||
|
/** |
||||||
|
* 审批注释。 |
||||||
|
*/ |
||||||
|
private String taskComment; |
||||||
|
|
||||||
|
private static final ThreadLocal<TransactionalFlowBusinessData> FLOW_BUSINESS_DATA_THREAD_LOCAL = new ThreadLocal<>(); |
||||||
|
|
||||||
|
public TransactionalFlowBusinessData() { |
||||||
|
super(); |
||||||
|
} |
||||||
|
|
||||||
|
public TransactionalFlowBusinessData(HttpServletRequest request) { |
||||||
|
super(request); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取HttpServletRequest属性中的事物性时间对象。如果没有情趣对象,则从线程本地存储中获取。 |
||||||
|
* |
||||||
|
* @return 返回设置在当前请求属性中的事务性时间对象。如果不存在则返回NULL。 |
||||||
|
*/ |
||||||
|
public static TransactionalFlowBusinessData getFromRequestAttribute() { |
||||||
|
HttpServletRequest request = ContextUtil.getHttpRequest(); |
||||||
|
if (request != null) { |
||||||
|
return (TransactionalFlowBusinessData) request.getAttribute(BUSINESS_DATA_ATTR_KEY); |
||||||
|
} |
||||||
|
return FLOW_BUSINESS_DATA_THREAD_LOCAL.get(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取HttpServletRequest属性中的事物性时间对象。如果存在直接返回,否则创建新对象,并设置到当前请求的指定属性中。 |
||||||
|
* 如果没有情趣对象,则从线程本地存储中创建。 |
||||||
|
* |
||||||
|
* @return 返回设置在当前请求属性中的事务性时间对象。 |
||||||
|
*/ |
||||||
|
public static TransactionalFlowBusinessData getOrCreateFromRequestAttribute() { |
||||||
|
HttpServletRequest request = ContextUtil.getHttpRequest(); |
||||||
|
TransactionalFlowBusinessData data; |
||||||
|
if (request != null) { |
||||||
|
data = (TransactionalFlowBusinessData) request.getAttribute(BUSINESS_DATA_ATTR_KEY); |
||||||
|
if (data != null) { |
||||||
|
return data; |
||||||
|
} |
||||||
|
data = new TransactionalFlowBusinessData(request); |
||||||
|
request.setAttribute(BUSINESS_DATA_ATTR_KEY, data); |
||||||
|
} else { |
||||||
|
data = FLOW_BUSINESS_DATA_THREAD_LOCAL.get(); |
||||||
|
if (data != null) { |
||||||
|
return data; |
||||||
|
} |
||||||
|
data = new TransactionalFlowBusinessData(); |
||||||
|
FLOW_BUSINESS_DATA_THREAD_LOCAL.set(data); |
||||||
|
} |
||||||
|
return data; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 移除该对象。 |
||||||
|
*/ |
||||||
|
public static void removeFromRequestAttribute() { |
||||||
|
if (ContextUtil.hasRequestContext()) { |
||||||
|
ContextUtil.getHttpRequest().removeAttribute(BUSINESS_DATA_ATTR_KEY); |
||||||
|
} else { |
||||||
|
FLOW_BUSINESS_DATA_THREAD_LOCAL.remove(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,13 @@ |
|||||||
|
package apelet.common.flow.online.service; |
||||||
|
|
||||||
|
import apelet.common.flow.model.FlowEntry; |
||||||
|
|
||||||
|
import javax.xml.stream.XMLStreamException; |
||||||
|
|
||||||
|
public interface FlowEntryOnlineService { |
||||||
|
|
||||||
|
void publish(FlowEntry flowEntry, String initTaskInfo) throws XMLStreamException; |
||||||
|
|
||||||
|
|
||||||
|
void processFlowTaskExtList(FlowEntry flowEntry, String taskInfo) throws XMLStreamException; |
||||||
|
} |
||||||
@ -0,0 +1,163 @@ |
|||||||
|
package apelet.common.flow.online.service; |
||||||
|
|
||||||
|
import apelet.common.flow.model.FlowTaskComment; |
||||||
|
import apelet.common.flow.model.FlowTransProducer; |
||||||
|
import apelet.common.flow.model.FlowWorkOrder; |
||||||
|
import apelet.common.online.model.OnlineDatasource; |
||||||
|
import apelet.common.online.model.OnlineDatasourceRelation; |
||||||
|
import apelet.common.online.model.OnlineTable; |
||||||
|
import com.alibaba.fastjson.JSONObject; |
||||||
|
import org.flowable.engine.runtime.ProcessInstance; |
||||||
|
import org.flowable.task.api.Task; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
/** |
||||||
|
* 流程操作服务接口。 |
||||||
|
* |
||||||
|
* @author guifc |
||||||
|
* @date 2023-08-04 |
||||||
|
*/ |
||||||
|
public interface FlowOnlineOperationService { |
||||||
|
|
||||||
|
/** |
||||||
|
* 启动流程实例,并将业务主键Id传给新启动的流程实例。 |
||||||
|
* |
||||||
|
* @param processDefinitionId 流程实例Id。 |
||||||
|
* @param dataId 业务主键Id。 |
||||||
|
*/ |
||||||
|
ProcessInstance startWithBusinessKey(String processDefinitionId, String dataId); |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 启动流程实例,并将业务主键Id传给新启动的流程实例。 |
||||||
|
* |
||||||
|
* @param processDefinitionId 流程实例Id。 |
||||||
|
* @param dataId 业务主键Id。 |
||||||
|
*/ |
||||||
|
void startWithBusinessKeyExt(String processDefinitionId, String dataId,Long formId); |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 保存在线表单的数据,同时启动流程。如果当前用户是第一个用户任务的Assignee, |
||||||
|
* 或者第一个用户任务的Assignee是流程发起人变量,该方法还会自动Take第一个任务。 |
||||||
|
* |
||||||
|
* @param processDefinitionId 流程定义Id。 |
||||||
|
* @param flowTaskComment 流程审批批注对象。 |
||||||
|
* @param taskVariableData 流程任务的变量数据。 |
||||||
|
* @param table 表对象。 |
||||||
|
* @param data 表数据。 |
||||||
|
*/ |
||||||
|
void saveNewAndStartProcess( |
||||||
|
String processDefinitionId, |
||||||
|
FlowTaskComment flowTaskComment, |
||||||
|
JSONObject taskVariableData, |
||||||
|
OnlineTable table, |
||||||
|
JSONObject data); |
||||||
|
|
||||||
|
/** |
||||||
|
* 保存在线表单的数据,同时启动流程。如果当前用户是第一个用户任务的Assignee, |
||||||
|
* 或者第一个用户任务的Assignee是流程发起人变量,该方法还会自动Take第一个任务。 |
||||||
|
* |
||||||
|
* @param processDefinitionId 流程定义Id。 |
||||||
|
* @param flowTaskComment 流程审批批注对象。 |
||||||
|
* @param taskVariableData 流程任务的变量数据。 |
||||||
|
* @param masterTable 主表对象。 |
||||||
|
* @param masterData 主表数据。 |
||||||
|
* @param slaveDataListMap 关联从表数据Map。 |
||||||
|
*/ |
||||||
|
void saveNewAndStartProcess( |
||||||
|
String processDefinitionId, |
||||||
|
FlowTaskComment flowTaskComment, |
||||||
|
JSONObject taskVariableData, |
||||||
|
OnlineTable masterTable, |
||||||
|
JSONObject masterData, |
||||||
|
Map<OnlineDatasourceRelation, List<JSONObject>> slaveDataListMap); |
||||||
|
|
||||||
|
/** |
||||||
|
* 保存在线表单的草稿数据,同时启动一个流程实例。 |
||||||
|
* |
||||||
|
* @param processDefinitionId 流程定义Id。 |
||||||
|
* @param tableId 在线表单主表Id。 |
||||||
|
* @param masterData 主表数据。 |
||||||
|
* @param slaveData 所有关联从表数据。 |
||||||
|
* @return 流程工单对象。 |
||||||
|
*/ |
||||||
|
FlowWorkOrder saveNewDraftAndStartProcess( |
||||||
|
String processDefinitionId, Long tableId, JSONObject masterData, JSONObject slaveData); |
||||||
|
|
||||||
|
/** |
||||||
|
* 保存在线表单的数据,同时Take用户任务。 |
||||||
|
* |
||||||
|
* @param processInstanceId 流程实例Id。 |
||||||
|
* @param taskId 流程任务Id。 |
||||||
|
* @param flowTaskComment 流程审批批注对象。 |
||||||
|
* @param taskVariableData 流程任务的变量数据。 |
||||||
|
* @param table 表对象。 |
||||||
|
* @param data 表数据。 |
||||||
|
*/ |
||||||
|
void saveNewAndTakeTask( |
||||||
|
String processInstanceId, |
||||||
|
String taskId, |
||||||
|
FlowTaskComment flowTaskComment, |
||||||
|
JSONObject taskVariableData, |
||||||
|
OnlineTable table, |
||||||
|
JSONObject data); |
||||||
|
|
||||||
|
/** |
||||||
|
* 保存在线表单的数据,同时Take用户任务。 |
||||||
|
* |
||||||
|
* @param processInstanceId 流程实例Id。 |
||||||
|
* @param taskId 流程任务Id。 |
||||||
|
* @param flowTaskComment 流程审批批注对象。 |
||||||
|
* @param taskVariableData 流程任务的变量数据。 |
||||||
|
* @param masterTable 主表对象。 |
||||||
|
* @param masterData 主表数据。 |
||||||
|
* @param slaveDataListMap 关联从表数据Map。 |
||||||
|
*/ |
||||||
|
void saveNewAndTakeTask( |
||||||
|
String processInstanceId, |
||||||
|
String taskId, |
||||||
|
FlowTaskComment flowTaskComment, |
||||||
|
JSONObject taskVariableData, |
||||||
|
OnlineTable masterTable, |
||||||
|
JSONObject masterData, |
||||||
|
Map<OnlineDatasourceRelation, List<JSONObject>> slaveDataListMap); |
||||||
|
|
||||||
|
/** |
||||||
|
* 保存业务表数据,同时接收流程任务。 |
||||||
|
* |
||||||
|
* @param task 流程任务。 |
||||||
|
* @param flowTaskComment 流程审批批注对象。 |
||||||
|
* @param taskVariableData 流程任务的变量数据。 |
||||||
|
* @param datasource 主表所在数据源。 |
||||||
|
* @param masterData 主表数据。 |
||||||
|
* @param masterDataId 主表数据主键。 |
||||||
|
* @param slaveDataListMap 从表数据。 |
||||||
|
*/ |
||||||
|
void updateAndTakeTask( |
||||||
|
Task task, |
||||||
|
FlowTaskComment flowTaskComment, |
||||||
|
JSONObject taskVariableData, |
||||||
|
OnlineDatasource datasource, |
||||||
|
JSONObject masterData, |
||||||
|
String masterDataId, |
||||||
|
Map<OnlineDatasourceRelation, List<JSONObject>> slaveDataListMap); |
||||||
|
|
||||||
|
/** |
||||||
|
* 修复业务数据。 |
||||||
|
* |
||||||
|
* @param flowTransProducer 流程操作流水生产者对象。 |
||||||
|
*/ |
||||||
|
void fixBusinessData(FlowTransProducer flowTransProducer); |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取在线表单工作流Id所关联的权限数据,包括权限字列表和权限资源列表。 |
||||||
|
* |
||||||
|
* @param onlineFormEntryIds 在线表单工作流Id集合。 |
||||||
|
* @return 参数中在线表单工作流Id集合所关联的权限数据。 |
||||||
|
*/ |
||||||
|
List<Map<String, Object>> calculatePermData(Set<Long> onlineFormEntryIds); |
||||||
|
} |
||||||
@ -0,0 +1,319 @@ |
|||||||
|
package apelet.common.flow.online.service.impl; |
||||||
|
|
||||||
|
import apelet.common.core.object.TokenData; |
||||||
|
import apelet.common.core.util.MyModelUtil; |
||||||
|
import apelet.common.flow.constant.FlowConstant; |
||||||
|
import apelet.common.flow.dao.FlowEntryMapper; |
||||||
|
import apelet.common.flow.dao.FlowEntryPublishMapper; |
||||||
|
import apelet.common.flow.dao.FlowEntryPublishVariableMapper; |
||||||
|
import apelet.common.flow.listener.*; |
||||||
|
import apelet.common.flow.model.*; |
||||||
|
import apelet.common.flow.model.constant.FlowEntryStatus; |
||||||
|
import apelet.common.flow.object.*; |
||||||
|
import apelet.common.flow.online.listener.ApprovalSettingsByCreateListener; |
||||||
|
import apelet.common.flow.online.service.FlowEntryOnlineService; |
||||||
|
import apelet.common.flow.service.*; |
||||||
|
import apelet.common.flow.util.BaseFlowIdentityExtHelper; |
||||||
|
import apelet.common.flow.util.FlowCustomExtFactory; |
||||||
|
import apelet.common.flow.util.FlowRedisKeyUtil; |
||||||
|
import apelet.common.redis.util.CommonRedisUtil; |
||||||
|
import apelet.common.sequence.wrapper.IdGeneratorWrapper; |
||||||
|
import cn.hutool.core.collection.CollUtil; |
||||||
|
import cn.hutool.core.lang.Assert; |
||||||
|
import cn.hutool.core.util.BooleanUtil; |
||||||
|
import cn.hutool.core.util.StrUtil; |
||||||
|
import com.alibaba.fastjson.JSON; |
||||||
|
import com.alibaba.fastjson.JSONObject; |
||||||
|
import lombok.Cleanup; |
||||||
|
import org.flowable.bpmn.converter.BpmnXMLConverter; |
||||||
|
import org.flowable.bpmn.model.*; |
||||||
|
import org.flowable.engine.RepositoryService; |
||||||
|
import org.flowable.engine.repository.Deployment; |
||||||
|
import org.flowable.engine.repository.ProcessDefinition; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
import org.springframework.transaction.annotation.Transactional; |
||||||
|
|
||||||
|
import javax.xml.stream.XMLInputFactory; |
||||||
|
import javax.xml.stream.XMLStreamException; |
||||||
|
import javax.xml.stream.XMLStreamReader; |
||||||
|
import java.io.ByteArrayInputStream; |
||||||
|
import java.io.InputStream; |
||||||
|
import java.nio.charset.StandardCharsets; |
||||||
|
import java.util.*; |
||||||
|
import java.util.stream.Collectors; |
||||||
|
|
||||||
|
@Service("flowEntryOnlineService") |
||||||
|
public class FlowEntryOnlineServiceImpl implements FlowEntryOnlineService { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private FlowEntryMapper flowEntryMapper; |
||||||
|
@Autowired |
||||||
|
private FlowEntryPublishMapper flowEntryPublishMapper; |
||||||
|
@Autowired |
||||||
|
private FlowEntryPublishVariableMapper flowEntryPublishVariableMapper; |
||||||
|
@Autowired |
||||||
|
private FlowEntryVariableService flowEntryVariableService; |
||||||
|
@Autowired |
||||||
|
private FlowCategoryService flowCategoryService; |
||||||
|
@Autowired |
||||||
|
private FlowTaskExtService flowTaskExtService; |
||||||
|
@Autowired |
||||||
|
private FlowApiService flowApiService; |
||||||
|
@Autowired |
||||||
|
private FlowCustomExtFactory flowCustomExtFactory; |
||||||
|
@Autowired |
||||||
|
private RepositoryService repositoryService; |
||||||
|
@Autowired |
||||||
|
private IdGeneratorWrapper idGenerator; |
||||||
|
@Autowired |
||||||
|
private CommonRedisUtil commonRedisUtil; |
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class) |
||||||
|
@Override |
||||||
|
public void publish(FlowEntry flowEntry, String initTaskInfo) throws XMLStreamException { |
||||||
|
commonRedisUtil.evictFormCache( |
||||||
|
FlowRedisKeyUtil.makeFlowEntryKey(flowEntry.getProcessDefinitionKey())); |
||||||
|
FlowCategory flowCategory = flowCategoryService.getById(flowEntry.getCategoryId()); |
||||||
|
InputStream xmlStream = new ByteArrayInputStream( |
||||||
|
flowEntry.getBpmnXml().getBytes(StandardCharsets.UTF_8)); |
||||||
|
@Cleanup XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(xmlStream); |
||||||
|
BpmnXMLConverter converter = new BpmnXMLConverter(); |
||||||
|
BpmnModel bpmnModel = converter.convertToBpmnModel(reader); |
||||||
|
bpmnModel.getMainProcess().setName(flowEntry.getProcessDefinitionName()); |
||||||
|
bpmnModel.getMainProcess().setId(flowEntry.getProcessDefinitionKey()); |
||||||
|
flowApiService.addProcessInstanceEndListener(bpmnModel, FlowFinishedListener.class); |
||||||
|
List<FlowTaskExt> flowTaskExtList = flowTaskExtService.buildTaskExtList(bpmnModel); |
||||||
|
if (StrUtil.isNotBlank(flowEntry.getExtensionData())) { |
||||||
|
FlowEntryExtensionData flowEntryExtensionData = |
||||||
|
JSON.parseObject(flowEntry.getExtensionData(), FlowEntryExtensionData.class); |
||||||
|
this.mergeTaskNotifyData(flowEntryExtensionData, flowTaskExtList); |
||||||
|
this.processFlowTaskRevive(flowEntryExtensionData, bpmnModel); |
||||||
|
} |
||||||
|
this.processFlowTaskExtList(flowTaskExtList, bpmnModel); |
||||||
|
TokenData tokenData = TokenData.takeFromRequest(); |
||||||
|
Deployment deploy = repositoryService.createDeployment() |
||||||
|
.addBpmnModel(flowEntry.getProcessDefinitionKey() + ".bpmn", bpmnModel) |
||||||
|
.tenantId(tokenData.getTenantId() != null ? tokenData.getTenantId().toString() : tokenData.getAppCode()) |
||||||
|
.name(flowEntry.getProcessDefinitionName()) |
||||||
|
.key(flowEntry.getProcessDefinitionKey()) |
||||||
|
.category(flowCategory.getCode()) |
||||||
|
.deploy(); |
||||||
|
ProcessDefinition processDefinition = flowApiService.getProcessDefinitionByDeployId(deploy.getId()); |
||||||
|
FlowEntryPublish flowEntryPublish = new FlowEntryPublish(); |
||||||
|
flowEntryPublish.setEntryPublishId(idGenerator.nextLongId()); |
||||||
|
flowEntryPublish.setEntryId(flowEntry.getEntryId()); |
||||||
|
flowEntryPublish.setProcessDefinitionId(processDefinition.getId()); |
||||||
|
flowEntryPublish.setDeployId(processDefinition.getDeploymentId()); |
||||||
|
flowEntryPublish.setPublishVersion(processDefinition.getVersion()); |
||||||
|
flowEntryPublish.setActiveStatus(true); |
||||||
|
flowEntryPublish.setMainVersion(flowEntry.getStatus().equals(FlowEntryStatus.UNPUBLISHED)); |
||||||
|
flowEntryPublish.setCreateUserId(TokenData.takeFromRequest().getUserId()); |
||||||
|
flowEntryPublish.setPublishTime(new Date()); |
||||||
|
flowEntryPublish.setInitTaskInfo(initTaskInfo); |
||||||
|
flowEntryPublish.setExtensionData(flowEntry.getExtensionData()); |
||||||
|
flowEntryPublish.setStartConditions(flowEntry.getStartConditions()); |
||||||
|
AnalyzedNode rootNode = flowApiService.analyzeBpmnRoads(processDefinition.getId()); |
||||||
|
flowEntryPublish.setAnalyzedNodeJson(JSON.toJSONString(rootNode)); |
||||||
|
flowEntryPublishMapper.insert(flowEntryPublish); |
||||||
|
FlowEntry updatedFlowEntry = new FlowEntry(); |
||||||
|
updatedFlowEntry.setEntryId(flowEntry.getEntryId()); |
||||||
|
updatedFlowEntry.setStatus(FlowEntryStatus.PUBLISHED); |
||||||
|
updatedFlowEntry.setLatestPublishTime(new Date()); |
||||||
|
// 对于从未发布过的工作,第一次发布的时候会将本地发布置位主版本。
|
||||||
|
if (flowEntry.getStatus().equals(FlowEntryStatus.UNPUBLISHED)) { |
||||||
|
updatedFlowEntry.setMainEntryPublishId(flowEntryPublish.getEntryPublishId()); |
||||||
|
} |
||||||
|
flowEntryMapper.updateById(updatedFlowEntry); |
||||||
|
FlowEntryVariable flowEntryVariableFilter = new FlowEntryVariable(); |
||||||
|
flowEntryVariableFilter.setEntryId(flowEntry.getEntryId()); |
||||||
|
List<FlowEntryVariable> flowEntryVariableList = |
||||||
|
flowEntryVariableService.getFlowEntryVariableList(flowEntryVariableFilter, null); |
||||||
|
if (CollUtil.isNotEmpty(flowTaskExtList)) { |
||||||
|
flowTaskExtList.forEach(t -> t.setProcessDefinitionId(processDefinition.getId())); |
||||||
|
flowTaskExtService.saveBatch(flowTaskExtList); |
||||||
|
} |
||||||
|
this.insertEntryPublishVariables(flowEntryVariableList, flowEntryPublish.getEntryPublishId()); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void processFlowTaskExtList(FlowEntry flowEntry,String taskInfo) throws XMLStreamException { |
||||||
|
|
||||||
|
InputStream xmlStream = new ByteArrayInputStream( |
||||||
|
flowEntry.getBpmnXml().getBytes(StandardCharsets.UTF_8)); |
||||||
|
@Cleanup XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(xmlStream); |
||||||
|
BpmnXMLConverter converter = new BpmnXMLConverter(); |
||||||
|
BpmnModel bpmnModel = converter.convertToBpmnModel(reader); |
||||||
|
bpmnModel.getMainProcess().setName(flowEntry.getProcessDefinitionName()); |
||||||
|
bpmnModel.getMainProcess().setId(flowEntry.getProcessDefinitionKey()); |
||||||
|
|
||||||
|
List<FlowTaskExt> flowTaskExtList = flowTaskExtService.buildTaskExtList(bpmnModel); |
||||||
|
|
||||||
|
List<FlowElement> elementList = new LinkedList<>(); |
||||||
|
this.calculateAllElementList(bpmnModel.getMainProcess().getFlowElements(), elementList); |
||||||
|
|
||||||
|
Map<String, FlowElement> elementMap = elementList.stream() |
||||||
|
.filter(UserTask.class::isInstance).collect(Collectors.toMap(FlowElement::getId, c -> c)); |
||||||
|
for (FlowTaskExt t : flowTaskExtList) { |
||||||
|
UserTask userTask = (UserTask) elementMap.get(t.getTaskId()); |
||||||
|
// create 创建
|
||||||
|
flowApiService.addTaskListenerByEvent(userTask, ApprovalSettingsByCreateListener.class, "create"); |
||||||
|
// assignment 分配/指派
|
||||||
|
flowApiService.addTaskListenerByEvent(userTask, ApprovalSettingsByCreateListener.class, "assignment"); |
||||||
|
// complete 完成
|
||||||
|
flowApiService.addTaskListenerByEvent(userTask, ApprovalSettingsByCreateListener.class, "complete"); |
||||||
|
// delete 删除
|
||||||
|
flowApiService.addTaskListenerByEvent(userTask, ApprovalSettingsByCreateListener.class, "delete"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void calculateAllElementList(Collection<FlowElement> elements, List<FlowElement> resultList) { |
||||||
|
resultList.addAll(elements); |
||||||
|
for (FlowElement element : elements) { |
||||||
|
if (element instanceof SubProcess) { |
||||||
|
this.calculateAllElementList(((SubProcess) element).getFlowElements(), resultList); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void mergeTaskNotifyData(FlowEntryExtensionData flowEntryExtensionData, List<FlowTaskExt> flowTaskExtList) { |
||||||
|
if (CollUtil.isEmpty(flowEntryExtensionData.getNotifyTypes())) { |
||||||
|
return; |
||||||
|
} |
||||||
|
List<String> flowTaskNotifyTypes = |
||||||
|
flowEntryExtensionData.getNotifyTypes().stream().filter(StrUtil::isNotBlank).collect(Collectors.toList()); |
||||||
|
if (CollUtil.isEmpty(flowTaskNotifyTypes)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
for (FlowTaskExt flowTaskExt : flowTaskExtList) { |
||||||
|
if (flowTaskExt.getExtraDataJson() == null) { |
||||||
|
JSONObject o = new JSONObject(); |
||||||
|
o.put(FlowConstant.USER_TASK_NOTIFY_TYPES_KEY, flowTaskNotifyTypes); |
||||||
|
flowTaskExt.setExtraDataJson(o.toJSONString()); |
||||||
|
} else { |
||||||
|
FlowUserTaskExtData taskExtData = |
||||||
|
JSON.parseObject(flowTaskExt.getExtraDataJson(), FlowUserTaskExtData.class); |
||||||
|
if (CollUtil.isEmpty(taskExtData.getFlowNotifyTypeList())) { |
||||||
|
taskExtData.setFlowNotifyTypeList(flowTaskNotifyTypes); |
||||||
|
} else { |
||||||
|
Set<String> notifyTypesSet = taskExtData.getFlowNotifyTypeList() |
||||||
|
.stream().filter(StrUtil::isNotBlank).collect(Collectors.toSet()); |
||||||
|
notifyTypesSet.addAll(flowTaskNotifyTypes); |
||||||
|
taskExtData.setFlowNotifyTypeList(new LinkedList<>(notifyTypesSet)); |
||||||
|
} |
||||||
|
flowTaskExt.setExtraDataJson(JSON.toJSONString(taskExtData)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void processFlowTaskRevive(FlowEntryExtensionData flowEntryExtensionData, BpmnModel bpmnModel) { |
||||||
|
if (BooleanUtil.isTrue(flowEntryExtensionData.getSupportRevive())) { |
||||||
|
List<UserTask> mainProcessUserTasks = bpmnModel.getMainProcess().getFlowElements() |
||||||
|
.stream().filter(UserTask.class::isInstance).map(t -> (UserTask) t).collect(Collectors.toList()); |
||||||
|
mainProcessUserTasks.forEach(t -> flowApiService.addTaskCreateListener(t, FlowTaskReviveListener.class)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void processFlowTaskExtList(List<FlowTaskExt> flowTaskExtList, BpmnModel bpmnModel) { |
||||||
|
List<FlowElement> elementList = new LinkedList<>(); |
||||||
|
this.calculateAllElementList(bpmnModel.getMainProcess().getFlowElements(), elementList); |
||||||
|
this.doAddLatestApprovalStatusListener(elementList); |
||||||
|
Map<String, FlowElement> elementMap = elementList.stream() |
||||||
|
.filter(UserTask.class::isInstance).collect(Collectors.toMap(FlowElement::getId, c -> c)); |
||||||
|
BaseFlowIdentityExtHelper flowIdentityExtHelper = flowCustomExtFactory.getFlowIdentityExtHelper(); |
||||||
|
for (FlowTaskExt t : flowTaskExtList) { |
||||||
|
UserTask userTask = (UserTask) elementMap.get(t.getTaskId()); |
||||||
|
flowApiService.addTaskCreateListener(userTask, FlowUserTaskListener.class); |
||||||
|
// create 创建
|
||||||
|
flowApiService.addTaskListenerByEvent(userTask, ApprovalSettingsByCreateListener.class, "create"); |
||||||
|
// assignment 分配/指派
|
||||||
|
flowApiService.addTaskListenerByEvent(userTask, ApprovalSettingsByCreateListener.class, "assignment"); |
||||||
|
// complete 完成
|
||||||
|
flowApiService.addTaskListenerByEvent(userTask, ApprovalSettingsByCreateListener.class, "complete"); |
||||||
|
// delete 删除
|
||||||
|
flowApiService.addTaskListenerByEvent(userTask, ApprovalSettingsByCreateListener.class, "delete"); |
||||||
|
|
||||||
|
Map<String, List<ExtensionAttribute>> attributes = userTask.getAttributes(); |
||||||
|
if (CollUtil.isNotEmpty(attributes.get(FlowConstant.USER_TASK_AUTO_SKIP_KEY))) { |
||||||
|
flowApiService.addTaskCreateListener(userTask, AutoSkipTaskListener.class); |
||||||
|
} |
||||||
|
// 如果流程图中包含部门领导审批和上级部门领导审批的选项,就需要注册 FlowCustomExtFactory 工厂中的
|
||||||
|
// BaseFlowIdentityExtHelper 对象,该注册操作需要业务模块中实现。
|
||||||
|
if (StrUtil.equals(t.getGroupType(), FlowConstant.GROUP_TYPE_UP_DEPT_POST_LEADER)) { |
||||||
|
userTask.setCandidateGroups( |
||||||
|
CollUtil.newArrayList("${" + FlowConstant.GROUP_TYPE_UP_DEPT_POST_LEADER_VAR + "}")); |
||||||
|
Assert.notNull(flowIdentityExtHelper); |
||||||
|
flowApiService.addTaskCreateListener(userTask, flowIdentityExtHelper.getUpDeptPostLeaderListener()); |
||||||
|
} else if (StrUtil.equals(t.getGroupType(), FlowConstant.GROUP_TYPE_DEPT_POST_LEADER)) { |
||||||
|
userTask.setCandidateGroups( |
||||||
|
CollUtil.newArrayList("${" + FlowConstant.GROUP_TYPE_DEPT_POST_LEADER_VAR + "}")); |
||||||
|
Assert.notNull(flowIdentityExtHelper); |
||||||
|
flowApiService.addTaskCreateListener(userTask, flowIdentityExtHelper.getDeptPostLeaderListener()); |
||||||
|
} else if (StrUtil.equals(t.getGroupType(), FlowConstant.GROUP_TYPE_POST)) { |
||||||
|
Assert.notNull(t.getDeptPostListJson()); |
||||||
|
List<FlowTaskPostCandidateGroup> groupDataList = |
||||||
|
JSON.parseArray(t.getDeptPostListJson(), FlowTaskPostCandidateGroup.class); |
||||||
|
List<String> candidateGroupList = |
||||||
|
FlowTaskPostCandidateGroup.buildCandidateGroupList(groupDataList); |
||||||
|
userTask.setCandidateGroups(candidateGroupList); |
||||||
|
} |
||||||
|
this.processFlowTaskExtListener(userTask, t); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void insertEntryPublishVariables(List<FlowEntryVariable> entryVariableList, Long entryPublishId) { |
||||||
|
if (CollUtil.isEmpty(entryVariableList)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
List<FlowEntryPublishVariable> entryPublishVariableList = |
||||||
|
MyModelUtil.copyCollectionTo(entryVariableList, FlowEntryPublishVariable.class); |
||||||
|
for (FlowEntryPublishVariable variable : entryPublishVariableList) { |
||||||
|
variable.setVariableId(idGenerator.nextLongId()); |
||||||
|
variable.setEntryPublishId(entryPublishId); |
||||||
|
} |
||||||
|
flowEntryPublishVariableMapper.insertList(entryPublishVariableList); |
||||||
|
} |
||||||
|
|
||||||
|
private void doAddLatestApprovalStatusListener(Collection<FlowElement> elementList) { |
||||||
|
List<FlowElement> sequenceFlowList = |
||||||
|
elementList.stream().filter(SequenceFlow.class::isInstance).collect(Collectors.toList()); |
||||||
|
for (FlowElement sequenceFlow : sequenceFlowList) { |
||||||
|
FlowElementExtProperty extProperty = flowTaskExtService.buildFlowElementExt(sequenceFlow); |
||||||
|
if (extProperty != null && extProperty.getLatestApprovalStatus() != null) { |
||||||
|
List<FieldExtension> fieldExtensions = new LinkedList<>(); |
||||||
|
FieldExtension fieldExtension = new FieldExtension(); |
||||||
|
fieldExtension.setFieldName(FlowConstant.LATEST_APPROVAL_STATUS_KEY); |
||||||
|
fieldExtension.setStringValue(extProperty.getLatestApprovalStatus().toString()); |
||||||
|
fieldExtensions.add(fieldExtension); |
||||||
|
flowApiService.addExecutionListener( |
||||||
|
sequenceFlow, UpdateLatestApprovalStatusListener.class, "start", fieldExtensions); |
||||||
|
} |
||||||
|
} |
||||||
|
List<SubProcess> subProcesseList = elementList.stream() |
||||||
|
.filter(SubProcess.class::isInstance).map(SubProcess.class::cast).collect(Collectors.toList()); |
||||||
|
for (SubProcess subProcess : subProcesseList) { |
||||||
|
this.doAddLatestApprovalStatusListener(subProcess.getFlowElements()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void processFlowTaskExtListener(UserTask userTask, FlowTaskExt taskExt) { |
||||||
|
if (StrUtil.isBlank(taskExt.getExtraDataJson())) { |
||||||
|
return; |
||||||
|
} |
||||||
|
FlowUserTaskExtData userTaskExtData = |
||||||
|
JSON.parseObject(taskExt.getExtraDataJson(), FlowUserTaskExtData.class); |
||||||
|
if (CollUtil.isNotEmpty(userTaskExtData.getFlowNotifyTypeList())) { |
||||||
|
flowApiService.addTaskCreateListener(userTask, FlowTaskNotifyListener.class); |
||||||
|
} |
||||||
|
if (userTaskExtData.getRejectType().equals(FlowUserTaskExtData.REJECT_TYPE_BACK_TO_SOURCE)) { |
||||||
|
flowApiService.addTaskCreateListener(userTask, FlowTaskRejectBackListener.class); |
||||||
|
} |
||||||
|
if (StrUtil.isNotBlank(userTaskExtData.getTimeoutHandleWay())) { |
||||||
|
flowApiService.addTaskCreateListener(userTask, FlowTaskTimeoutListener.class); |
||||||
|
} |
||||||
|
if (StrUtil.isNotBlank(userTaskExtData.getEmptyUserHandleWay())) { |
||||||
|
flowApiService.addTaskCreateListener(userTask, FlowEmptyUserHandleListener.class); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,102 @@ |
|||||||
|
package apelet.common.flow.online.service.impl; |
||||||
|
|
||||||
|
import apelet.common.core.annotation.MyDataSource; |
||||||
|
import apelet.common.core.constant.ApplicationConstant; |
||||||
|
import apelet.common.flow.base.service.BaseFlowOnlineService; |
||||||
|
import apelet.common.flow.model.FlowWorkOrder; |
||||||
|
import apelet.common.flow.online.object.TransactionalFlowBusinessData; |
||||||
|
import apelet.common.flow.util.FlowCustomExtFactory; |
||||||
|
import apelet.common.online.exception.OnlineRuntimeException; |
||||||
|
import apelet.common.online.model.*; |
||||||
|
import apelet.common.online.model.constant.FieldKind; |
||||||
|
import apelet.common.online.service.*; |
||||||
|
import cn.hutool.core.collection.CollUtil; |
||||||
|
import cn.hutool.core.util.ObjectUtil; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
import org.springframework.transaction.annotation.Transactional; |
||||||
|
|
||||||
|
import javax.annotation.PostConstruct; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* 在线表单和流程监听器进行数据对接时的服务实现类。 |
||||||
|
* |
||||||
|
* @author guifc |
||||||
|
* @date 2023-08-04 |
||||||
|
*/ |
||||||
|
@Slf4j |
||||||
|
@MyDataSource(ApplicationConstant.COMMON_FLOW_AND_ONLINE_DATASOURCE_TYPE) |
||||||
|
@Service("flowOnlineBusinessService") |
||||||
|
public class FlowOnlineBusinessServiceImpl implements BaseFlowOnlineService { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private FlowCustomExtFactory flowCustomExtFactory; |
||||||
|
@Autowired |
||||||
|
private OnlineTableService onlineTableService; |
||||||
|
@Autowired |
||||||
|
private OnlineDatasourceService onlineDatasourceService; |
||||||
|
@Autowired |
||||||
|
private OnlineDatasourceRelationService onlineDatasourceRelationService; |
||||||
|
@Autowired |
||||||
|
private OnlineOperationService onlineOperationService; |
||||||
|
|
||||||
|
@PostConstruct |
||||||
|
public void doRegister() { |
||||||
|
flowCustomExtFactory.getOnlineBusinessDataExtHelper().setOnlineBusinessService(this); |
||||||
|
} |
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class) |
||||||
|
@Override |
||||||
|
public void updateFlowStatus(FlowWorkOrder workOrder) { |
||||||
|
OnlineTable onlineTable = onlineTableService.getOnlineTableFromCache(workOrder.getOnlineTableId()); |
||||||
|
if (onlineTable == null) { |
||||||
|
log.error("OnlineTableId [{}] doesn't exist while calling FlowOnlineBusinessServiceImpl.updateFlowStatus", |
||||||
|
workOrder.getOnlineTableId()); |
||||||
|
return; |
||||||
|
} |
||||||
|
String dataId = workOrder.getBusinessKey(); |
||||||
|
this.handleTransactionalFlowBusinessData(workOrder, "FlowOnlineBusinessServiceImpl.updateFlowStatus"); |
||||||
|
for (OnlineColumn column : onlineTable.getColumnMap().values()) { |
||||||
|
if (ObjectUtil.equals(column.getFieldKind(), FieldKind.FLOW_FINISHED_STATUS)) { |
||||||
|
onlineOperationService.updateColumn(onlineTable, dataId, column, workOrder.getFlowStatus()); |
||||||
|
} |
||||||
|
if (ObjectUtil.equals(column.getFieldKind(), FieldKind.FLOW_APPROVAL_STATUS)) { |
||||||
|
onlineOperationService.updateColumn(onlineTable, dataId, column, workOrder.getLatestApprovalStatus()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void deleteBusinessData(FlowWorkOrder workOrder) { |
||||||
|
OnlineTable onlineTable = onlineTableService.getOnlineTableFromCache(workOrder.getOnlineTableId()); |
||||||
|
if (onlineTable == null) { |
||||||
|
log.error("OnlineTableId [{}] doesn't exist while calling FlowOnlineBusinessServiceImpl.deleteBusinessData", |
||||||
|
workOrder.getOnlineTableId()); |
||||||
|
return; |
||||||
|
} |
||||||
|
OnlineDatasource datasource = |
||||||
|
onlineDatasourceService.getOnlineDatasourceByMasterTableId(onlineTable.getTableId()); |
||||||
|
List<OnlineDatasourceRelation> relationList = |
||||||
|
onlineDatasourceRelationService.getOnlineDatasourceRelationListFromCache(CollUtil.newHashSet(datasource.getDatasourceId())); |
||||||
|
String dataId = workOrder.getBusinessKey(); |
||||||
|
for (OnlineDatasourceRelation relation : relationList) { |
||||||
|
OnlineTable slaveTable = onlineTableService.getOnlineTableFromCache(relation.getSlaveTableId()); |
||||||
|
if (slaveTable == null) { |
||||||
|
throw new OnlineRuntimeException("数据验证失败,数据源关联 [" + relation.getRelationName() + "] 的从表Id不存在!"); |
||||||
|
} |
||||||
|
relation.setSlaveTable(slaveTable); |
||||||
|
} |
||||||
|
this.handleTransactionalFlowBusinessData(workOrder, "FlowOnlineBusinessServiceImpl.deleteBusinessData"); |
||||||
|
onlineOperationService.delete(onlineTable, relationList, dataId); |
||||||
|
} |
||||||
|
|
||||||
|
private void handleTransactionalFlowBusinessData(FlowWorkOrder workOrder, String desc) { |
||||||
|
TransactionalFlowBusinessData eventData = TransactionalFlowBusinessData.getFromRequestAttribute(); |
||||||
|
if (eventData != null) { |
||||||
|
eventData.setProcessInstanceId(workOrder.getProcessInstanceId()); |
||||||
|
eventData.setOperationDesc(desc); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,434 @@ |
|||||||
|
package apelet.common.flow.online.service.impl; |
||||||
|
|
||||||
|
import apelet.common.core.annotation.MultiDatabaseWriteMethod; |
||||||
|
import apelet.common.core.annotation.MyDataSource; |
||||||
|
import apelet.common.core.config.CoreProperties; |
||||||
|
import apelet.common.core.constant.ApplicationConstant; |
||||||
|
import apelet.common.core.object.CallResult; |
||||||
|
import apelet.common.core.object.ObjectValue; |
||||||
|
import apelet.common.dbutil.provider.DataSourceProvider; |
||||||
|
import apelet.common.dbutil.provider.PostgreSqlProvider; |
||||||
|
import apelet.common.flow.config.FlowProperties; |
||||||
|
import apelet.common.flow.constant.FlowApprovalType; |
||||||
|
import apelet.common.flow.constant.FlowConstant; |
||||||
|
import apelet.common.flow.constant.FlowTaskStatus; |
||||||
|
import apelet.common.flow.dao.FlowTransProducerMapper; |
||||||
|
import apelet.common.flow.exception.FlowOperationException; |
||||||
|
import apelet.common.flow.model.*; |
||||||
|
import apelet.common.flow.online.object.TransactionalFlowBusinessData; |
||||||
|
import apelet.common.flow.online.service.FlowOnlineOperationService; |
||||||
|
import apelet.common.flow.service.FlowApiService; |
||||||
|
import apelet.common.flow.service.FlowEntryService; |
||||||
|
import apelet.common.flow.service.FlowWorkOrderService; |
||||||
|
import apelet.common.generator.utils.OrmGenDataSourceUtil; |
||||||
|
import apelet.common.online.config.OnlineProperties; |
||||||
|
import apelet.common.online.exception.OnlineRuntimeException; |
||||||
|
import apelet.common.online.model.*; |
||||||
|
import apelet.common.online.object.TransactionalBusinessData; |
||||||
|
import apelet.common.online.service.*; |
||||||
|
import apelet.common.online.util.OnlineDataSourceUtil; |
||||||
|
import apelet.common.orm.impl.Selector; |
||||||
|
import apelet.common.orm.impl.SelectorItem; |
||||||
|
import cn.hutool.core.collection.CollUtil; |
||||||
|
import cn.hutool.core.lang.Assert; |
||||||
|
import cn.hutool.core.map.MapUtil; |
||||||
|
import cn.hutool.core.util.StrUtil; |
||||||
|
import com.alibaba.fastjson.JSON; |
||||||
|
import com.alibaba.fastjson.JSONObject; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.flowable.engine.runtime.ProcessInstance; |
||||||
|
import org.flowable.task.api.Task; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
import org.springframework.transaction.annotation.Transactional; |
||||||
|
import org.springframework.transaction.event.TransactionPhase; |
||||||
|
import org.springframework.transaction.event.TransactionalEventListener; |
||||||
|
|
||||||
|
import java.sql.Connection; |
||||||
|
import java.util.*; |
||||||
|
import java.util.stream.Collectors; |
||||||
|
|
||||||
|
@Slf4j |
||||||
|
@MyDataSource(ApplicationConstant.COMMON_FLOW_AND_ONLINE_DATASOURCE_TYPE) |
||||||
|
@Service("flowOnlineOperationService") |
||||||
|
public class FlowOnlineOperationServiceImpl implements FlowOnlineOperationService { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private FlowApiService flowApiService; |
||||||
|
@Autowired |
||||||
|
private FlowWorkOrderService flowWorkOrderService; |
||||||
|
@Autowired |
||||||
|
private FlowEntryService flowEntryService; |
||||||
|
@Autowired |
||||||
|
private OnlineOperationService onlineOperationService; |
||||||
|
@Autowired |
||||||
|
private OnlineDatasourceService onlineDatasourceService; |
||||||
|
@Autowired |
||||||
|
private OnlineProperties onlineProperties; |
||||||
|
@Autowired |
||||||
|
private FlowProperties flowProperties; |
||||||
|
@Autowired |
||||||
|
private CoreProperties coreProperties; |
||||||
|
@Autowired |
||||||
|
private OnlineDataSourceUtil dataSourceUtil; |
||||||
|
@Autowired |
||||||
|
private FlowTransProducerMapper flowTransProducerMapper; |
||||||
|
@Autowired |
||||||
|
private OnlineFormService onlineFormService; |
||||||
|
@Autowired |
||||||
|
private OnlineTableService onlineTableService; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private OrmGenDataSourceUtil ormGenDataSourceUtil; |
||||||
|
|
||||||
|
@MultiDatabaseWriteMethod |
||||||
|
@Transactional(rollbackFor = Exception.class) |
||||||
|
@Override |
||||||
|
public ProcessInstance startWithBusinessKey(String processDefinitionId, String dataId) { |
||||||
|
ProcessInstance instance = flowApiService.start(processDefinitionId, dataId); |
||||||
|
flowWorkOrderService.saveNew(instance, dataId, null, null); |
||||||
|
return instance; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void startWithBusinessKeyExt(String processDefinitionId, String dataId, Long formId) { |
||||||
|
OnlineForm OnlineForm = onlineFormService.getOnlineFormFromCache(formId); |
||||||
|
OnlineTable onlineTable = onlineTableService.getOnlineTableFromCache(OnlineForm.getMasterTableId()); |
||||||
|
Selector selector = new Selector(); |
||||||
|
selector.getList().add(new SelectorItem("billstatus")); |
||||||
|
ObjectValue objectValue = ormGenDataSourceUtil.queryOne(onlineTable.getTableName(),Long.valueOf(dataId),selector); |
||||||
|
if(objectValue == null){ |
||||||
|
String errorMessage = "无效数据!"; |
||||||
|
throw new RuntimeException(errorMessage); |
||||||
|
} |
||||||
|
if(!objectValue.get("billstatus").equals("A")){ |
||||||
|
throw new RuntimeException("只有保存状态才能提交"); |
||||||
|
} |
||||||
|
objectValue.put("billstatus","B"); |
||||||
|
try { |
||||||
|
ormGenDataSourceUtil.update(onlineTable.getTableName(),objectValue,selector); |
||||||
|
}catch (Exception e){ |
||||||
|
e.printStackTrace(); |
||||||
|
String errorMessage = "更新失败!错误信息:"+e.getMessage(); |
||||||
|
throw new RuntimeException(errorMessage); |
||||||
|
} |
||||||
|
if(processDefinitionId != null){ |
||||||
|
JSONObject taskVariableData = new JSONObject(); |
||||||
|
ProcessInstance instance = this.startWithBusinessKey(processDefinitionId,dataId); |
||||||
|
FlowTaskComment flowTaskComment = new FlowTaskComment(); |
||||||
|
flowTaskComment.setApprovalType("agree"); |
||||||
|
flowTaskComment.setTaskComment("发起人"); |
||||||
|
flowApiService.takeFirstTask(instance.getProcessInstanceId(), flowTaskComment, taskVariableData); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@MultiDatabaseWriteMethod |
||||||
|
@Transactional(rollbackFor = Exception.class) |
||||||
|
@Override |
||||||
|
public void saveNewAndStartProcess( |
||||||
|
String processDefinitionId, |
||||||
|
FlowTaskComment flowTaskComment, |
||||||
|
JSONObject taskVariableData, |
||||||
|
OnlineTable table, |
||||||
|
JSONObject data) { |
||||||
|
this.saveNewAndStartProcess(processDefinitionId, flowTaskComment, taskVariableData, table, data, null); |
||||||
|
} |
||||||
|
|
||||||
|
@MultiDatabaseWriteMethod |
||||||
|
@Transactional(rollbackFor = Exception.class) |
||||||
|
@Override |
||||||
|
public void saveNewAndStartProcess( |
||||||
|
String processDefinitionId, |
||||||
|
FlowTaskComment flowTaskComment, |
||||||
|
JSONObject taskVariableData, |
||||||
|
OnlineTable masterTable, |
||||||
|
JSONObject masterData, |
||||||
|
Map<OnlineDatasourceRelation, List<JSONObject>> slaveDataListMap) { |
||||||
|
Object dataId = onlineOperationService.saveNewWithRelation(masterTable, masterData, slaveDataListMap); |
||||||
|
Assert.notNull(dataId); |
||||||
|
if (taskVariableData == null) { |
||||||
|
taskVariableData = new JSONObject(); |
||||||
|
} |
||||||
|
taskVariableData.put(FlowConstant.MASTER_DATA_KEY, masterData); |
||||||
|
taskVariableData.put(FlowConstant.SLAVE_DATA_KEY, this.normailizeSlaveDataListMap(slaveDataListMap)); |
||||||
|
taskVariableData.put(FlowConstant.MASTER_TABLE_KEY, masterTable); |
||||||
|
ProcessInstance instance = flowApiService.start(processDefinitionId, dataId); |
||||||
|
flowWorkOrderService.saveNew(instance, dataId, masterTable.getTableId(), null); |
||||||
|
flowApiService.takeFirstTask(instance.getProcessInstanceId(), flowTaskComment, taskVariableData); |
||||||
|
// 这里需要在创建工单后再次更新一下工单状态,在flowApiService.completeTask中的更新,
|
||||||
|
// 因为当时没有创建工单对象,更新会不起任何作用,所以这里要补偿一下。
|
||||||
|
Integer approvalStatus = MapUtil.getInt(taskVariableData, FlowConstant.LATEST_APPROVAL_STATUS_KEY); |
||||||
|
flowWorkOrderService.updateLatestApprovalStatusByProcessInstanceId(instance.getId(), approvalStatus); |
||||||
|
} |
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class) |
||||||
|
@Override |
||||||
|
public FlowWorkOrder saveNewDraftAndStartProcess( |
||||||
|
String processDefinitionId, Long tableId, JSONObject masterData, JSONObject slaveData) { |
||||||
|
ProcessInstance instance = flowApiService.start(processDefinitionId, null); |
||||||
|
return flowWorkOrderService.saveNewWithDraft( |
||||||
|
instance, tableId, null, JSON.toJSONString(masterData), JSON.toJSONString(slaveData)); |
||||||
|
} |
||||||
|
|
||||||
|
@MultiDatabaseWriteMethod |
||||||
|
@Transactional(rollbackFor = Exception.class) |
||||||
|
@Override |
||||||
|
public void saveNewAndTakeTask( |
||||||
|
String processInstanceId, |
||||||
|
String taskId, |
||||||
|
FlowTaskComment flowTaskComment, |
||||||
|
JSONObject taskVariableData, |
||||||
|
OnlineTable table, |
||||||
|
JSONObject data) { |
||||||
|
this.saveNewAndTakeTask( |
||||||
|
processInstanceId, taskId, flowTaskComment, taskVariableData, table, data, null); |
||||||
|
} |
||||||
|
|
||||||
|
@MultiDatabaseWriteMethod |
||||||
|
@Transactional(rollbackFor = Exception.class) |
||||||
|
@Override |
||||||
|
public void saveNewAndTakeTask( |
||||||
|
String processInstanceId, |
||||||
|
String taskId, |
||||||
|
FlowTaskComment flowTaskComment, |
||||||
|
JSONObject taskVariableData, |
||||||
|
OnlineTable masterTable, |
||||||
|
JSONObject masterData, |
||||||
|
Map<OnlineDatasourceRelation, List<JSONObject>> slaveDataListMap) { |
||||||
|
Object dataId = onlineOperationService.saveNewWithRelation(masterTable, masterData, slaveDataListMap); |
||||||
|
Assert.notNull(dataId); |
||||||
|
Task task = flowApiService.getProcessInstanceActiveTask(processInstanceId, taskId); |
||||||
|
flowApiService.setBusinessKeyForProcessInstance(processInstanceId, dataId); |
||||||
|
Map<String, Object> variables = |
||||||
|
flowApiService.initAndGetProcessInstanceVariables(task.getProcessDefinitionId()); |
||||||
|
if (taskVariableData == null) { |
||||||
|
taskVariableData = new JSONObject(); |
||||||
|
} |
||||||
|
taskVariableData.putAll(variables); |
||||||
|
taskVariableData.put(FlowConstant.MASTER_DATA_KEY, masterData); |
||||||
|
taskVariableData.put(FlowConstant.SLAVE_DATA_KEY, this.normailizeSlaveDataListMap(slaveDataListMap)); |
||||||
|
taskVariableData.put(FlowConstant.MASTER_TABLE_KEY, masterTable); |
||||||
|
flowApiService.completeTask(task, flowTaskComment, taskVariableData, null); |
||||||
|
ProcessInstance instance = flowApiService.getProcessInstance(processInstanceId); |
||||||
|
FlowWorkOrder flowWorkOrder = |
||||||
|
flowWorkOrderService.getFlowWorkOrderByProcessInstanceId(instance.getProcessInstanceId()); |
||||||
|
if (flowWorkOrder == null) { |
||||||
|
flowWorkOrderService.saveNew(instance, dataId, masterTable.getTableId(), null); |
||||||
|
} else { |
||||||
|
flowWorkOrder.setBusinessKey(dataId.toString()); |
||||||
|
flowWorkOrder.setUpdateTime(new Date()); |
||||||
|
flowWorkOrder.setFlowStatus(FlowTaskStatus.SUBMITTED); |
||||||
|
flowWorkOrderService.updateById(flowWorkOrder); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@MultiDatabaseWriteMethod |
||||||
|
@Transactional(rollbackFor = Exception.class) |
||||||
|
@Override |
||||||
|
public void updateAndTakeTask( |
||||||
|
Task task, |
||||||
|
FlowTaskComment flowTaskComment, |
||||||
|
JSONObject taskVariableData, |
||||||
|
OnlineDatasource datasource, |
||||||
|
JSONObject masterData, |
||||||
|
String masterDataId, |
||||||
|
Map<OnlineDatasourceRelation, List<JSONObject>> slaveDataListMap) { |
||||||
|
int flowStatus = FlowTaskStatus.APPROVING; |
||||||
|
if (flowTaskComment.getApprovalType().equals(FlowApprovalType.REFUSE)) { |
||||||
|
flowStatus = FlowTaskStatus.REFUSED; |
||||||
|
} else if (flowTaskComment.getApprovalType().equals(FlowApprovalType.STOP)) { |
||||||
|
flowStatus = FlowTaskStatus.FINISHED; |
||||||
|
} |
||||||
|
OnlineTable masterTable = datasource.getMasterTable(); |
||||||
|
Long datasourceId = datasource.getDatasourceId(); |
||||||
|
flowWorkOrderService.updateFlowStatusByProcessInstanceId(task.getProcessInstanceId(), flowStatus); |
||||||
|
this.updateMasterData(masterTable, masterData, masterDataId); |
||||||
|
if (slaveDataListMap != null) { |
||||||
|
for (Map.Entry<OnlineDatasourceRelation, List<JSONObject>> relationEntry : slaveDataListMap.entrySet()) { |
||||||
|
Long relationId = relationEntry.getKey().getRelationId(); |
||||||
|
onlineOperationService.updateRelationData( |
||||||
|
masterTable, masterData, masterDataId, datasourceId, relationId, relationEntry.getValue()); |
||||||
|
} |
||||||
|
} |
||||||
|
if (flowTaskComment.getApprovalType().equals(FlowApprovalType.STOP)) { |
||||||
|
Integer s = MapUtil.getInt(taskVariableData, FlowConstant.LATEST_APPROVAL_STATUS_KEY); |
||||||
|
flowWorkOrderService.updateLatestApprovalStatusByProcessInstanceId(task.getProcessInstanceId(), s); |
||||||
|
CallResult stopResult = flowApiService.stopProcessInstance( |
||||||
|
task.getProcessInstanceId(), flowTaskComment.getTaskComment(), flowStatus); |
||||||
|
if (!stopResult.isSuccess()) { |
||||||
|
throw new FlowOperationException(stopResult.getErrorMessage()); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (taskVariableData == null) { |
||||||
|
taskVariableData = new JSONObject(); |
||||||
|
} |
||||||
|
taskVariableData.put(FlowConstant.MASTER_DATA_KEY, masterData); |
||||||
|
taskVariableData.put(FlowConstant.SLAVE_DATA_KEY, this.normailizeSlaveDataListMap(slaveDataListMap)); |
||||||
|
taskVariableData.put(FlowConstant.MASTER_TABLE_KEY, masterTable); |
||||||
|
flowApiService.completeTask(task, flowTaskComment, taskVariableData, null); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void fixBusinessData(FlowTransProducer flowTransProducer) { |
||||||
|
try { |
||||||
|
String sql = "SELECT * FROM zz_flow_trans_consumer WHERE trans_id = " + flowTransProducer.getTransId(); |
||||||
|
List<Map<String, Object>> dataList = dataSourceUtil.query(flowTransProducer.getDblinkId(), sql); |
||||||
|
if (CollUtil.isNotEmpty(dataList)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
} catch (Exception e) { |
||||||
|
log.error("Failed to call dataSourceUtil.query", e); |
||||||
|
throw new OnlineRuntimeException(e.getMessage()); |
||||||
|
} |
||||||
|
TransactionalFlowBusinessData businessData = new TransactionalFlowBusinessData(); |
||||||
|
businessData.setTransId(flowTransProducer.getTransId()); |
||||||
|
businessData.setDblinkId(flowTransProducer.getDblinkId()); |
||||||
|
List<TransactionalBusinessData.BusinessSqlData> sqlDataList = |
||||||
|
JSON.parseArray(flowTransProducer.getSqlData(), TransactionalBusinessData.BusinessSqlData.class); |
||||||
|
businessData.setSqlDataList(sqlDataList); |
||||||
|
try { |
||||||
|
this.doHandle(businessData); |
||||||
|
} catch (Exception e) { |
||||||
|
log.error(e.getMessage(), e); |
||||||
|
throw new OnlineRuntimeException(e.getMessage()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<Map<String, Object>> calculatePermData(Set<Long> onlineFormEntryIds) { |
||||||
|
if (CollUtil.isEmpty(onlineFormEntryIds)) { |
||||||
|
return new LinkedList<>(); |
||||||
|
} |
||||||
|
List<Map<String, Object>> permDataList = new LinkedList<>(); |
||||||
|
List<FlowEntry> flowEntries = flowEntryService.getInList(onlineFormEntryIds); |
||||||
|
Set<Long> pageIds = flowEntries.stream().map(FlowEntry::getPageId).collect(Collectors.toSet()); |
||||||
|
Map<Long, String> pageAndVariableNameMap = |
||||||
|
onlineDatasourceService.getPageIdAndVariableNameMapByPageIds(pageIds); |
||||||
|
for (FlowEntry flowEntry : flowEntries) { |
||||||
|
JSONObject permData = new JSONObject(); |
||||||
|
permData.put("entryId", flowEntry.getEntryId()); |
||||||
|
String key = StrUtil.upperFirst(flowEntry.getProcessDefinitionKey()); |
||||||
|
List<String> permCodeList = new LinkedList<>(); |
||||||
|
String formPermCode = "form" + key; |
||||||
|
permCodeList.add(formPermCode); |
||||||
|
permCodeList.add(formPermCode + ":fragment" + key); |
||||||
|
permData.put("permCodeList", permCodeList); |
||||||
|
String flowUrlPrefix = flowProperties.getUrlPrefix(); |
||||||
|
String onlineUrlPrefix = onlineProperties.getUrlPrefix(); |
||||||
|
List<String> permList = CollUtil.newLinkedList( |
||||||
|
onlineUrlPrefix + "/onlineForm/view", |
||||||
|
onlineUrlPrefix + "/onlineForm/render", |
||||||
|
onlineUrlPrefix + "/onlineOperation/listByOneToManyRelationId/" + pageAndVariableNameMap.get(flowEntry.getPageId()), |
||||||
|
flowUrlPrefix + "/flowOperation/viewInitialHistoricTaskInfo", |
||||||
|
flowUrlPrefix + "/flowOperation/startOnly", |
||||||
|
flowUrlPrefix + "/flowOperation/viewInitialTaskInfo", |
||||||
|
flowUrlPrefix + "/flowOperation/viewRuntimeTaskInfo", |
||||||
|
flowUrlPrefix + "/flowOperation/viewProcessBpmn", |
||||||
|
flowUrlPrefix + "/flowOperation/viewHighlightFlowData", |
||||||
|
flowUrlPrefix + "/flowOperation/listFlowTaskComment", |
||||||
|
flowUrlPrefix + "/flowOperation/cancelWorkOrder", |
||||||
|
flowUrlPrefix + "/flowOperation/listRuntimeTask", |
||||||
|
flowUrlPrefix + "/flowOperation/listHistoricProcessInstance", |
||||||
|
flowUrlPrefix + "/flowOperation/listHistoricTask", |
||||||
|
flowUrlPrefix + "/flowOperation/freeJumpTo", |
||||||
|
flowUrlPrefix + "/flowOnlineOperation/startPreview", |
||||||
|
flowUrlPrefix + "/flowOnlineOperation/viewUserTask", |
||||||
|
flowUrlPrefix + "/flowOnlineOperation/viewHistoricProcessInstance", |
||||||
|
flowUrlPrefix + "/flowOnlineOperation/submitUserTask", |
||||||
|
flowUrlPrefix + "/flowOnlineOperation/upload", |
||||||
|
flowUrlPrefix + "/flowOnlineOperation/download", |
||||||
|
flowUrlPrefix + "/flowOperation/submitConsign", |
||||||
|
flowUrlPrefix + "/flowOnlineOperation/startAndTakeUserTask/" + flowEntry.getProcessDefinitionKey(), |
||||||
|
flowUrlPrefix + "/flowOnlineOperation/startAndSaveDraft/" + flowEntry.getProcessDefinitionKey(), |
||||||
|
flowUrlPrefix + "/flowOnlineOperation/listWorkOrder/" + flowEntry.getProcessDefinitionKey(), |
||||||
|
flowUrlPrefix + "/flowOnlineOperation/printWorkOrder/" + flowEntry.getProcessDefinitionKey() |
||||||
|
); |
||||||
|
permData.put("permList", permList); |
||||||
|
permDataList.add(permData); |
||||||
|
} |
||||||
|
return permDataList; |
||||||
|
} |
||||||
|
|
||||||
|
// @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
|
||||||
|
// public void bulkHandleBusinessData(TransactionalFlowBusinessData businessData) {
|
||||||
|
// try {
|
||||||
|
// this.doHandle(businessData);
|
||||||
|
// // 这里会切换回原有的在线表单表所在的数据库上线文。
|
||||||
|
// flowTransProducerMapper.deleteById(businessData.getTransId());
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// log.error("Failed to commit online business data [** " + JSON.toJSONString(businessData) + " **]", e);
|
||||||
|
// FlowTransProducer transProducer = flowTransProducerMapper.selectById(businessData.getTransId());
|
||||||
|
// transProducer.setErrorReason(e.getMessage());
|
||||||
|
// flowTransProducerMapper.updateById(transProducer);
|
||||||
|
// businessData.setErrorReason(e.getMessage());
|
||||||
|
// throw new OnlineRuntimeException(e.getMessage());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
private void doHandle(TransactionalFlowBusinessData businessData) throws Exception { |
||||||
|
Connection conn = null; |
||||||
|
try { |
||||||
|
conn = dataSourceUtil.getConnection(businessData.getDblinkId()); |
||||||
|
conn.setAutoCommit(false); |
||||||
|
for (TransactionalBusinessData.BusinessSqlData s : businessData.getSqlDataList()) { |
||||||
|
List<Object> paramList = null; |
||||||
|
if (CollUtil.isNotEmpty(s.getColumnValueList())) { |
||||||
|
paramList = s.getColumnValueList().stream().map(Object.class::cast).collect(Collectors.toList()); |
||||||
|
} |
||||||
|
dataSourceUtil.execute(conn, s.getSql(), paramList); |
||||||
|
} |
||||||
|
this.insertFlowConsumerTrans(conn, businessData); |
||||||
|
conn.commit(); |
||||||
|
} catch (Exception e) { |
||||||
|
if (conn != null) { |
||||||
|
conn.rollback(); |
||||||
|
} |
||||||
|
log.error(e.getMessage(), e); |
||||||
|
throw new OnlineRuntimeException(e.getMessage()); |
||||||
|
} finally { |
||||||
|
if (conn != null) { |
||||||
|
conn.close(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void insertFlowConsumerTrans(Connection conn, TransactionalFlowBusinessData businessData) { |
||||||
|
DataSourceProvider provider = dataSourceUtil.getProvider(businessData.getDblinkId()); |
||||||
|
Long transId = businessData.getTransId(); |
||||||
|
String sql = "INSERT INTO zz_flow_trans_consumer VALUES(?,?)"; |
||||||
|
if (provider instanceof PostgreSqlProvider) { |
||||||
|
dataSourceUtil.execute(conn, sql, CollUtil.newArrayList(transId, new java.sql.Date(System.currentTimeMillis()))); |
||||||
|
} else { |
||||||
|
dataSourceUtil.execute(conn, sql, CollUtil.newArrayList(transId, new Date())); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void updateMasterData(OnlineTable masterTable, JSONObject masterData, String dataId) { |
||||||
|
if (masterData == null) { |
||||||
|
return; |
||||||
|
} |
||||||
|
// 如果存在主表数据,就执行主表数据的更新。
|
||||||
|
Map<String, Object> originalMasterData = |
||||||
|
onlineOperationService.getMasterData(masterTable, null, null, dataId); |
||||||
|
for (Map.Entry<String, Object> entry : originalMasterData.entrySet()) { |
||||||
|
masterData.putIfAbsent(entry.getKey(), entry.getValue()); |
||||||
|
} |
||||||
|
if (!onlineOperationService.update(masterTable, masterData)) { |
||||||
|
throw new FlowOperationException("主表数据不存在!"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private Map<String, List<JSONObject>> normailizeSlaveDataListMap( |
||||||
|
Map<OnlineDatasourceRelation, List<JSONObject>> slaveDataListMap) { |
||||||
|
if (slaveDataListMap == null || slaveDataListMap.size() == 0) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
Map<String, List<JSONObject>> resultMap = new HashMap<>(slaveDataListMap.size()); |
||||||
|
for (Map.Entry<OnlineDatasourceRelation, List<JSONObject>> entry : slaveDataListMap.entrySet()) { |
||||||
|
resultMap.put(entry.getKey().getSlaveTable().getTableName(), entry.getValue()); |
||||||
|
} |
||||||
|
return resultMap; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,2 @@ |
|||||||
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ |
||||||
|
apelet.common.flow.online.config.FlowOnlineAutoConfig |
||||||
Loading…
Reference in new issue