工作流模拟的业务情景如下:
1.用户到银行转账业务
2.银行工作人员查询用户余额
3.银行工作人员帮助用户转账
手工触发执行是指,执行到流程中某个个结点后流程暂时停止运行,直到收到外部发送的信号
以后,才会继续向前推进,这样情况可以更加精细地控制流程。
针对用户手动执行的任务可以采用手工触发执行
通过<receiveTask>和<userTask>元素都可以实现流程的手工触发执行。
本文讲解ReceiveTask方式实现:
配置如下:
- <receiveTask id="receivetask2" name="开始转账">
- <extensionElements>
- <activiti:executionListener event="start" class="com.easyway.workflow.activiti.CheckMerchantMoneyTask"></activiti:executionListener>
- </extensionElements>
- </receiveTask>
流程图如下:
流程配置如下:
- <?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: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="BankUserTask" name="BankUserTask">
- <documentation>Place documentation for the 'BankUserTask' process here.</documentation>
- <startEvent id="startevent1" name="准备转账业务"></startEvent>
- <endEvent id="endevent1" name="转账结束"></endEvent>
- <receiveTask id="receivetask1" name="检查账户余额">
- <extensionElements>
- <activiti:executionListener event="start" class="com.easyway.workflow.activiti.CheckBankAccountMoneyTask"/>
- </extensionElements>
- </receiveTask>
- <receiveTask id="receivetask2" name="开始转账">
- <extensionElements>
- <activiti:executionListener event="start" class="com.easyway.workflow.activiti.CheckMerchantMoneyTask"></activiti:executionListener>
- </extensionElements>
- </receiveTask>
- <sequenceFlow id="flow1" name="" sourceRef="startevent1" targetRef="receivetask1"></sequenceFlow>
- <sequenceFlow id="flow2" name="" sourceRef="receivetask1" targetRef="receivetask2"></sequenceFlow>
- <sequenceFlow id="flow3" name="" sourceRef="receivetask2" targetRef="endevent1"></sequenceFlow>
- <sequenceFlow id="flow4" name="" sourceRef="receivetask1" targetRef="endevent1"></sequenceFlow>
- </process>
- <bpmndi:BPMNDiagram id="BPMNDiagram_BankUserTask">
- <bpmndi:BPMNPlane bpmnElement="BankUserTask" id="BPMNPlane_BankUserTask">
- <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
- <omgdc:Bounds height="35" width="35" x="76" y="218"></omgdc:Bounds>
- </bpmndi:BPMNShape>
- <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
- <omgdc:Bounds height="35" width="35" x="590" y="220"></omgdc:Bounds>
- </bpmndi:BPMNShape>
- <bpmndi:BPMNShape bpmnElement="receivetask1" id="BPMNShape_receivetask1">
- <omgdc:Bounds height="55" width="105" x="160" y="210"></omgdc:Bounds>
- </bpmndi:BPMNShape>
- <bpmndi:BPMNShape bpmnElement="receivetask2" id="BPMNShape_receivetask2">
- <omgdc:Bounds height="55" width="105" x="340" y="210"></omgdc:Bounds>
- </bpmndi:BPMNShape>
- <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
- <omgdi:waypoint x="111" y="235"></omgdi:waypoint>
- <omgdi:waypoint x="160" y="237"></omgdi:waypoint>
- </bpmndi:BPMNEdge>
- <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
- <omgdi:waypoint x="265" y="237"></omgdi:waypoint>
- <omgdi:waypoint x="340" y="237"></omgdi:waypoint>
- </bpmndi:BPMNEdge>
- <bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
- <omgdi:waypoint x="445" y="237"></omgdi:waypoint>
- <omgdi:waypoint x="590" y="237"></omgdi:waypoint>
- </bpmndi:BPMNEdge>
- <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">
- <omgdi:waypoint x="265" y="237"></omgdi:waypoint>
- <omgdi:waypoint x="212" y="338"></omgdi:waypoint>
- <omgdi:waypoint x="385" y="338"></omgdi:waypoint>
- <omgdi:waypoint x="607" y="338"></omgdi:waypoint>
- <omgdi:waypoint x="607" y="255"></omgdi:waypoint>
- </bpmndi:BPMNEdge>
- </bpmndi:BPMNPlane>
- </bpmndi:BPMNDiagram>
- </definitions>
代码实现如下:
- /**
- package com.easyway.workflow.activiti;
- import java.util.HashMap;
- /**
- * 银行工作人员开始查询用户余额的事件
- *
- * @author longgangbai
- *
- * 2011-12-17 上午09:37:50
- */
- public class CheckBankAccountMoneyTask implements JavaDelegate {
- private final Logger log = Logger.getLogger(CheckBankAccountMoneyTask.class.getName());
- @SuppressWarnings("unchecked")
- @Override
- public void execute(DelegateExecution execution) throws Exception {
- log.info("根据输入参数,开始检查银行账户余额........");
- System.out.println("in : " + execution.getVariables());
- ((HashMap<String, Object>)execution.getVariables().get("in")).put("next", "CheckBankTask");
- ((HashMap<String, Object>)execution.getVariables().get("out")).put("reponse", "subprocess:CheckBankReceiveTask->CheckMerchantReceiveTask");
- }
- }
- package com.easyway.workflow.activiti;
- import java.util.HashMap;
- /**
- *
- * 银行工作人员开始转账过程
- * @author longgangbai
- *
- * 2011-12-17 下午09:39:14
- */
- public class CheckMerchantMoneyTask implements JavaDelegate {
- private final Logger log = Logger.getLogger(CheckMerchantMoneyTask.class.getName());
- @SuppressWarnings("unchecked")
- @Override
- public void execute(DelegateExecution execution) throws Exception {
- log.info("正在转账中.........");
- System.out.println("in : " + execution.getVariables());
- ((HashMap<String, Object>)execution.getVariables().get("in")).put("previous", "CheckMerchantReceiveTask");
- }
- }
- package com.easyway.workflow.activiti;
- import junit.framework.TestCase;
- /**
- * 主要是在测试之前做一些初始化工作,主要包括流程引擎实例
- * 的构建,及其流程提供的基本服务。
- * 目的:让开发者熟悉工作流使用过程使用的几个步骤
- * 1.加载相关的工作流全局配置文件activiti.cfg.xml配置文件信息
- * 2.获取工作流相关的服务(RepositoryService,RuntimeService,
- * TaskService,HistoryService,FormService,ManagementService,
- * IdentityService等)
- * 2.加载工作流文件*.bpmn20.xml信息
- *
- * 3.部署工作流
- * 部署工作流由多种方式,在以后会相继讲解
- *
- * @author longgangbai
- *
- * 2011-12-17 下午07:48:59
- */
- public abstract class AbstractTest extends TestCase {
- private ProcessEngine processEngine;
- protected String deploymentId;
- protected RepositoryService repositoryService;
- protected RuntimeService runtimeService;
- protected TaskService taskService;
- protected FormService formService;
- protected HistoryService historyService;
- protected IdentityService identityService;
- protected ManagementService managementService;
- /**
- * 测试用例开始初始化工作
- * 1.创建相关的工作流程对象ProcessEngine
- * 2.创建相关的服务
- * 3.
- */
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- //由于ProcessEngine为线程安全性对象,整个项目可以共用一个
- if(processEngine==null) {
- //此处使用此种方法调用的activiti的配置文件为 classpath路径下的activiti.cfg.xml
- //采用的H2的数据库
- processEngine = ProcessEngines.getDefaultProcessEngine();
- }
- //获取工作流的各种服务信息
- repositoryService = processEngine.getRepositoryService();
- runtimeService = processEngine.getRuntimeService();
- taskService = processEngine.getTaskService();
- formService = processEngine.getFormService();
- historyService = processEngine.getHistoryService();
- identityService = processEngine.getIdentityService();
- managementService = processEngine.getManagementService();
- //调用扩展的初始化工作
- initialize();
- }
- /**
- * test销毁方法
- */
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- destroy();
- }
- /**
- * 便于子类的工作的初始化的扩展工作
- *
- *
- * @throws Exception
- */
- protected abstract void initialize() throws Exception;
- /**
- * 便于子类的工作的销毁的扩展工作
- *
- * @throws Exception
- */
- protected abstract void destroy() throws Exception;
- }
- /**
- package com.easyway.workflow.activiti;
- import java.util.HashMap;
- /**
- *
- * 自定义测试的工作流的方式
- *
- * @author longgangbai
- *
- * 2011-12-17 下午10:12:54
- */
- public class CustomBankAccountMoneyTaskJunit3Test extends AbstractTest {
- /**
- * 初始化工作流程的方法
- */
- @Override
- protected void initialize() throws Exception {
- Deployment deployment = repositoryService
- .createDeployment()
- .addClasspathResource(
- "com/easyway/workflow/activiti/BankUserTaskActiviti.bpmn20.xml")
- .deploy();
- deploymentId = deployment.getId();
- }
- /**
- * 销毁工作流对象的方法
- */
- @Override
- protected void destroy() throws Exception {
- repositoryService.deleteDeployment(deploymentId, true);
- }
- /**
- * 测试工作流流程的方法
- */
- public void testSubProcess() {
- // prepare data packet
- Map<String, Object> variables = new HashMap<String, Object>();
- Map<String, Object> subVariables = new HashMap<String, Object>();
- variables.put("maxTransCount", 1000000);
- variables.put("merchant", "ICBC");
- variables.put("protocol", "UM32");
- variables.put("repository", "10.10.38.99:/home/shirdrn/repository");
- variables.put("in", subVariables);
- variables.put("out", new HashMap<String, Object>());
- // start process instance
- //将初始化时候创建流程时设置参数
- ProcessInstance pi = runtimeService.startProcessInstanceByKey("BankUserTask", variables);
- List<Execution> executions = runtimeService.createExecutionQuery().list();
- assertEquals(1, executions.size());
- Execution execution = runtimeService.createExecutionQuery().singleResult();
- runtimeService.setVariable(execution.getId(), "type", "receiveTask");
- //同意执行信息发送信号
- runtimeService.signal(execution.getId());
- assertEquals(1, executions.size());
- execution = runtimeService.createExecutionQuery().list().get(0);
- assertNotNull(execution);
- //设置工作流实例对应的变量
- runtimeService.setVariable(execution.getId(), "oper", "shirdrn");
- runtimeService.signal(execution.getId());
- }
- }
采用官方推荐Junit3实现测试如下:
- /**
- package com.easyway.workflow.activiti;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import org.activiti.engine.runtime.Execution;
- import org.activiti.engine.runtime.ProcessInstance;
- import org.activiti.engine.test.ActivitiTestCase;
- import org.activiti.engine.test.Deployment;
- /**
- * 手工触发执行是指,执行到流程中某个个结点后流程暂时停止运行,直到收到外部发送的信号
- * 以后,才会继续向前推进,这样情况可以更加精细地控制流程。
- * 手工触发执行
- * 通过<receiveTask>和<userTask>元素都可以实现流程的手工触发执行。
- *
- *
- * 版本单元测试采用官方推荐的Junit3方式测试Activiti工作流
- * ,必须实现继承自ActivtiTestCase类实现的,默认activiti全局配置文件采用.
- * activiti.cfg.xml并且测试的工作流文件的名称是测试类的名称,
- * ActivitiTestCase 的 protected void setUp()方法调用如下
- * deploymentId = TestHelper.annotationDeploymentSetUp(processEngine, getClass(), getName());
- *
- * TestHelper类调用说明如下:
- *
- * * get a resource location by convention based on a class (type) and a
- * * relative resource name. The return value will be the full classpath
- * * location of the type, plus a suffix built from the name parameter:
- * * <code>.<name>.bpmn20.xml</code>.
- * public static String getBpmnProcessDefinitionResource(Class< ? > type, String name) {
- * return type.getName().replace('.', '/') + "." + name + "." + BpmnDeployer.BPMN_RESOURCE_SUFFIX;
- * }
- *
- * @author longgangbai
- *
- * 2011-12-17 下午09:51:13
- */
- public class CheckBankAccountMoneyTaskJunit3Test extends ActivitiTestCase {
- /**
- * 採用Junit3方式测试工作流中的方法
- */
- @Deployment(resources="com/easyway/workflow/activiti/BankUserTaskActiviti.bpmn20.xml")
- public void testSubProcess() {
- // prepare data packet
- //设置开始执行的工作流的初始化参数
- Map<String, Object> variables = new HashMap<String, Object>();
- Map<String, Object> subVariables = new HashMap<String, Object>();
- variables.put("maxTransCount", 1000000);
- variables.put("merchant", "ICBC");
- variables.put("protocol", "UM32");
- variables.put("repository", "10.10.38.99:/home/shirdrn/repository");
- variables.put("in", subVariables);
- variables.put("out", new HashMap<String, Object>());
- // start process instance
- //根据工作流ID获取工作流引擎实例
- ProcessInstance pi = runtimeService.startProcessInstanceByKey("BankUserTask", variables);
- deploymentId=pi.getProcessDefinitionId();
- System.out.println("deploymentId="+deploymentId);
- //获取中的实例数
- List<Execution> executions = runtimeService.createExecutionQuery().list();
- assertEquals(1, executions.size());
- //查询单个实例
- Execution execution = runtimeService.createExecutionQuery().singleResult();
- //设置运行时服务变量
- runtimeService.setVariable(execution.getId(), "type", "receiveTask");
- //向特定的流程实例发送触发器执行的信号
- runtimeService.signal(execution.getId());
- assertEquals(1, executions.size());
- execution = runtimeService.createExecutionQuery().list().get(0);
- assertNotNull(execution);
- runtimeService.setVariable(execution.getId(), "oper", "shirdrn");
- runtimeService.signal(execution.getId());
- }
- }
采用官方推荐Junit4实现测试如下:
- /**
- package com.easyway.workflow.activiti;
- import static org.junit.Assert.assertEquals;
- /**
- *
- *
- * 工作流模拟的业务情景如下:
- * 1.用户到银行转账业务
- * 2.银行工作人员查询用户余额
- * 3.银行工作人员帮助用户转账
- *
- * 在工作流activiti中使用Junit4测试需要使用ActivitiRule对象,创建各种对象。
- *
- * @author longgangbai
- *
- * 2011-12-17 下午11:17:35
- */
- public class CheckBankAccountMoneyTaskJunit4Test {
- @Rule
- public ActivitiRule activitiRule = new ActivitiRule();
- @Test
- @Deployment(resources="com/easyway/workflow/activiti/BankUserTaskActiviti.bpmn20.xml")
- public void ruleUsageExample() {
- //设置开始执行的工作流的初始化参数
- Map<String, Object> variables = new HashMap<String, Object>();
- Map<String, Object> subVariables = new HashMap<String, Object>();
- variables.put("maxTransCount", 1000000);
- variables.put("merchant", "ICBC");
- variables.put("protocol", "UM32");
- variables.put("repository", "10.10.38.99:/home/shirdrn/repository");
- variables.put("in", subVariables);
- variables.put("out", new HashMap<String, Object>());
- // start process instance
- //根据工作流ID获取工作流引擎实例
- RuntimeService runtimeService = activitiRule.getRuntimeService();
- ProcessInstance pi = runtimeService.startProcessInstanceByKey("BankUserTask", variables);
- String deploymentId=pi.getProcessDefinitionId();
- System.out.println("deploymentId="+deploymentId);
- //获取中的实例数
- List<Execution> executions = runtimeService.createExecutionQuery().list();
- assertEquals(1, executions.size());
- //查询单个实例
- Execution execution = runtimeService.createExecutionQuery().singleResult();
- //设置运行时服务变量
- runtimeService.setVariable(execution.getId(), "type", "receiveTask");
- //向特定的流程实例发送触发器执行的信号
- runtimeService.signal(execution.getId());
- assertEquals(1, executions.size());
- execution = runtimeService.createExecutionQuery().list().get(0);
- assertNotNull(execution);
- runtimeService.setVariable(execution.getId(), "oper", "shirdrn");
- runtimeService.signal(execution.getId());
- }
- }
运行结果如下:
- 2011-12-18 13:08:45 org.activiti.engine.impl.ProcessEngineImpl <init>
- 信息: ProcessEngine default created
- 2011-12-18 13:08:45 org.activiti.engine.impl.jobexecutor.JobAcquisitionThread run
- 信息: <span style="color: #ff0000;">JobAcquisitionThread starting to acquire jobs</span>
- 2011-12-18 13:08:45 org.activiti.engine.impl.bpmn.deployer.BpmnDeployer deploy
- 信息: <span style="color: #ff0000;">Processing resource com/easyway/workflow/activiti/BankUserTaskActiviti.bpmn20.xml</span>
- 2011-12-18 13:08:45 org.activiti.engine.impl.bpmn.parser.BpmnParse parseDefinitionsAttributes
- 信息:<span style="color: #ff0000;"> XMLSchema currently not supported as typeLanguage</span>
- 2011-12-18 13:08:45 org.activiti.engine.impl.bpmn.parser.BpmnParse parseDefinitionsAttributes
- 信息: <span style="color: #ff0000;">XPath currently not supported as expressionLanguage</span>
- 2011-12-18 13:08:46 com.easyway.workflow.activiti.CheckBankAccountMoneyTask execute
- 信息: <span style="color: #ff0000;">根据输入参数,开始检查银行账户余额........</span>
- in : {protocol=UM32, repository=10.10.38.99:/home/shirdrn/repository, merchant=ICBC, maxTransCount=1000000, in={}, out={}}
- deploymentId=BankUserTask:1:1313
- 2011-12-18 13:08:46 com.easyway.workflow.activiti.CheckMerchantMoneyTask execute
- 信息:<span style="color: #ff0000;"> 正在转账中.........</span>
- in : {protocol=UM32, repository=10.10.38.99:/home/shirdrn/repository, merchant=ICBC, maxTransCount=1000000, type=receiveTask, in={}, out={}}