工作流Activiti5.13学习笔记(一)
了解工作流
1、工作流(Workflow),就是“业务过程的部分或整体在计算机应用环境下的自动化”,它主要解决的是“使在多个参与者之间按照某种预定义的规则传递文档、信息或任务的过程自动进行,从而实现某个预期的业务目标,或者促使此目标的实现。
2、工作流管理系统(Workflow Management System, WfMS)是一个软件系统,它完成工作量的定义和管理,并按照在系统中预先定义好的工作流逻辑进行工作流实例的执行。工作流管理系统不是企业的业务系统,而是为企业的业务系统的运行提供了一个软件的支撑环境。
3、常见的工作流框架有Activity、JBPM、OSWorkFlow、WorkFlow。本系列使用activiti5.13版本。
4、工作流框架底层需要有数据库提供支持,activiti5.13版本,有23张表。JBPM4.4框架有18张表。JBPM底层使用hibernate操作数据库。Activiti框架底层使用的mybatis操作数据库。
Activiti介绍
Activiti5是由Alfresco软件在2010年5月17日发布的业务流程管理(BPM)框架,它是覆盖了业务流程管理、工作流、服务协作等领域的一个开源的、灵活的、易扩展的可执行流程语言框架。Activiti基于Apache许可的开源BPM平台,创始人Tom Baeyens是JBoss jBPM的项目架构师,它特色是提供了eclipse插件,开发人员可以通过插件直接绘画出业务流程图。
下载与目录结构
官网:https://www.activiti.org/ ,没啥用,打开了也没啥东西。直接在GitHub上下载。
GitHub:https://github.com/Activiti/Activiti
目录结构如下:
database :提供了建表语句。
docs:该目录包含了三种文档:javadocs、userguide、xsd。
- javadocs:API文档,包名按照功能模块划分,org.activiti.engine.*。
- userguide:用户手册,包含环境配置、10分钟快速入门以及各个功能模块的使用教程。
- xsd:包含BPMN2.0规范的XSD文件以及Activiti扩展的自定义标签XSD。
libs:开发用的jar包和源码包。
wars:提供了两个例子程序。
安装activiti流程设计器插件
1、eclipse中安装如下:
1.1、获得插件的安装包
1.2、解压安装包,复制到eclipse中的dropins目录中
1.3、重启eclipse,勾选save选项
2、IDEA中安装:具体参考此文。
初始化表结构
方式1、使用activiti框架提供的建表语句
在database目录下找到相应数据库的建表语句,执行即可。
方式2、使用activiti框架的自动建表功能。activiti框架提供了和hibernate类似的自动建表功能。
创建一个java项目,导入jar包,不知道导哪些jar包,可以到war目录解压示例程序。把lib目录中的jar包拷过来即可。当然数据库驱动包时必不可少的。
1、 不使用配置文件(不建议)
@Test
public void test1(){
//1.创建一个流程引擎配置对象
ProcessEngineConfiguration configuration= ProcessEngineConfiguration.createStandaloneInMemProcessEngineConfiguration();
//设置数据源
configuration.setJdbcDriver("com.mysql.jdbc.Driver");
configuration.setJdbcUrl("jdbc:mysql:///activiti_demo");
configuration.setJdbcUsername("root");
configuration.setJdbcPassword("123456"); //设置自动建表
configuration.setDatabaseSchema("true"); //创建一个流程引擎对象,在创建流程引擎对象时会自动建表
ProcessEngine engine= configuration.buildProcessEngine();
}
2、使用配置文件
配置文件可以到示例程序的class目录拷贝 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.StandaloneInMemProcessEngineConfiguration">
<property name="jdbcDriver" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///activiti_demo"/>
<property name="jdbcUsername" value="root" />
<property name="jdbcPassword" value="123456" />
<property name="databaseSchemaUpdate" value="true"/>
</bean>
</bean>
java代码
//使用配置文件
@Test
public void test2(){
//1.创建一个流程引擎配置对象
String resource="activiti-context.xml";
String beanName="processEngineConfiguration";
ProcessEngineConfiguration configuration= ProcessEngineConfiguration.createProcessEngineConfigurationFromResource(resource,beanName); //创建一个流程引擎对象,在创建流程引擎对象时会自动建表
ProcessEngine engine= configuration.buildProcessEngine();
}
3、使用配置文件(使用默认配置),要求配置文件名称必须为activiti-context.xml或者activiti.cfg.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.StandaloneInMemProcessEngineConfiguration">
<property name="jdbcDriver" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///activiti_demo"/>
<property name="jdbcUsername" value="root" />
<property name="jdbcPassword" value="123456" />
<property name="databaseSchemaUpdate" value="true"/>
</bean>
<!--配置工厂,用于创建流程引擎 id必须为processEngine-->
<bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
<property name="processEngineConfiguration" ref="processEngineConfiguration" />
</bean>
</bean>
java代码
//使用默认配置文件
@Test
public void test3(){
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
}
了解23张表
Activiti的后台是有数据库的支持,所有的表都以ACT_开头。 第二部分是表示表的用途的两个字母标识。 用途也和服务的API对应。
- ACT_RE_*: 'RE'表示repository。 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。
- ACT_RU_*: 'RU'表示runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务等运行中的数据。 Activiti只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表可以一直很小速度很快。
- ACT_ID_*: 'ID'表示identity。 这些表包含身份信息,比如用户,组等等。
- ACT_HI_*: 'HI'表示history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。
- ACT_GE_*: 通用数据, 用于不同场景下。
使用框架提供的API完成流程操作
可以在项目中加入log4j,将框架执行的sql输出到控制台,log4j提供的日志级别:Fatal error warn info debug trace
部署流程定义
需要先画好流程图
/**
* 部署流程定义(操作数据表:act_re_deployment、act_re_procdef、act_ge_bytearray)
*/
@Test
public void test4() {
// 获得一个部署构建器对象,用于加载流程定义文件(test1.bpmn,test.png)完成流程定义的部署
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
DeploymentBuilder builder= processEngine.getRepositoryService().createDeployment();
// 加载流程定义文件
builder.addClasspathResource("process/test1.bpmn");
builder.addClasspathResource("process/test1.png");
// 部署流程定义
Deployment deployment = builder.deploy();
System.out.println(deployment.getId());
}
查询流程定义列表
@Test
public void test5() {
//流程定义查询对象,用于查询act_re_procdef表
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
ProcessDefinitionQuery query = processEngine.getRepositoryService().createProcessDefinitionQuery();
//添加查询条件
query.processDefinitionKey("bxlc");
query.orderByDeploymentId().desc();
//分页查询
query.listPage(, );
List<ProcessDefinition> list = query.list();
for (ProcessDefinition item : list) {
System.out.print(item.getId());
}
}
启动流程实例
什么是流程实例?根据一个流程定义具体的一次执行过程就是一个流程实例,一个流程定义对应多个流程实例(一对多关系)
为了演示:在流程图中指定办理人是谁,现在是写死的,表示只能张三能提交请假申请。后面会讲解如何动态指定。
//根据流程定义的Id启动一个流程实例(操作ACT_RU_EXECUTION、ACT_RU_TASK、ACT_HI_PROCINST、ACT_HI_ACTINST、ACT_HI_TASKINST、ACT_RU_IDENTITYLINK、ACT_HI_IDENTITYLINK表)
@Test
public void test6() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
String processDefinitionId="qjlc:1:104";
ProcessInstance processInstance = processEngine.getRuntimeService().startProcessInstanceById(processDefinitionId);
System.out.print(processInstance.getId());//
}
查询个人任务列表
@Test
public void test7() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskQuery query = processEngine.getTaskService().createTaskQuery();
query.taskAssignee("张三");
List<Task> list = query.list();
for (Task item : list) {
System.out.print(item.getId()+"==="+item.getName());//204===提交请假申请
}
}
办理任务
//办理任务(主要操作ACT_RU_EXECUTION、ACT_RU_TASK表)
@Test
public void test8() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
processEngine.getTaskService().complete("204");
}
办理任务后,流程就走到了下一个节点,再次查询张三个人任务列表就查不到了,此时用李四去查就可以了。
使用Activiti框架的API操作流程
/**
* 使用Activiti框架的API操作流程
*/
public class ActivitiAPITest {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
/**
* 部署流程定义 方式一:读取单个的流程定义文件 方式二:读取zip压缩文件
*/
@Test
public void test1() {
DeploymentBuilder deploymentBuilder = processEngine.getRepositoryService().createDeployment(); // 方式一:读取单个的流程定义文件
deploymentBuilder.addClasspathResource("test1.bpmn");
deploymentBuilder.addClasspathResource("test1.png");
Deployment deployment = deploymentBuilder.deploy(); // 方式二:读取zip压缩文件
/*ZipInputStream zipInputStream = new ZipInputStream(this.getClass().getClassLoader().getResourceAsStream("process.zip"));
deploymentBuilder.addZipInputStream(zipInputStream);
deploymentBuilder.name("请假流程部署");
Deployment deployment = deploymentBuilder.deploy();*/
} /**
* 查询部署列表
*/
@Test
public void test2() {
// 部署查询对象,查询表act_re_deployment
DeploymentQuery query = processEngine.getRepositoryService().createDeploymentQuery();
List<Deployment> list = query.list();
for (Deployment deployment : list) {
String id = deployment.getId();
System.out.println(id);
}
} /**
* 查询流程定义列表
*/
@Test
public void test3() {
// 流程定义查询对象,查询表act_re_procdef
ProcessDefinitionQuery query = processEngine.getRepositoryService().createProcessDefinitionQuery();
List<ProcessDefinition> list = query.list();
for (ProcessDefinition pd : list) {
System.out.println(pd.getName() + "" + pd.getId());
}
} /**
* 删除部署信息
*/
@Test
public void test4() {
String deploymentId = "1001";
// processEngine.getRepositoryService().deleteDeployment(deploymentId);
processEngine.getRepositoryService().deleteDeployment(deploymentId,true);
} /**
* 删除流程定义(通过删除部署信息达到删除流程定义的目的)
*/
@Test
public void test5() {
String deploymentId = "1401";
// processEngine.getRepositoryService().deleteDeployment(deploymentId);
processEngine.getRepositoryService().deleteDeployment(deploymentId,
true);
} /**
* 查询一次部署对应的流程定义文件名称和对应的输入流(bpmn png)
*
* @throws Exception
*/
@Test
public void test6() throws Exception {
String deploymentId = "101";
List<String> names = processEngine.getRepositoryService()
.getDeploymentResourceNames(deploymentId);
for (String name : names) {
System.out.println(name);
InputStream in = processEngine.getRepositoryService()
.getResourceAsStream(deploymentId, name);
// 将文件保存到本地磁盘
/*
* OutputStream out = new FileOutputStream(new File("d:\\" + name));
* byte[] b = new byte[1024]; int len = 0; while((len =
* in.read(b))!=-1) { out.write(b, 0, len); } out.close();
*/
FileUtils.copyInputStreamToFile(in, new File("d:\\" + name));
in.close();
}
} /**
* 获得png文件的输入流
*
* @throws Exception
*/
@Test
public void test7() throws Exception {
String processDefinitionId = "qjlc:9:1204";
InputStream pngInputStream = processEngine.getRepositoryService()
.getProcessDiagram(processDefinitionId);
FileUtils.copyInputStreamToFile(pngInputStream, new File("d:\\my.png"));
} /**
* 启动流程实例 方式一:根据流程定义的id启动 方式二:根据流程定义的key启动(自动选择最新版本的流程定义启动流程实例)
*/
@Test
public void test8() {
/*
* String processDefinitionId = "qjlc:9:1204"; ProcessInstance
* processInstance =
* processEngine.getRuntimeService().startProcessInstanceById
* (processDefinitionId ); System.out.println(processInstance.getId());
*/ String processDefinitionKey = "qjlc";
ProcessInstance processInstance = processEngine.getRuntimeService()
.startProcessInstanceByKey(processDefinitionKey);
System.out.println(processInstance.getId());
} /**
* 查询流程实例列表,查询act_ru_execution表
*/
@Test
public void test9(){
//流程实例查询对象,查询act_ru_execution表
ProcessInstanceQuery query = processEngine.getRuntimeService().createProcessInstanceQuery();
query.processDefinitionKey("qjlc");
query.orderByProcessInstanceId().desc();
query.listPage(0, 2);
List<ProcessInstance> list = query.list();
for (ProcessInstance pi : list) {
System.out.println(pi.getId() + " " + pi.getActivityId());
}
} /**
* 结束流程实例,操作的表act_ru_execution act_ru_task
*/
@Test
public void test10(){
String processInstanceId = "1601";
processEngine.getRuntimeService().deleteProcessInstance(processInstanceId , "我愿意");
} /**
* 查询任务列表
*/
@Test
public void test11(){
//任务查询对象,查询act_ru_task表
TaskQuery query = processEngine.getTaskService().createTaskQuery();
String assignee = "李四";
query.taskAssignee(assignee);
query.orderByTaskCreateTime().desc();
List<Task> list = query.list();
for (Task task : list) {
System.out.println(task.getId());
}
} /**
* 办理任务
*/
@Test
public void test12(){
String taskId = "2902";
processEngine.getTaskService().complete(taskId);
} /**
* 直接将流程向下执行一步
*/
@Test
public void test13(){
String executionId = "2701";//流程实例id
processEngine.getRuntimeService().signal(executionId);
} /**
* 查询最新版本的流程定义列表
*/
@Test
public void test14(){
ProcessDefinitionQuery query = processEngine.getRepositoryService().createProcessDefinitionQuery();
query.orderByProcessDefinitionVersion().asc();
List<ProcessDefinition> list = query.list();
Map<String, ProcessDefinition> map = new HashMap<String, ProcessDefinition>();
for (ProcessDefinition pd : list) {
map.put(pd.getKey(), pd);
}
ArrayList<ProcessDefinition> lastList = new ArrayList<>(map.values());
for (ProcessDefinition processDefinition : lastList) {
System.out.println(processDefinition.getName() + " "+ processDefinition.getVersion() );
}
}
}
Activiti框架提供的Service对象
- RepositoryService----操作静态的资源(流程定义,bpmn、png)
- RuntimeService-----操作流程实例(启动流程实例、查询流程实例、结束流程实例)
- TaskService-----操作任务(查询任务、办理任务)
- HistoryService----操作历史数据
Activiti框架提供的对象(和表有对应关系)
- Deployment-----act_re_deployment
- ProcessDefinition----act_re_procdef
- ProcessInstance-----act_ru_execution
- Task-----act_ru_task
使用网页版流程设计器
1、将activiti-explorer.war复制到tomcat中
2、启动tomcat,访问http://lcoalhost:8080/activiti-explorer
3、使用kermit/kermit登录
4、
5、
参考文档:http://www.cnblogs.com/llzgzljl/archive/2013/10/07/3356108.html
学习资源:http://www.mossle.com/index.do
工作流Activiti5.13学习笔记(一)的更多相关文章
- 【Python】2.13学习笔记 数学函数和随机函数
我死了,今天看课看过头了,忘了发作业,被典明批评 而且化学作业还是瞎搞的,直接就发了 我觉得我已经提前死亡了,现在不死亡,开学也会的 函数 挺容易的,有很多语言之间重合的部分 注意 在使用某些数学函数 ...
- Dynamic CRM 2013学习笔记(四十一)流程4 - 异步工作流(Workflow)用法图解
在CRM 2013 里,工作流被分成二类:异步工作流和实时工作流.异步工作流依赖一个windows 服务: Microsoft Dynamics CRM Asynchronous Processing ...
- Dynamic CRM 2013学习笔记(四十二)流程5 - 实时/同步工作流(Workflow)用法图解
实时工作流跟插件一样,也是用事件执行管道来执行,能在pre,post或核心操作中执行.跟插件一样,不能在创建之前和删除之后执行.如果执行过程中有异常发生,会取消并回滚整个操作.实时工作流里所有的活动和 ...
- 《深入Java虚拟机学习笔记》- 第13章 逻辑运算
<深入Java虚拟机学习笔记>- 第13章 浮点运算
- Ext.Net学习笔记13:Ext.Net GridPanel Sorter用法
Ext.Net学习笔记13:Ext.Net GridPanel Sorter用法 这篇笔记将介绍如何使用Ext.Net GridPanel 中使用Sorter. 默认情况下,Ext.Net GridP ...
- SQL反模式学习笔记13 使用索引
目标:优化性能 改善性能最好的技术就是在数据库中合理地使用索引. 索引也是数据结构,它能使数据库将指定列中的某个值快速定位在相应的行. 反模式:无规划的使用索引 1.不使用索引或索引不足 2.使用了 ...
- Linux 学习笔记之超详细基础linux命令 Part 13
Linux学习笔记之超详细基础linux命令 by:授客 QQ:1033553122 ---------------------------------接Part 12---------------- ...
- #Python学习笔记:1-3章 (基于《python编程,从入门到实践)
第1-3章 这个文档是记录我学习python时一些学习笔记以及一些想法也可以称作复习笔记 第一章:起步这一章主要是从第一个"hello world"程序到python环境的搭建与配 ...
- golang学习笔记13 Golang 类型转换整理 go语言string、int、int64、float64、complex 互相转换
golang学习笔记13 Golang 类型转换整理 go语言string.int.int64.float64.complex 互相转换 #string到intint,err:=strconv.Ato ...
随机推荐
- Linux显示机器的处理器架构
Linux显示机器的处理器架构 youhaidong@youhaidong-ThinkPad-Edge-E545:~$ arch x86_64 youhaidong@youhaidong-ThinkP ...
- OpenStack_I版 1.准备过程
openstack是一个开源云平台,python开发 此次部署为实验环境, 采用扁平化简单的网络架构部署 优点:低耦合的,模块化 ...
- 浅谈js中null和undefined的区别
在JS中,null和undefined是经常让人摸不着头脑的东西,尤其是在数据初始化以及处理的过程中,经常稍微不注意,就会让页面在渲染时出现报错,下面来细说下,这两者之间的区别: null 表示一个对 ...
- [Luogu2852][USACO06DEC]牛奶模式Milk Patterns
Luogu 一句话题意 给出一个串,求至少出现了\(K\)次的子串的最长长度. sol 对这个串求后缀数组. 二分最长长度. 如果有\(K\)个不同后缀他们两两的\(lcp\)都\(>=mid\ ...
- 【Luogu2759】奇怪的函数(数论)
[Luogu2759]奇怪的函数(数论) 题面 题目描述 使得 \(x^{x}\)达到或超过 n 位数字的最小正整数 x 是多少? 输入输出格式 输入格式: 一个正整数 n 输出格式: 使得 \(x^ ...
- [SDOI2008]沙拉公主的困惑
题面 传送门 Sol 题目要求\(\sum_{i=1}^{n!}[gcd(i, m!)==1]\) 设\(N=n!,M=m!\),莫比乌斯反演一波 就变成了\(\sum_{d|M}\mu(d)\fra ...
- java 提取目录下所有子目录的文件到指定位置
package folder; import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundExcept ...
- 2017angular、vue、react热度
中国,过去一年: 中国,过去五年: 全球,过去一年: 全球,过去五年: 其他相关: 数据来源自:Google Trends
- Several ports (8005, 8080, 8009)被占用
启动Tomcat服务器报错: Several ports (8005, 8080, 8009) required by Tomcat v5.5 Server at localhost are alre ...
- python打造社工脚本
0x00前言: 大家都知道图片是有Exif信息的.里面包含着 你的GPS信息.还有拍摄时间等等的敏感信息. 0x01准备: exifread requests 0x02思路: 读取图片的Exif信息. ...