通过学习上一篇的内容,我们已经完成了项目的初始化。Activiti流程引擎所需要的23张数据表已经在数据库中创建成功,在这一篇中,我们将通过HelloWorld示例模拟流程的运行过程,初步体会流程的执行过程和框架核心API的使用。
本篇将分为两个部分,第一部分是绘制流程图,第二部分通过代码模拟一个完整流程的运行过程。
绘制流程图
创建bpmn文件
继续上一篇创建的工程,选中项目src/main/resources
目录下的包diagrams,右键New->Other…->Activiti,选择创建Activiti Diagram,将文件命名为helloworld,然后,按照一般步骤点击直到结束。
这样我们就创建好了一个helloworld.bpmn文件。
绘制流程
打开helloworld.bpmn文件,可以在IDE右侧看到如下面板,遵循如下步骤创建流程图

拖拽Start event下的StartEvent,创建开始节点
拖拽End event下的EndEvent,创建结束节点
拖拽Task下的UserTask,创建任务节点
选择IDE顶部菜单Window->Show View->Properties,此时会打开一个界面,这个界面有助于我们编辑这些节点的属性,对于不同节点,Properties面板里的内容会有一定的差异,这是未选中节点时流程图的全局Propertis配置项界面

选择任务节点时的界面

编辑任务节点,设置任务节点名称
- 选择刚才创建的任务节点,将Name改为提交申请;
- 再创建一个任务节点,将Name改为审批【部门经理】
- 最后创建一个任务节点,将Name改为审批【总经理】
找到右侧Activiti面板里Connection->SequenceFlow,将各个节点从开始节点到结束节点依次连接起来,如下图所示

编辑任务节点,设置每个任务节点的办理人,在Properties界面里的Main config->Assignee里设置
- 提交申请任务节点的Assignee为张三
- 审批【部门经理】任务节点的Assignee为李四
- 审批【总经理】任务节点的Assignee为王五
点击空白处,此时出现全局Propertis配置项界面
- 设置Process->Id为helloworld
- 设置Process->Name为helloworldProcess
点击保存,即会生成对应流程图的图片文件
使用XML方式打开bpmn文件,可以看到如下代码
<?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="http://www.activiti.org/test"> <process id="helloworld" name="helloworldProcess" isExecutable="true"> <startEvent id="startevent1" name="Start"></startEvent> <endEvent id="endevent1" name="End"></endEvent> <userTask id="usertask1" name="提交申请" activiti:assignee="张三"></userTask> <userTask id="usertask2" name="审批【部门经理】" activiti:assignee="李四"></userTask> <userTask id="usertask3" name="审批【总经理】" activiti:assignee="王五"></userTask> <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow> <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow> <sequenceFlow id="flow3" sourceRef="usertask2" targetRef="usertask3"></sequenceFlow> <sequenceFlow id="flow4" sourceRef="usertask3" targetRef="endevent1"></sequenceFlow> </process> <bpmndi:BPMNDiagram id="BPMNDiagram_helloworld"> <bpmndi:BPMNPlane bpmnElement="helloworld" id="BPMNPlane_helloworld"> <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1"> <omgdc:Bounds height="35.0" width="35.0" x="390.0" y="50.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1"> <omgdc:Bounds height="35.0" width="35.0" x="390.0" y="380.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1"> <omgdc:Bounds height="55.0" width="105.0" x="355.0" y="120.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2"> <omgdc:Bounds height="55.0" width="105.0" x="355.0" y="200.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3"> <omgdc:Bounds height="55.0" width="105.0" x="355.0" y="290.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1"> <omgdi:waypoint x="407.0" y="85.0"></omgdi:waypoint> <omgdi:waypoint x="407.0" y="120.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2"> <omgdi:waypoint x="407.0" y="175.0"></omgdi:waypoint> <omgdi:waypoint x="407.0" y="200.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3"> <omgdi:waypoint x="407.0" y="255.0"></omgdi:waypoint> <omgdi:waypoint x="407.0" y="290.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4"> <omgdi:waypoint x="407.0" y="345.0"></omgdi:waypoint> <omgdi:waypoint x="407.0" y="380.0"></omgdi:waypoint> </bpmndi:BPMNEdge> </bpmndi:BPMNPlane> </bpmndi:BPMNDiagram> </definitions>
|
可以看到,该XML代码描述的过程和bpmn文件所图示的内容是一致的
模拟流程执行
在绘画完流程图后,此时,可以写代码模拟流程运行了。在src/main/java
下新建包cn.demo.helloworld
,并创建类HelloWorld
该流程执行的主要步骤有
- 部署流程定义
- 启动流程实例
- 查询当前人的个人任务
- 完成个人的任务
下面来看一下这些步骤的相关代码
部署流程定义
@Test public void deploymentProcessDefinition() { Deployment deploy = processEngine.getRepositoryService() .createDeployment() .name("helloworld入门程序") .addClasspathResource("diagrams/helloworld.bpmn") .addClasspathResource("diagrams/helloworld.png").deploy(); System.out.println("部署ID: " + deploy.getId()); System.out.println("部署名称: " + deploy.getName()); }
|
对于一个流程来说,首先需要做的就是部署流程定义,而流程部署和定义需要使用repositoryService,通过该服务,我们可以获得一个部署对象,获取流程定义相关信息
启动流程实例
@Test public void startProcessInstance() { String processDefinitionKey = "helloworld"; ProcessInstance processInstance = processEngine.getRuntimeService() .startProcessInstanceByKey(processDefinitionKey); System.out.println("流程实例ID: " + processInstance.getId());
System.out.println("流程定义ID: " + processInstance.getProcessDefinitionId());
}
|
部署完流程之后,就可以使用runtimeService启动一个具体流程实例
查询当前人的个人任务
流程在不断的执行,当流程执行到当前人的时候,就可以查询到当前人的个人任务
@Test public void findMyPersonalTask() { String assignee = "张三"; List<Task> list = processEngine.getTaskService() .createTaskQuery() .taskAssignee(assignee) .list(); if (list != null && list.size() > 0) { for (Task task : list) { System.out.println("任务ID: " + task.getId()); System.out.println("任务名称: " + task.getName()); System.out.println("任务的创建时间: " + task.getCreateTime()); System.out.println("任务的办理人: " + task.getAssignee()); System.out.println("流程实例ID: " + task.getProcessInstanceId()); System.out.println("执行对象ID: " + task.getExecutionId()); System.out.println("流程定义ID: " + task.getProcessDefinitionId()); System.out.println("#######################################"); } } }
|
完成个人的任务
@Test public void completeMyPersonalTask() { String taskId = "104"; processEngine.getTaskService().complete(taskId); System.out.println("完成任务:任务Id:" + taskId); }
|
当我们查询到当前我们有任务时,可以对该任务进行处理。当处理完毕之后,流程就执行到下一步了。当流程全部步骤执行完成后,会存储到历史表中
完整代码
package cn.demo.helloworld;
import java.util.List;
import org.activiti.engine.ProcessEngine; import org.activiti.engine.ProcessEngines; import org.activiti.engine.repository.Deployment; import org.activiti.engine.runtime.ProcessInstance; import org.activiti.engine.task.Task; import org.junit.Test;
public class HelloWorld {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
@Test public void deploymentProcessDefinition() { Deployment deploy = processEngine.getRepositoryService() .createDeployment() .name("helloworld入门程序") .addClasspathResource("diagrams/helloworld.bpmn") .addClasspathResource("diagrams/helloworld.png").deploy(); System.out.println("部署ID: " + deploy.getId()); System.out.println("部署名称: " + deploy.getName()); }
@Test public void startProcessInstance() { String processDefinitionKey = "helloworld"; ProcessInstance processInstance = processEngine.getRuntimeService() .startProcessInstanceByKey(processDefinitionKey); System.out.println("流程实例ID: " + processInstance.getId()); System.out.println("流程定义ID: " + processInstance.getProcessDefinitionId()); }
@Test public void findMyPersonalTask() { String assignee = "张三"; List<Task> list = processEngine.getTaskService() .createTaskQuery() .taskAssignee(assignee) .list(); if (list != null && list.size() > 0) { for (Task task : list) { System.out.println("任务ID: " + task.getId()); System.out.println("任务名称: " + task.getName()); System.out.println("任务的创建时间: " + task.getCreateTime()); System.out.println("任务的办理人: " + task.getAssignee()); System.out.println("流程实例ID: " + task.getProcessInstanceId()); System.out.println("执行对象ID: " + task.getExecutionId()); System.out.println("流程定义ID: " + task.getProcessDefinitionId()); System.out.println("#######################################"); } } }
@Test public void completeMyPersonalTask() { String taskId = "104"; processEngine.getTaskService().complete(taskId); System.out.println("完成任务:任务Id:" + taskId); }
}
|
演示流程任务执行
根据上面所绘制的流程图步骤,如下操作
- 首先,设置当前人的任务的assignee为张三并执行查询当前人的任务方法,得到张三的任务ID
- 将当前人的任务ID带入并执行完成个人任务方法
- 然后将步骤1中的assignee设置为李四,得到李四的任务ID,将李四的任务ID带入并执行步骤2
- 最后将assignee设置为王五,得到王五的任务ID,将王五的任务ID带入并执行步骤2
- 当以上步骤都完成时,就完成了模拟流程任务执行的过程
当前人 |
任务ID |
张三 |
104 |
李四 |
202 |
王五 |
302 |
总结
通过上面的例子,可以总结出一般流程执行的主要步骤
- 部署流程定义
- 启动流程实例
- 查询当前人的个人任务
- 完成个人的任务
- 重复执行3、4步,直到满足条件结束