提供的Service方法如下:

Java

/**
* 获取当前任务流程图
*
* @param processInstanceId
* @return
*/
@Override
public InputStream generateDiagram(String processInstanceId) {
//方法中用到的参数是流程实例ID,其实TaskId也可以转为这个。调用taskService查询即可。
Command<InputStream> cmd = new ProcessInstanceDiagramCmd(processInstanceId, runtimeService, repositoryService, processEngine, historyService);
return managementService.executeCommand(cmd);
}

而ProcessInstanceDiagramCmd采用了Activiti的命令模式。就是继承Command接口,其实这个地方完全可以使用纯Service方法去搞定,我之所以这么写,还是受到了国内临远大师的影响。

本次绘制的流程图分为两种情况:1、流程实例还未执行完毕,也就是流程还没有结束,还有运行的任务。2、已经执行完毕的流程,流程已经进入了流程历史。不管属于以上哪种情况的流程图都会绘制流程走向。

具体代码如下:

Java

import com.google.common.collect.Lists;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.activiti.spring.ProcessEngineFactoryBean; import java.io.InputStream;
import java.util.*; /**
* 根据流程实例ID生成流程图
*
* @author Chen Zhiguo
*/
public class ProcessInstanceDiagramCmd implements Command<InputStream> { protected String processInstanceId; private RuntimeService runtimeService; private RepositoryService repositoryService; private ProcessEngineFactoryBean processEngine; private HistoryService historyService; public ProcessInstanceDiagramCmd(String processInstanceId, RuntimeService runtimeService, RepositoryService repositoryService, ProcessEngineFactoryBean processEngine, HistoryService historyService) {
this.processInstanceId = processInstanceId;
this.runtimeService = runtimeService;
this.repositoryService = repositoryService;
this.processEngine = processEngine;
this.historyService = historyService;
} public InputStream execute(CommandContext commandContext) {
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId(processInstanceId).singleResult(); HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); if (processInstance == null && historicProcessInstance == null) {
return null;
} ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) repositoryService
.getProcessDefinition(processInstance == null ? historicProcessInstance.getProcessDefinitionId() : processInstance.getProcessDefinitionId()); BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId()); List<String> activeActivityIds = Lists.newArrayList();
if (processInstance != null) {
activeActivityIds = runtimeService.getActiveActivityIds(processInstance.getProcessInstanceId());
} else {
activeActivityIds.add(historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).activityType("endEvent")
.singleResult().getActivityId());
}
// 使用spring注入引擎请使用下面的这行代码
Context.setProcessEngineConfiguration(processEngine.getProcessEngineConfiguration()); List<String> highLightedFlows = getHighLightedFlows(processDefinition, processInstanceId); InputStream imageStream = new DefaultProcessDiagramGenerator().generateDiagram(bpmnModel, "png", activeActivityIds,
highLightedFlows); return imageStream;
} /**
* getHighLightedFlows
*
* @param processDefinition
* @param processInstanceId
* @return
*/
private List<String> getHighLightedFlows(ProcessDefinitionEntity processDefinition, String processInstanceId) { List<String> highLightedFlows = new ArrayList<String>(); // List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery()
// .processInstanceId(processInstanceId)
// //order by startime asc is not correct. use default order is correct.
// //.orderByHistoricActivityInstanceStartTime().asc()/*.orderByActivityId().asc()*/
// .list();
//上面注释掉的代码是官方的rest方法中提供的方案,可是我在实际测试中有Bug出现,所以做了一下修改。注意下面List内容的排序会影响流程走向红线丢失的问题
List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId)
.orderByHistoricActivityInstanceStartTime().orderByHistoricActivityInstanceEndTime().asc().list();
LinkedList<HistoricActivityInstance> hisActInstList = new LinkedList<HistoricActivityInstance>();
hisActInstList.addAll(historicActivityInstances); getHighlightedFlows(processDefinition.getActivities(), hisActInstList, highLightedFlows); return highLightedFlows;
} /**
* getHighlightedFlows
* <p/>
* code logic:
* 1. Loop all activities by id asc order;
* 2. Check each activity's outgoing transitions and eventBoundery outgoing transitions, if outgoing transitions's destination.id is in other executed activityIds, add this transition to highLightedFlows List;
* 3. But if activity is not a parallelGateway or inclusiveGateway, only choose the earliest flow.
*
* @param activityList
* @param hisActInstList
* @param highLightedFlows
*/
private void getHighlightedFlows(List<ActivityImpl> activityList, LinkedList<HistoricActivityInstance> hisActInstList, List<String> highLightedFlows) { //check out startEvents in activityList
List<ActivityImpl> startEventActList = new ArrayList<ActivityImpl>();
Map<String, ActivityImpl> activityMap = new HashMap<String, ActivityImpl>(activityList.size());
for (ActivityImpl activity : activityList) { activityMap.put(activity.getId(), activity); String actType = (String) activity.getProperty("type");
if (actType != null && actType.toLowerCase().indexOf("startevent") >= 0) {
startEventActList.add(activity);
}
} //These codes is used to avoid a bug:
//ACT-1728 If the process instance was started by a callActivity, it will be not have the startEvent activity in ACT_HI_ACTINST table
//Code logic:
//Check the first activity if it is a startEvent, if not check out the startEvent's highlight outgoing flow.
HistoricActivityInstance firstHistActInst = hisActInstList.getFirst();
String firstActType = (String) firstHistActInst.getActivityType();
if (firstActType != null && firstActType.toLowerCase().indexOf("startevent") < 0) {
PvmTransition startTrans = getStartTransaction(startEventActList, firstHistActInst);
if (startTrans != null) {
highLightedFlows.add(startTrans.getId());
}
} while (!hisActInstList.isEmpty()) {
HistoricActivityInstance histActInst = hisActInstList.removeFirst();
ActivityImpl activity = activityMap.get(histActInst.getActivityId());
if (activity != null) {
boolean isParallel = false;
String type = histActInst.getActivityType();
if ("parallelGateway".equals(type) || "inclusiveGateway".equals(type)) {
isParallel = true;
} else if ("subProcess".equals(histActInst.getActivityType())) {
getHighlightedFlows(activity.getActivities(), hisActInstList, highLightedFlows);
} List<PvmTransition> allOutgoingTrans = new ArrayList<PvmTransition>();
allOutgoingTrans.addAll(activity.getOutgoingTransitions());
allOutgoingTrans.addAll(getBoundaryEventOutgoingTransitions(activity));
List<String> activityHighLightedFlowIds = getHighlightedFlows(allOutgoingTrans, hisActInstList, isParallel);
highLightedFlows.addAll(activityHighLightedFlowIds);
}
}
} /**
* Check out the outgoing transition connected to firstActInst from startEventActList
*
* @param startEventActList
* @param firstActInst
* @return
*/
private PvmTransition getStartTransaction(List<ActivityImpl> startEventActList, HistoricActivityInstance firstActInst) {
for (ActivityImpl startEventAct : startEventActList) {
for (PvmTransition trans : startEventAct.getOutgoingTransitions()) {
if (trans.getDestination().getId().equals(firstActInst.getActivityId())) {
return trans;
}
}
}
return null;
} /**
* getBoundaryEventOutgoingTransitions
*
* @param activity
* @return
*/
private List<PvmTransition> getBoundaryEventOutgoingTransitions(ActivityImpl activity) {
List<PvmTransition> boundaryTrans = new ArrayList<PvmTransition>();
for (ActivityImpl subActivity : activity.getActivities()) {
String type = (String) subActivity.getProperty("type");
if (type != null && type.toLowerCase().indexOf("boundary") >= 0) {
boundaryTrans.addAll(subActivity.getOutgoingTransitions());
}
}
return boundaryTrans;
} /**
* find out single activity's highlighted flowIds
*
* @param pvmTransitionList
* @param hisActInstList
* @param isParallel
* @return
*/
private List<String> getHighlightedFlows(List<PvmTransition> pvmTransitionList, LinkedList<HistoricActivityInstance> hisActInstList, boolean isParallel) { List<String> highLightedFlowIds = new ArrayList<String>(); PvmTransition earliestTrans = null;
HistoricActivityInstance earliestHisActInst = null; for (PvmTransition pvmTransition : pvmTransitionList) { String destActId = pvmTransition.getDestination().getId();
HistoricActivityInstance destHisActInst = findHisActInst(hisActInstList, destActId);
if (destHisActInst != null) {
if (isParallel) {
highLightedFlowIds.add(pvmTransition.getId());
} else if (earliestHisActInst == null || (earliestHisActInst.getId().compareTo(destHisActInst.getId()) > 0)) {
earliestTrans = pvmTransition;
earliestHisActInst = destHisActInst;
}
}
} if ((!isParallel) && earliestTrans != null) {
highLightedFlowIds.add(earliestTrans.getId());
} return highLightedFlowIds;
} private HistoricActivityInstance findHisActInst(LinkedList<HistoricActivityInstance> hisActInstList, String actId) {
for (HistoricActivityInstance hisActInst : hisActInstList) {
if (hisActInst.getActivityId().equals(actId)) {
return hisActInst;
}
}
return null;
}
} 最重要的是在控制层,通过流程实例id获取到流程图的文件流时,通过以下方法可以展示在jsp页面上:
public String viewImage(){
InputStream in = repositoryService.getResourceAsStream.getImageStream(deploymentId,imageName);
//此处方法实际项目应该放在service里面
HttpServletResponse resp = ServletActionContext.getResponse();
try { OutputStream out = resp.getOutputStream(); // 把图片的输入流程写入resp的输出流中
byte[] b = new byte[1024];
for (int len = -1; (len= in.read(b))!=-1; ) {
out.write(b, 0, len);
} // 关闭流
out.close();
in.close(); }
catch (IOException e) {
e.printStackTrace();
}
return null;
}
上面这个方法是控制层的代码,在jsp页面上,使用一个<img>标签来展示流程图
<img src = ""> <img>标签的src属性为上面这个方法的路径

activity通过流程实例id动态获取流程图并展示在jsp页面上的更多相关文章

  1. activiti学习6:启动流程后动态获取流程图

    目录 activiti学习6:启动流程后动态获取流程图 一.绘图原理 二.根据流程定义id绘图 三.根据流程实例id绘图 3.1 基本原理 3.2 当前节点的获取 3.3 走过的节点的获取 3.4 绘 ...

  2. activiti7启动流程实例,动态设置assignee人

    package com.zcc.activiti03; import org.activiti.engine.ProcessEngine;import org.activiti.engine.Proc ...

  3. 根据流程实例ID获取当前任务

    JAVA: Task task = this.processEngine.getTaskService().createTaskQuery().processInstanceId(“132501”). ...

  4. jquery 获取json文件数据,显示到jsp页面上, 或者html页面上

    [{"name":"中国工商银行","code":102},{"name":"中国农业银行",&qu ...

  5. 工作流学习——Activiti流程实例、任务管理四步曲 (zhuan)

    http://blog.csdn.net/zwk626542417/article/details/46646565 ***************************************** ...

  6. Activiti第二篇【管理流程定义、执行任务和流程实例、流程变量】

    上篇Activiti只是一个快速入门案例,这篇就讲定义.部署.查看任务等等的一些细节[涉及到的数据库表.对象等等]- 管理流程定义 管理流程定义主要涉及到以下的4张表: -- 流程部署相关的表 SEL ...

  7. JBPM流程实例(PI)Process Instance

    /** * 流程实例 *    *  启动流程实例 *    *  完成任务 *    *  查询 *      *  查询流程实例 *      *  查询任务 *          *  查询正在 ...

  8. 工作流activiti-03数据查询(流程定义 流程实例 代办任务) 以及个人小练习

    在做数据查询的时候通过调用api来查询数据是相当的简单 对分页也进行了封装listPage(0, 4) ;listPage:分页查询 0:表示起始位置,4:表示查询长度 但是公司的框架封装了分页数据  ...

  9. jBPM学习之利用API完成流程实例

    流程引擎对象ProcessEngine是jBPM4所有的Service API之源.在jBPM4中各种服务相互依存,但所有的Service API都从ProcessEngine中获得,由此可见Proc ...

随机推荐

  1. python获取当前文件路径

    python获取当前文件路径 学习了:https://www.cnblogs.com/strongYaYa/p/7200357.html https://blog.csdn.net/heatdeath ...

  2. UVALive 3971 Assemble(模拟 + 二分)

    UVALive 3971 题意:有b块钱.想要组装一台电脑,给出n个配件的种类,名字,价格,品质因子.若各种类配件各买一个,总价格<=b,求最差品质配件的最大品质因子. 思路: 求最大的最小值一 ...

  3. Splunk 会议回想: 大数据的关键是机器学习

    作者 Jonathan Allen ,译者 张晓鹏 Splunk的用户大会已经接近尾声.三天时间的会议里,共进行了160多个主题研讨.涵盖了从安全.运营到商业智能.甚至包含物联网,会议中一遍又一遍出现 ...

  4. 在FASTBuild中使用Caching

    上一篇:初识FASTBuild 在FASTBuild中使用缓存只需要注意三个环节: 一.设置编译选项 对于GCC\SNC\Clang编译器,没有特殊的要求 对于MSVC编译器,必须设置/Z7调试模式. ...

  5. C++五种迭代器之间的关系

    迭代器操作                      说明(1)所有迭代器p++                              后置自增迭代器++p                     ...

  6. 使用AVPlayer制作一个播放器

    代码地址如下:http://www.demodashi.com/demo/11685.html AVPlayer 是一个强大的视频播放器,可以播放多种格式的视频,缺点是没有控制界面,需要自己去实现. ...

  7. Nginx主动连接与被动连接的差别

    1.主动连接是指Nginx主动发起的同上游server的连接:被动连接是指Nginx接收到的来自client主动发起的连接; 2.主动连接用ngx_peer_connection_t结构体表示:被动连 ...

  8. Matlab、R向量与矩阵操作

    Matlab.R向量与矩阵操作   描    述 Matlab R 1 建立行向量v=[1 2  3 4] v=[1 2 3 4] v<-c(1,2,3,4)或v<-scan(),然后输入 ...

  9. asp.net+mvc+easyui+sqlite 简单用户系统学习之旅(一)—— 手把手教你创建第一个三层架构+mvc的asp.net项目

    下面开启项目 1. 打开vs2010-文件-新建项目 2. 先创建一个空的解决方案: 选择其他项目类型-visual studio 解决方案-空白解决方案(默认.NET Framework 4),项目 ...

  10. wamp通过phpMyAdmin修改登录密码

    初始安装wamp后,默认mysql是没有密码的,这个时候如果想要修改密码,可以按照以下步骤进行: 第一.打开phpMyAdmin,看到界面如图所示: 第二.通过导航找到“用户”,再找到“编辑权限”进行 ...