一、背景
最近工作上有审批需求场景要用到工作流,最终选型还是选择了activity7版本,话不多说,进入主题
二、如何画流程图
1.1 进入activity官网 https://www.activiti.org/get-started
1.2 下载
1.3下载后解压,在war目录下会有3个war包,然后将activiti-app.war 拷贝到我们自己的tomcat的webapp目录下,并启动tomcat
1.4 启动成功,浏览器输入 http://localhost:8080/activiti-app 进入到登录页
默认用户名:admin
默认密码:test
1.5页面默认是英文版,网上搜了下汉化资料,最终效果还可以,如有需要请私信留邮箱。
1.6 新建自己的流程,画好后将流程图进行导出保存在本地,放在项目classpath下,新建processes文件夹xx.bpmn20.xml
三、整合SpringBoot
因为工作流框架自己业务表有23个表,因此,在架构设计的时候考虑将工作流项目与业务系统解耦抽象出来,封装成微服务,其他微服务通过feign来调用工作流接口。
引入依赖:
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
<version>7.1.0.M6</version>
</dependency>
配置文件:
spring:
activiti:
database-schema-update: true //如果表不存在,则Activiti会自动创建
history-level: full //保存历史数据级别设置为full最高级别
db-history-used: true //检测历史表是否存在
单元测试一 部署流程
@Test
public void deployProcess() throws IOException {
String name = "school_apply";
// 1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
//指定clapath路径资源
ClassPathResource classPathResource = new ClassPathResource("processes/school_apply.bpmn20.xml");
InputStream inputStream = classPathResource.getInputStream();
Deployment deployment = repositoryService.createDeployment()
.name(name)
.key(name)
.addInputStream("school_apply.bpmn20.xml",inputStream)
.deploy();
String deploymentId = deployment.getId();
log.info("新文件部署成功:详情 == "+ JSON.toJSONString(deployment.toString()));
}
单元测试二 启动一个流程
@Test
public void testStartProcess() {
// 1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取RunTimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
// 3、根据流程定义的id启动流程
//设置流程变量,流程变量可以用于设置审核人或者审核部门,或者通过变量判断网关从而控制流程走向
Map<String,Object> map = new HashMap<>();
map.put("cityBoardEduDept","10");
ProcessInstance instance = runtimeService.startProcessInstanceByKey(key,"业务唯一编号",map);
// 4、输出内容
System.out.println("流程定义ID:" + instance.getProcessDefinitionId());
System.out.println("流程实例ID:" + instance.getId());
System.out.println("当前活动的ID:" + instance.getActivityId());
//流程定义ID:school_apply:5:76f2b410-dd67-11ec-82b8-52eb71925941
//流程实例ID:df87517b-dd67-11ec-8a94-52eb71925941
//建议启动一个流程后,业务侧也保存一下流程的定义id以及流程实例id
}
单元测试三 查询我的待办
@Test
public void testFindTaskListByProcessId() {
// 1、获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取taskService
TaskService taskService = processEngine.getTaskService();
//根据候选组查询
List<Task> taskList = taskService.createTaskQuery()
.taskCandidateGroup("10").list();
//根据候选人或者分配人去查询待办
List<Task> taskList = taskService.createTaskQuery()
.taskCandidateOrAssigned("1").list();
}
tips: 业务侧可能会需要支持查询条件,并结合工作流数据返回用户当前待办,我在开发时候是这样的思路:
首先根据查询条件去分页查询业务数据库,查询出来的数据组合流程实例id集合,去工作流中过滤查询
单元测试四 处理我的待办
@Test
public void testTaskAssignCityBoardEdu(){
// 1、获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取taskService
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery().
processInstanceId("b43e2736-e08f-11ec-92fa-fa163eb5b637")
.taskCandidateOrAssigned("1")
.singleResult();
Map<String,Object> map = new HashMap<>();
map.put("cityPass",1);
map.put("areaBoardEduDeptUserIds","1");
taskService.addComment(task.getId(),"b43e2736-e08f-11ec-92fa-fa163eb5b637","我这边审批就算过了");//添加审批备注
taskService.claim(task.getId(),"1");//认领当前任务
taskService.complete(task.getId(),map);//完成当前任务,并且设置task的环境变量,可以设置下一个task环境的审核人员id或者部门id
}
单元测试五 根据taskId获取审批备注comment
private String getCommentStrByTaskId(String id) {
List<Comment> comments = taskService.getTaskComments(id);
if(CollectionUtil.isNotEmpty(comments)){
return comments.stream().map(t- >t.getFullMessage()).collect(Collectors.joining(";"));
}
}
单元测试六 根据taskId获取task的环境变量
HistoricVariableInstance nextDeptInstance = historyService.createHistoricVariableInstanceQuery().taskId(t.getId()).variableName("nextDept").singleResult();
String value = (String)nextDeptInstance.getValue());