介绍工作流
网上工作流的定义一大堆,这里就不去复制了,通俗的理解,工作流就是类似OA系统中请假审批、报销审批等一系列流程,下级提交的申请只有直系领导才能审批,其他人是没有权限的,而只有直系领导审批通过后,直系领导的直系领导才可以看到申请,并进行审批,以此类推。。。
而Activiti工作流就可以实现类似的功能,本笔记将以最简单的方式让你明白怎么使用Activiti工作流,直接上代码
准备环境
1) JDK1.6或者更高版本
2) 支持的数据库有:h2, mysql, oracle, postgres, mssql, db2等。
3) 支持activiti5运行的jar包
4) 开发环境为Eclipse3.7或者以上版本,myeclipse为8.6版本
安装流程设计器(eclipse插件)
方案一:
在有网络的情况下,安装流程设计器步骤如下:
1) 打开 Help -> Install New Software. 在如下面板中:
2) 在如下Install界面板中,点击Add按钮:
3) 然后填入下列字段
Name: Activiti BPMN 2.0 designer
Location: http://activiti.org/designer/update/
4) 回到Install界面,在面板正中列表中把所有展示出来的项目都勾上:
5) 点击复选框
在Detail部分记得选中 "Contact all updates sites.." , 因为它会检查所有当前安装所需要的插件并可以被Eclipse下载.
6) 安装完以后,点击新建工程new->Other…打开面板,如果看到下图内容:
说明安装成功了。
方案二
在没有网络的情况下,安装流程设计器步骤如下:
首先下载离线插件包:
https://files.cnblogs.com/files/lm970585581/activiti.zip
将压缩包解压后
这两个文件夹复制到Eclipse根目录下 ,重启即可
注意:
打开菜单Windows->Preferences->Activiti->Save下流程流程图片的生成方式:
虽然流程引擎在单独部署bpmn文件时会自动生成图片,但在实际开发过程中,自动生成的图片会导致和BPMN中的坐标有出入,在实际项目中展示流程当前位置图会有问题。
所在完成以上配置后,会由我们自己来管理流程图片。在发布流程时把流程规则文件和流程图片一起上传就行了。
准备Activiti5开发环境
在activiti-5.13->wars目录下是一些示例项目,解压activiti-rest项目,导入activiti-rest目录中WEB-INFlib下所有包。添加到classpath中。
另外需要根据我们正在使用的数据库添加相应的数据库jar包
初始化数据库
可以在activiti-restWEB-INFclasses下找到配置文件:如下
代码语言:javascript复制<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>
<property name="jdbcUrl" value="jdbc:mysql://192.168.220.130:3306/activiti?useUnicode=true&characterEncoding=utf8"></property>
<property name="jdbcUsername" value="root"></property>
<property name="jdbcPassword" value="root"></property>
<!--
创建表的策略
-->
<property name="databaseSchemaUpdate" value="true"></property>
</bean>
</beans>
调用以下java代码,即可把需要的表创建出来
代码语言:javascript复制import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.junit.Test;
public class CreateTable {
@Test
public void testCreateTable(){
ProcessEngine processEngine = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml")
.buildProcessEngine();
}
}
HelloWorld程序
先画请假流程图
注意:
properties=>General中的ID和NAME可以设置每个步骤的名称:
每个审批过程的properties=>Main config=>Assignee:设置能够审批的对象,这里部门经理审批设置为:张三,总经理审批设置为:李四
保存后,在根目录下生成:
JAVA程序如下:
代码语言:javascript复制import java.util.List;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.task.Task;
import org.junit.Test;
/**
* 1、部署流程图
* 2、启动流程实例
* 3、发起申请
* 4、审批
* @author zd
*
*/
public class HelloWorld {
/**
* 部署流程图
*/
@Test
public void testDeploy(){
//产生流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取仓库流程的实例
processEngine.getRepositoryService()
.createDeployment()
.addClasspathResource("qingjia.bpmn")
.addClasspathResource("qingjia.png")
.deploy();
/**
* 这里使用RepositoryService部署流程定义
addClasspathResource表示从类路径下加载资源文件,一次只能加载一个文件
*/
}
/**
* 启动流程实例 pi=process instance
*/
@Test
public void testStartPI(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
processEngine.getRuntimeService()
.startProcessInstanceById("qingjia:1:4");//ID在act_re_procdef这个表中可以看到
//这里使用RuntimeService启动流程实例
}
/**
* 完成任务
*/
@Test
public void testFinishTask(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
processEngine.getTaskService()
.complete("104");//act_ru_task表中获取
}
/**
* 根据张三查询任务
*/
@Test
public void testQueryTask(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//查询任务列表
List<Task> tasks = processEngine.getTaskService()
.createTaskQuery()
.taskAssignee("张三")
.list();
for (Task task : tasks) {
System.out.println(task.getName());
}
}
}
流程定义
代码语言:javascript复制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.ProcessDefinition;
import org.junit.Test;
import org.springframework.transaction.annotation.Transactional;
/**
* pd=process definition
* @author zd
* 1、把流程图部署到activiti的引擎中 重点
* classpath
* inputstream
* zipinputstream
* 2、对流程图进行删除 重点
* 3、获取到流程图和bpmn文件 重点
* 4、查询 了解
* 查询部署
* 查询流程定义
*/
public class PDTest {
/**
* 涉及到的表
* act_ge_bytearray
* 1、说明
* 该表存储了bpmn文件和png图片
* 从字段可以看出,根据deploymentID可以查询bpmn文件和png图片
* 2、字段
* name_:存储该文件的路径名称
* deploymentid_id_:部署表的ID
* byte_:存放值(bpmn和png)
* act_re_deployment
* 1、说明
* 该表存储了部署的动作
* 2、字段
* ID_:部署ID 主键
* act_re_procdef
* 1、说明
* 流程定义表
* 2、字段
* id: 是由${name}:${version}:随机数 确定唯一的流程
* name_: 流程定义名称
* key_: 流程定义名称
* version_: 某一个流程定义的版本
* deployment_id_:部署表的ID
*
* 说明:
* 1、根据deploymentID-->查询图片和bpmn文件
* 2、根据deploymentID-->查询流程定义
* 3、只要流程名称不变,部署一次,版本号加1,id就发生变化,生成了一个新的deploymentID
* 4、所以deploymentID和pdid是一一对应的关系
*/
@Test
public void testDeployFromClasspath(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
processEngine.getRepositoryService()
.createDeployment()
.addClasspathResource("qingjia.bpmn")
.addClasspathResource("qingjia.png")
.deploy();
}
/**
* 通过inputStream的方式部署
*/
@Test
public void testDeployFromInputStream(){
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("qingjia.bpmn");
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
processEngine.getRepositoryService()
.createDeployment()
.addInputStream("qingjia.bpmn", inputStream)
.deploy();
}
/**
* 通过zip的方式部署
*/
@Test
public void testDeployFromZip(){
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("qingjia.zip");
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
processEngine.getRepositoryService()
.createDeployment()
.addZipInputStream(zipInputStream)
.deploy();
}
/**
* 把查询出来的图片放到E盘的根目录下
*/
@Test
public void testShowImage() throws Exception{
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
InputStream inputStream = processEngine.getRepositoryService()
/**
* 参数为pdid
*/
.getProcessDiagram("qingjia:1:4");
/**
* 得到一个图片
*/
// OutputStream outputStream = new FileOutputStream("e:/processimg.png");
// for(int b=-1;(b=inputStream.read())!=-1;){
// outputStream.write(b);
// }
// inputStream.close();
// outputStream.close();
/***************************************************************************************/
/**
* 第一个参数为deploymentId
* 第二个参数为resourceName
*/
/********************************************************************************/
/**
* 得到的是一个图片
*/
// InputStream inputStream2 = processEngine.getRepositoryService()
// .getResourceAsStream("101", "qingjia.png");
//
// OutputStream outputStream2 = new FileOutputStream("e:/processimg2.png");
// for(int b=-1;(b=inputStream2.read())!=-1;){
// outputStream2.write(b);
// }
// inputStream2.close();
// outputStream2.close();
/**********************************************************************************/
/**
* 得到的是bpmn文件
*/
InputStream inputStream3 = processEngine.getRepositoryService()
.getProcessModel("qingjia:1:4");
OutputStream outputStream3 = new FileOutputStream("e:/processimg3.bpmn");
for(int b=-1;(b=inputStream3.read())!=-1;){
outputStream3.write(b);
}
inputStream3.close();
outputStream3.close();
/*************************************************************************************/
}
/**
* 查询流程部署
*/
@Test
public void testQueryDeploy(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
List<Deployment> deployments = processEngine.getRepositoryService()
.createDeploymentQuery()
.list();
for (Deployment deployment : deployments) {
System.out.println(deployment.getId());
}
}
/**
* 根据部署ID查询部署 一个结果
*/
@Test
public void testQueryDeployById(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
Deployment deployment = processEngine.getRepositoryService()
.createDeploymentQuery()
.deploymentId("1")
.singleResult();
System.out.println(deployment.getId());
}
/**
* 查询所有的流程定义
*/
@Test
public void testQueryPD(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
List<ProcessDefinition> processDefinitions = processEngine.getRepositoryService()
.createProcessDefinitionQuery()
.list();
for (ProcessDefinition processDefinition : processDefinitions) {
System.out.println(processDefinition.getKey());
System.out.println(processDefinition.getId());
System.out.println(processDefinition.getVersion());
}
}
/**
* 按照版本的从高到低进行排序
*/
@Test
public void testQueryPDByVersion(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
List<ProcessDefinition> processDefinitions = processEngine.getRepositoryService()
.createProcessDefinitionQuery()
.orderByProcessDefinitionVersion()
.desc()
.list();
for (ProcessDefinition processDefinition : processDefinitions) {
System.out.println(processDefinition.getKey());
System.out.println(processDefinition.getId());
System.out.println(processDefinition.getVersion());
}
}
/**
* 根据pdid查询流程定义
* 根据 pdkey查询流程定义
*/
//略。。
/**
* 删除
*/
@Test
public void testDelete(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
processEngine.getRepositoryService()
//.deleteDeployment("");//该方法只能删除流程定义,一般不会使用
.deleteDeployment("1", true);//该方法不仅能够删除流程定义,而且能够删除正在运行的流程实例
}
}
流程实例、任务的执行
代码语言:javascript复制import java.util.List;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.bpmn.parser.handler.ProcessParseHandler;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;
/**
* pi=process instance
* @author zd
* 1、启动流程实例
* 2、完成任务
* 3、任务的查询
* 1、根据任务的执行人查询任务
* 2、可以根据任务查询任务的执行人
* 3、查看历史任务
* 4、怎么样查看流程实例是否结束
*/
public class PITest {
/**
* 启动流程实例
* 涉及到的表
* act_hi_actinst hi:history actinst:action instance
* 1、概念
* 所有的正在执行的或者已经完成的节点
* 2、字段
* act_type_:为节点的类型
* end_time_: 如果有值,说明该节点已经结束了
* act_hi_procinst procinst:process instance
* 1、概念
* 所有的正在执行的或者已经完成的流程实例
* 2、字段
* end_time_:如果该字段有值,说明这个流程实例已经结束了
* end_act_id_:说明该流程实例是在哪个节点结束的
* act_hi_taskinst taskinst:task instance
* 1、概念
* 所有的正在执行的或者已经完成的任务节点
* 2、字段
* end_time_:如果该字段有值,说明任务已经完成了
* delete_reason:如果该值为completed,说明该任务处于完成的状态
* act_ru_execution ru:runtime
* 1、概念
* 代表正在执行的流程实例
* 2、字段
* id_:主键 executionid
* proc_inst_id_: process instanceid
* proc_def_id_:pdid
* act_id_:当前的流程实例正在执行的节点的ID的值
* act_ru_task
* 1、概念
* 代表正在执行的任务
* 2、字段
* id_:主键 任务ID
* execution_id_:piid,executionid
* name_:任务名称
* 3、说明
* 该表是一个临时表,该表中的任务完成以后,这一行会被删除掉
*
*/
@Test
public void testStartPI(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
ProcessInstance pi = processEngine.getRuntimeService()
.startProcessInstanceById("qingjia:1:304");
System.out.println(pi.getId());
}
/**
* 查询所有的正在执行的流程实例
*/
@Test
public void testQueryPI(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
List<ProcessInstance> processInstances = processEngine.getRuntimeService()
.createProcessInstanceQuery()
.list();
for (ProcessInstance processInstance : processInstances) {
System.out.println(processInstance.getActivityId());
System.out.println(processInstance.getId());
}
}
/**
* 查询当前正在执行的节点
*/
@Test
public void testQueryActivity(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
List<String> strings = processEngine.getRuntimeService()
.getActiveActivityIds("401");
for (String string : strings) {
System.out.println(string);
}
}
/**
*获取当前的流程实例正在运行的节点的坐标
*/
@Test
public void getPix(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
/**
* processDefinitionEntity代表流程图对象的实体
*
* 根据pdid获取到流程定义实体
*/
ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity)processEngine.getRepositoryService()
.getProcessDefinition("qingjia:1:304");
List<String> strings = processEngine.getRuntimeService()
.getActiveActivityIds("401"); //piid
for (String string : strings) {
/**
* ActivityImpl代表流程图上的每一个节点
*/
ActivityImpl activityImpl = processDefinitionEntity.findActivity(string);
/**
* 获取到正在执行的流程节点的坐标
*/
System.out.println(activityImpl.getHeight());
System.out.println(activityImpl.getWidth());
System.out.println(activityImpl.getX());
System.out.println(activityImpl.getY());
}
}
/**
* 查询所有的任务
*/
@Test
public void testQueryAllTask(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
List<Task> tasks = processEngine.getTaskService()
.createTaskQuery()
.list();
for (Task task : tasks) {
System.out.println(task.getId());
System.out.println(task.getName());
}
}
/**
* 完成任务
* 需要一个参数:taskId
*/
@Test
public void testFinishTask(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
processEngine.getTaskService()
.complete("602");
}
/**
* 根据任务的执行人查看任务
*/
@Test
public void testQueryTaskByAssignee(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
List<Task> tasks = processEngine.getTaskService()
.createTaskQuery()
.taskAssignee("张三")
.list();
for (Task task : tasks) {
System.out.println(task.getId());
System.out.println(task.getName());
}
}
/**
* 根据任务的执行人查看任务,并且按照时间的倒叙排序
*/
@Test
public void testQueryTaskByAssigneeByTime_DESC(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
List<Task> tasks = processEngine.getTaskService()
.createTaskQuery()
.taskAssignee("张三")
.orderByTaskCreateTime()
.desc()
.list();
for (Task task : tasks) {
System.out.println(task.getId());
System.out.println(task.getName());
}
}
/**
* 根据piid判断流程实例是否结束
*/
@Test
public void testQueryPIByPIID(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
ProcessInstance pi = processEngine.getRuntimeService()
.createProcessInstanceQuery()
.processInstanceId("401")
.singleResult();
if(pi==null){
System.out.println("该流程实例已经结束了");
}else{
System.out.println("该流程实例正在执行中");
}
}
/**
* 查询已经完成的任务
*/
@Test
public void testQueryHistoryTask(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
List<HistoricTaskInstance> historicTaskInstances = processEngine.getHistoryService()
.createHistoricTaskInstanceQuery()
.finished()
.list();
for (HistoricTaskInstance historicTaskInstance : historicTaskInstances) {
System.out.println(historicTaskInstance.getAssignee());
System.out.println(historicTaskInstance.getName());
System.out.println(historicTaskInstance.getId());
}
}
/**
* 查询已经完成的activityimpl
*/
@Test
public void testQueryHistoryActivityImpl(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
List<HistoricActivityInstance> historicActivityInstances = processEngine.getHistoryService()
.createHistoricActivityInstanceQuery()
.list();
for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
System.out.println(historicActivityInstance.getActivityName());
}
}
}
Activiti5工作流笔记二