1、JBPM4-回退
回退指的是用户主动回退到当前任务的上一流程节点(上一步骤)。
- 应用场景示例:
当前用户接收任务后,发现这个任务不该由他办理或者这个任务存在严重的业务问题,这时就需要回退给上一步的办理者重新办理。 - 解决方案:
(1)定义【回退监听器】:
回退监听器接收一个参数,用于指定回退目的地的活动 ID。之所以这样设计是因为,回退的出发地与目的地可能相隔着多个活动。这个参数也可以设计为流程变量,这样可以在流程运行时动态算出。然后在需要回退时,动态创建一条转移路径,退回到目的地。
(2)添加【回退监听器】
在流程定义中识别 “需要具有回退能力” 的任务,为具有回退功能的任务活动设置专门用于处理回退逻辑的监听器。
(3)定义【回退任务】API:
如果回退操作造成业务 “损失”,那么就必须在【回退任务】API 中予以补偿;如果需要清除 “历史痕迹”,那么在【回退任务】API 还需要删除相关的历史记录。
2、实例
2.1 流程图及JPDL文件
对应的JPDL文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<process name="testProcess" xmlns="http://jbpm.org/4.4/jpdl">
<swimlane candidate-groups="anhui" name="anhui"/>
<start g="-6,173,72,48" name="start1">
<transition g="-22,-25" name="to 申请" to="申请"/>
</start>
<end g="1129,60,82,51" name="end1"/>
<task g="91,166,102,56" name="申请" swimlane="anhui">
<transition name="to 审批" to="审批" g="-22,-18"/>
</task>
<task g="257,168,109,52" name="审批" swimlane="anhui">
<!-- 为【审批】活动添加具有回退到【申请】功能的监听器 - 监听器定义见2.2节-->
<on event="start">
<event-listener class="com.math.jbpm.util.RollbackListener">
<field name="rollbackTo">
<string value="申请"/>
</field>
</event-listener>
</on>
<transition name="to end" to="end" g="-25,-20"/>
</task>
<end g="417,169,48,48" name="end"/>
</process>
2.2 定义【回退监听器】- java 实现
RollbackListener 是定义的回退监听器,它会根据注入的 rollbackTo 参数值来动态生成一条通向回退目的地的转移路径。定义如下:
import org.apache.log4j.Logger;
import org.jbpm.api.ProcessInstance;
import org.jbpm.api.listener.EventListener;
import org.jbpm.api.listener.EventListenerExecution;
import org.jbpm.pvm.internal.model.ActivityImpl;
import org.jbpm.pvm.internal.model.ProcessDefinitionImpl;
import org.jbpm.pvm.internal.model.TransitionImpl;
/**
* 工作流任务回退监听器
* @author rmling
*/
public class RollbackListener implements EventListener{
public Logger logger = Logger.getLogger(RollbackListener.class);
/**回退的目的地*/
private String rollbackTo ;
@Override
public void notify(EventListenerExecution execution) throws Exception {
//获取流程定义对象
ProcessInstance processInstance = execution.getProcessInstance();
ProcessDefinitionImpl processDefinition = (ProcessDefinitionImpl)JbpmUtil.getProcessEngine().processEngine
.createProcessDefinitionQuery()
.processDefinitionId(processInstance.getProcessDefinitionId())
.uniqueResult();
//获取退回目的地活动的定义对象
ActivityImpl toActivityImpl = processDefinition.findActivity(rollbackTo);
if(toActivityImpl == null){//退回目的地不存在
String mes = "在此"+processInstance.getProcessDefinitionId()+" 流程中不存在 "+rollbackTo+"活动";
logger.error(mes);
throw new Exception(mes);
}
//获取当前活动的定义对象
ActivityImpl fromActivityImpl = (ActivityImpl) execution.getActivity();
//建立退回路径
TransitionImpl transition1 = fromActivityImpl.createOutgoingTransition();
System.out.println("transition:"+fromActivityImpl.getName()+" to "+rollbackTo);
transition1.setName(fromActivityImpl.getName()+" to "+rollbackTo);
transition1.setDestination(toActivityImpl);
}
}
2.3 【回退】任务API
/**
* 任务回退
* @param taskID
* @param rollbackToActivityName
*/
public void completedTaskRollback(String taskID, String rollbackToActivityName) {
Task task = JbpmUtil.taskService.getTask(taskID);
if(task != null){
if(rollbackToActivityName != null){
JbpmUtil.taskService.completeTask(task.getId(),task.getName()+" to "+rollbackToActivityName);
}else{
JbpmUtil.taskService.completeTask(task.getId());
}
logger.info("-- 工作流"+processID+" 任务 '"+task.getName()+"' 已完成 --");
}
}
2.4 主测试函数
public static void main(String[] args) {
User user = createTestUser();
//初始化工作流
ProcessForJbpm process = new ProcessForJbpm("com/math/jbpm/test/rollback/","testProcess",ProcessType.Unknown);
process.startProcessInstance(111111l,null);
//工作流启动
process.startTask(user);
// start->申请->审批->end
try {
//申请
Task task = process.findActiveTask();
System.out.println(" -- 当前任务:"+task.getName());
System.out.println(" -- 结束任务:"+task.getName());
process.completedTask(null, user.getId(), user.getName());
task = process.findActiveTask();
//审批
System.out.println(" -- 当前任务:"+task.getName());
System.out.println(" -- 假设【审批】未通过,任务回退");
System.out.println("outcomes:"+process.getTaskOutcomes(task.getId()).toString());
//假设【审批】未通过,回退到【申请】
process.completedTaskRollback(task.getId(),"申请",user.getId(),user.getName());
task = process.findActiveTask();
System.out.println("outcomes:"+process.getTaskOutcomes(task.getId()).toString());
//【审批】通过,结束任务
process.completedTask(null, user.getId(), user.getName());
} catch (Exception e) {
System.err.println(e.getMessage());
}
//关闭工作流
process.closedProcess();
}
测试函数输出结果如下(工作流自身日志没截取,只截取了部分流程日志):
1、当前任务:【申请】
2、结束任务【申请】,进入【审批】任务
3、【审批】任务添加了【回退】监听器,此时,假设【审批】未通过,回退到【申请】任务
4、结束【回退】任务后,进入【审批】任务
5、结束【审批】任务, 工作流结束
2.5 其他相关函数定义
/**完成任务函数*/
public void completedTask(String outboundTransName, String userID, String userName) {
Task task = findTask(userID, false);
if(task != null){
if(outboundTransName != null){
JbpmUtil.taskService.completeTask(task.getId(),outboundTransName);
}else{
JbpmUtil.taskService.completeTask(task.getId());
}
}
}
/** 获取一个任务的所有外向转移名称
* @param taskId*/
public Set<String> getTaskOutcomes(String taskId){
return JbpmUtil.taskService.getOutcomes(taskId);
}
/**获取当前激活的所有活动名称*/
public Set<String> findActiveActivityNames() {
return JbpmUtil.executionService.createProcessInstanceQuery().processInstanceId(processID).uniqueResult().findActiveActivityNames();
}
/**获取工作流中当前正在进行的任务 */
public Task findActiveTask(){
return JbpmUtil.taskService.createTaskQuery().processInstanceId(processID).uniqueResult();
}
import org.hibernate.Session;
import org.jbpm.api.Configuration;
import org.jbpm.api.Deployment;
import org.jbpm.api.ExecutionService;
import org.jbpm.api.HistoryService;
import org.jbpm.api.ProcessEngine;
import org.jbpm.api.RepositoryService;
import org.jbpm.api.TaskService;
/**
* 工作流工具类
* @author mling
*/
public class JbpmUtil {
/**流程引擎*/
public static ProcessEngine processEngine;
/**流程管理:流程模板的部署、查询、删除*/
public static RepositoryService repositoryService;
/**流程执行:设置流程实例的发起、执行*/
public static ExecutionService executionService;
/**任务服务*/
public static TaskService taskService;
/**历史服务*/
public static HistoryService historyService;
public static Session session;
static{
//流程定义引擎的初始化
processEngine = Configuration.getProcessEngine();
//管理流程定义
repositoryService = processEngine.getRepositoryService();
//executionService 用于执行流程定义实例
executionService = processEngine.getExecutionService();
//任务服务
taskService = processEngine.getTaskService();
//历史服务
historyService = processEngine.getHistoryService();
//由于JBPM4没有清除历史数据的服务API直接提供,所以这里要获取的是Hibernate Session对象
session = processEngine.get(Session.class);
}
}