前言
本系列在之前的章节中介绍了Activiti工作流管理系统的所有基本操作,包括发布、启动、执行、查看实例等操作。这一篇将是系列的完结篇,介绍最后一个主要功能:流程图的查看。该功能旨在能够实时查看当前流程图所在环节,使得用户能够更加清楚的掌握当前工作流的流转进度,也可以说是本系统的一个必不可少的功能点。闲话少说,进入正题。
系列五内容
流程图的查看
界面展示
说明:以上两处截图,功能模块分别位于流程定义列表和运行实例中的查看流程功能,二者功能主体完全一样,只是传参不同,以下贴出代码并对于不同的部分进行区分,完全相同的部分不再重复贴出代码。
正在运行中实例查看流程图
前端代码
API:activityManagement.js
/**查看流程图(流程运行中)**/
export const showImageActive = params => {
return axios.request({
url:'workflow/showImageActive',
params:params,
method:'get',
headers: {
'Content-Type': 'application/json'
},
responseType: 'arraybuffer'
})
}
/**查看流程图(流程定义列表)**/
export const showImage = params => {
return axios.request({
url:'workflow/showImage',
params:params,
method:'get',
headers: {
'Content-Type': 'application/json'
},
responseType: 'arraybuffer'
})
}
ActiveProcess.vue
<Button type="primary" size="small" @click="showImageActive(row)">查看流程图</Button>
<Modal :closable="false" :mask-closable="false" v-model="imageModal">
<Card>
<div style="display: flex ; align-items: center ;justify-content: center">
<img :src="fileField " width="100%">
</div>
</Card>
<div slot="footer" style="text-align: center">
<Button type="primary" @click="imageModal=false">确定</Button>
</div>
</Modal>
<script>
showImageActive(row){
//不同点:这里是通过流程实例ID进行查询
const processInstanceId = row.processInstanceId ;
//在这执行查看流程图图片操作,打开Modal
showImageActive({
processInstanceId: processInstanceId
}).then(res => {
const data = res.data
this.fileField = 'data:image/png;base64,' + btoa(new Uint8Array(data).reduce((data, byte) => data + String.fromCharCode(byte), ''))
this.imageModal = true ;
}).catch(function (reason) {
that.$Message.error('获取数据异常,打开失败!');
})
}
</script>
后端代码
WorkflowController
/**
* 在页面获取流程图图片
* 适用于运行时查看
* @param processInstanceId
* @return
*/
@RequestMapping("/showImageActive")
public String showImageActive(String processInstanceId, HttpServletResponse response) throws IOException {
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
if(processInstance == null){
return null ;
}
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processInstance.getProcessDefinitionId()).singleResult();
//如果为空,则未找到指定的流程定义对象
if(processDefinition == null){
return null ;
}
List<String> highLightedActivities = runtimeService.getActiveActivityIds(processInstanceId);
BpmnModel model = repositoryService.getBpmnModel(processDefinition.getId()) ;
ProcessDiagramGenerator processDiagramGenerator = new DefaultProcessDiagramGenerator();
//这里需要获取到model
InputStream inputStream = processDiagramGenerator
.generateDiagram(
model,
Globals.ACTIVITY_SUFFIX,
highLightedActivities,
Collections.<String>emptyList(),
Globals.ACTIVITY_FONT, Globals.ACTIVITY_FONT, Globals.ACTIVITY_FONT,
null, Globals.ACTIVITY_SCALE_FACTOR
);
BufferedInputStream bins = new BufferedInputStream(inputStream); //放到缓冲流里面
OutputStream outs = null; //获取文件输出IO流
BufferedOutputStream bouts = null ;
try {
outs = response.getOutputStream();
bouts = new BufferedOutputStream(outs);
int bytesRead = 0;
byte[] buffer = new byte[8192];
//开始向网络传输文件流
while ((bytesRead = bins.read(buffer, 0, 8192)) != -1) {
bouts.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
inputStream.close();
bouts.flush();//这里一定要调用flush()方法
bins.close();
outs.close();
bouts.close();
}
return null;
}
流程定义列表中查看流程图
前端代码
TableData.vue
<Button type="primary" @click="showImage">查看流程图</Button>
<Modal :closable="false" :mask-closable="false" v-model="imageModal">
<Card>
<div style="display: flex ; align-items: center ;justify-content: center">
<img :src="fileField " width="100%">
</div>
</Card>
<div slot="footer" style="text-align: center">
<Button type="primary" @click="imageModal=false">确定</Button>
</div>
</Modal>
<script>
showImage(){
//不同点:这里通过选取行并获取流程定义ID进行查看,其余部分完全一样
const selectRow = this.$refs.selection.getSelection() ;
//catch里无法获取this对象,因此在catch外部先将this对象赋值为that并在catch内部使用
const that = this ;
if(selectRow.length == 1){
const defId = selectRow[0].defId ;
//在这执行查看流程图图片操作,打开Modal
showImage({
defId: defId
}).then(res => {
const data = res.data
this.fileField = 'data:image/png;base64,' + btoa(new Uint8Array(data).reduce((data, byte) => data + String.fromCharCode(byte), ''))
this.imageModal = true ;
}).catch(function (reason) {
that.$Message.error('获取数据异常,打开失败!');
})
}else{
this.$Message.warning('请选中且仅选中唯一一条数据进行查看!') ;
}
}
</script>
后端代码
WorkflowController
/**
* 在页面获取流程图图片
* @param defId
* @return
*/
@RequestMapping("/showImage")
public String showImage(String defId, HttpServletResponse response) throws IOException {
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(defId).singleResult();
//如果为空,则未找到指定的流程定义对象
if(processDefinition == null){
return null ;
}
BpmnModel model = repositoryService.getBpmnModel(processDefinition.getId()) ;
ProcessDiagramGenerator processDiagramGenerator = new DefaultProcessDiagramGenerator();
//这里需要获取到model
InputStream inputStream = processDiagramGenerator.generateDiagram(model, Globals.ACTIVITY_SUFFIX,Globals.ACTIVITY_FONT, Globals.ACTIVITY_FONT, Globals.ACTIVITY_FONT, null, Globals.ACTIVITY_SCALE_FACTOR);
BufferedInputStream bins = new BufferedInputStream(inputStream); //放到缓冲流里面
OutputStream outs = null; //获取文件输出IO流
BufferedOutputStream bouts = null ;
try {
outs = response.getOutputStream();
bouts = new BufferedOutputStream(outs);
int bytesRead = 0;
byte[] buffer = new byte[8192];
//开始向网络传输文件流
while ((bytesRead = bins.read(buffer, 0, 8192)) != -1) {
bouts.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
inputStream.close();
bouts.flush();//这里一定要调用flush()方法
bins.close();
outs.close();
bouts.close();
}
return null;
}
总结
至此,整个系列的内容全部展示说明完毕,关于Activiti工作流管理系统的开发也告一段落。总体而言,Activiti工作流引擎是十分好用的,其操作的便捷性,功能完善性都十分出色。并且结合Activiti在线作图应用,使得工作流作图功能在线化和可视化,方便在实际项目中能够更加方便的使用。
感谢各位大佬对本系列内容的支持,希望各位对此有什么意见或建议都可以在下方留言共同讨论,谢谢大家!