工作流模拟的业务情景如下:
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=";/spec/BPMN/20100524/MODEL"; xmlns:xsi=";/2001/XMLSchema-instance";
xmlns:activiti=";http://activiti.org/bpmn";
xmlns:bpmndi=";/spec/BPMN/20100524/DI";
xmlns:omgdc=";/spec/DD/20100524/DC";
xmlns:omgdi=";/spec/DD/20100524/DI";
typeLanguage=";/2001/XMLSchema";
expressionLanguage=";/1999/XPath";
targetNamespace=";/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";
sourceRef=";receivetask1";
sourceRef=";receivetask2";
sourceRef=";receivetask1"; targetRef=";receivetask1";>;<;/sequenceFlow>; <;sequenceFlow id=";flow2"; name=";"; targetRef=";receivetask2";>;<;/sequenceFlow>; <;sequenceFlow id=";flow3"; name=";"; targetRef=";endevent1";>;<;/sequenceFlow>; <;sequenceFlow id=";flow4"; name=";";
targetRef=";endevent1";>;<;/sequenceFlow>;
<;/process>;
<;bpmndi:BPMNDiagram id=";BPMNDiagram_BankUserTask";>;
<;bpmndi:BPMNPlane bpmnElement=";BankUserTask"; id=";BPMNPlane_BankUserTask";>;
<;bpmndi:BPMNShape
id=";BPMNShape_startevent1";>;
<;omgdc:Bounds height=";35";
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
id=";BPMNShape_receivetask1";>;
<;omgdc:Bounds height=";55";
y=";210";>;<;/omgdc:Bounds>;
<;/bpmndi:BPMNShape>;
<;bpmndi:BPMNShape
id=";BPMNShape_receivetask2";>;
<;omgdc:Bounds height=";55";
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>; bpmnElement=";receivetask2"; width=";105"; x=";340"; bpmnElement=";receivetask1"; width=";105"; x=";160"; bpmnElement=";startevent1"; width=";35"; x=";76";
<;/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 { } /** * 便于子类的工作的初始化的扩展工作 * * * @throws Exception */ protected abstract void initialize() throws Exception; /** * 便于子类的工作的销毁的扩展工作 * * @throws Exception */ super.tearDown(); destroy();
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>;.&;lt;name&;gt;.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>;
runtimeService.createExecutionQuery().list();
assertEquals(1, executions.size()); //查询单个实例 Execution execution = executions = 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(),
";receiveTask";);
//向特定的流程实例发送触发器执行的信号 runtimeService.signal(execution.getId()); assertEquals(1, executions.size()); execution = runtimeService.createExecutionQuery().list().get(0); ";type";,
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={}}