activity通过流程实例id动态获取流程图并展⽰在jsp页⾯上提供的Service⽅法如下:
Java
/**
* 获取当前任务流程图
*
* @param processInstanceId
* @return
*/
@Override
public InputStream generateDiagram(String processInstanceId) {
//⽅法中⽤到的参数是流程实例ID,其实TaskId也可以转为这个。调⽤taskService查询即可。
Command<InputStream> cmd = new ProcessInstanceDiagramCmd(processInstanceId, runtimeService, repositoryService, processEngine, historyService);
uteCommand(cmd);
}
⽽ProcessInstanceDiagramCmd采⽤了Activiti的命令模式。就是继承Command接⼝,其实这个地⽅完全可以使⽤纯Service⽅法去搞定,我之所以这么写,还是受到了国内临远⼤师的影响。
本次绘制的流程图分为两种情况:1、流程实例还未执⾏完毕,也就是流程还没有结束,还有运⾏的任务。2、已经执⾏完毕的流程,流程已经进⼊了流程历史。不管属于以上哪种情况的流程图都会绘制流程⾛向。
具体代码如下:
Java
llect.Lists;
import org.del.BpmnModel;
import ine.HistoryService;
import ine.RepositoryService;
import ine.RuntimeService;
import ine.history.HistoricActivityInstance;
import ine.history.HistoricProcessInstance;
import t.Context;
import ine.impl.interceptor.Command;
import ine.impl.interceptor.CommandContext;
import ine.ity.ProcessDefinitionEntity;
import ine.impl.pvm.PvmTransition;
import ine.impl.pvm.process.ActivityImpl;
import ine.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 ProcessEngineFactoryBean processEngine;
private HistoryService historyService;
public ProcessInstanceDiagramCmd(String processInstanceId, RuntimeService runtimeService, RepositoryService repositoryService, ProcessEngineFactoryBean processEngine, HistoryService historyService) {
this.processInstanceId = processInstanceId;
this.runtimeService = runtimeService;
this.processEngine = processEngine;
this.historyService = historyService;
}
public InputStream execute(CommandContext commandContext) {
ProcessInstance processInstance = ateProcessInstanceQuery()
.processInstanceId(processInstanceId).singleResult();
HistoricProcessInstance historicProcessInstance =
if (processInstance == null && historicProcessInstance == null) {
return null;
}
ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) repositoryService
.getProcessDefinition(processInstance == null ? ProcessDefinitionId() : ProcessDefinitionId()); BpmnModel bpmnModel = Id());
List<String> activeActivityIds = wArrayList();
if (processInstance != null) {
activeActivityIds = ProcessInstanceId());
} else {
activeActivityIds.ateHistoricActivityInstanceQuery().processInstanceId(processInstanceId).activityType("endEvent")
.singleResult().getActivityId());
}
// 使⽤spring注⼊引擎请使⽤下⾯的这⾏代码
Context.ProcessEngineConfiguration());
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 = ateHistoricActivityInstanceQuery()
// .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 = ateHistoricActivityInstanceQuery().processInstanceId(processInstanceId)
List<HistoricActivityInstance> historicActivityInstances = ateHistoricActivityInstanceQuery().processInstanceId(processInstanceId) .orderByHistoricActivityInstanceStartTime().orderByHistoricActivityInstanceEndTime().asc().list();
LinkedList<HistoricActivityInstance> hisActInstList = new LinkedList<HistoricActivityInstance>();
hisActInstList.addAll(historicActivityInstances);
Activities(), 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.Id(), activity);
String actType = (String) Property("type");
if (actType != null && LowerCase().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 = First();
String firstActType = (String) ActivityType();
if (firstActType != null && LowerCase().indexOf("startevent") < 0) {
PvmTransition startTrans = getStartTransaction(startEventActList, firstHistActInst);
if (startTrans != null) {
highLightedFlows.Id());
}
}
while (!hisActInstList.isEmpty()) {
HistoricActivityInstance histActInst = veFirst();
ActivityImpl activity = (ActivityId());
if (activity != null) {
boolean isParallel = false;
String type = ActivityType();
if ("parallelGateway".equals(type) || "inclusiveGateway".equals(type)) {
isParallel = true;
} else if ("subProcess".ActivityType())) {
Activities(), hisActInstList, highLightedFlows);
}
List<PvmTransition> allOutgoingTrans = new ArrayList<PvmTransition>();
allOutgoingTrans.OutgoingTransitions());
allOutgoingTrans.addAll(getBoundaryEventOutgoingTransitions(activity));
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 : OutgoingTransitions()) {
if (Destination().getId().ActivityId())) {
return trans;
}
}
}
return null;
}
/**
* getBoundaryEventOutgoingTransitions
*
* @param activity
* @return
*/
private List<PvmTransition> getBoundaryEventOutgoingTransitions(ActivityImpl activity) {
List<PvmTransition> boundaryTrans = new ArrayList<PvmTransition>();
for (ActivityImpl subActivity : Activities()) {
String type = (String) Property("type");
if (type != null && LowerCase().indexOf("boundary") >= 0) {
boundaryTrans.OutgoingTransitions());
}
}
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 = Destination().getId();
HistoricActivityInstance destHisActInst = findHisActInst(hisActInstList, destActId);
if (destHisActInst != null) {
if (isParallel) {
highLightedFlowIds.Id());
} else if (earliestHisActInst == null || (Id()Id()) > 0)) {
} else if (earliestHisActInst == null || (Id()Id()) > 0)) { earliestTrans = pvmTransition;
earliestHisActInst = destHisActInst;
}
}
}
if ((!isParallel) && earliestTrans != null) {
highLightedFlowIds.Id());
}
return highLightedFlowIds;
}
private HistoricActivityInstance findHisActInst(LinkedList<HistoricActivityInstance> hisActInstList, String actId) { for (HistoricActivityInstance hisActInst : hisActInstList) {
if (ActivityId().equals(actId)) {
return hisActInst;
}
}
return null;
}
}
最重要的是在控制层,通过流程实例id获取到流程图的⽂件流时,通过以下⽅法可以展⽰在jsp页⾯上:
createprocessapublic String viewImage(){
InputStream in = ImageStream(deploymentId,imageName);
//此处⽅法实际项⽬应该放在service⾥⾯
HttpServletResponse resp = Response();
try { OutputStream out = OutputStream(); // 把图⽚的输⼊流程写⼊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属性为上⾯这个⽅法的路径
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论