day57_BOS项目_09
- 今天内容安排:
- 1、工作流概念
- 2、安装流程设计器插件(是eclipse插件)–> 可以设计流程图
- 3、了解activiti 框架目录结构
- 4、创建activiti 数据库(共23张表)
- 5、使用activiti 的API操作流程
- 6、总结activiti 的API
1、工作流概念
- 工作流(Workflow),就是“业务过程的部分或整体在计算机应用环境下的自动化”,它主要解决的是“使在多个参与者之间按照某种预定义的规则传递文档、信息或任务的过程自动进行,从而实现某个预期的业务目标,或者促使此目标的实现”。
- 工作流管理系统(Workflow Management System, WfMS)是一个软件系统,它完成工作量的定义和管理,并按照在系统中预先定义好的工作流逻辑进行工作流实例的执行。工作流管理系统不是企业的业务系统,而是为企业的业务系统的运行提供了一个软件的支撑环境。
- 工作流管理联盟(WfMC,Workflow Management Coalition)给出的关于工作流管理系统的定义是:
工作流管理系统是一个软件系统
,它通过执行经过计算的流程定义去支持一批专门设定的业务流程
。工作流管理系统被用来定义、管理、和执行工作流程。 - 工作流管理系统的目标:管理工作的流程以确保工作在正确的时间被期望的人员所执行–在自动化进行的业务过程中插入人工的执行和干预。
2、安装流程设计器插件(是eclipse插件)–> 可以设计流程图
方式一:
第一步:获得activiti-eclipse-plugin.zip文件
第二步:将zip文件解压到eclipse的dropins目录中
第三步:重启eclipse,打开Window –> Preferences –> Activiti — > Save –> 勾选 Export marshallers 选项
方式一不一定能安装成功,因为activiti版本可能与eclipse的版本不符。
方式二:
第一步:点击eclipse上方工具栏的Help,选择 Install New Software… –> Add..
第二步:填写插件名称和安装地址
Name: Activiti BPMN 2.0 designer
Location: http://activiti.org/designer/update/
之后点击OK
之后点击Next –> I accept the terms of the license agreements –> Finish,稍等几分钟,等待安装。
第三步:安装完成后,我们在new的时候,操作面板中便有activiti的相关文件了。
方式二也有可能不成功,我们这里推荐方式三。
方式三:
第一步:先下载好对应的离线包,可以是jar或者zip格式的,下载地址为:http://www.activiti.org/designer/archived/activiti-designer-5.18.0.zip
第二步:然后还是在下述对话框中,只是不再输入url,而是改为选择已经下来的zip离线包的路径
第三步:然后下一步下一步安装即可。
注意:由于我在第一步中已经使用在线的方式安装过,所以即使我这里选择了离线包,后续安装的时候eclipse还是会尝试从网络上去下载,所以需要在Install New SoftWare 对话框中选择 “Avaible Software Suits”或 “Manage..”,在弹出的对话框中选中刚才http路径的那个资源,把他删了,然后再来使用离线方式安装,此时才会真正使用离线安装包。
第四步:重启eclipse,打开Window –> Preferences –> Activiti — > Save –> 勾选 Export marshallers 选项
第五步:使用安装好的插件设计流程图,点击新建工程New –> Other… 打开面板,如果看到下图内容:
演示使用效果:
3、了解activiti 框架目录结构
- 工作流框架底层需要有数据库支持。
- activiti5.13版本对应23张表,activiti框架底层使用mybatis操作数据库。
- JBPM4.4框架底层对应18张表,底层使用hibernate操作数据库。
- BPMN业务流程建模与标注(Business Process Model and Notation,BPMN) ,描述流程的基本符号,包括这些图元如何组合成一个业务流程图(Business Process Diagram)。
4、创建activiti 数据库(共23张表)
4.1、执行框架提供的sql文件建表(建议)
23张表如下:
23张表的命名详解:
Activiti的后台是有数据库的支持,所有的表都以ACT_开头。 第二部分是表示表的用途的两个字母标识。 `用途也和服务的API对应`。
1) ACT_RE_*: 'RE'表示repository。 这个前缀的表包含了流程定义和流程静态资源,比如:图片、规则等等。
2) ACT_RU_*: 'RU'表示runtime。 这些表示运行时的表,包含流程实例、任务、变量、异步任务,等运行中的数据。 Activiti只在流程实例执行过程中保存这些数据,在流程结束时就会删除这些记录。 这样运行时表可以一直很小速度很快。
3) ACT_ID_*: 'ID'表示identity。 这些表包含身份信息,比如:用户、组等等。
4) ACT_HI_*: 'HI'表示history。 这些表包含历史数据,比如:历史流程实例、变量、任务等等。
5) ACT_GE_*: 通用数据, 用于不同场景下。
4.2、使用框架提供的自动建表方式(不建议)
第一步:创建普通Java项目并导入jar包
第二步:提供配置文件activiti-context.xml,进行相应的配置
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<!-- 配置流程引擎配置对象 -->
<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_day01"/>
<property name="jdbcUsername" value="root"/>
<property name="jdbcPassword" value="root"/>
<property name="databaseSchemaUpdate" value="true"/><!-- 自动建表 -->
</bean>
<!-- 使用工厂创建流程引擎对象 -->
<bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
<property name="processEngineConfiguration" ref="processEngineConfiguration"></property>
</bean>
</beans>
第三步:创建流程引擎对象,自动建表(2种方式)
package com.itheima.activiti;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.ProcessEngines;
import org.junit.Test;
public class HelloWorld {
/**
* 使用框架提供的自动建表方式创建23张表
*/
@Test
public void test1() {
String resource = "activiti-context.xml"; // 配置文件
String beanName = "processEngineConfiguration";
// 读取配置文件,获得流程引擎对象
ProcessEngineConfiguration config = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource(resource, beanName);
ProcessEngine processEngine = config.buildProcessEngine();
}
/**
* 使用默认配置的要求:
* 1、配置文件必须在classpath根目录下
* 2、配置文件名称必须为activiti-context.xml或者activiti.cfg.xml
* 3、配置文件中配置对象的id必须为processEngineConfiguration
* 4、工厂对象的id必须为processEngine
*/
@Test
public void test2() {
// 获得默认的流程引擎对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
}
}
5、使用activiti 的API操作流程
使用插件设计一个流程图:
5.1、部署流程定义
- 即就是将流程定义规则保存到数据库。
示例代码如下:
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
/**
* 部署 流程定义,一共操作了3张数据表:
* act_re_deployment(部署表)
* act_re_procdef(流程定义表)
* act_ge_bytearray(二进制表)
*/
@Test
public void test3() {
// 创建一个部署构建器对象
DeploymentBuilder deploymentBuilder = processEngine.getRepositoryService().createDeployment();
// 读取流程定义文件(bpmn、png)
deploymentBuilder.addClasspathResource("qingjialiucheng.bpmn");
deploymentBuilder.addClasspathResource("qingjialiucheng.png");
// 部署流程定义
Deployment deployment = deploymentBuilder.deploy();
System.out.println(deployment.getId());
}
5.2、查询流程定义
/**
* 查询 流程定义,activiti框架一共操作了1张数据库表:
* act_re_procdef(流程定义表)
*/
@Test
public void test4() {
// 创建流程定义查询对象
ProcessDefinitionQuery query = processEngine.getRepositoryService().createProcessDefinitionQuery();
List<ProcessDefinition> list = query.list();
for (ProcessDefinition pd : list) {
System.out.println(" id = " + pd.getId() +
" name = " + pd.getName() +
" version = " + pd.getVersion() +
" key = " + pd.getKey());
}
}
5.3、根据流程定义启动流程实例
- 流程实例:根据某个流程定义一次具体的执行过程就是一个流程实例。流程定义和流程实例的关系是一对多。
/**
* 根据流程定义启动流程实例,activiti框架一共操作了2张数据库表:
* act_ru_execution(流程实例表)
* act_ru_task(任务表)
*/
@Test
public void test5() {
String processDefinitionId = "qingjialiucheng:2:104"; // 流程定义id
// 创建流程实例对象
ProcessInstance processInstance = processEngine.getRuntimeService().startProcessInstanceById(processDefinitionId);
System.out.println(processInstance.getId());
}
5.4、查询个人任务
/**
* 查询 个人任务,activiti框架一共操作了1张数据库表:
* act_ru_task(任务表)
*/
@Test
public void test6() {
// 创建任务查询对象
TaskQuery query = processEngine.getTaskService().createTaskQuery();
query.taskAssignee("王五"); // 根据办理人过滤
query.orderByTaskCreateTime().desc(); // 根据任务创建时间排序,降序
List<Task> list = query.listPage(0, 10);
for (Task task : list) {
System.out.println(" id = " + task.getId() +
" name = " + task.getName() +
" processInstanceId = " + task.getProcessInstanceId());
}
}
5.5、办理个人任务
/**
* 办理 个人任务,activiti框架一共操作了2张数据库表:
* act_ru_execution(流程实例表)
* act_ru_task(任务表)
*/
@Test
public void test7() {
String taskId = "304"; // 任务id
processEngine.getTaskService().complete(taskId);
}
6、总结activiti 的API
-
几个接口(和表有对应关系):
- Deployment –> act_re_deployment(部署表)
- ProcessDefinition –> act_re_procdef(流程定义表)
- ProcessInstance –> act_ru_execution(流程实例表)
- Task –> act_ru_task(任务表)
-
几个Query对象
- DeploymentQuery –> act_re_deployment
- ProcessDefinitionQuery –> act_re_procdef
- ProcessInstanceQuery –> act_ru_execution
- TaskQuery –> act_ru_task
-
几个Service
- RepositoryService –> 操作部署表、流程定义表、二进制表等静态资源信息表
- RuntimeService –> 操作流程实例表、任务表等动态信息表
- TaskService –> 操作任务表
- HistoryService –> 操作历史表
- IdentityService –> 操作用户表、组表、关系表
示例代码如下:
package com.itheima.activiti;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.zip.ZipInputStream;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.apache.commons.io.FileUtils;
import org.junit.Test;
public class ActivitiAPITest {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
/**
* 部署 流程定义
* 方式一:加载单个的流程定义文件 方式二:加载zip文件
* @throws FileNotFoundException
*/
@Test
public void test1() throws FileNotFoundException {
DeploymentBuilder deploymentBuilder = processEngine.getRepositoryService().createDeployment();
// 方式一:加载单个的流程定义文件
// deploymentBuilder.addClasspathResource("qingjialiucheng.bpmn");
// deploymentBuilder.addClasspathResource("qingjialiucheng.png");
// Deployment deployment = deploymentBuilder.deploy();
// 方式二:加载zip文件
// 从根路径下读一个文件,并返回该文件对应的输入流,使用类加载器对象获取classpath路径下的文件
// ZipInputStream zipInputStream = new ZipInputStream(this.getClass().getClassLoader().getResourceAsStream("process.zip"));
// 直接new一个文件输入流,文件位置灵活
ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(new File("e:\\process.zip"))); // 将.png文件和.bpmn文件压缩到process.zip中
deploymentBuilder.addZipInputStream(zipInputStream);
deploymentBuilder.deploy();
}
/**
* 删除 流程定义
*/
@Test
public void test2() {
String deploymentId = "501"; // 部署id
boolean cascade = true; // 级联删除(cascade级联),很少使用
processEngine.getRepositoryService().deleteDeployment(deploymentId, cascade);
}
/**
* 查询 流程定义
processEngine.getRepositoryService().createDeploymentQuery().list();
processEngine.getRepositoryService().createProcessDefinitionQuery().list();
processEngine.getRuntimeService().createProcessInstanceQuery().list();
processEngine.getTaskService().createTaskQuery().list();
processEngine.getIdentityService().createUserQuery().list();
processEngine.getHistoryService().createHistoricActivityInstanceQuery().list();
*/
@Test
public void test3() {
ProcessDefinitionQuery query = processEngine.getRepositoryService().createProcessDefinitionQuery();
query.processDefinitionKey("qingjialiucheng"); // 根据key过滤,在流程定义表中,key是流程的标识,key相同,表示同一流程
query.orderByProcessDefinitionVersion().asc();
List<ProcessDefinition> list = query.listPage(0, 10);
for (ProcessDefinition processDefinition : list) {
System.out.println(processDefinition.getId());
}
}
/**
* 方法一:查询 部署对应的流程定义文件的名称和输入流,该方式需要部署的id和文件名称,不够直接
* 案例中两种方式都会用到
* 我们知道,一旦我们将流程部署完毕,我们就跟项目中的process目录没有关系了,我们在浏览器上看到的png图片文件来自于二进制表,图片已经被我们存成二进制数据了
* @throws FileNotFoundException
*/
@Test
public void test4() throws Exception {
String deploymentId = "501"; // 部署id
List<String> names = processEngine.getRepositoryService().getDeploymentResourceNames(deploymentId);
for (String name : names) {
// 获取文件输入流
InputStream in = processEngine.getRepositoryService().getResourceAsStream(deploymentId, name);
// 方式一:原始方法
// 将文件输入流读取出来,然后通过文件输出流写入到磁盘上
/*
OutputStream out = new FileOutputStream(new File("e:\\" + name));
byte[] b = new byte[1024];
int len = 0;
while ((len = in.read(b)) != -1) {
out.write(b, 0, len);
}
out.close();
in.close();
*/
// 方式二:通过工具类
FileUtils.copyInputStreamToFile(in, new File("e:\\" + name));
in.close();
}
}
/**
*
* 方法二:查询 部署对应的流程定义文件的输入流,该方式只需要流程定义id即可,够直接,但注意,该方法只能返回图片的输入流,xml的输入流返回不了
* 案例中两种方式都会用到
* @throws FileNotFoundException
*/
@Test
public void test5() throws Exception {
String processDefinitionId = "qingjialiucheng:1:504"; // 流程定义id
InputStream pngStream = processEngine.getRepositoryService().getProcessDiagram(processDefinitionId);
FileUtils.copyInputStreamToFile(pngStream, new File("e:\\abc.png"));
}
/**
* 根据流程定义启动流程实例
* 方式一:根据流程定义id启动流程实例
* 方式二:根据流程定义key启动流程实例(建议方式) --> 因为该方式可以根据当前最新版本的流程定义启动流程实例(即最新version值)
*/
@Test
public void test6() throws Exception {
// 方式一:根据流程定义id启动流程实例
// String processDefinitionId = "qingjialiucheng:1:504"; // 流程定义id
// ProcessInstance processInstance = processEngine.getRuntimeService().startProcessInstanceById(processDefinitionId);
// System.out.println(processInstance.getId() + " " + processInstance.getProcessDefinitionId());
// 方式二:根据流程定义key启动流程实例
String processDefinitionKey = "qingjialiucheng";
ProcessInstance processInstance = processEngine.getRuntimeService().startProcessInstanceByKey(processDefinitionKey);
System.out.println(processInstance.getId() + " " + processInstance.getProcessDefinitionId());
}
/**
* 查询 流程实例
*/
@Test
public void test7() throws Exception {
List<ProcessInstance> list = processEngine.getRuntimeService().createProcessInstanceQuery().list();
for (ProcessInstance processInstance : list) {
System.out.println(processInstance.getId());
}
}
/**
* 删除 流程实例
*/
@Test
public void test8() throws Exception {
String processInstanceId = "701";
String deleteReason = "女票过来安慰我了,突然又不想请假了";
processEngine.getRuntimeService().deleteProcessInstance(processInstanceId, deleteReason);
}
/**
* 查询 个人任务
*/
@Test
public void test9() throws Exception {
TaskQuery query = processEngine.getTaskService().createTaskQuery();
query.taskAssignee("张三"); // 任务处理人
query.orderByTaskCreateTime().desc(); // 根据任务创建时间排序,降序
List<Task> list = query.list();
for (Task task : list) {
System.out.println(task.getId());
}
}
/**
* 办理 个人任务
*/
@Test
public void test10() throws Exception{
String taskId = "1004"; // 任务id
processEngine.getTaskService().complete(taskId);
}
}