Activiti开发案例之代码生成工作流图片
图例

环境
| 软件 | 版本 |
|---|---|
| SpringBoot | 1.5.10 |
| activiti-spring-boot-starter-basic | 6.0 |
生成代码
以下是简化代码:
/**
* 查看实例流程图,根据流程实例ID获取流程图
*/
@RequestMapping(value="traceprocess/{instanceId}",method=RequestMethod.GET)
public void traceprocess(HttpServletResponse response,@PathVariable("instanceId")String instanceId) throws Exception{
InputStream in = flowUtils.getResourceDiagramInputStream(instanceId);
ServletOutputStream output = response.getOutputStream();
IOUtils.copy(in, output);
}
Flow 工具类:
/**
* Flow 工具类
* @author zhipeng.zhang
*/
@Component
public class FlowUtils {
@Autowired
RuntimeService runservice;
@Autowired
private HistoryService historyService;
@Autowired
private RepositoryService repositoryService;
@Autowired
private ProcessEngineFactoryBean processEngine;
/**
* 获取历史节点流程图
* @param id
* @return
*/
public InputStream getResourceDiagramInputStream(String id) {
try {
// 获取历史流程实例
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult();
// 获取流程中已经执行的节点,按照执行先后顺序排序
List<HistoricActivityInstance> historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery().processInstanceId(id).orderByHistoricActivityInstanceId().asc().list();
// 构造已执行的节点ID集合
List<String> executedActivityIdList = new ArrayList<String>();
for (HistoricActivityInstance activityInstance : historicActivityInstanceList) {
executedActivityIdList.add(activityInstance.getActivityId());
}
// 获取bpmnModel
BpmnModel bpmnModel = repositoryService.getBpmnModel(historicProcessInstance.getProcessDefinitionId());
// 获取流程已发生流转的线ID集合
List<String> flowIds = this.getExecutedFlows(bpmnModel, historicActivityInstanceList);
// 使用默认配置获得流程图表生成器,并生成追踪图片字符流
ProcessDiagramGenerator processDiagramGenerator = processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator();
//你也可以 new 一个
//DefaultProcessDiagramGenerator processDiagramGenerator = new DefaultProcessDiagramGenerator();
InputStream imageStream = processDiagramGenerator.generateDiagram(bpmnModel, "png", executedActivityIdList, flowIds, "宋体", "微软雅黑", "黑体", null, 2.0);
return imageStream;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private List<String> getExecutedFlows(BpmnModel bpmnModel, List<HistoricActivityInstance> historicActivityInstances) {
// 流转线ID集合
List<String> flowIdList = new ArrayList<String>();
// 全部活动实例
List<FlowNode> historicFlowNodeList = new LinkedList<FlowNode>();
// 已完成的历史活动节点
List<HistoricActivityInstance> finishedActivityInstanceList = new LinkedList<HistoricActivityInstance>();
for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
historicFlowNodeList.add((FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstance.getActivityId(), true));
if (historicActivityInstance.getEndTime() != null) {
finishedActivityInstanceList.add(historicActivityInstance);
}
}
// 遍历已完成的活动实例,从每个实例的outgoingFlows中找到已执行的
FlowNode currentFlowNode = null;
for (HistoricActivityInstance currentActivityInstance : finishedActivityInstanceList) {
// 获得当前活动对应的节点信息及outgoingFlows信息
currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivityInstance.getActivityId(), true);
List<SequenceFlow> sequenceFlowList = currentFlowNode.getOutgoingFlows();
/**
* 遍历outgoingFlows并找到已已流转的
* 满足如下条件认为已已流转:
* 1.当前节点是并行网关或包含网关,则通过outgoingFlows能够在历史活动中找到的全部节点均为已流转
* 2.当前节点是以上两种类型之外的,通过outgoingFlows查找到的时间最近的流转节点视为有效流转
*/
FlowNode targetFlowNode = null;
if (BpmsActivityTypeEnum.PARALLEL_GATEWAY.getType().equals(currentActivityInstance.getActivityType())
|| BpmsActivityTypeEnum.INCLUSIVE_GATEWAY.getType().equals(currentActivityInstance.getActivityType())) {
// 遍历历史活动节点,找到匹配Flow目标节点的
for (SequenceFlow sequenceFlow : sequenceFlowList) {
targetFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(sequenceFlow.getTargetRef(), true);
if (historicFlowNodeList.contains(targetFlowNode)) {
flowIdList.add(sequenceFlow.getId());
}
}
} else {
List<Map<String, String>> tempMapList = new LinkedList<Map<String,String>>();
// 遍历历史活动节点,找到匹配Flow目标节点的
for (SequenceFlow sequenceFlow : sequenceFlowList) {
for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
if (historicActivityInstance.getActivityId().equals(sequenceFlow.getTargetRef())) {
tempMapList.add(UtilMisc.toMap("flowId", sequenceFlow.getId(), "activityStartTime", String.valueOf(historicActivityInstance.getStartTime().getTime())));
}
}
}
// 遍历匹配的集合,取得开始时间最早的一个
long earliestStamp = 0L;
String flowId = null;
for (Map<String, String> map : tempMapList) {
long activityStartTime = Long.valueOf(map.get("activityStartTime"));
if (earliestStamp == 0 || earliestStamp >= activityStartTime) {
earliestStamp = activityStartTime;
flowId = map.get("flowId");
}
}
flowIdList.add(flowId);
}
}
return flowIdList;
}
}
UtilMisc 工具类:
public class UtilMisc {
public static <V, V1 extends V, V2 extends V> Map<String, V> toMap(String name1, V1 value1, String name2, V2 value2) {
return populateMap(new HashMap<String, V>(), name1, value1, name2, value2);
}
@SuppressWarnings("unchecked")
private static <K, V> Map<String, V> populateMap(Map<String, V> map, Object... data) {
for (int i = 0; i < data.length;) {
map.put((String) data[i++], (V) data[i++]);
}
return map;
}
}
工作流枚举类:
/**
* 工作流枚举类
* @author zhipeng.zhang
*/
public enum BpmsActivityTypeEnum {
START_EVENT("startEvent", "开始事件"),
END_EVENT("endEvent", "结束事件"),
USER_TASK("userTask", "用户任务"),
EXCLUSIVE_GATEWAY("exclusiveGateway", "排他网关"),
PARALLEL_GATEWAY("parallelGateway", "并行网关"),
INCLUSIVE_GATEWAY("inclusiveGateway", "包含网关");
private String type;
private String name;
private BpmsActivityTypeEnum(String type, String name) {
this.type = type;
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
浏览器直接发送以下格式请求,就可以查看实时流程图:
# traceprocess 后面追加流程ID
http://localhost:8080/traceprocess/20190214
Activiti开发案例之代码生成工作流图片的更多相关文章
- Activiti开发案例之activiti-app工作流导出图片
前言 自从 Activiti 和 JBPM4 分家以后,Activiti 目前已经发展到了版本7,本着稳定性原则我们最终选择了6,之前还有一个版本5. 问题 在开发使用的过程中发现 Activiti ...
- Activiti 开发案例之动态指派任务
流程图 以上是一个请假的流程图,以下为流程任务节点描述: 员工发起请假流程 部门经理审批 同意则进入人事审批 拒绝则调整申请或者直接结束流程 人事审批通过则进入销假环节 人事审批拒绝则调整申请或者直接 ...
- Activiti开发案例之activiti-app更换数据源
前言 由于Activiti 默认使用的数据库是H2数据库,重启服务后相关数据会丢失.为了永久保存,所以要配置关系型数据库,这里我们选择 SqlServer ,有钱任性. 环境 Activiti6,Sq ...
- 百度UEditor开发案例(JSP)
本案例的开发环境:MyEclipse+tomcat+jdk 本案例的开发内容: 用百度编辑器发布新闻(UEditor的初始化开发部署) 编辑已发过的新闻(UEditor的应用——编辑旧文章) ...
- webpack打包多html开发案例新
闲来无事在原来简单打包案例的基础上,参考vue-cli的打包代码,改为多文件打包. 区别于上篇文章<webpack打包多html开发案例>,此次打包根据开发的不同环节进行打包,也就是有开发 ...
- 《实战突击:PHP项目开发案例整合(第2版)(含DVD光盘1张)》
<实战突击:PHP项目开发案例整合(第2版)(含DVD光盘1张)> 基本信息 作者: 徐康明 辛洪郁 出版社:电子工业出版社 ISBN:9787121221378 上架时间:2014 ...
- 前端到后台ThinkPHP开发整站--php开发案例
前端到后台ThinkPHP开发整站--php开发案例 总结 还是需要做几个案例,一天一个为佳,那样才能做得快. 从需求分析着手,任务体系要构建好,这样才能非常高效. 转自: 前端到后台ThinkPHP ...
- Bootstrap手机网站开发案例
Bootstrap手机网站开发案例 一.总结 一句话总结:Bootstrap手机网站开发注意事项(3点):a.引入viewpoint声明,b.通过屏幕宽动态控制元素显隐 c.图片添加自适应 1.Boo ...
- iOS开发系列--无限循环的图片浏览器
--UIKit之UIScrollView 概述 UIKit框架中有大量的控件供开发者使用,在iOS开发中不仅可以直接使用这些控件还可以在这些控件的基础上进行扩展打造自己的控件.在这个系列中如果每个控件 ...
随机推荐
- 安装虚拟机,磁盘选择厚置备延迟置零与厚置备置零和Thin Provision有什么区别
(1)厚置备延迟置零: (2)厚置备置零: (3)Thin Provision(精简置备). 这三种类型的磁盘,每一种类型的磁盘创建的方式和磁盘性能都有所不同,具体解释如下.1.厚置备延迟置零举例,本 ...
- Solr 14 - SolrJ操作SolrCloud集群 (Solr的Java API)
目录 1 pom.xml文件的配置 2 SolrJ操作SolrCloud 1 pom.xml文件的配置 项目的pom.xml依赖信息请参照: Solr 09 - SolrJ操作Solr单机服务 (So ...
- RDIFramework.NET V3.3 WinForm版新增日程管理功能模块
功能描述 日程管理基于月.周.日的日历视图,把安排到每一天的具体时间点,让每一天的时间都充分利用:甚至您也可以把个人非工作事项也安排进来,完全是属于自己的全时间管理.就是将每天的工作和事务安排在日期中 ...
- springcloud情操陶冶-初识springcloud
许久之前便听到了springcloud如雷贯耳的大名,但是不曾谋面,其主要应用于微服务的相关架构.笔者对微服务并不是很了解,但其既然比较出众,遂也稍微接触研究下 springcloud特性 sprin ...
- 基础设施DevOps演进之路
Related Links:Zuul https://github.com/Netflix/zuulCAT https://github.com/dianping/cat Apollo h ...
- I/O输入流基础之FileInputStream
InputStream:是所有字节输入流的父类,其作用是:用这个流把网络数据(getOutputStream()),文件系统的数据读入内存 由与 public abstract class Inpu ...
- Saslauthd服务实现SMTP发信认证
一.SMTP发信认证 通过sasl库中的saslauthd服务实现SMTP认证 二.部署 1.先安装postifx 略 2.生成sasl配置文件,实现使用sasl认证 vim /usr/lib64/s ...
- spring boot拦截器中获取request post请求中的参数
最近有一个需要从拦截器中获取post请求的参数的需求,这里记录一下处理过程中出现的问题. 首先想到的就是request.getParameter(String )方法,但是这个方法只能在get请求中取 ...
- vue学习记录①(vue-cli脚手架构建项目结构)
我们直接从vue的工程化开始入手. 在这里用git命令行搭建项目环境.(当然直接cmd命令行下也是一样的) git下载安装地址:https://www.git-scm.com/download/win ...
- 006. SSO 单点登录(同域SSO/跨域SSO)
SSO 单点登录:一次登录,处处登录. 只需在一个登录认证服务下进行登录后,就可访问所有相互信任的应用 同域 SSO 1. session-cookie机制:服务端通过cookie认证客户端. 用户第 ...