这是我参与更文挑战的第9天,活动详情查看: 更文挑战
使用Activiti服务
如上所述,与 Activiti 引擎交互的方式是通过org.activiti.engine.ProcessEngine类的实例公开的服务。下面的代码片段假设你有一个可用的 Activiti 环境,即你可以访问一个有效的org.activiti.engine.ProcessEngine. 如果您只是想尝试下面的代码,您可以下载或克隆Activiti 单元测试模板,将其导入您的 IDE 并testUserguideCode()为org.activiti.MyUnitTest单元测试添加一个方法。
这个小教程的最终目标是建立一个工作业务流程,模拟公司的简单休假申请流程:
部署流程
与静态数据(例如流程定义)相关的所有内容都通过RepositoryService访问。从概念上讲,每个这样的静态数据都是Activiti 引擎存储库的内容。
使用以下内容VacationRequest.bpmn20.xml在src/test/resources/org/activiti/test资源文件夹(或其他任何地方,如果您不使用单元测试模板)中创建一个新的 xml 文件。请注意,本节不会解释上面示例中使用的 xml 构造。如果需要,请先阅读BPMN 2.0 章节以熟悉这些结构。
<?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());
完成任务
当流程开始时,第一步将是用户任务。这是系统用户必须执行的步骤。通常,这样的用户会有一个任务收件箱,其中列出了该用户需要完成的所有任务。以下代码片段显示了如何执行此类查询:
TaskService taskService = processEngine.getTaskService();
List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("management").list();
for (Task task : tasks) {
Log.info("Task available: " + task.getName());
}
为了继续流程实例,我们需要完成这个任务。对于 Activiti 引擎,这意味着您需要complete完成任务。以下代码段显示了这是如何完成的:
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();
}