工作流模拟的业务情景如下:
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
信息: JobAcquisitionThread starting to acquire jobs
2011-12-18 13:08:45 org.activiti.engine.impl.bpmn.deployer.BpmnDeployer deploy
信息: Processing resource com/easyway/workflow/activiti/BankUserTaskActiviti.bpmn20.xml
2011-12-18 13:08:45 org.activiti.engine.impl.bpmn.parser.BpmnParse parseDefinitionsAttributes
信息: XMLSchema currently not supported as typeLanguage
2011-12-18 13:08:45 org.activiti.engine.impl.bpmn.parser.BpmnParse parseDefinitionsAttributes
信息: XPath currently not supported as expressionLanguage
2011-12-18 13:08:46 com.easyway.workflow.activiti.CheckBankAccountMoneyTask execute
信息: 根据输入参数,开始检查银行账户余额........
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
信息: 正在转账中.........
in : {protocol=UM32, repository=10.10.38.99:/home/shirdrn/repository, merchant=ICBC, maxTransCount=1000000, type=receiveTask, in={}, out={}}