也谈一下Activiti工作流节点的自由跳转

那么怎么办呢?我想说的是,Activiti的封装做得很厚,想完全看懂是太难的。目前我还没想完全看懂,直接吐槽一下,与后人分享其中的痛苦:

public static void setCommandContext(CommandContext commandContext) {getStack(commandContextThreadLocal).push(commandContext); }

总之,代码看得那是相当郁闷!debug的时候,调用栈极其深,而且大部分都会落在如下两段代码中:

代码1:

public <T> T execute(CommandConfig config, Command<T> command) {if (!log.isDebugEnabled()) {// do nothing here if we cannot logreturn next.execute(config, command);}log.debug("\n");log.debug("— starting {} ——————————————————–", command.getClass().getSimpleName());try {return next.execute(config, command);} finally {log.debug("— {} finished ——————————————————–", command.getClass().getSimpleName());log.debug("\n");} }

代码2:

try {// Push on stackContext.setCommandContext(context);Context.setProcessEngineConfiguration(processEngineConfiguration);return next.execute(config, command);} catch (Exception e) {context.exception(e);} finally {try {if (!contextReused) {context.close();}} finally {// Pop from stackContext.removeCommandContext();Context.removeProcessEngineConfiguration();}}看到那么多的next没?足够让人疯掉的*_*

由于时间关系,我没有细细的去理解每个类,,但最终还是找出了一个极妙、极安全的方法,那就是:自己写Command!然后扔给CommandExecutor()了事!

最终形成的代码如下所示:

package org.openwebflow.ctrl;import org.activiti.engine.ProcessEngine;import org.activiti.engine.TaskService;import org.activiti.engine.impl.RuntimeServiceImpl;import org.activiti.engine.impl.interceptor.Command;import org.activiti.engine.impl.interceptor.CommandContext;import org.activiti.engine.impl.persistence.entity.ExecutionEntity;import org.activiti.engine.impl.persistence.entity.TaskEntity;import org.activiti.engine.impl.pvm.process.ActivityImpl;import org.openwebflow.util.ActivityUtils;public class TaskFlowControlService{ProcessEngine _processEngine;private String _processId;public TaskFlowControlService(ProcessEngine processEngine, String processId){_processEngine = processEngine;_processId = processId;}/** * 跳转至指定活动节点 * * @param targetTaskDefinitionKey * @throws Exception */public void jump(String targetTaskDefinitionKey) throws Exception{TaskEntity currentTask = (TaskEntity) _processEngine.getTaskService().createTaskQuery().processInstanceId(_processId).singleResult();jump(currentTask, targetTaskDefinitionKey);}/** * * @param currentTaskEntity *当前任务节点 * @param targetTaskDefinitionKey *目标任务节点(在模型定义里面的节点名称) * @throws Exception */private void jump(final TaskEntity currentTaskEntity, String targetTaskDefinitionKey) throws Exception{final ActivityImpl activity = ActivityUtils.getActivity(_processEngine,currentTaskEntity.getProcessDefinitionId(), targetTaskDefinitionKey);final ExecutionEntity execution = (ExecutionEntity) _processEngine.getRuntimeService().createExecutionQuery().executionId(currentTaskEntity.getExecutionId()).singleResult();final TaskService taskService = _processEngine.getTaskService();//包装一个Command对象((RuntimeServiceImpl) _processEngine.getRuntimeService()).getCommandExecutor().execute(new Command<java.lang.Void>(){@Overridepublic Void execute(CommandContext commandContext){//创建新任务execution.setActivity(activity);execution.executeActivity(activity);//删除当前的任务//不能删除当前正在执行的任务,所以要先清除掉关联currentTaskEntity.setExecutionId(null);taskService.saveTask(currentTaskEntity);taskService.deleteTask(currentTaskEntity.getId(), true);return null;}});}}代码源码地址在https://github.com/bluejoe2008/openwebflow/blob/master/src/main/java/org/openwebflow/ctrl/TaskFlowControlService.java

最后写了一个测试类,代码如下:

@Testpublic void testTaskSequence() throws Exception{//_processDef对应于vacationRequest流程,参见https://github.com/bluejoe2008/openwebflow/blob/master/models/test.bpmnProcessInstance instance = _processEngine.getRuntimeService().startProcessInstanceByKey(_processDef.getKey());String instanceId = instance.getId();TaskService taskService = _processEngine.getTaskService();Task task1 = taskService.createTaskQuery().singleResult();Assert.assertEquals("step2", task1.getTaskDefinitionKey());Map<String, Object> vars = new HashMap<String, Object>();vars.put("vacationApproved", false);vars.put("numberOfDays", 10);vars.put("managerMotivation", "get sick");String taskId = taskService.createTaskQuery().taskCandidateUser("kermit").singleResult().getId();taskService.complete(taskId, vars);Task task2 = taskService.createTaskQuery().singleResult();Assert.assertEquals("adjustVacationRequestTask", task2.getTaskDefinitionKey());TaskFlowControlService tfcs = new TaskFlowControlService(_processEngine, instanceId);//跳回至 step2tfcs.jump("step2");Task task3 = taskService.createTaskQuery().singleResult();Assert.assertEquals("step2", task3.getTaskDefinitionKey());//确认权限都拷贝过来了//management可以访问该taskAssert.assertEquals(1, taskService.createTaskQuery().taskCandidateGroup("management").count());//engineering不可以访问该taskAssert.assertEquals(0, taskService.createTaskQuery().taskCandidateGroup("engineering").count());//确认历史轨迹里已保存List<HistoricActivityInstance> activities = _processEngine.getHistoryService().createHistoricActivityInstanceQuery().processInstanceId(instanceId).list();Assert.assertEquals(5, activities.size());Assert.assertEquals("step1", activities.get(0).getActivityId());Assert.assertEquals("step2", activities.get(1).getActivityId());Assert.assertEquals("requestApprovedDecision", activities.get(2).getActivityId());Assert.assertEquals("adjustVacationRequestTask", activities.get(3).getActivityId());Assert.assertEquals("step2", activities.get(4).getActivityId());//测试一下往前跳tfcs.jump("adjustVacationRequestTask");Task task4 = taskService.createTaskQuery().singleResult();Assert.assertEquals("adjustVacationRequestTask", task4.getTaskDefinitionKey());activities = _processEngine.getHistoryService().createHistoricActivityInstanceQuery().processInstanceId(instanceId).list();Assert.assertEquals(6, activities.size());Assert.assertEquals("adjustVacationRequestTask", activities.get(5).getActivityId());_processEngine.getRuntimeService().deleteProcessInstance(instanceId, "test");}完整的测试代码见https://github.com/bluejoe2008/openwebflow/

你是自由的,不仅是身体上的自由,

也谈一下Activiti工作流节点的自由跳转

相关文章:

你感兴趣的文章:

标签云: