使用Activiti服务
与Activiti引擎进行交互的方式是通过org.activiti.engine.ProcessEngine
类的实例公开的服务,以下代码段假定你拥有一个有效的Activiti环境,即你可以访问有效的org.activiti.engine.ProcessEngine
。如果你只想尝试下面的代码,则可以下载或克隆Activiti单元测试模板,将其导入IDE中,然后将testUserguideCode()
方法添加到org.activiti.MyUnitTest
单元测试中。
这个小教程的最终目标是要有一个能正常工作的业务流程,该流程模仿公司中一个简单的请假流程:
部署流程
与静态数据相关的所有内容(例如流程定义)都可以通过RepositoryService
访问,从概念上讲,每个此类静态数据都是Activiti引擎存储库的内容。
在src/test/resources/org/activiti/test
资源文件夹(或如果不使用单元测试模板的其他任何地方)中创建具有以下内容的新xml文件VacationRequest.bpmn20.xml
。
<?xml version="1.0" encoding="UTF-8" ?>
<definitions id="definitions"
targetNamespace="http://activiti.org/bpmn20"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:activiti="http://activiti.org/bpmn">
<process id="vacationRequest" name="Vacation request">
<startEvent id="request" activiti:initiator="employeeName">
<extensionElements>
<activiti:formProperty id="numberOfDays" name="Number of days" type="long" value="1" required="true"/>
<activiti:formProperty id="startDate" name="First day of holiday (dd-MM-yyy)" datePattern="dd-MM-yyyy hh:mm" type="date" required="true" />
<activiti:formProperty id="vacationMotivation" name="Motivation" type="string" />
</extensionElements>
</startEvent>
<sequenceFlow id="flow1" sourceRef="request" targetRef="handleRequest" />
<userTask id="handleRequest" name="Handle vacation request" >
<documentation>
${employeeName} would like to take ${numberOfDays} day(s) of vacation (Motivation: ${vacationMotivation}).
</documentation>
<extensionElements>
<activiti:formProperty id="vacationApproved" name="Do you approve this vacation" type="enum" required="true">
<activiti:value id="true" name="Approve" />
<activiti:value id="false" name="Reject" />
</activiti:formProperty>
<activiti:formProperty id="managerMotivation" name="Motivation" type="string" />
</extensionElements>
<potentialOwner>
<resourceAssignmentExpression>
<formalExpression>management</formalExpression>
</resourceAssignmentExpression>
</potentialOwner>
</userTask>
<sequenceFlow id="flow2" sourceRef="handleRequest" targetRef="requestApprovedDecision" />
<exclusiveGateway id="requestApprovedDecision" name="Request approved?" />
<sequenceFlow id="flow3" sourceRef="requestApprovedDecision" targetRef="sendApprovalMail">
<conditionExpression xsi:type="tFormalExpression">${vacationApproved == 'true'}</conditionExpression>
</sequenceFlow>
<task id="sendApprovalMail" name="Send confirmation e-mail" />
<sequenceFlow id="flow4" sourceRef="sendApprovalMail" targetRef="theEnd1" />
<endEvent id="theEnd1" />
<sequenceFlow id="flow5" sourceRef="requestApprovedDecision" targetRef="adjustVacationRequestTask">
<conditionExpression xsi:type="tFormalExpression">${vacationApproved == 'false'}</conditionExpression>
</sequenceFlow>
<userTask id="adjustVacationRequestTask" name="Adjust vacation request">
<documentation>
Your manager has disapproved your vacation request for ${numberOfDays} days.
Reason: ${managerMotivation}
</documentation>
<extensionElements>
<activiti:formProperty id="numberOfDays" name="Number of days" value="${numberOfDays}" type="long" required="true"/>
<activiti:formProperty id="startDate" name="First day of holiday (dd-MM-yyy)" value="${startDate}" datePattern="dd-MM-yyyy hh:mm" type="date" required="true" />
<activiti:formProperty id="vacationMotivation" name="Motivation" value="${vacationMotivation}" type="string" />
<activiti:formProperty id="resendRequest" name="Resend vacation request to manager?" type="enum" required="true">
<activiti:value id="true" name="Yes" />
<activiti:value id="false" name="No" />
</activiti:formProperty>
</extensionElements>
<humanPerformer>
<resourceAssignmentExpression>
<formalExpression>${employeeName}</formalExpression>
</resourceAssignmentExpression>
</humanPerformer>
</userTask>
<sequenceFlow id="flow6" sourceRef="adjustVacationRequestTask" targetRef="resendRequestDecision" />
<exclusiveGateway id="resendRequestDecision" name="Resend request?" />
<sequenceFlow id="flow7" sourceRef="resendRequestDecision" targetRef="handleRequest">
<conditionExpression xsi:type="tFormalExpression">${resendRequest == 'true'}</conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow8" sourceRef="resendRequestDecision" targetRef="theEnd2">
<conditionExpression xsi:type="tFormalExpression">${resendRequest == 'false'}</conditionExpression>
</sequenceFlow>
<endEvent id="theEnd2" />
</process>
</definitions>
为了使Activiti引擎知道此流程,我们必须先进行部署,部署意味着引擎将BPMN 2.0 xml解析为可执行文件,并将为部署中包含的每个流程定义添加新的数据库记录,这样,当引擎重新启动时,它仍然会知道所有已部署的流程:
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
repositoryService.createDeployment()
.addClasspathResource("org/activiti/test/VacationRequest.bpmn20.xml")
.deploy();
Log.info("Number of process definitions: " + repositoryService.createProcessDefinitionQuery().count());
启动流程实例
将流程定义部署到Activiti引擎后,我们可以从中启动新流程实例,对于每个流程定义,通常有许多流程实例,流程定义是蓝图,而流程实例是其运行时执行。
与流程的运行时状态相关的所有内容都可以在RuntimeService
中找到,有多种启动新流程实例的方法。在以下代码段中,我们使用在流程定义xml中定义的键来启动流程实例,我们还在流程实例启动时提供了一些流程变量,因为第一个用户任务的描述将在其表达式中使用它们。流程变量是常用的,因为它们赋予特定流程定义的流程实例以意义,通常,流程变量使流程实例彼此不同。
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("employeeName", "Kermit");
variables.put("numberOfDays", new Integer(4));
variables.put("vacationMotivation", "I'm really tired!");
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("vacationRequest", variables);
// Verify that we started a new process instance
Log.info("Number of process instances: " + runtimeService.createProcessInstanceQuery().count());
完成任务
该流程开始时,第一步将是用户任务,这是系统用户必须执行的步骤,通常,此类用户将有一个任务收件箱,其中列出了该用户需要完成的所有任务,以下代码段显示了如何执行这种查询:
// Fetch all tasks for the management group
TaskService taskService = processEngine.getTaskService();
List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("management").list();
for (Task task : tasks) {
Log.info("Task available: " + task.getName());
}
要继续该流程实例,我们需要完成此任务,对于Activiti引擎,这意味着你需要完成任务,以下片段显示了如何完成此操作:
Task task = tasks.get(0);
Map<String, Object> taskVariables = new HashMap<String, Object>();
taskVariables.put("vacationApproved", "false");
taskVariables.put("managerMotivation", "We have a tight deadline!");
taskService.complete(task.getId(), taskVariables);
该流程实例现在将继续进行下一步,在此示例中,下一步允许员工填写可调整其原始休假请求的表格,员工可以重新提交休假请求,这将导致流程循环回到启动任务。
暂停和激活流程
可以暂停流程定义,流程定义被暂停后,将无法创建新的流程实例(将引发异常),通过RepositoryService
暂停流程定义:
repositoryService.suspendProcessDefinitionByKey("vacationRequest");
try {
runtimeService.startProcessInstanceByKey("vacationRequest");
} catch (ActivitiException e) {
e.printStackTrace();
}
要重新激活流程定义,只需调用repositoryService.activateProcessDefinitionXXX
方法之一。
也可以暂停流程实例,暂停后,该流程将无法继续执行(例如,完成任务会引发异常),并且不会执行任何作业(例如计时器),可以通过调用runtimeService.suspendProcessInstance
方法来挂起流程实例,通过调用runtimeService.activateProcessInstanceXXX
方法来再次激活流程实例。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。