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开发中不仅可以直接使用这些控件还可以在这些控件的基础上进行扩展打造自己的控件.在这个系列中如果每个控件 ...
随机推荐
- 重新发现MATLAB
现场编辑 创建不仅捕获代码的脚本 - 它们讲述了可以与他人共享的故事.自动化的上下文提示可让您在编程时快速移动,并将结果和可视化与代码一起显示. 学到更多 访问MATLAB实时脚本库 ...
- jquery.data()&jquery.extend()
JQuery.data()方法 Jquery提供的在节点存取数据的方法. var $el = $('#app'); //使用键值对的方式存数据 $el.data('name', 'jinx'); $e ...
- [Swift-2019力扣杯春季决赛]3. 最长重复子串
给定字符串 S,找出最长重复子串的长度.如果不存在重复子串就返回 0. 示例 1: 输入:"abcd" 输出:0 解释:没有重复子串. 示例 2: 输入:"abbaba& ...
- swagger文档转换为WebApiClient声明式代码
1 swagger简介 Swagger是一个规范且完整的框架,提供描述.生产.消费和可视化RESTful Web Service.其核心是使用json来规范描述RESTful接口,另外有提供UI来查看 ...
- Asp.Net Core 轻松学-项目目录和文件作用介绍
前言 上一章介绍了 Asp.Net Core 的前世今生,并创建了一个控制台项目编译并运行成功,本章的内容介绍 .NETCore 的各种常用命令.Asp.Net Core MVC 项目文件目录 ...
- 你所忽略的DNS---DNS实战及深度解读
很多人没有dns的概念,或者仅仅知道dns负责解析从域名到ip地址,这对普通人来说,也许是够的,但对于开发者来说,就远远不够了. 很多中高级开发者的眼中的DNS是这样的(以百度为例): 读取hosts ...
- 以太坊工作原理之txpool详解
txpool详解 交易池txpool作为区块链系统的重要组成部分,对系统的安全性和稳定性具有重要作用.功能可归纳为:交易缓存.交易验证和交易过滤. 基本介绍 交易分类和缓存 txpool主要包含两个重 ...
- c#进阶一:使用ILDASM来查看c#中间语言
平时工作的时候总是使用ctrl c+ctrl v去快速开发实现业务功能,但是在工作之余,我们也应该要注意静下心来去学习和提高自己.进阶的文章随性来写,不定时更新.希望可以和大家共同学习,共同进步.今天 ...
- oracle锁表与解表
查看锁表进程SQL语句1: select sess.sid, sess.serial#, lo.oracle_username, lo.os_user_name, ao.object_name, lo ...
- java的设计模式 - 静态工厂方法
静态工厂方法,也不知道为何叫这个名字.其实也就是一个静态函数,可以替代构造函数用.大名鼎鼎的 guava 就大量使用这种模式,这是非常有用的模式. 比如是 Integer i = Integer.va ...