很多同学想入手学一下工作流,但是按着资料集成到项目里了却又不知道该怎么使用,其实不难理解,工作流的目的就是为了能让实施人员便捷的在系统中配置使用审批流程,从这个目的入手,就会有目标了,比如,如何配置一个流程?如何使用这个配置好的流程?如何确定流程节点的审批人?这里会做个简单的代码实现以供参考(前提项目中已整合好activiti)
首先先了解几个名词,模型(可以理解成流程的模板),流程实例(根据模型启动起来的流程实例,一个模型可以关联多个流程实例),流程节点(每个流程实例会有多个节点,跟流程图中的节点对应)。
如果整合好了activiti-Modeler那你肯定能看到模型的创建过程,即ModelEditorJsonRestResource.java的create方法,这里主要说一下怎么把模型跟业务表单关联起来,大多数流程中表单都是动态定制的,所以这边加一个小功能来模拟一下场景,
每条表单记录对应一个html表单,现在要做的是把这个表单记录跟模型关联起来,我们来改造一下模型的创建方法,在原来的基础上多加一个formid参数,然后在保存模型后把模型key和formid存进数据库关联
/**
* 创建模型
*/
@RequestMapping(value = "/process/modeler/create")
@ResponseBody
public Map create(@RequestParam("name") String name, @RequestParam("key") String key,
@RequestParam(value = "description", required = false) String description,@RequestParam("formId") String formId) {
Map res = new HashMap<>();
try {
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode editorNode = objectMapper.createObjectNode();
editorNode.put("id", "canvas");
editorNode.put("resourceId", "canvas");
ObjectNode stencilSetNode = objectMapper.createObjectNode();
stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
editorNode.put("stencilset", stencilSetNode);
ObjectNode modelObjectNode = objectMapper.createObjectNode();
modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, name);
modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
description = StringUtils.defaultString(description);
modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
Model newModel = repositoryService.newModel();
newModel.setMetaInfo(modelObjectNode.toString());
newModel.setName(name);
newModel.setKey(StringUtils.defaultString(key));
repositoryService.saveModel(newModel);
repositoryService.addModelEditorSource(newModel.getId(), editorNode.toString().getBytes("utf-8"));
//绑定数据表单
jdbcTemplate.update("insert into design_process_form (process_type,form_id)values(?,?)",key,formId);
res.put("success",true);
res.put("modelId",newModel.getId());
return res;
} catch (Exception e) {
e.printStackTrace();
}
res.put("success",false);
return res;
}
新建模型页面大概就是这样,“测试表单”就是我们刚才在表单列表看到的那条表单记录
建完模型后的步骤就是画流程图了(这部分使用可以再详细百度一下),这里简单画了一个,审批人 均使用 用户集合的形式,
比如部门领导审批这我们使用#{deptLeader}变量作为审批人,那么后台只要我们在启动流程的时候把该用户对应的部门领导放进variables的变量列表中就行
画好流程图以后就可以正常启动一个流程实例了,下面是我的启动代码,datapojo参数大家不用考虑,这个代表的是我demo里的表单数据,
/**
* 启动一个流程实例
* @param dataPojo 表单数据
* @param processType 流程类型
* @param loginName 登录名
* @return
*/
public ProcessInstance startProcessInstanceByKey(DataPojo dataPojo, String processType, String loginName){
Map variables = new HashMap<>();
variables.put("deptLeader","xiaom,xiaohong");
variables.put("hr","hr01,hr02");
String businessKey = dataPojo.getId(); // 实体类 ID,作为流程的业务 key
// 用来设置启动流程的人员ID,引擎会自动把用户ID保存到activiti:initiator中;会把人员id设置到流程图中启动元素的发起人字段里
identityService.setAuthenticatedUserId(loginName);
ProcessInstance processInstance = runtimeService // 启动流程时设置业务 key
.startProcessInstanceByKey(processType, businessKey,variables);
String processInstanceId = processInstance.getId();
String formId = jdbcTemplateUtil.queryForString("select ifNULL(form_id,'') from design_process_form where process_type=?",processType);
if(StringUtils.isNotEmpty(formId)){
//保存表单数据
jdbcTemplate.update("insert into design_data (data_json,form_id,data_id)values(?,?,?)",dataPojo.getDataJson(),formId,dataPojo.getId());
}
return processInstance;
}
我这里直接把部门领导的审批人写死了,正常业务里应该是根据申请人的部门对应查询出来的。
启动后流程就会按照对应的节点和审批人来自动跑了,首先按照流程定义,第一个节点(申请人报批)应该是出现在申请人的待办里,那么如何来查询一个人的待办列表呢
/**
* 查询待办列表
* @param processType
* @param loginName
* @return
*/
public List
需要注意的是查询待办需要查询两个,一个个人任务,一个组任务,然后再把两个结果集合并到一块,展示到页面就是下面这种
我们点击完成任务,再登录部门领导的账号去看一下,可以看到流程是正确走下去的
我们直接使用对应账号把流程跑完,跑完以后我们按正常的逻辑应该是可以在已办列表里查询到历史流程,那么已办怎么查询呢,
/**
* 查询已办列表
* @param processType
* @param loginName
* @return
*/
public List> doneTaskList(String processType,String loginName){
List> tasks = new ArrayList();
//查询已办任务
List deneList ;
//如果有流程类型就差对应的,没有就查询全部的
if(StringUtils.isNotEmpty(processType)){
deneList = historyService.createHistoricTaskInstanceQuery()
.processDefinitionKey(processType)
.taskAssignee(loginName)
.finished()
.orderByHistoricTaskInstanceEndTime()
.desc()
.list();
}else {
deneList = historyService.createHistoricTaskInstanceQuery()
.taskAssignee(loginName)
.finished()
.orderByHistoricTaskInstanceEndTime()
.desc()
.list();
}
for (HistoricTaskInstance task:deneList) {
HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
String businessKey = processInstance.getBusinessKey();
//根据流程类型和业务id查询表单数据
String dataJson = StringUtils.isNotEmpty(businessKey)?jdbcTemplateUtil.queryForString("select data_json from design_data where data_id=?",businessKey):"";
String template = jdbcTemplateUtil.queryForString("select t.template from design_form t left join design_process_form t2 on t.id=t2.form_id where t2.process_type=?",processInstance.getProcessDefinitionKey());
if(StringUtils.isNotEmpty(dataJson)){
JSONArray arr = null;
try{
arr = JSONArray.parseArray(dataJson);
}catch (Exception e){}
if(arr!=null){
for (int i=0;i data = new HashMap<>();
data.put("data",template);
data.put("data_id",businessKey);
data.put("taskId",task.getId());
data.put("pProcessInstanceId",task.getProcessInstanceId());
data.put("taskName",task.getName());
//获取启动人用户信息
User user = identityService.createUserQuery().userId(processInstance.getStartUserId()).singleResult();
data.put("startUserName",user.getFirstName());
data.put("type","已办");
data.put("createTime",task.getCreateTime());
data.put("claimTime",task.getClaimTime());
tasks.add(data);
}
return tasks;
}
逻辑和待办的基本一样,我们再在页面上加两个记录查看功能,方便看一下流程的历程
比如查询这个流程实例的节点记录
/**
* 根据流程实例id查询历史节点
* @param instanceId
* @return
*/
public List findhisTaskByInstanceId(String instanceId){
List list=historyService // 历史相关Service
.createHistoricTaskInstanceQuery() // 创建历史任务实例查询
.processInstanceId(instanceId) // 用流程实例id查询
.finished() // 查询已经完成的任务
.orderByHistoricTaskInstanceEndTime()
.desc()
.list();
return list;
}
这样就是activiti下简单的一个流程使用步骤了,而且activiti里文档也比较全,正常的一些业务定制使用activiti的几个api也可以简单实现。
总结一下使用步骤就是:创建模型并关联表单---->绘制对应流程图---->启动一个流程实例---->对应人员来审批处理流程---->流程记录归档