以前采用jbpm编写流程,后来决定采用activiti在新系统中进行流程实现,所以重新编写了流程历史图形展示
[list=1]
首先需要获取流程定义图
ByteArrayOutputStream os = new ByteArrayOutputStream();
InputStream is = getProcessEngine().getRepositoryService().getProcessDiagram(processDefinitionId);
try {
new BASE64Encoder().encode(is, os);
is.close();
} catch (Exception e) {
;
}
String image = os.toString();
将image缓存起来备用
读取流程定义信息,获取流程节点信息 基于BPMN2.0的Activiti流程图定义是以xml形式记录的,内容中不仅保存了流程信息,还保存了流程图示信息,我们可以解析流程图示信息,用于之后流程节点的展示
我们定义如下的流程图
它的xml定义为
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema"
expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
<process id="process1" name="process1">
<startEvent id="startevent1" name="Start"></startEvent>
<endEvent id="endevent1" name="End"></endEvent>
<userTask id="usertask1" name="User Task1"></userTask>
<sequenceFlow id="flow1" name="" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>
<sequenceFlow id="flow2" name="" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow>
<userTask id="usertask2" name="User Task2"></userTask>
<sequenceFlow id="flow3" name="" sourceRef="usertask2" targetRef="endevent1"></sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_process1">
<bpmndi:BPMNPlane bpmnElement="process1" id="BPMNPlane_process1">
<bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
<omgdc:Bounds height="35" width="35" x="70" y="20"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
<omgdc:Bounds height="35" width="35" x="70" y="260"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
<omgdc:Bounds height="55" width="105" x="35" y="90"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2">
<omgdc:Bounds height="55" width="105" x="35" y="170"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
<omgdi:waypoint x="87" y="55"></omgdi:waypoint>
<omgdi:waypoint x="87" y="90"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
<omgdi:waypoint x="87" y="145"></omgdi:waypoint>
<omgdi:waypoint x="87" y="170"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
<omgdi:waypoint x="87" y="225"></omgdi:waypoint>
<omgdi:waypoint x="87" y="260"></omgdi:waypoint>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
其中bpmndi:BPMNDiagram记录了流程图示信息,bpmndi:BPMNShape记录节点,omgdc:Bounds记录节点的位置和大小信息,我们只需要通过sax解析该xml文件,即可获得节点图示信息
InputStream is = getProcessEngine().getRepositoryService().getProcessModel(processDefinitionId);
try {
SAXParserFactory.newInstance().newSAXParser().parse(is, new DefaultHandler() {
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
switch (qName) {
case SHAPE:
n = attributes.getValue(SHAPE_NAME);
ds = new Double[4];
break;
case BOUND:
if (ds != null) {
ds[0] = Double.parseDouble(attributes.getValue("x"));
ds[1] = Double.parseDouble(attributes.getValue("y"));
ds[2] = Double.parseDouble(attributes.getValue("width"));
ds[3] = Double.parseDouble(attributes.getValue("height"));
}
break;
default:
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.equals(SHAPE)) {
// TODO 存储节点图示信息
// k = processDefinitionId + n
// v = ds
n = null;
ds = null;
}
}
private static final String SHAPE = "bpmndi:BPMNShape";
private static final String SHAPE_NAME = "bpmnElement";
private static final String BOUND = "omgdc:Bounds";
private String n;
private Double[] ds;
});
} catch (Exception e) {
e.printStackTrace();
}
在代码的TODO部分,将节点图示信息缓存起来备用
展示流程运行情况 通过activiti api获取历史审核情况
HistoricTaskInstanceQuery taskQuery = getProcessEngine().getHistoryService().createHistoricTaskInstanceQuery();
taskQuery.processInstanceId(processInstanceId);
List<HistoricTaskInstance> list = taskQuery.list();
for (HistoricTaskInstance taskInstance : list) {
Double[] shape = getShape(processDefinitionId, taskInstance.getTaskDefinitionKey()); // TODO 从缓存获取节点图示信息
taskInstance.getAssignee();
taskInstance.getStartTime();
taskInstance.getEndTime();
}
在代码的TODO部分,从缓存获取节点图示信息;
并且可以从taskInstance获取节点审核相关信息,这些信息就可以用于在页面上通过html进行展示
页面上,由于流程定义图已经以base64编码,所以可以直接用
展示,而审核历史节点,则采用<div style="left:px,top:px,width:px,height:px"></div>以position:absolute;展示在流程定义图上
由于流程图上的节点可能有圆角,所以css上还需要加上radius来展示
实际使用效果如图
我们还可以 除了审核历史节点,还可以通过taskquery查询等待审核的节点,以不同的效果展现
我们还可以在鼠标放到节点上的时候,展示节点的审核信息,如审核人、审核时间、审核意见和办结花费时间等
由于流程审核过程可能比较复杂,所以还可以作一个过程展示,按审核顺序依次加亮审核节点,用于过程展示
[/list]