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

图例

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
 */@Componentpublic 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 后面追加流程IDhttp://localhost:8080/traceprocess/20190214


上一篇:activiti流程变量的设置和获取


下一篇:【安富莱专题教程第4期】SEGGER的J-Scope波形上位机软件,HSS模式简单易用,无需额外资源,也不需要写目标板代码