When used by Activiti, it usually needs to be closely tied to the business, and some business is very complex, such as a simple procurement process: The process is as follows:
When a new product is delivered to the supplier, the business audit is submitted, and the business audit is returned to the supplier by submitting the operation Audit.
The operation Audit was successfully submitted to the contract for signature. Failure to return business audits or direct return of the supplier to the Operation Audit Audit.
The conclusion of the contract is concluded, and the contract is not approved by return to the operation audit or return to the business audit, or return to the supplier.
There is a problem with the process above, what is the problem?
Let's look at the problem of the return line.
1. Business audit returned to the supplier on new.
2. The Operation Audit may return the business audit, the operation Audit may return the supplier to the new.
3. The signing of the contract may be returned to the Operation Audit, the contract may be returned to the business audit, the contract may be returned to the supplier of new.
4...
If our process in addition to the new department audit, is not our return line is much more. In fact, is the problem of n!, do we not add a node, we should draw a lot of return lines? This is obviously a bad design. Oh my God.
The problem is that if we want our processes to be more generic, we may need to add a lot of return line controls to prevent business changes and processes from changing as we design them, which is responding to changes while adding redundant designs.
Is there a better way to solve the problem? Obviously this is the problem we want to solve in this chapter.
1.1.1. activiti node Jump implementation
Before we realize it, we'll consider a few questions.
1. Which node is the current process.
2. The process needs to jump to the target node.
3. Do you want to add a variable after you jump to the target node? There may be a need to put, always can not jump to the target node for no reason. Traces must be recorded.
4. Jump to the target node, the current node configuration of the task monitoring needs to be triggered? (Refer to the Activiti Listener for use). When the current node jumps to the target node, if the current node is configured for the Task Listener service, the current task node's trigger task listener must be able to support the flexible configuration before it is turned to the target node.
The above point of thought is what we need to focus on next. Let's start with the design below.
1.1.1.1. Flow Chart
Let's first define a process as shown in the following illustration:
1.1.1.2. XML
Here we first define an XML definition as follows:
<?xml version= "1.0" encoding= "UTF-8"?> <definitions xmlns= "Http://www.omg.org/spec/BPMN/20100524/MODEL" Xmlns:xsi= "Http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd= "Http://www.w3.org/2001/XMLSchema" xmlns: Activiti= "HTTP://ACTIVITI.ORG/BPMN" xmlns:bpmndi= "Http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc= "http://" Www.omg.org/spec/DD/20100524/DC "xmlns:omgdi=" Http://www.omg.org/spec/DD/20100524/DI "typelanguage=" http:// Www.w3.org/2001/XMLSchema "expressionlanguage=" Http://www.w3.org/1999/XPath "targetnamespace=" daling "> < Process id= "daling" name= "name_daling" isexecutable= "true" activiti:candidatestarterusers= "A,b,c,d" > < Usertask id= "Usertask2" name= "Usertask2" activiti:assignee= "C" ></userTask> <usertask id= "USERTASK3" name = "Usertask3" ></userTask> <sequenceflow id= "flow4" sourceref= "Usertask2" targetref= "Usertask3" ></ sequenceflow> <usertask id= "Usertask4" name= "Usertask4" ></userTask> <SEQUENCEFLow id= "flow5" sourceref= "Usertask3" targetref= "Usertask4" ></sequenceFlow> <usertask id= "USERTASK5" name = "Usertask5" ></userTask> <sequenceflow id= "flow6" sourceref= "Usertask4" targetref= "Usertask5" ></ sequenceflow> <endevent id= "endevent1" name= "End" ></endEvent> <sequenceflow id= "Flow7" Usertask5 "targetref=" Endevent1 "></sequenceFlow> <startevent id=" startevent1 "name=" "Start" ></ startevent> <sequenceflow id= "Flow8" sourceref= "Startevent1" targetref= "Usertask2" ></sequenceFlow> & lt;/process> <bpmndi:bpmndiagram id= "bpmndiagram_daling" > <bpmndi:bpmnplane bpmnElement= "daling" Bpmnplane_daling "> <bpmndi:bpmnshape bpmnelement=" usertask2 "id=" Bpmnshape_usertask2 "> <omgdc:bounds height= "55.0" width= "105.0" x= "300.0" y= "90.0" ></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:bpmns Hape bpmnelement= "Usertask3" id= "Bpmnshape_useRtask3 "> <omgdc:bounds height=" 55.0 width= "105.0" x= "450.0" y= "90.0" ></omgdc:Bounds> </bpmndi: bpmnshape> <bpmndi:bpmnshape bpmnelement= "Usertask4" id= "Bpmnshape_usertask4" > <omgdc:bounds height= " 55.0 "width=" 105.0 "x=" 600.0 "y=" 90.0 "></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:bpmnshape BPM Nelement= "Usertask5" id= "Bpmnshape_usertask5" > <omgdc:bounds height= "55.0" width= "105.0" x= "750.0" y= "90.0" ;</omgdc:bounds> </bpmndi:BPMNShape> <bpmndi:bpmnshape bpmnelement= "endevent1" id= "Bpmnshape_endeve" Nt1 "> <omgdc:bounds height=" 35.0 width= "35.0" x= "900.0" y= "100.0" ></omgdc:Bounds> </bpmndi:bpm nshape> <bpmndi:bpmnshape bpmnelement= "startevent1" id= "Bpmnshape_startevent1" > <omgdc:bounds height= "35.0" width= "35.0" x= "140.0" y= "90.0" ></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:bpmnedge BPMN Element= "Flow4" id= "BpmneDge_flow4 "> <omgdi:waypoint x=" 405.0 "y=" 117.0 "></omgdi:waypoint> <omgdi:waypoint x=" 450.0 "y= "117.0" ></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:bpmnedge bpmnelement= "flow5 id=" Bpmnedge_f Low5 "> <omgdi:waypoint x=" 555.0 "y=" 117.0 "></omgdi:waypoint> <omgdi:waypoint x=" 600.0 "y=" 117. 0 "></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:bpmnedge bpmnelement=" flow6 "id=" BPMNEDGE_FLOW6 " > <omgdi:waypoint x= "705.0" y= "117.0" ></omgdi:waypoint> <omgdi:waypoint x= "750.0" y= "117.0"
;</omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:bpmnedge bpmnelement= "flow7" id= "Bpmnedge_flow7" > <omgdi:waypoint x= "855.0" y= "117.0" ></omgdi:waypoint> <omgdi:waypoint x= "900.0" y= "117.0" ><
/omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:bpmnedge bpmnelement= "Flow8" id= "Bpmnedge_flow8" > <omgdi:waypoint x= "175.0 "y=" 107.0 "></omgdi:waypoint> <omgdi:waypoint x=" 300.0 "y=" 117.0 "></omgdi:waypoint> </ bpmndi:bpmnedge> </bpmndi:BPMNPlane> </bpmndi:BPMNDiagram> </definitions>
1.1.1.3.&NBSP Code Implementation
Package COM.DALING.CH1.JD;
Import Java.util.Iterator;
Import Java.util.Map;
Import Org.activiti.engine.impl.context.Context;
Import Org.activiti.engine.impl.interceptor.Command;
Import Org.activiti.engine.impl.interceptor.CommandContext;
Import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
Import Org.activiti.engine.impl.persistence.entity.ExecutionEntityManager;
Import org.activiti.engine.impl.persistence.entity.TaskEntity;
Import Org.activiti.engine.impl.pvm.process.ActivityImpl; /** * * JD node of the jump * to share the original cattle (respect for original reprint when the first line please specify, reproduced from the source to share cattle http://blog.csdn.net/qq_30739519)/public class JDJUMPTASKCM
D implements command<void> {protected String Executionid;
protected Activityimpl desactivity;
Protected map<string, object> Paramvar;
protected Activityimpl currentactivity; /** * Share Cow Original (respect original reprint when the first line please specify, reproduced from the source of sharing cattle http://blog.csdn.net/qq_30739519)/public Void execute (commandcontext comman Dcontext) {Executionentitymanager executionentityManager = context. Getcommandcontext (). Getexecutionentitymanager ();
Gets the executionid of the current process, because Executionid is unique in the case of concurrency.
Executionentity executionentity = Executionentitymanager. Findexecutionbyid (Executionid);
Executionentity.setvariables (Paramvar);
Executionentity.seteventsource (this.currentactivity);
Executionentity.setactivity (this.currentactivity); Gets the task iterator<taskentity> localiterator = Context.getcommandcontext () by Executionid. GetTaskEntityManager (
). Findtasksbyexecutionid (This.executionid). iterator ();
while (Localiterator.hasnext ()) {taskentity taskentity = (taskentity) localiterator.next ();
Trigger Task Monitoring Taskentity.fireevent ("complete");
The reason for deleting a task Context.getcommandcontext (). Gettaskentitymanager (). Deletetask (Taskentity, "completed", false);
} executionentity.executeactivity (this.desactivity);
return null; /** * Construction Parameters can add more fields according to their business needs * share the original cattle (respect for original reprint of the first line please specify, reproduced from the source to share cattle http://blog.csdn.net/qq_30739519) * @param execu Tionid * @param DESActivity * @param paramvar * @param currentactivity/Public Jdjumptaskcmd (String Executionid, Activityimpl desacti
Vity, map<string, object> Paramvar, Activityimpl currentactivity) {This.executionid = ExecutionId;
this.desactivity = desactivity;
This.paramvar = Paramvar;
this.currentactivity = currentactivity; }
}
1.1.1.4. Use
Let's start the test jump by first letting the process run to the USERTASK3 node.
How to use the above Jdjumptaskcmd class, direct new Jdjumptaskcmd () call, certainly not, because the Activiti engine program did not get, certainly the error, the correct way to use the following:
1.1.1.4.1. The first way
We first look at the Database Act_ru_task table task record information to facilitate our operation, the database records as shown in the following figure:
Can see the current node in Usertask3, we now usertask3 to jump to the USERTASK5 node to see if it can be successful, because USERTASK3 to usertask5 no connection, if successful, it means that our method is correct.
Execute the following code, modify the corresponding value according to your own database information.
map<string, object> vars = new hashmap<string, object> ();
String[] v = {"Shareniu1", "Shareniu2", "Shareniu3", "Shareniu4"};
Vars.put ("Assigneelist", Arrays.aslist (v));
Share Cow Original (respect original reprint when the first line please specify, reproduced from the source of the share of cattle http://blog.csdn.net/qq_30739519)
repositoryservice repositoryservice = Demo.getrepositoryservice ();
Readonlyprocessdefinition processdefinitionentity = (readonlyprocessdefinition) repositoryservice
. Getprocessdefinition ("daling:29:137504");
Target node
activityimpl destinationactivity = (activityimpl) processdefinitionentity
. Findactivity ("Usertask5" );
String Executionid = "137509";
Current node
activityimpl currentactivity = (activityimpl) processdefinitionentity
. Findactivity ("Usertask3");
Demo.getmanagementservice (). ExecuteCommand (
new Jdjumptaskcmd (Executionid, destinationactivity, VARs,
After executing the above code, we look at the records in the database.
The node did jump to Usertask5. Ok this method can be no problem, let's say the second way to execute the executecommand command.
1.1.1.4.2. The second way
map<string, object> vars = new hashmap<string, object> ();
String[] v = {"Shareniu1", "Shareniu2", "Shareniu3", "Shareniu4"};
Vars.put ("Assigneelist", Arrays.aslist (v));
Share Cow Original (respect original reprint when the first line please specify, reproduced from the source of the share of cattle http://blog.csdn.net/qq_30739519)
commandexecutor commandexecutor = Taskserviceimpl
. Getcommandexecutor ();
Commandexecutor.execute (New Jdjumptaskcmd (Executionid,
You can perform the custom command subclass in both of the above ways. Readers choose the way they like to use it.
1.1.2. Summary
1. Any node of the jump, provided that the node must be in the template definition.
2. Any node of the jump temporarily can not jump across the process.
3. The jump of any node does not need to connect,
4. Any node of the jump can achieve rollback, transfer, read, Leapfrog Report, a step in the end, and so on functions, about these more actual combat, we will be in the final work of the actual project in a step-by-step package. Use.
The above is a small set to introduce the Activiti node jump related knowledge, I hope to help you!