前言
这篇文章将主要介绍工作流系统的发布功能,发布功能的旨在将满足bpmn协议的xml文档(流程图定义文件)发布到工作流引擎中,以便工作流引擎可以正常使用本流程图,因此作为工作流系统的首要及核心功能在第二篇文章进行说明。
说明:所有项目配置均在系列第一篇文章中进行介绍,配置系列通用。
系列二内容
发布功能的前端和后端实现
页面展示
功能详细说明
实现方案
说明
根据官方文档介绍,主要实现方案有以下几种:各位在实际使用过程中可以根据自己的实际需求进行实现。
1.加载classpath方式:
DeploymentBuilder addClasspathResource(String resource);
2.InputStream方式(本系列用法):
DeploymentBuilder addInputStream(String resourceName, InputStream inputStream);
3.String方式
DeploymentBuilder addString(String resourceName, String text);
4.Zip方式
DeploymentBuilder addZipInputStream(ZipInputStream zipInputStream);
5.Bpmn模型图方式
DeploymentBuilder addBpmnModel(String resourceName, BpmnModel bpmnModel);
说明:以上五种方式实现效果相同,根据不同方式做不同处理后即可进行发布,若返回正常的deployment对象,则证明发布成功。
发布的统一语法:
Deployment deployment=repositoryService.createDeployment().addInputStream(bpmnUrl, input).deploy();
业务嵌入
由于本系列管理系统,除使用最基本的工作流外,还为了方便业务进行处理,因此加入了业务模块的代码。
当发布成功时,系统会根据发布到工作流引擎(即已经成功发布)的工作流配置中,读取配置信息,生成对应的任务关系图,并保存在业务表的task_def表中,这个表对于业务来说是十分关键的,它更加直接的表明了该流程配置中所有任务环节的基本信息和各环节的逻辑关系,对于之后业务的实现提供了很大遍历。
前端页面展示
后台关键代码
ActivityUtils-getTaskList方法
public static List getTaskList(RepositoryService repositoryService, FlowDef fd) throws Exception{
List listTaskDef = new ArrayList() ;
BpmnModel model = repositoryService.getBpmnModel(fd.getDefId());
if(model != null){
TaskDef tdObject = null;
TaskDef tnObject = null;
Collection flowElements = model.getMainProcess().getFlowElements();
for(FlowElement e : flowElements){
switch (e.getClass().toString()){
case Globals.USER_TASK:
tdObject = new TaskDef() ;
tdObject.setFlowId(fd.getId());
UserTask userTask = (UserTask)e ;
tdObject.setDescription(userTask.getDocumentation());
//方便后续添加,为开放修改任务定义接口做保留
tdObject.setRemark("");
//基本数据
tdObject.setTaskKey(e.getId());
tdObject.setName(e.getName());
tdObject.setType(e.getClass().toString());
listTaskDef.addAll(getTaskNexts(userTask,model,tdObject)) ;
break;
case Globals.PARALLEL_GATEWAY:
ParallelGateway pg = (ParallelGateway)e ;
tdObject = new TaskDef() ;
tdObject.setFlowId(fd.getId());
tdObject.setDescription(pg.getDocumentation());
//方便后续添加,为开放修改任务定义接口做保留
tdObject.setRemark("");
//基本数据
tdObject.setTaskKey(e.getId());
tdObject.setName(e.getName());
tdObject.setType(e.getClass().toString());
listTaskDef.addAll(getTaskNexts(pg, model, tdObject)) ;
break;
case Globals.START_EVENT:
tdObject = new TaskDef() ;
tdObject.setFlowId(fd.getId());
/**
* 思路:先找到startEvent然后一个一个向下找直到找到所有的endEvent
*/
StartEvent se = (StartEvent)e ;
tdObject.setOrderNum(orderNum);
tdObject.setDescription(se.getDocumentation());
//方便后续添加,为开放修改任务定义接口做保留
tdObject.setRemark("");
//基本数据
tdObject.setTaskKey(e.getId());
tdObject.setName(e.getName());
tdObject.setType(e.getClass().toString());
tdObject.setFlowId(fd.getId());
listTaskDef.add(tdObject) ;
listTaskDef.addAll(getTaskNexts(se,model,tdObject)) ;
break;
case Globals.END_EVENT:
EndEvent ee = (EndEvent)e ;
tdObject = new TaskDef() ;
tdObject.setFlowId(fd.getId());
tdObject.setDescription(ee.getDocumentation());
//方便后续添加,为开放修改任务定义接口做保留
tdObject.setRemark("");
//基本数据
tdObject.setTaskKey(e.getId());
tdObject.setName(e.getName());
tdObject.setType(e.getClass().toString());
listTaskDef.addAll(getTaskNexts(ee,model,tdObject)) ;
break;
case Globals.EXCLUSIVE_GATEWAY:
ExclusiveGateway eg = (ExclusiveGateway)e ;
tdObject = new TaskDef() ;
tdObject.setFlowId(fd.getId());
tdObject.setDescription(eg.getDocumentation());
//方便后续添加,为开放修改任务定义接口做保留
tdObject.setRemark("");
//基本数据
tdObject.setTaskKey(e.getId());
tdObject.setName(e.getName());
tdObject.setType(e.getClass().toString());
listTaskDef.addAll(getTaskNexts(eg,model,tdObject)) ;
break;
default:
//需要考虑serviceTask的情况,即自动任务
break;
}
}
}
return listTaskDef;
}
getTaskNexts方法(私有)
//定义全局变量:排序码
private static Long orderNum = 1l;
private static List getTaskNexts(Object o, BpmnModel model, TaskDef tdObject) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//通过反射获取对象中的getOutgoingFlows方法
Class> clazz = Class.forName(o.getClass().getName()) ;
Method method = clazz.getMethod("getOutgoingFlows") ;
List listSF = (List) method.invoke(o) ;
List tnObjects = new ArrayList() ;
TaskDef tnObject = new TaskDef() ;
for(SequenceFlow sf : listSF){
FlowElement fe = model.getFlowElement(sf.getTargetRef()) ;
tnObject = new TaskDef() ;
tnObject.setFlowId(tdObject.getFlowId());
tnObject.setType(fe.getClass().toString());
tnObject.setDescription(fe.getDocumentation());
tnObject.setOrderNum(++orderNum);
tnObject.setExpression(sf.getConditionExpression());
tnObject.setTaskKey(fe.getId());
tnObject.setName(fe.getName());
//这个最重要,把parentKey存入
tnObject.setParentKey(tdObject.getTaskKey());
tnObjects.add(tnObject) ;
}
return tnObjects ;
}
以上就是实现此业务方案的全部代码(附加内容)~
发布功能实现
前端
TableData.vue
deploy(row){
if(row.instanceQuantity !== 0){
this.$Message.warning('此定义下存在正在运行的实例,无法进行发布操作!');
return
}
let id = row.id
deploy({
id:id
}).then(res =>{
if(res.data.responseCode === 1){
this.$Message.success('发布成功!');
}else {
this.$Message.error('发布失败!');
}
this.getTableData() ;
})
}
activityManagement.js
/**发布**/
export const deploy = id => {
return axios.request({
url: 'flowDef/deploy',
params: id,
method: 'post'
})
}
后端
FlowDefController
@RequestMapping("/deploy")
@Transactional
public JsonResult deploy(Long id) throws IOException {
JsonResult jr = new JsonResult() ;
resultMap = new HashMap() ;
InputStream input = null;
try {
FlowDef flowDef = flowDefService.selectByPrimaryKey(id) ;
String bpmnUrl = flowDef.getBpmn() ;
input = new FileInputStream(new File(bpmnUrl));
// 根据bpmn文件部署流程
Deployment deployment = repositoryService.createDeployment().addInputStream(bpmnUrl, input).deploy();
//获取流程定义
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).singleResult();
flowDef.setPublishDate(new Date());
flowDef.setDefId(processDefinition.getId());
flowDef.setVersion(processDefinition.getVersion()+"");
// flowDef.setInstanceQuantity(flowDef.getInstanceQuantity() == null?0:flowDef.getInstanceQuantity());
//正常启用状态
flowDef.setStatus("1");
flowDefService.update(flowDef) ;
//插入任务定义表中(含继承关系)
List taskList = ActivityUtils.getTaskList(repositoryService, flowDef);
//先清空之前所有的task
taskDefService.deleteBatchByFlowId(id);
//而后执行批量插入
taskDefService.insertBatch(taskList) ;
jr.setResponseCode(1);
resultMap.put("data",processDefinition.getId()) ;
jr.setResponseData(resultMap);
jr.setResponseMessage(ResultEnum.SUCCESS);
} catch (Exception e) {
e.printStackTrace();
jr.setResponseCode(0);
jr.setResponseMessage(ResultEnum.EXCEPTION);
}finally {
if(input != null) {
input.close();
}
}
return jr ;
}
总结
至此,有关于发布功能的开发全部完成,其中除工作流本身的API调用之外,还加入了大量业务端实现,以方便管理。各位若对代码有任何不同的意见或建议欢迎下方留言,大家共同进步!
下篇预告
1.工作流初始化参数的配置
2.工作流的启动
3.工作流的执行
敬请期待~~~
第二篇完结~