java工作流
Activiti工作流
一、Activiti介绍
1、Activiti 的概述
工作流(Workflow),就是“业务过程的部分或整体在计算机应用环境下的自动化”,它主要解决的是“使在多个参与者之间按照某种预定义的规则传递文档、信息或任务的过程自动进行,从而实现某个预期的业务目标,或者促使此目标的实现”。
工作流管理系统(Workflow Management System, WfMS)是一个软件系统,它完成工作量的定义和管理,并按照在系统中预先定义好的工作流规则进行工作流实例的执行。工作流管理系统不是企业的业务系统,而是为企业的业务系统的运行提供了一个软件的支撑环境。
工作流管理联盟(WfMC,Workflow Management Coalition)给出的关于工作流管理系统的定义是:工作流管理系统是一个软件系统,它通过执行经过计算的流程定义去支持一批专门设定的业务流程。工作流管理系统被用来定义、管理、和执行工作流程。
工作流管理系统的目标:管理工作的流程以确保工作在正确的时间被期望的人员所执行——在自动化进行的业务过程中插入人工的执行和干预。
2、常见的开源工作流引擎框架
1、OSWorkFlow
2、JBPM(Jboss business process management)
3、Activiti工作流(是JBPM的升级)
3、Activiti工作流介绍
1、工作流引擎:ProcessEngine对象,它是Activiti的核心类,由该类可以获取其他服务实例(历史服务、创库服务、任务服务、用户参与者服务);
2、BPMN:业务流程建模与标注(Business Process Model and Notation,BPMN) ,描述流程的基本符号,包括这些图元如何组合成一个业务流程图(Business Process Diagram);
3、数据库(先学后看)
Activiti的后台是有数据库来支持的,所有的表都是由ACT开头的。第二部分是表示表的用途的两个字母标识。
用途也和服务的API对应。Activiti工作流的数据库有23张表。
ACT_RE_*: 'RE’表示repository。 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。
ACT_RU_*: 'RU’表示runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。 Activiti只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表可以一直很小速度很快。
ACT_ID_*: 'ID’表示identity。 这些表包含身份信息,比如用户,组等等。
ACT_HI_*: 'HI’表示history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。
ACT_GE_*: 通用数据, 用于不同场景下,如存放资源文件。
3.3.1:资源库流程规则表
1) act_re_deployment 部署信息表
2) act_re_model 流程设计模型部署表
3) act_re_procdef 流程定义数据表
3.3.2:运行时数据库表
1) act_ru_execution 运行时流程执行实例表
2) act_ru_identitylink 运行时流程人员表,主要存储任务节点与参与者的相关信息
3) act_ru_task 运行时任务节点表
4) act_ru_variable 运行时流程变量数据表
3.3.3:历史数据库表
1) act_hi_actinst 历史节点表
2) act_hi_attachment 历史附件表
3) act_hi_comment 历史意见表
4) act_hi_identitylink 历史流程人员表
5) act_hi_detail 历史详情表,提供历史变量的查询
6) act_hi_procinst 历史流程实例表
7) act_hi_taskinst 历史任务实例表
8) act_hi_varinst 历史变量表
3.3.4:组织机构表
1) act_id_group 用户组信息表
2) act_id_info 用户扩展信息表
3) act_id_membership 用户与用户组对应信息表
4) act_id_user 用户信息表
这四张表很常见,基本的组织机构管理,关于用户认证方面建议还是自己开发一套,组件自带的功能太简单,使用中有很多需求难以满足
3.3.5:通用数据表
1) act_ge_bytearray 二进制数据表
2) act_ge_property 属性数据表存储整个流程引擎级别的数据,初始化表结构时,会默认插入三条记录,
二、activiti.cfg.xml(activiti的配置文件)
Activiti核心配置文件,配置流程引擎创建工具的基本参数和数据库连接池参数。
定义数据库配置参数:
jdbcUrl: 数据库的JDBC URL。
jdbcDriver: 对应不同数据库类型的驱动。
jdbcUsername: 连接数据库的用户名。
jdbcPassword: 连接数据库的密码。
基于JDBC参数配置的数据库连接 会使用默认的MyBATis连接池。 下面的参数可以用来配置连接池(来自MyBatis参数):
jdbcMaxActiveConnections: 连接池中处于被使用状态的连接的最大值。默认为10。
jdbcMaxIdleConnections: 连接池中处于空闲状态的连接的最大值。
jdbcMaxCheckoutTime: 连接被取出使用的最长时间,超过时间会被强制回收。 默认为20000(20秒)。
jdbcMaxWaitTime: 这是一个底层配置,让连接池可以在长时间无法获得连接时, 打印一条日志,并重新尝试获取一个连接。(避免因为错误配置导致沉默的操作失败)。 默认为20000(20秒)。
示例数据库配置:
三、activiti开发环境搭建
1:activiti5 软件环境
-
JDK1.6或者更高版本
-
支持activiti5运行的jar包
-
开发环境为Eclipse3.7或者以上版本,myeclipse为8.6版本
2:相关资源下载
- JDK可以到sun的官网下载
http://www.oracle.com/technetwork/java/javase/downloads/index.html
2)数据库,例如:mysql可以在官网上下载。
http://www.mysql.com
- activiti也可以到Activiti官方网站下载得到。
http://activiti.org/download.html
- Eclipse3.7或者MyEclipse8.6也可以到相应的网站上获得下载。
3:安装流程设计器(eclipse插件)
3.1:安装方式一
在有网络的情况下,安装流程设计器步骤如下:
- 打开 Help -> Install from site .
- 在如下Install界面板中,点击Add按钮:
- 然后填入下列字段:
Name: Activiti BPMN 2.0 designer
Location: http://www.activiti.org/designer/update/
4)回到Install界面,在面板正中列表中把所有展示出来的项目都勾上:
5)点击复选框
在Detail部分记得选中 “Contact all updates sites…” , 因为它会检查所有当前安装所需要的插件并可以被Eclipse下载.
6)安装完以后,点击新建工程new->Other…打开面板
说明安装成功!
3.2:安装方式一
在没有网络的情况下,安装流程设计器步骤如下:
1)将activiti-eclipse-plugin.zip的内容放入eclipse根目录的dropins文件夹下;
- 重启eclipse,点击新建工程new->Other…打开面板,如果看到下图内容:
3.3、对流程设计器的使用说明
打开菜单windows->Preferences->Activiti->Save下流程流程图片的生成方式:
虽然流程引擎在单独部署bpmn文件时会自动生成图片,但在实际开发过程中,自动生成的图片会导致和BPMN中的坐标有出入,在实际项目中展示流程当前位置图会有问题。
所在完成以上配置后,会由我们自己来管理流程图片。在发布流程时把流程规则文件和流程图片一起上传就行了。
四、Activiti项目
1、LeaveBill.png
2、LeaveBill.bpmn
LeaveBill.bpmn是上面LeaveBill.png工作流的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
<process id="leaveBill" name="leaveProcess" isExecutable="true">
<startEvent id="startevent1" name="Start"></startEvent>
<!--开启了三个工作流-->
<userTask id="usertask1" name="请假申请" activiti:assignee="张三"></userTask>
<userTask id="usertask2" name="审批[主管]" activiti:assignee="李四"></userTask>
<userTask id="usertask3" name="审批[经理]" activiti:assignee="王五"></userTask>
<endEvent id="endevent1" name="End"></endEvent>
<sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>
<sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow>
<sequenceFlow id="flow3" sourceRef="usertask2" targetRef="usertask3"></sequenceFlow>
<sequenceFlow id="leaveBill" sourceRef="usertask3" targetRef="endevent1"></sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_leaveBill">
<bpmndi:BPMNPlane bpmnElement="leaveBill" id="BPMNPlane_leaveBill">
<bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
<omgdc:Bounds height="35.0" width="35.0" x="295.0" y="20.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
<omgdc:Bounds height="55.0" width="105.0" x="260.0" y="80.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2">
<omgdc:Bounds height="55.0" width="105.0" x="260.0" y="160.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3">
<omgdc:Bounds height="55.0" width="105.0" x="260.0" y="250.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
<omgdc:Bounds height="35.0" width="35.0" x="290.0" y="350.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
<omgdi:waypoint x="312.0" y="55.0"></omgdi:waypoint>
<omgdi:waypoint x="312.0" y="80.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
<omgdi:waypoint x="312.0" y="135.0"></omgdi:waypoint>
<omgdi:waypoint x="312.0" y="160.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
<omgdi:waypoint x="312.0" y="215.0"></omgdi:waypoint>
<omgdi:waypoint x="312.0" y="250.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="leaveBill" id="BPMNEdge_leaveBill">
<omgdi:waypoint x="312.0" y="305.0"></omgdi:waypoint>
<omgdi:waypoint x="307.0" y="350.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
3、代码方式创建ProcessEngine对象
1、创建工作流引擎及工作流的数据表;
----数据库及表可以自动创建,可以在配置数据库连接时,实现自动创建数据库与表
—获取ProcessEngine对象
的先获取ProcessEngineconfiguration对象,再由该对象来构造ProcessEngine对象
package cn.lice.activiti.a;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.junit.Test;
/**
* 模拟Activiti工作流
*
* @author 11606
*
*/
public class TestActiviti {
// 1.获取的流引擎,自动创建Activiti涉及的表
@Test
public void createprocessEngine() {
// 获取ProcessEngineConfiguration对象,它是抽象 类,不能new出来
ProcessEngineConfiguration engineConfiguration = ProcessEngineConfiguration
.createstandaloneProcessEngineConfiguration();
// 配置数据库连接
engineConfiguration.setJdbcDriver("com.mysql.jdbc.Driver");
engineConfiguration.setJdbcUrl("jdbc:mysql://localhost:3306/ActivitiDB?createDatabaseIfNotExist=true"
+ "&useunicode=true&characterEncoding=UTF8");
engineConfiguration.setJdbcUsername("root");
engineConfiguration.setJdbcPassword("root");
// 设置表的创建表的策略(当没有表时,自动创建)
/**
*
* public static final java.lang.String DB_SCHEMA_UPDATE_FALSE = "false"; 不会自动创建表,没有则会抛异常
* public static final java.lang.String DB_SCHEMA_UPDATE_CREATE_DROP = "create-drop"; 先删除,再创建
* public static final java.lang.String DB_SCHEMA_UPDATE_TRUE = "true"; 假如没有则自动创建
*
*/
engineConfiguration.setDatabaseSchemaUpdate("true");
//通过ProcessEngineConfiguration对象,创建ProcessEngine
ProcessEngine processEngine = engineConfiguration.buildProcessEngine();
System.out.println("创建ProcessEngine成功:"+processEngine);
}
}
4、xml方式创建ProcessEngine对象
通过加载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">
<!-- 配置ProcessEngineConfiguration -->
<bean id="processEngineConfiguration" class=" org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration">
<property name="jdbcDriver" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/ActivitiDB1?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=UTF8"/>
<property name="jdbcUsername" value="root"/>
<property name="jdbcPassword" value="root"/>
<!-- 创建表策略 -->
<property name="databaseSchemaUpdate" value="true"></property>
</bean>
</beans>
java代码加载activiti.cfg.xml
//2.xml方式获取的流引擎,自动创建Activiti涉及的表
@Test
public void createProcessEngineByXml() {
ProcessEngineConfiguration engineConfiguration =
ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
ProcessEngine processEngine = engineConfiguration.buildProcessEngine();
System.out.println("创建ProcessEngine通过xml:"+processEngine);
}
5、部署流程定义
通过上面的LeaveBill.png与LeaveBill.bpmn已经设计好了工作流程,因此需要将设计好的工作流程部署到系统中
@Test
public void deploy() {
//获取工作流引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取创库服务:管理流程定义
RepositoryService pRepositoryService = processEngine.getRepositoryService();
Deployment deploy = pRepositoryService.createDeployment() //创建一个部署构建器
.addClasspathResource("diagrams/LeaveBill.bpmn") //从类路径中添加资源,一次只能添加一个资源
.addClasspathResource("diagrams/LeaveBill.png")
.name("请求单流程") //设置部署名称
.category("办公类别") //设置部署类别
.deploy();
System.out.println("部署的Id:"+deploy.getId());
System.out.println("部署的name:"+deploy.getName());
}
影响的表:
SELECT * FROM `act_re_procdef`; ---- 流程定义表
SELECT * FROM `act_re_deployment`; ---- 部署表
SELECT * FROM `act_ge_property`; --- 通用属性表 id生成策略 next.dbid 影响部署的id
act_re_procdef
:流程定义表
该表的key值是bpmn的id决定;该表的name值是bpmn的name属性决定。
act_re_deployment
:部署表:id由act_ge_property的next.dbid 决定
act_ge_property
:通用属性表
6、启动流程
任务流程部署完成,则需要启动流程
//启动流程
@Test
public void startProcess() {
String processDefikey="leaveBill";
//取运行的服务
RuntimeService runtimeService = processEngine.getRuntimeService();
//通过流程定义的key,来启动流程
ProcessInstance pInstance = runtimeService.startProcessInstanceByKey(processDefikey);
System.out.println("流程实例的id:"+pInstance.getId());
System.out.println("流程定义的id:"+pInstance.getProcessDefinitionId());
}
7、任务完成
//完成任务
@Test
public void compileTask() {
String tackId = "204";
processEngine.getTaskService().complete(tackId);
System.out.println("当前任务执行完毕");
}
任务完成
五、管理流程定义
1、涉及的对象及表
涉及的对象:ProcessEngine、RepositoryService、Deployment、ProcessDefinition
涉及的表:
act_re_deployment:部署对象表
act_re_procdef:流程定义表
act_ge_bytearray:资源文件表
act_ge_property:主键生成策略表
2、设置流程定义图
2.1、流程图设计
2.2、bpmn与png文件
3、部署流程定义
3.1 、通过bpmn与png格式加载及部署
package cn.lice.activiti.b;
//流程定义管理
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.repository.Deployment;
import org.junit.Test;
public class ProcessDefinitionManager {
private ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//定义部署
@Test
public void deploy() {
Deployment deployment = processEngine.getRepositoryService()
.createDeployment()
.name("采购流程")
.addClasspathResource("diagrams/BuyBill.bpmn")
.addClasspathResource("diagrams/BuyBill.png")
.deploy();
System.out.println("部署名称:"+deployment.getName());
System.out.println("部署Id:"+deployment.getId());
}
}
3.2、通过zip格式加载及部署
//定义部署,zip格式
@Test
public void deployByZip() {
//从类路径中获取文件getClass().getClassLoader().getResourceAsStream("BuyBill.zip")
InputStream in = getClass().getClassLoader().getResourceAsStream("BuyBill.zip");
Deployment deployment = processEngine.getRepositoryService()
.createDeployment()
.name("采购流程")
.addZipInputStream(new ZipInputStream(in))
.deploy();
System.out.println("部署名称:"+deployment.getName());
System.out.println("部署Id:"+deployment.getId());
}
3.3、查看流定义
//查看流程定义
@Test
public void queryProcessDefinition() {
String proDefiKey = "BuyBill";
List<ProcessDefinition> list = processEngine.getRepositoryService().createProcessDefinitionQuery()
//查询,相当于where
// .processDefinitionCategory(category) // 流程定义目录
// .processDefinitionId(id) //流程定义id
// .processDefinitionKey(proDefiKey) //流程定义key
// .processDefinitionName(name) //流程定义name
// .processDefinitionVersion(version) //流程定义版本
// .latestVersion() //最新版本
.orderbyProcessDefinitionVersion().desc() //排序 按版本降序
//结果
// .count() //统计数
// .listPage(arg0, arg1) //分页
.list();
if (list!=null&& list.size()>0) {
for (ProcessDefinition processDefinition : list) {
System.out.print("流程定义id:"+processDefinition.getId());
System.out.print("流程定义name:"+processDefinition.getName());
System.out.print("流程定义版本:"+processDefinition.getVersion());
System.out.print("流程定义部署id:"+processDefinition.getDeploymentId());
System.out.println("流程定义key:"+processDefinition.getKey());
}
}
}
3.4、删除流定义
通过创库服务,根据部署id来删除流程定义。删除之后,与它相关的表都会被删除!
//删除流程定义
@Test
public void deleteProcessDefi() {
//获取工作流引擎,以及创库服务,通过流程部署id来删除
String deployId = "1";
processEngine.getRepositoryService().deleteDeployment(deployId);
}
3.5 、获取流定义的文档的资源(查看流程图附加)
3.6、查看最新版本的流定义
processEngine.getRepositoryService().createProcessDefinitionQuery().latestVersion() //最新版本
六、流程实例、任务执行
1、涉及的对象及表
2、启动流程实例
private ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//流程定义开始
@Test
public void startProcess() {
String processDefiKey = "buyBill";
ProcessInstance processInstance = processEngine.getRuntimeService().startProcessInstanceByKey(processDefiKey);
System.out.println("流程执行对象的id:"+processInstance.getId());
System.out.println("流程实例对象的id:"+processInstance.getProcessInstanceId());
System.out.println("流程定义的id:"+processInstance.getProcessDefinitionId());
}
3、查看的我的任务
//查询正在运行的任务,所有的正在执行的任务
@Test
public void queryTask() {
TaskService taskService = processEngine.getTaskService();
//创建一个任务对象
TaskQuery taskQuery = taskService.createTaskQuery();
//办理人任务列表
List<Task> list = (List<Task>) taskQuery.list();
//遍历办理人
if (list!=null && list.size()>0) {
for (Task task : list) {
System.out.println("任务办理人:"+task.getAssignee());
System.out.println("任务id:"+task.getId());
System.out.println("任务name:"+task.getName());
}
}
}
4、办理任务(完成任务)
//完成任务
@Test
public void compileTask() {
String tackId = "604";
processEngine.getTaskService().complete(tackId);
System.out.println("当前任务执行完毕");
}
5、查询流程实例状态(判断流程正在执行,还是结束)
//获取流程实例的状态
@Test
public void queryProcessTaskState() {
String processInstanceId="201";
ProcessInstance pInstance = processEngine.getRuntimeService().createProcessInstanceQuery()
.processInstanceId(processInstanceId)
.singleResult();//返回的数据要么是单例,要么是空
//判断流程实例的状态
if (pInstance!=null) {
System.out.println("该流程实例:"+processInstanceId+"在运行....."+pInstance.getActivityId());
}else {
System.out.println("当前的流程实例"+pInstance+"已经结束");
}
}
SELECT * FROM `act_hi_procinst`; --- 历史流程实例表
6、查看历史任务
SELECT * FROM `act_hi_taskinst`; --- 历史流程任务表
//查历史流程的实例的信息
@Test
public void queryHistoryProcessInstance() {
List<HistoricProcessInstance> list =
(List<HistoricProcessInstance>) processEngine.getHistoryService()
.createHistoricProcessInstanceQuery()
.list();
if (list!=null && list.size()>0) {
for (HistoricProcessInstance historicProcessInstance : list) {
System.out.println("历史流程实例id:"+historicProcessInstance.getId());
System.out.println("历史流程实例定义的id:"+historicProcessInstance.getProcessDefinitionId());
}
}
}
7、查看历史流程实例
//查看历史执行流程的任务信息
@Test
public void queryHistoryTask() {
String processInstanceId="601";
List<HistoricTaskInstance> list =
(List<HistoricTaskInstance>) processEngine.getHistoryService()
.createHistoricTaskInstanceQuery()
.processInstanceId(processInstanceId)
.list();
if (list!=null && list.size()>0) {
for (HistoricTaskInstance historicTaskInstance : list) {
System.out.println("历史流程实例id:"+historicTaskInstance.getId());
System.out.println("历史流程定义实例id:"+historicTaskInstance.getProcessDefinitionId());
System.out.println("历史流程任务的名称:"+historicTaskInstance.getName());
System.out.println("历史流程任务处理人:"+historicTaskInstance.getAssignee());
}
}
}
七、流程变量
涉及到的表
act_ru_variable:正在执行的流程变量表
act_hi_varinst:流程变量历史表
1、流程变量的作用
----传递业务参数(申请人、天数、事件、原因)
----动态指定办理人
-----指定连接,完成任务(同意或拒绝)
2、设置简易的bpmn流程图
3、部署流程定义及启动流程实例
ic class ProcessVariable {
private ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 定义部署
@Test
public void deploy() {
Deployment deployment = processEngine.getRepositoryService().createDeployment().name("支付流程")
.addClasspathResource("diagrams/APPayBill.bpmn").addClasspathResource("diagrams/appayBill.png")
.deploy();
System.out.println("部署名称:" + deployment.getName());
System.out.println("部署Id:" + deployment.getId());
}
// 流程定义开始
@Test
public void startProcess() {
String processDefiKey = "appayBill";
ProcessInstance processInstance = processEngine.getRuntimeService().startProcessInstanceByKey(processDefiKey);
System.out.println("流程执行对象的id:" + processInstance.getId());
System.out.println("流程实例对象的id:" + processInstance.getProcessInstanceId());
System.out.println("流程定义的id:" + processInstance.getProcessDefinitionId());
}
4、设置流程变量
-
通过 TaskService 和 RuntimeService 服务设置变量
-
Execution 与 ProcessInstance 区别
- Execution:只一个流程实例具体要执行的过程对象
- ProcessInstance:流程实例 ProcessInstance(1)–>Execution(N) ,且N>=1
- 值等情况: act_ru_execution 的id和 proc_inst_id 相同 ,该流程没有子流程
- 值不等情况: 只会出现在子流程中(嵌套、引入),act_ru_execution 的id和 proc_inst_id 不相同,但parent_id 等于当前流程实例的 id 和proc_inst_id
- 比如一个购物流程中除了下单、出库节点,
可能还有一个付款子流程,一般付款流程都是作为公用的流程,当任务达到子流程时,引擎会自动创建一个付款子流程
-
setValiable 与 setLocalValiable区别 作用域 : page、request、session、application
//设置流程变量值 @Test public void setVariable(){ String taskId="1804";//任务id //采用TaskService来设置流程变量 //1. 第一次设置流程变量 // TaskService taskService = processEngine.getTaskService(); // taskService.setVariable(taskId, "cost", 1000);//设置单一的变量,作用域在整个流程实例 // taskService.setVariable(taskId, "申请时间", new Date()); // taskService.setVariableLocal(taskId, "申请人", "何某某");//该变量只有在本任务中是有效的 //2. 在不同的任务中设置变量 // TaskService taskService = processEngine.getTaskService(); // taskService.setVariable(taskId, "cost", 5000);//设置单一的变量,作用域在整个流程实例 // taskService.setVariable(taskId, "申请时间", new Date()); // taskService.setVariableLocal(taskId, "申请人", "李某某");//该变量只有在本任务中是有效的 /** * 3. 变量支持的类型 * - 简单的类型 :String 、boolean、integer、double、date * - 自定义对象bean */ TaskService taskService = processEngine.getTaskService(); //传递的一个自定义bean对象 AppayBillBean appayBillBean=new AppayBillBean(); appayBillBean.setId(1); appayBillBean.setCost(300); appayBillBean.setDate(new Date()); appayBillBean.setAppayPerson("何某某"); taskService.setVariable(taskId, "appayBillBean", appayBillBean); System.out.println("设置成功!"); }
import java.util.Date; public class AppayBillBean { private Integer id; private Integer cost;//金额 private String appayPerson;//申请人 private Date date;//申请日期 public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getCost() { return cost; } public void setCost(Integer cost) { this.cost = cost; } public String getAppayPerson() { return appayPerson; } public void setAppayPerson(String appayPerson) { this.appayPerson = appayPerson; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } }
5、获取流程变量
//模拟流程变量设置
@Test
public void getAndSetProcessVariable(){
//有两种服务可以设置流程变量
// TaskService taskService = processEngine.getTaskService();
// RuntimeService runtimeService = processEngine.getRuntimeService();
/**1.通过 runtimeService 来设置流程变量
* exxcutionId: 执行对象
* variableName:变量名
* values:变量值
*/
// runtimeService.setVariable(exxcutionId, variableName, values);
// runtimeService.setVariableLocal(executionId, variableName, values);
//设置本执行对象的变量 ,该变量的作用域只在当前的execution对象
// runtimeService.setVariables(exxcutionId, variables);
//可以设置多个变量 放在 Map<key,value> Map<String,Object>
/**2. 通过TaskService来设置流程变量
* taskId:任务id
*/
// taskService.setVariable(taskId, variableName, values);
// taskService.setVariableLocal(taskId, variableName, values);
//// 设置本执行对象的变量 ,该变量的作用域只在当前的execution对象
// taskService.setVariables(taskId, variables); //设置的是Map<key,values>
/**3. 当流程开始执行的时候,设置变量参数
* processDefiKey: 流程定义的key
* variables: 设置多个变量 Map<key,values>
*/
// processEngine.getRuntimeService()
// .startProcessInstanceByKey(processDefiKey, variables)
/**4. 当执行任务时候,可以设置流程变量
* taskId:任务id
* variables: 设置多个变量 Map<key,values>
*/
// processEngine.getTaskService().complete(taskId, variables);
/** 5. 通过RuntimeService取变量值
* exxcutionId: 执行对象
*
*/
// runtimeService.getVariable(exxcutionId, variableName);//取变量
// runtimeService.getVariableLocal(exxcutionId, variableName);//取本执行对象的某个变量
// runtimeService.getVariables(variablesName);//取当前执行对象的所有变量
/** 6. 通过TaskService取变量值
* TaskId: 执行对象
*
*/
// taskService.getVariable(taskId, variableName);//取变量
// taskService.getVariableLocal(taskId, variableName);//取本执行对象的某个变量
// taskService.getVariables(taskId);//取当前执行对象的所有变量
}
6、查询历史的流程变量
7、流程变量支持的类型
八、连线
连线中,只有一条线程;没有并行的任务。有点像Java中的if流程。
-
设置bpmn流程图
-
部署和执行流程
-
查询和完成任务
-
如何设置条件变量
连线–>main config–>condition
表达式的结果必须是布尔型
- #{variable==‘value’}
- ${variable==value}
-
总结
一个活动中可以指定一个或多个SequenceFlow(Start中有一个,End中没有)。
- 开始活动中有一个SequenceFlow 。
- 结束活动中没有SequenceFlow 。
- 其他活动中有1条或多条SequenceFlow
如果只有一个,则可以不使用流程变量设置codition的名称;
连线代码:
package cn.lice.activiti.e;
import java.util.List;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.junit.Test;
//连线流程
public class SequenceFlow {
private ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 定义部署
@Test
public void deploy() {
Deployment deployment = processEngine.getRepositoryService().createDeployment().name("连线流程")
.addClasspathResource("diagrams/SequenceFlow.bpmn")
.deploy();
System.out.println("部署名称:" + deployment.getName());
System.out.println("部署Id:" + deployment.getId());
}
// 流程定义开始
@Test
public void startProcess() {
String processDefiKey = "sequenceBill";
ProcessInstance processInstance = processEngine.getRuntimeService().startProcessInstanceByKey(processDefiKey);
System.out.println("流程执行对象的id:" + processInstance.getId());
System.out.println("流程实例对象的id:" + processInstance.getProcessInstanceId());
System.out.println("流程定义的id:" + processInstance.getProcessDefinitionId());
}
// 查询正在运行任务
@Test
public void queryTask() {
// 取得任务服务
TaskService taskService = processEngine.getTaskService();
// 创建一个任务查询对象
TaskQuery taskQuery = taskService.createTaskQuery();
// 办理人的任务列表
List<Task> list = taskQuery.list();
// 遍历任务列表
if (list != null && list.size() > 0) {
for (Task task : list) {
System.out.println("任务的办理人:" + task.getAssignee());
System.out.println("任务的id:" + task.getId());
System.out.println("任务的名称:" + task.getName());
}
}
}
// 完成任务
@Test
public void compileTask() {
String taskId = "1502";
// taskId:任务id
processEngine.getTaskService().complete(taskId);
System.out.println("当前任务执行完毕");
}
}
设置信息,让工作流程按照指定的连线去执行
// 完成任务
@Test
public void compileTask() {
String taskId = "1204";
Map<String,Object> params=new HashMap<String, Object>();
params.put("message", "不知道重不重要");
// taskId:任务id
processEngine.getTaskService().complete(taskId, params);
// processEngine.getTaskService().complete(taskId);
System.out.println("当前任务执行完毕");
}
总结:
1、一个活动中可以指定一个或多个SequenceFlow(Start中有一个,End中没有)。
* 开始活动中有一个SequenceFlow 。
* 结束活动中没有SequenceFlow 。
* 其他活动中有1条或多条SequenceFlow
2、如果只有一个,则可以不使用流程变量设置codition的名称;
如果有多个,则需要使用流程变量设置codition的名称。message表示流程变量的名称,‘不重要’表示流程变量的值,${}中间的内容要使用boolean类型的表达式,用来判断应该执行的连线。
九、排他网关(ExclusiveGateWay)
-
设置bpmn流程图
-
部署与执行流程
package cn.lice.activiti.f; import java.util.HashMap; import java.util.List; import java.util.Map; import org.activiti.engine.ProcessEngine; import org.activiti.engine.ProcessEngines; import org.activiti.engine.TaskService; import org.activiti.engine.repository.Deployment; import org.activiti.engine.runtime.ProcessInstance; import org.activiti.engine.task.Task; import org.activiti.engine.task.TaskQuery; import org.junit.Test; //排他网关 public class ExclusiveGateway { private ProcessEngine processEngine = ProcessEngines .getDefaultProcessEngine(); // 部署流程定义,资源来在bpmn格式 @Test public void deployProcessDefi() { Deployment deploy = processEngine.getRepositoryService() .createDeployment().name("排他网关流程") .addClasspathResource("diagrams/ExclusiveGateway.bpmn") .deploy(); System.out.println("部署名称:" + deploy.getName()); System.out.println("部署id:" + deploy.getId()); } // 执行流程,开始跑流程 @Test public void startProcess() { String processDefiKey = "bankBill";// bpmn 的 process id属性 ProcessInstance pi = processEngine.getRuntimeService() .startProcessInstanceByKey(processDefiKey); System.out.println("流程执行对象的id:" + pi.getId());// Execution 对象 System.out.println("流程实例的id:" + pi.getProcessInstanceId());// ProcessInstance // 对象 System.out.println("流程定义的id:" + pi.getProcessDefinitionId());// 默认执行的是最新版本的流程定义 } // 查询正在运行任务 @Test public void queryTask() { // 取得任务服务 TaskService taskService = processEngine.getTaskService(); // 创建一个任务查询对象 TaskQuery taskQuery = taskService.createTaskQuery(); // 办理人的任务列表 List<Task> list = taskQuery.list(); // 遍历任务列表 if (list != null && list.size() > 0) { for (Task task : list) { System.out.println("任务的办理人:" + task.getAssignee()); System.out.println("任务的id:" + task.getId()); System.out.println("任务的名称:" + task.getName()); } } }
-
查询和完成任务
// 完成任务 @Test public void compileTask() { String taskId = "1501"; Map<String,Object> params=new HashMap<String, Object>(); params.put("visitor", 6); // taskId:任务id processEngine.getTaskService().complete(taskId, params); // processEngine.getTaskService().complete(taskId); System.out.println("当前任务执行完毕"); }
-
总结
1.一个排他网关对应一个以上的顺序流
2.由排他网关流出的顺序流都有个conditionExpression元素,在内部维护返回boolean类型的决策结果。
3.决策网关只会返回一条结果。当流程执行到排他网关时,流程引擎会自动检索网关出口,从上到下检索如果发现 第一条决策结果为true或者没有设置条件的(默认为成立),则流出。
4.如果没有任何一个出口符合条件,则抛出异常
5.使用流程变量,设置连线的条件,并按照连线的条件执行工作流,如果没有条件符合的条件,则以默认的连线离开,但是默认的连线不能设置条件
十、并行网关
1、流程图
![img](file:///C:/Users/11606/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg)
2、部署流程定义+启动流程实例
![img](file:///C:/Users/11606/AppData/Local/Temp/msohtmlclip1/01/clip_image004.jpg)
3、查询我的个人任务
![img](file:///C:/Users/11606/AppData/Local/Temp/msohtmlclip1/01/clip_image006.jpg)
4、完成我的个人任务
![img](file:///C:/Users/11606/AppData/Local/Temp/msohtmlclip1/01/clip_image008.jpg)
说明:
1) 一个流程中流程实例只有1个,执行对象有多个
2) 并行网关的功能是基于进入和外出的顺序流的:
分支(fork): 并行后的所有外出顺序流,为每个顺序流都创建一个并发分支。
汇聚(join): 所有到达并行网关,在此等待的进入分支, 直到所有进入顺序流的分支都到达以后, 流程就会通过汇聚网关。
3) 并行网关的进入和外出都是使用相同节点标识
4) 如果同一个并行网关有多个进入和多个外出顺序流, 它就同时具有分支和汇聚功能。 这时,网关会先汇聚所有进入的顺序流,然后再切分成多个并行分支。
5) 并行网关不会解析条件。 即使顺序流中定义了条件,也会被忽略。
6) 并行网关不需要是“平衡的”(比如, 对应并行网关的进入和外出节点数目不一定相等)。如图中标示是合法的:![img](file:///C:/Users/11606/AppData/Local/Temp/msohtmlclip1/01/clip_image010.gif)
5、开始活动节点
5.1、流程图
![img](file:///C:/Users/11606/AppData/Local/Temp/msohtmlclip1/01/clip_image011.gif)
5.2 、部署流程定义+启动流程实例+查询流程实例+查询历史流程实例
![img](file:///C:/Users/11606/AppData/Local/Temp/msohtmlclip1/01/clip_image013.jpg)
6、总结
1):结束节点没有出口
2):其他节点有一个或多个出口。
如果有一个出口,则代表是一个单线流程;
如果有多个出口,则代表是开启并发流程。
7、接收活动(receiveTask,即等待活动)
接收任务是一个简单任务,它会等待对应消息的到达。 当前,官方只实现了这个任务的java语义。 当流程达到接收任务,流程状态会保存到数据库中。
在任务创建后,意味着流程会进入等待状态, 直到引擎接收了一个特定的消息, 这会触发流程穿过接收任务继续执行。
7.1、流程图
![img](file:///C:/Users/11606/AppData/Local/Temp/msohtmlclip1/01/clip_image017.gif)
7.2、部署流程定义+启动流程实例
/**
* ReceiceTask任务,机器自动完成的任务
* 只会在act_ru_execution表中产生一条数据
* @throws Exception
*/
@Test
public void testExecution() throws Exception {
// 1 发布流程
InputStream inputStreamBpmn = this.getClass().getResourceAsStream("receiveTask.bpmn");
InputStream inputStreamPng = this.getClass().getResourceAsStream("receiveTask.png");
processEngine.getRepositoryService()//
.createDeployment()//
.addInputStream("receiveTask.bpmn", inputStreamBpmn)//
.addInputStream("receiveTask.png", inputStreamPng)//
.deploy();
// 2 启动流程
ProcessInstance pi = processEngine.getRuntimeService()//
.startProcessInstanceByKey("receiveTaskDemo");
System.out.println("pid:" + pi.getId());
String pid = pi.getId();
// 3**查询是否有一个执行对象在描述”汇总当日销售额“**
Execution e1 = processEngine.getRuntimeService()//
.createExecutionQuery()//
.processInstanceId(pid)//
.activityId("汇总当日销售额")//
.singleResult();
// 4**执行一堆逻辑,并设置流程变量**
Map<String,Object> vars = new HashMap<String, Object>();
vars.put("当日销售额", 10000);
// 5**流程向后执行一步:往后推移e1,使用signal给流程引擎信号,告诉他当前任务已经完成了,可以往后执行**
processEngine.getRuntimeService()
.signal(e1.getId(),vars);
// 6**判断当前流程是否在”给老板发短信“节点**
Execution e2 = processEngine.getRuntimeService()//
.createExecutionQuery()//
.processInstanceId(pid)//
.activityId("给总经理发短信")//
.singleResult();
// 7**获取流程变量**
Integer money = (Integer) processEngine.getRuntimeService()//
.getVariable(e2.getId(), "当日销售额");
System.out.println("老板,今天赚了" +money);
// 8**向后执行一步:任务完成,往后推移”给老板发短信“任务**
processEngine.getRuntimeService()//
.signal(e2.getId());
// 9**查询流程状态**
pi = processEngine.getRuntimeService()//
.createProcessInstanceQuery()//
.processInstanceId(pid)//
.singleResult();
if(pi==null){
System.out.println("流程正常执行!!!,已经结束了");
}
}
说明:
1) 当前任务(一般指机器自动完成,但需要耗费一定时间的工作)完成后,向后推移流程,可以调用runtimeService.signal(executionId),传递接收执行对象的id。
十一、用户任务(userTask)
- 个人任务
- 个人分配任务方式1:直接指定
- 个人分配任务方式2:采用流程变量
相关阅读
【案例背景:申请者填写申请单,启动流程,如果不大于10万元,部门经理审批,同意则告知申请人,不同意则流程直接结束;如果大于10万元,总经理审
有工作流使用经验的朋友请进来,最近在做一个工作流方面的项目;
在工作中我们使用流程图的频率极高,一方面利用它能清楚展示各个项目活动的流程,另一方面还可以明确各部分之间的逻辑关系。这么实用
某家公司接手新项目,需要市场营销部做出推广→市场部对接好业务→活动部协调好发布会,在整个过程中,多个部分、多位工作人员