什么是工作流
工作流(Workflow),就是通过计算机对业务流程自动化执行管理。它主要解决的是“使在多个参与者之间按照某种预定义的规则自动进行传递文档、信息或任务的过程,从而实现某个预期的业务目标,或者促使此目标的实现”。
什么是 Activiti7
1)Activiti 介绍
Activiti 是一个工作流引擎,activiti 可以将业务系统中复杂的业务流程抽取出来,使用专门的建模语言(BPMN2.0)进行定义,业务系统按照预先定义的流程进行执行,实现了业务系统的业务流程由 activiti 进行管理,减少业务系统由于流程变更进行系统升级改造的工作量,从而提高系统的健壮性,同时也减少了系统开发维护成本。官方网站:https://www.activiti.org/
2)BPMN
BPMN(Business Process Model And Notation)- 业务流程模型和符号是由 BPMI(Business Process Management Initiative)开发的一套标准的业务流程建模符号,使用 BPMN 提供的符号可以创建业务流程。
Activiti 就是使用 BPMN 2.0 进行流程建模、流程执行管理,它包括很多的建模符号,比如:Event 用一个圆圈表示,它是流程中运行过程中发生的事情。
一个 bpmn 图形的例子:
- 首先当事人发起一个请假单
- 其次他所在部门的经理对请假单进行审核
- 然后人事经理进行复核并进行备案
- 最后请假流程结束
Activit 如何使用
1)部署 activiti
Activiti 是一个工作流引擎(其实就是一堆 jar 包 API),业务系统使用 activiti 来对系统的业务流程进行自动化管理,为了方便业务系统访问(操作)activiti 的接口或功能,通常将 activiti 环境与业务系统的环境集成在一起。
2)流程定义
使用 activiti 流程建模工具 (activity-designer) 定义业务流程(.bpmn 文件)。.bpmn 文件就是业务流程定义文件,通过 xml 定义业务流程。
3)流程定义部署
向 activiti 部署业务流程定义(.bpmn 文件)。使用 activiti 提供的 api 向 activiti 中部署.bpmn 文件(一般情况还需要一块儿部署业务流程的图片.png)
4)启动一个流程实例(ProcessInstance)
启动一个流程实例表示开始一次业务流程的运行,比如员工请假流程部署完成,如果张三要请假就可以启动一个流程实例,如果李四要请假也启动一个流程实例,两个流程的执行互相不影响,就好比定义一个 java 类,实例化两个对象一样,部署的流程就好比 java 类,启动一个流程实例就好比 new 一个 java 对象。
5)用户查询待办任务 (Task)
因为现在系统的业务流程已经交给 activiti 管理,通过 activiti 就可以查询当前流程执行到哪了,当前用户需要办理什么任务了,这些 activiti 帮我们管理了
6)用户办理任务
用户查询待办任务后,就可以办理某个任务,如果这个任务办理完成还需要其它用户办理,比如采购单创建后由部门经理审核,这个过程也是由 activiti 帮我们完成了,不需要我们在代码中硬编码指定下一个任务办理人了。
7)流程结束
当任务办理完成没有下一个任务 / 结点了,这个流程实例就完成了。
Activiti 入门体验
1. 安装 Activiti Designer 插件
在 IDEA 的 File 菜单中找到子菜单”Settings”, 后面我们再选择左侧的“plugins”菜单,搜索 actiBPM 插件,安装成功后如下图所示:
重启 IDEA 就可以使用了
2. 数据库表的命名规则
Activiti 的表都以 ACT_开头。第二部分是表示表的用途的两个字母标识。用途也和服务的 API 对应。
- ACT_RE_*: ‘RE’ 表示 repository。这个前缀的表包含了流程定义和流程静态资源(图片,规则,等等)。
- ACT_RU_*: ‘RU’ 表示 runtime。这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。Activiti 只在流程实例执行过程中保存这些数据,在流程结束时就会删除这些记录。这样运行时表可以一直很小速度很快。
- ACT_HI_*: ‘HI’ 表示 history。这些表包含历史数据,比如历史流程实例,变量,任务等等。
- ACT_GE_*:GE 表示 general。通用数据,用于不同场景下。
3.ProcessEngine
工作流引擎,相当于一个门面接口,通过 ProcessEngineConfiguration 创建 processEngine,通过 ProcessEngine 创建各个 service 接口。
- RepositoryService
是 activiti 的资源管理类,提供了管理和控制流程发布包和流程定义的操作。使用工作流建模工具设计的业务流程图需要使用此 service 将流程定义文件的内容部署到计算机 - RuntimeService
它是 activiti 的流程运行管理类。可以从这个服务类中获取很多关于流程执行相关的信息 - TaskService
是 activiti 的任务管理类。可以从这个类中获取任务的信息 - HistoryService
是 activiti 的历史管理类,可以查询历史信息,执行流程时,引擎会保存很多数据(根据配置),比如流程实例启动时间,任务的参与者,完成任务的时间,每个流程实例的执行路径,等等。这个服务主要通过查询功能来获得这些数据。 - ManagementService
是 activiti 的引擎管理类,提供了对 Activiti 流程引擎的管理和维护功能,这些功能不在工作流驱动的应用程序中使用,主要用于 Activiti 系统的日常维护
4. 新建流程
1)首先选中存放图形的目录(选择 resources 下的 bpmn 目录),点击菜单:New-BpmnFile
2)绘制流程
3)指定任务负责人
4)搭建工作流项目,部署流程定义,参考 https://segmentfault.com/a/11…,要将上边绘制的图形即流程定义(.bpmn)部署在工作流程引擎 activiti 中
/**
* 流程定义的部署
* activiti 表有哪些?* act_re_deployment 部署信息
* act_re_procdef 流程定义的一些信息
* act_ge_bytearray 流程定义的 bpmn 文件及 png 文件
*/
@Test
public void createDeploy() {RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("diagram/holiday.bpmn")// 添加 bpmn 资源
.addClasspathResource("diagram/holiday.png")
.name("请假申请单流程")
.deploy();
log.info("流程部署 id:" + deployment.getName());
log.info("流程部署名称:" + deployment.getId());
}
执行此操作后 activiti 会将上边代码中指定的 bpm 文件和图片文件保存在 activiti 数据库。
5)启动一个流程实例
流程定义部署在 activiti 后就可以通过工作流管理业务流程了,也就是说上边部署的请假申请流程可以使用了。
针对该流程,启动一个流程表示发起一个新的请假申请单,这就相当于 java 类与 java 对象的关系,类定义好后需要 new 创建一个对象使用,当然可以 new 多个对象。
对于请假申请流程,张三发起一个请假申请单需要启动一个流程实例,李四发起一个请假单也需要启动一个流程实例。
/**
* 启动流程实例:
* 前提是先已经完成流程定义的部署工作
* <p>
* 背后影响的表:* act_hi_actinst 已完成的活动信息
* act_hi_identitylink 参与者信息
* act_hi_procinst 流程实例
* act_hi_taskinst 任务实例
* act_ru_execution 执行表
* act_ru_identitylink 参与者信息
* act_ru_task 任务
*/
@Test
public void startProcessInstance() {RuntimeService runtimeService = processEngine.getRuntimeService();
// 启动流程实例
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("holiday");
log.info("流程定义 ID:" + processInstance.getProcessDefinitionId());
log.info("流程实例 ID:" + processInstance.getId());
}
6)任务查询
流程启动后,各各任务的负责人就可以查询自己当前需要处理的任务,查询出来的任务都是该用户的待办任务。
/**
* 查询当前用户的任务列表
*/
@Test
public void findPersonalTaskList() {TaskService taskService = processEngine.getTaskService();
// 根据流程定义的 key, 负责人 assignee 来实现当前用户的任务列表查询
List<Task> taskList = taskService.createTaskQuery()
.processDefinitionKey("holiday")
.taskAssignee("张三")
.list();
for (Task task : taskList) {System.out.println("-----------------------");
System.out.println("流程实例 ID:" + task.getProcessInstanceId());
System.out.println("任务 ID:" + task.getId());
System.out.println("任务负责人:" + task.getAssignee());
System.out.println("任务名称:" + task.getName());
}
}
7)任务处理
任务负责人查询待办任务,选择任务进行处理,完成任务。
/**
* 处理当前用户的任务
* 背后操作的表:* act_hi_actinst
* act_hi_identitylink
* act_hi_taskinst
* act_ru_identitylink
* act_ru_task
*/
@Test
public void completeTask() {
String processDefinitionKey = "holiday";
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery().processDefinitionKey(processDefinitionKey)
.taskAssignee("张三").singleResult();
if(task != null){
// 处理任务, 结合当前用户任务列表的查询操作的话
taskService.complete(task.getId());
log.info("处理完成当前用户的任务");
}else{log.info("当前用户暂无任务");
}
}
8)查询历史
@Test
public void queryHistory() {HistoryService historyService = processEngine.getHistoryService();
RepositoryService repositoryService = processEngine.getRepositoryService();
// 查询流程定义
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
String processDefinitionKey = "holiday";
// 遍历查询结果
ProcessDefinition processDefinition = processDefinitionQuery.processDefinitionKey(processDefinitionKey)
.orderByProcessDefinitionVersion().desc().singleResult();
if (processDefinition != null) {HistoricActivityInstanceQuery query = historyService.createHistoricActivityInstanceQuery();
List<HistoricActivityInstance> list = query.processDefinitionId(processDefinition.getId())
.orderByHistoricActivityInstanceStartTime().asc().list();// 排序 StartTime
for (HistoricActivityInstance ai : list) {System.out.println(ai.getActivityId());
System.out.println(ai.getActivityName());
System.out.println(ai.getProcessDefinitionId());
System.out.println(ai.getProcessInstanceId());
System.out.println("==============================");
}
}
}