该笔记是看黑马程序员课程,自己跟着敲记录的,可以去下载老师的笔记更全
百度网盘地址: https://pan.baidu.com/s/1rii67cdsIt_Y9p1lWQCcJg 提取码:506g
目录
一、activiti理解
工作流(Workflow),就是通过计算机对业务流程自动化执行管理。它主要解决的是“使在多个参与者之间按照某种预定义的规则自动进行传递文档、信息或任务的过程,从而实现某个预期的业务目标,或者促使此目标的实现”。
一个软件系统中具有工作流的功能,我们把它称为工作流系统,一个系统中工作流的功能是什么?就是对系统的业务流程进行自动化管理,所以工作流是建立在业务流程的基础上,所以一个软件的系统核心根本上还是系统的业务流程,工作流只是协助进行业务流程管理。即使没有工作流业务系统也可以开发运行,只不过有了工作流可以更好的管理业务流程,提高系统的可扩展性。
用BPMN的符号来定义我们的流程,定义好后的流程,可以用activiti提供的接口来简化开发。
二、开发准备
1、idea安装activiti插件
安装插件 actiBPM
1、在idea搜不到这个插件,直接去官网
链接: https://plugins.jetbrains.com/plugin/7429-actibpm/versions
2、idea从文件夹安装下载的插件jar包
三、java开发、理解部分
1、activiti环境
1)、引入activiti相关依赖
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-engine</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<!-- bpmn 模型处理-->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-model</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-converter</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<!-- bpmn json数据转换-->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-json-converter</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<!-- bpmn 布局-->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-layout</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<!-- activiti云支持-->
<dependency>
<groupId>org.activiti.cloud</groupId>
<artifactId>activiti-cloud-services-api</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
2)、activiti配置文件
在resources下创建activiti.cfg.xml
文件,用于生成activiti表
注意要有mysql的相关依赖,才能连接
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 在默认方式下 bean的id 固定为processEngineConfiguration-->
<bean id="processEngineConfiguration"
class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<!-- 配置数据库相关信息-->
<!-- 数据库驱动-->
<property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
<!-- 数据库连接-->
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/activiti?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC&nullCatalogMeansCurrent=true" />
<!-- 数据库账号密码-->
<property name="jdbcUsername" value="root" />
<property name="jdbcPassword" value="123456" />
<!-- activiti:数据库在生成时的策略 true:如果数据库中已经存在相应的表,要么直接使用,如果不存在,会创建-->
<property name="databaseSchemaUpdate" value="true" />
</bean>
</beans>
3)、activiti工具类生成25张表
public static void main(String[] args) {
// 需要使用activiti提供的工具类 ProcessEngine,使用getDefaultProcessEngine方法
// getDefaultProcessEngine会默认从resource底下读取名字为activiti.cfg.xml
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
System.out.println("defaultProcessEngine = " + defaultProcessEngine);
}
遇到报Cause: java.sql.SQLSyntaxErrorException: Table ‘myactiviti.act_ge_property’ doesn’t exist错的,在数据库url加上nullCatalogMeansCurrent=true
.
url:
jdbc:mysql://localhost:3306/activiti?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC&nullCatalogMeansCurrent=true
4)、理解activiti表
_ge
: general 通用表,用在各种情况下
_hi
: history 历史记录,保存的都是历史数据,比如执行过的流程实例、变量、任务,等等。Activit默认提供了4种历史级别
_re
: repository 仓库,保存一些‘静态’信息,如流程定义和流程资源(如图片、规则等)
_ru
: runtime 运行时,保存一些流程实例、用户任务、变量等的运行时数据。Activiti只保存流程实例在执行过程中的运行时数据,并且当流程结束后会立即移除这些数据,这是为了保证运行时表尽量的小并运行的足够快;
表分类 | 表名称 | 表含义 |
---|---|---|
. | act_evt_log | 事件处理日志表 |
一般数据 | act_ge_bytearray | 通用的流程定义和流程资源 |
. | act_ge_property | 系统相关属性 |
流程历史记录 | act_hi_actinst | 历史的流程实例 |
. | act_hi_attachment | 历史的流程附件 |
. | act_hi_comment | 历史的说明性信息 |
. | act_hi_detail | 历史的流程运行中的细节信息 |
. | act_hi_identitylink | 历史的流程运行过程中用户关系 |
. | act_hi_procinst | 历史的流程实例 |
. | act_hi_varinst | 历史的流程运行中的变量信息 |
用户用户组表 | act_procdef_info | 死信任务 |
流程定义表 | act_re_deployment | 部署单元信息 |
. | act_re_model | 模型信息 |
. | act_re_procdef | 已部署的流程定义 |
运行实例表 | act_ru_deadletter_job | 执行失败任务表 |
. | act_ru_event_subscr | 运行时事件 |
. | act_ru_execution | 运行时流程执行实例 |
. | act_ru_identitylink | 运行时用户关系信息 |
. | act_ru_job | 运行时作业 |
. | act_ru_suspended_job | 运行时暂停任务 |
. | act_ru_task | 运行时任务 |
. | act_ru_timer_job | 运行时定时任务 |
. | act_ru_variable | 运行时变量表 |
2、activiti类关系图
1)、类关系图
新版IdentityService,FormService两个Serivce都已经删除了
2)、工作流引擎创建
1、默认方式
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
System.out.println("defaultProcessEngine = " + defaultProcessEngine);
2、一般创建方式
//先构建ProcessEngineConfiguration
ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
// 通过ProcessEngineConfiguration创建ProcessEngine,此时会创建数据库
ProcessEngine processEngine = configuration.buildProcessEngine();
3)、Service服务接口
1、Service创建方式
RuntimeService runtimeService = processEngine.getRuntimeService();
RepositoryService repositoryService = processEngine.getRepositoryService();
TaskService taskService = processEngine.getTaskService();
2、Service总览
service名称 | service作用 |
---|---|
RepositoryService | activiti的资源管理类 : 流程仓库服务,管理流程仓库,比如部署、删除、读取流程资源 |
RuntimeService | activiti的流程运行管理类 : 运行服务,处理所有正在运行态的流程实例、任务等。 |
TaskService | activiti的任务管理类 : 任务服务,管理(签收、办理、指派等)、查询任务。 |
HistoryService | activiti的历史管理类 : 历史服务,管理所有历史数据 |
ManagerService | activiti的引擎管理类 : 引擎管理服务,和具体业务无关,管理引擎。 |
3、activiti入门、操作
创建activiti工作流主要包含以下几步:
1、定义流程,按照BPMN的规范,使用流程定义工具,用流程符号把整个流程描述出来
2、部署流程,把画好的流程定义成文件,加载到数据库中,生成表的数据
3、启动流程,使用java代码操作数据库表中的内容
1)、流程符号
排他网关(x)
只有一条路径会被选择。流程执行到该网关时,按照输出流的顺序逐个计算,当条件的计算结果为true时,继续执行当前网关的输出流;
如果多条线路计算结果都是true,则会执行第一个值为true的线路。如果所有网关计算结果没有true,则引擎会抛出异常。
排他网关需要和条件顺序流结合使用,default属性指定默认顺序流,当所有的条件不满足时会执行默认顺序流
并行网关(+)
所有路径会被同时选择
.
拆分-----并行执行所有输出顺序流,为每一条顺序流创建一个并行执行线路
.
合并-----所有从并行网关拆分并执行完成的线路均在此等候,直到所有的线路都执行完成才继续向下执行
包容网关(+)
可以同时执行多条线路,也可以在网关上设置条件
.
拆分----计算每条线路上的表达式,当表达式计算结果为true时,创建一个并行线路并继续执行。
.
合并----所有从并行网关拆分并执行完成的线路均在此等候,直到所有的线路都执行完成才继续向下执行
事件网关(+)
专门为中间捕获事件设置的,允许设置多个输出流指向多个不同的中间捕获事件。当流程执行到事件网关后,流程处于等待状态,需要等待抛出事件才能将等待状态转换为活动状态。
2)、actiBPM使用
1、new–>bpmn文件
2、双击文件打开视图
3、拉取一个开始事件
4、再拉取Usertask,并取名Name、和受让人Assignee (Assignee 受让人:很重要,后面需要用这个查询这个人的任务列表)
5、再创建一个经理审批,并取名Name、和受让人Assignee
6、结束
流程可以自己设多一点,这里只做最简单的展示
7、流向
点住中间往下拖
8、点击空白,为流程指定key
和name
(很重要,后面的流程需要这个key当参数去查这个流程)
9、导出Png图片
拷贝一份bpmn文件,修改后缀名为.xml
右键查看视图,如果没有Diagrams,点击File–>settings–>Plugins–>UML勾上,重启
点击导出png
3)、解决中文乱码
还有c盘配置文件也加上
-Dfile.encoding=UTF-8
4)、流程部署实现(将定义好的流程写到数据库)
代码
/**
* 将流程保存到数据库
*/
public static void main(String[] args) {
// 1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取RespositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3、使用service进行流程的部署,定义一个流程的名字,把bpmn和png部署到数据库中
Deployment deploy = repositoryService.createDeployment().name("出差申请") // 设置名称
.addClasspathResource("bpmn/evection.bpmn20.xml") // 加入我们的bpmn文件
.addClasspathResource("bpmn/evection.png")
.deploy();
// 4、输出部署信息
System.out.println("流程部署id="+deploy.getId());
System.out.println("流程部署name="+deploy.getName());
}
看输出信息主要操作了
总操作四张表
act_ge_property —— 修改系统相关属性
act_re_procdef ——流程定义表
act_re_deployment ——流程部署表:每部署一次会增加一条记录
act_ge_bytearray ——流程资源表
5)、开启流程示例
开启这个按钮
刚刚部署的流程添加到了流程定义表,通过key启动流程
key就是我们在上方创建流程的第8步
/**
* 开始这个流程任务
* @param args
*/
public static void main(String[] args) {
// 1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取RunTimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
// 3、根据流程定义的id启动流程
/**
* 参数1:流程定义的key
* 参数2:businessKey,存出差申请单的id
*/
ProcessInstance evection = runtimeService.startProcessInstanceByKey("evection","1001");
// 4、输出内容
System.out.println("流程定义id " + evection.getProcessDefinitionId());
System.out.println("流程示例id " + evection.getId());
System.out.println("当前活动的id " + evection.getActivityId());
}
activiti只有流程的操作,并没有我们流程中具体的字段,如出差申请:出差时间,出差目的地等信息都没有,下一步审批的人的没有信息看,不能审批
主要操作就是在 创建流程实例时,把业务表id(businessKey)添加到activiti表
6)、查询个人待执行的任务
可以查出这个人有什么任务待执行,任务id
taskAssignee(“hmb”)就是我们创建流程第4步的受让人Assignee
/**
* 获取个人待执行任务
* @param args
*/
public static void main(String[] args) {
// 1、获取流程执行引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取taskService
TaskService taskService = processEngine.getTaskService();
// 3、根据流程key 和 任务的负责人 查询任务
List<Task> list = taskService.createTaskQuery().processDefinitionKey("evection") // 流程的key
.taskAssignee("hmb") // 要查询的负责人
.list();// 任务集合
// 4、输出
for (Task task:list){
System.out.println("流程示例id = " + task.getProcessDefinitionId());
System.out.println("任务id = " + task.getId());
System.out.println("任务的负责人 = " + task.getAssignee());
System.out.println("任务的名称 = " + task.getName());
}
}
主要执行了这个sql
7)、完成个人任务
通过任务id完成任务(就是上一步查出来的待执行的任务id)
/**
* 完成个人任务
*/
public static void main(String[] args) {
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取taskService
TaskService taskService = processEngine.getTaskService();
// 根据任务id完成任务
taskService.complete("2505");
}
通过用户完成任务
就是上两布的结合
/**
* 完成某个人任务
* @param args
*/
public static void main(String[] args) {
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取taskService
TaskService taskService = processEngine.getTaskService();
// 获取受让人的单个任务
Task task = taskService.createTaskQuery().processDefinitionKey("evection")
.taskAssignee("hwt")
.singleResult(); // 单个流程结果
// 完成该任务
taskService.complete(task.getId());
}
有兴趣的可以看打印的sql去看看它操作了什么表,操作了什么
8)、zip方式流程部署
文件少的可以用add一个个部署
但是文件多的时候,会很耗时,zip方式可以进行批量的部署
/**
* zip包进行批量的部署
*/
public void main(String[] args) {
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取repositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
// 流程部署
InputStream inputStream = this.getClass() // 获取这个类
.getClassLoader() // 获取这个工程的内容
.getResourceAsStream("bpmn/evection.zip"); // 获取resuorces目录的资源
// 用inputStream 构造 ZipInputStream
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
// 使用压缩包的流进行流程的部署
Deployment deploy = repositoryService.createDeployment()
.addZipInputStream(zipInputStream)
.deploy();
System.out.println("流程部署的id = " + deploy.getId());
System.out.println("流程部署的name = " + deploy.getName());
}
9)、流程定义信息查询
/**
* 查询流程定义
*/
public static void main(String[] args) {
// 获取引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取repositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
// 获取processDefinitionQuery对象
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
// 查询当前所有的流程定义
// processDefinitionKey(流程定义key)
List<ProcessDefinition> evection = processDefinitionQuery.processDefinitionKey("evection")
.orderByProcessDefinitionVersion().desc()// 排序
.list();// 返回list集合
// 输出信息
for (ProcessDefinition processDefinition:evection){
System.out.println("流程定义id = " + processDefinition.getId());
System.out.println("流程定义名称 = " + processDefinition.getName());
System.out.println("流程定义key = " + processDefinition.getKey());
System.out.println("流程定义版本 = " + processDefinition.getVersion());
System.out.println("流程定义部署id = " + processDefinition.getDeploymentId());
}
}
10)、流程定义删除
就是删除流程部署时放到表里的数据。
部署id就是上一步可以查出来的
1、通过部署id删除
deleteDeployment
参数1:部署id
参数2:加true 就是级联删除,如果没加,流程没结束删除不掉
public static void main(String[] args) {
// 获取引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取repositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
// 通过部署id来删除流程部署信息
repositoryService.deleteDeployment("1",true);
}
11)、下载资源文件
下载我们部署时上传的png文件、bpmn文件等
用到IO流工具依赖
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
/**
* 下载 资源文件
* @param args
*/
public static void main(String[] args) throws IOException {
// 获取引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取repositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
// 获取查询对象
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("evection")
.singleResult();
// 通过流程定义信息,获取部署id、png的name,bpmn的name
String deploymentId = processDefinition.getDeploymentId();
String pngName = processDefinition.getDiagramResourceName();
String bpmnName = processDefinition.getResourceName();
// 通过repositoryService,传递部署id,读取资源信息(png、bpmn)
// 获取图片的流
InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, pngName);
// 获取bpmn的流
InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, bpmnName);
// 构造OutPutStream流
File pngFile = new File("d:/evection.png");
File bpmnFile = new File("d:/evection.bpmn");
FileOutputStream pngOutputStream = new FileOutputStream(pngFile);
FileOutputStream bpmnOutputStream = new FileOutputStream(bpmnFile);
// 输入流、输出流的转换
IOUtils.copy(pngInput,pngOutputStream);
IOUtils.copy(bpmnInput,bpmnOutputStream);
// 关闭流
IOUtils.close();
}
12)、查看历史记录
操作act_hi_actinst表流程的历史记录
/**
* 查看历史信息
*/
public static void main(String[] args) {
// 获取引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取historyService
HistoryService historyService = processEngine.getHistoryService();
// 获取actinst表的查询对象
HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery();
//查询 actinst表
instanceQuery.processInstanceId("10001");
// instanceQuery.processDefinitionId("evection:1:7504") 或者根据DefinitionId查
// 增加排序操作
instanceQuery.orderByHistoricActivityInstanceStartTime().asc();
// 查询所有内容
List<HistoricActivityInstance> list = instanceQuery.list();
for (HistoricActivityInstance his:list){
System.out.println(his.getActivityId());
System.out.println(his.getActivityName());
System.out.println(his.getProcessDefinitionId());
System.out.println(his.getProcessInstanceId());
System.out.println("=======================");
}
}
13)、流程挂起与激活
业务中:
有每月最后一天不处理出差申请
或者某种原因,转正申请被暂停
需要将流程挂起,等到激活时才能继续往下走
1、挂起或激活整个流程(全部流程实例)
/**
* 全部流程实例挂起与激活
* suspended 暂停
* @param args
*/
public static void main(String[] args) {
// 1、创建ProcessEngine流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取repositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3、查询流程定义
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey("evection").singleResult();
// 4、获取当前流程定义的实例是否都挂起状态
boolean suspended = processDefinition.isSuspended();
// 5、获取流程定义id
String definitionId = processDefinition.getId();
// 如果是挂起状态,改为激活
if (suspended){
// 激活 参数1:流程定义Id ,参数2:是否激活 ,参数3:激活时间
repositoryService.activateProcessDefinitionById(definitionId,true,null);
}else { // 如果是正常状态,改为挂起
// 挂起 参数1:流程定义Id ,参数2:是否暂停 ,参数3:暂停时间
repositoryService.suspendProcessDefinitionById(definitionId,true,null);
}
}
2、挂起或激活单个流程实例
/**
* 全部单个流程实例挂起与激活
* suspended 暂停
* @param args
*/
public static void main(String[] args) {
// 获取processEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// RuntimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
// 查询流程定义的对象
ProcessInstance processInstance = runtimeService.
createProcessInstanceQuery().
processInstanceId("15001").
singleResult();
// 得到当前流程定义的实例是否都为暂停状态
boolean suspended = processInstance.isSuspended();
// 流程定义id
String processDefinitionId = processInstance.getId();
// 判断是否为暂停
if(suspended){
// 如果是暂停,可以执行激活操作 ,参数:流程定义id
runtimeService.activateProcessInstanceById(processDefinitionId);
System.out.println("流程定义:"+processDefinitionId+",已激活");
}else{
// 如果是激活状态,可以暂停,参数:流程定义id
runtimeService.suspendProcessInstanceById( processDefinitionId);
System.out.println("流程定义:"+processDefinitionId+",已挂起");
}
}