Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to realize the fallback of process by Activiti

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/03 Report--

1. Overview

Process fallback has always been an old problem, and there has been no good solution. This paper will elaborate on the solution of process fallback. First of all, let's analyze the approval of different processes, and implement the fallback processing of the process on the corresponding node, as well as the fallback processing that should be provided. of course, by fallback, we don't mean fallback to the desired node by drawing a line on the process node.

When fallback, there are two situations that need to be addressed:

Fall back to the sponsor

Go back to the previous step and step back gradually

Because the api of Activiti itself is not supported when fallback to any node, we can only achieve fallback to any node by expanding the api of activiti to achieve free jump, but there are exceptions. When fallback, we need to pay attention, otherwise the data will easily cause problems when activiti jumps, mainly when jumping outside the concurrent node branch (as shown in the following figure, when the B and D nodes return to node A) The instance Id that it executes can change, so you need to pay attention to some restrictions on the process jump in this case.

So we need to go back to any node for the current approval task, and how to expand it when realizing free jump. The following is how to extend activiti to achieve free jump:

Delete the node after the node and point to the new node. * @ param actDefId process definition ID * @ param nodeId process node ID * @ param aryDestination the node that needs to be redirected * @ return Map returns the collection of nodes and nodes to be recovered. * / @ SuppressWarnings ("unchecked") private Map prepare (String actDefId,String nodeId,String [] aryDestination) {Map map=new HashMap (); / / modify the process definition ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) repositoryService.getProcessDefinition (actDefId); ActivityImpl curAct= processDefinition.findActivity (nodeId); List outTrans= curAct.getOutgoingTransitions (); try {List cloneOutTrans= (List) FileUtil.cloneObject (outTrans); map.put ("outTrans", cloneOutTrans) } catch (Exception ex) {} / * resolves the problem of process termination caused by selecting free jump to point to the synchronization node. * Delete the flow pointing to yourself in the target node. * / for (Iterator it=outTrans.iterator (); it.hasNext ();) {PvmTransition transition=it.next (); PvmActivity activity= transition.getDestination (); List inTrans= activity.getIncomingTransitions (); for (Iterator itIn=inTrans.iterator (); itIn.hasNext ();) {PvmTransition inTransition=itIn.next (); if (inTransition.getSource (). GetId (). Equals (curAct.getId () {itIn.remove ();}} curAct.getOutgoingTransitions (). Clear () If {for (String dest:aryDestination) {/ / create a connection ActivityImpl destAct= processDefinition.findActivity (dest); TransitionImpl transitionImpl = curAct.createOutgoingTransition (); transitionImpl.setDestination (destAct);}} map.put ("activity", curAct); return map;} / * clear the temporary node and add it back to the original node. * @ param map * void * / @ SuppressWarnings ("unchecked") private void restore (Map map) {ActivityImpl curAct= (ActivityImpl) map.get ("activity"); List outTrans= (List) map.get ("outTrans"); curAct.getOutgoingTransitions () .clear (); curAct.getOutgoingTransitions () .addAll (outTrans) } / * realize the jump of the task by specifying the target node * @ param taskId task ID * @ param destNodeIds jump to the target node ID * @ param vars process variable * / public synchronized void completeTask (String taskId,String [] destNodeIds,Map vars) {TaskEntity task= (TaskEntity) taskService.createTaskQuery (). TaskId (taskId). SingleResult (); String curNodeId=task.getTaskDefinitionKey (); String actDefId=task.getProcessDefinitionId (); Map activityMap= prepare (actDefId, curNodeId, destNodeIds) Try {taskService.complete (taskId);} catch (Exception ex) {throw new RuntimeException (ex);} finally {/ / restore restore (activityMap);}}

If we need to jump, we need to know what node is the last step back. How to get the fallback node only through the process can not meet the needs of the business, because sometimes we need to go back to a certain node for processing, and the next step needs to go back to the original node, such as we are on the E node in the above figure. When we roll back, E fallback needs to go back to D or C, and then go back to B after completion. In this case, we can require E to go to the G1 node and go down. This kind of fallback will appear humanized, and at the same time, it also ensures that the signals and parameters of the process instance are normal in the subsequent execution process, so we need to have a complete record of the ID data of each node through which the process instance is executed, and through the following data, we can quickly find out which node should be fallback to when the current node is backed up, and who is the executive staff of this node at that time.

two。 How to record the execution of a process

In order to better record the tree nodes that the process passes through, we use a tree structure to store the process nodes that pass through when the process instance executes, as shown in the figure above, as shown in the tree diagram of its execution:

We need to find the parent node at each node where we can go back to the previous step, which requires an algorithm, such as fallback at B or D, we let him go back to A, at C back we let him go back to B, and if we go back at E, we need to get him back to G1. The implementation of this algorithm is not complex, with this tree type of execution tree data, everything becomes very simple. However, it should be noted that when we roll back, we need to record the node from which he came back. If the user has finished processing, he can be asked to go back to the original node directly, or he can be approved again according to the process definition. If you execute to E and ask him to roll back and re-approve, the tree diagram of his execution is as follows:

Notice G1, where it points to E, and when it's done, you can ask him to jump to E, and that's where you can find out which task node it should jump to when the task is complete.

3. The extended table records the path to the execution of the process / * = = * / * Table: BPM_RU_PATH * / / * = = * / CREATE TABLE BPM_RU_PATH (PATH_ID_ VARCHAR (64) NOT NULL, INST_ID_ VARCHAR (64) NOT NULL COMMENT 'process instance ID' ACT_DEF_ID_ VARCHAR (64) NOT NULL COMMENT 'Act definition ID', ACT_INST_ID_ VARCHAR (64) NOT NULL COMMENT' Act instance ID', SOL_ID_ VARCHAR (64) NOT NULL COMMENT 'solution ID', NODE_ID_ VARCHAR' NOT NULL COMMENT 'Node ID', NODE_NAME_ VARCHAR (255) COMMENT' Node name' NODE_TYPE_ VARCHAR (50) COMMENT 'Node Type', START_TIME_ DATETIME NOT NULL COMMENT 'start time', END_TIME_ DATETIME COMMENT 'end time', DURATION_ INT COMMENT 'duration', DURATION_VAL_ INT COMMENT 'valid approval duration', ASSIGNEE_ VARCHAR (64) COMMENT 'handler ID' TO_USER_ID_ VARCHAR (64) COMMENT 'Agent ID', IS_MULTIPLE_ VARCHAR (20) COMMENT' whether it is multiple instance', EXECUTION_ID_ VARCHAR (64) COMMENT 'activity executes ID', USER_IDS_ VARCHAR (300) COMMENT' original executor IDS', PARENT_ID_ VARCHAR (64) COMMENT 'parent ID', LEVEL_ INT COMMENT' hierarchy' OUT_TRAN_ID_ VARCHAR (255) COMMENT 'jump out of route ID', TOKEN_ VARCHAR (255) COMMENT' route token', JUMP_TYPE_ VARCHAR (50) COMMENT 'jump to this node normal jump free jump back jump', NEXT_JUMP_TYPE_ VARCHAR (50) COMMENT 'next jump mode' OPINION_ VARCHAR (500) COMMENT 'approval opinions', REF_PATH_ID_ VARCHAR (64) COMMENT 'reference path ID when fallback For the regenerated node, you need to record the referenced fallback node to facilitate the fallback of the newly generated path again.' , TENANT_ID_ VARCHAR (64) COMMENT 'leasing agency ID', CREATE_BY_ VARCHAR (64) COMMENT' creator ID', CREATE_TIME_ DATETIME COMMENT 'creation time, UPDATE_BY_ VARCHAR (64) COMMENT' updater ID', UPDATE_TIME_ DATETIME COMMENT 'update time, PRIMARY KEY (PATH_ID_))

ALTER TABLE BPM_RU_PATH COMMENT 'process instance run Route'

4. How to create an execution path

With the table structure, how to make activiti add the data we need to the above table in the process of execution, then we need to use activiti's global event listener. For specific implementation, please refer to my global event listening processing.

Activiti provides two good event listeners, one is the event ACTIVITY_STARTED created by the execution entity, and the other is the event ACTIVITY_COMPLETED completed by the entity. We can add the record creation and update of the bpm_ru_path table to these two events respectively. In its fallback, through the algorithm to find its need for fallback nodes, and then through the free jump method provided above, that is, the fallback of the process can be achieved.

5. Process fallback processing

With the above execution data, the fallback of the process can be found through the algorithm to find the process node that needs fallback, so that the fallback processing of the process can be realized. Note that the fallback node Id of the current task is obtained below, and then specify this node Id to be redirected to this node after the execution is completed.

Note that the code BpmRuPath bpmRuPath = getBackNodeId (task.getProcessInstanceId (), task.getTaskDefinitionKey ())

/ * * Task jumps down * * @ param taskId * @ param jsonData * @ param vars * @ throws Exception * / public void doNext (ProcessNextCmd cmd) throws Exception {boolean isSetBackPath = false; try {TaskEntity task = (TaskEntity) taskService.createTaskQuery (). TaskId (cmd.getTaskId ()). SingleResult (); UserTaskConfig userTaskConfig=bpmNodeSetManager.getTaskConfig (task.getSolId (), task.getTaskDefinitionKey ()); / / String processInstanceId = task.getProcessInstanceId () / / add executionId to record the execution path cmd.setNodeId (task.getTaskDefinitionKey ()); / / add the thread variable ProcessHandleHelper.setProcessCmd (cmd); BpmInst bpmInst = bpmInstManager.getByActInstId (task.getProcessInstanceId ()); BpmFormInst bpmFormInst = bpmFormInstManager.get (bpmInst.getFormInstId ()); try {String newJson = JSONUtil.copyJsons (bpmFormInst.getJsonData (), cmd.getJsonData ()); bpmFormInst.setJsonData (newJson); bpmFormInstManager.saveOrUpdate (bpmFormInst) } catch (Exception ex) {logger.error (ex.getCause ());} Map vars = handleTaskVars (task, cmd.getJsonData ()); / / plus the external variable if (cmd.getVars ()! = null) {vars.putAll (cmd.getVars ()) } / / if it is a fallback, the operation if (TaskOptionType.BACK.name (). Equals (cmd.getJumpType () {BpmRuPath bpmRuPath = getBackNodeId (task.getProcessInstanceId (), task.getTaskDefinitionKey ()); / / No fallback node was found, prompting the user if (bpmRuPath = = null) {ProcessHandleHelper.getProcessMessage (). GetErrorMsges (). Add ("this link cannot be backed back! Failed to find the previous fallback approval link!); return;} else {/ / set the fallback node cmd.setDestNodeId (bpmRuPath.getNodeId ()); ProcessHandleHelper.setBackPath (bpmRuPath); isSetBackPath = true;}} else if (TaskOptionType.BACK_TO_STARTOR.name (). Equals (cmd.getJumpType () {/ / back to the initiator ActNodeDef afterNode = actRepService.getNodeAfterStart (task.getProcessDefinitionId ()) If (afterNode = = null) {ProcessHandleHelper.getProcessMessage () .getErrorMsges () .add ("the approval process where the sponsor was not found!") ; return;} else {cmd.setDestNodeId (afterNode.getNodeId ());}} else {/ / finds whether the mode returned by the original route, that is, whether the current task is handled by fallback BpmRuPath ruPath = bpmRuPathManager.getFarestPath (task.getProcessInstanceId (), task.getTaskDefinitionKey ()); if (ruPath! = null & & ".equals (ruPath.getNextJumpType () {BpmRuPath toNodePath = bpmRuPathManager.get (ruPath.getParentId () If (toNodePath! = null) {cmd.setDestNodeId (toNodePath.getNodeId ());} / / plus pre-processing if (StringUtils.isNotEmpty (userTaskConfig.getPreHandle () {Object preBean=AppBeanUtil.getBean (userTaskConfig.getPreHandle ()); if (preBean instanceof TaskPreHandler) {TaskPreHandler handler= (TaskPreHandler) preBean; handler.taskPreHandle (cmd, task, bpmInst.getBusKey ()) }} / / the following is the task jump processing if (StringUtils.isNotEmpty (cmd.getDestNodeId () {/ / to jump actTaskService.completeTask (cmd.getTaskId (), new String [] {cmd.getDestNodeId ()}, vars) of the specified node;} else {/ / normal jump taskService.complete (cmd.getTaskId (), vars) } / / add post processing if (StringUtils.isNotEmpty (userTaskConfig.getAfterHandle () {Object preBean=AppBeanUtil.getBean (userTaskConfig.getAfterHandle ()); if (preBean instanceof TaskAfterHandler) {TaskAfterHandler handler= (TaskAfterHandler) preBean; handler.taskAfterHandle (cmd, task.getTaskDefinitionKey (), bpmInst.getBusKey ());}} catch (Exception e) {e.printStackTrace (); logger.error (e.getCause ()); throw e;} finally {ProcessHandleHelper.clearProcessCmd () If (isSetBackPath) {ProcessHandleHelper.clearBackPath ();}

For specific implementation results, please refer to the following online example

You need to open the fallback button in the node configuration of the process solution, as shown in the following figure:

Learn about consulting QQ:1361783075

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report