1)工作流程变量
1)概念:流程实例中设置的变量使用的变量,它在实例中可以共享数据,作用范围是工作流程中的实例,各个实例的流程变量是互不干扰的;
2)流程变量数据库的取值原理
1)启动流程实例时没有存储任务id,但能通过taskId查询,时因为底层做了兼容,获取不到taskId就获取ExecutionId
3)流程变量的使用
1)工作流程中设置变量值4种方式
1:启动流程的时候设置
// 启动流程实例
@Test
public void startProcess() throws Exception {
// 拿到核心对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
Map<String, Object> variables = new HashMap<>();
variables.put("账户余额", 0.06);
variables.put("话费余额", 1);
// 操作:启动的时候设置流程变量
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myProcess", variables);
// processInstanceId:2501
System.out.println("processInstanceId:" + processInstance.getId());
System.out.println("processInstanceName:" + processInstance.getName());
}
2:任务完成的时候设置
// taskService 完成complate时设置变量
@Test
public void complateYangTest() throws Exception {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// taskService设置变量
TaskService taskService = processEngine.getTaskService();
Map<String, Object> variables = new HashMap<>();
variables.put("请假原因", "想女朋友了");// 设置String
variables.put("请假天数", 3);// 设置Integer
variables.put("是否扣工资", true);// 设置boolean:存long型:1true;0false
variables.put("请假开始时间", new Date());// 设置Date类型
variables.put("扣多少钱", 666.666d);// 设置Double
TaskQuery taskQuery = taskService.createTaskQuery();
Task result = taskQuery.taskAssignee("yang")
.processInstanceId("2501")
.singleResult();// 在一次流程实例中一个人的任务是唯一的
String taskId = result.getId();
// 完成任务的时候设置:
taskService.complete(taskId, variables);
}
3:runtimeService设置()
// taskService 不在完成complate时设置变量
@Test
public void runtimeServiceYangTest2() throws Exception {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
Map<String, Object> variables = new HashMap<>();
variables.put("呵呵", "想女朋友了");// 设置String
variables.put("试试", 3);// 设置Integer
variables.put("是", true);// 设置boolean:存long型:1true;0false
variables.put("时间", new Date());// 设置Date类型
variables.put("钱", 666.666d);// 设置Double
//javabean
variables.put("技师", new Person("admin", "admin"));
// 使用RuntimeService存
ExecutionQuery executionQuery = runtimeService.createExecutionQuery();
Execution execution = executionQuery
.processInstanceId("2501")
.activityId("员工请假id")// 活动节点的id
.singleResult();
// 存一个
runtimeService.setVariable(execution.getId(), "解决", "好好好");
// 存多个
runtimeService.setVariables(execution.getId(), variables);
}
4:taskService设置(不完成任务)
// taskService 不在完成complate时设置变量
@Test
public void complateYangTest2() throws Exception {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
// taskService设置变量
TaskService taskService = processEngine.getTaskService();
TaskQuery taskQuery = taskService.createTaskQuery();
Task result = taskQuery
.taskAssignee("yang")
.processInstanceId("2501")
.singleResult();// 在一次流程实例中一个人的任务是唯一的
Map<String, Object> variables = new HashMap<>();
variables.put("呵呵", "想女朋友了");// 设置String
variables.put("试试", 3);// 设置Integer
variables.put("是", true);// 设置boolean:存long型:1true;0false
variables.put("时间", new Date());// 设置Date类型
variables.put("钱", 666.666d);// 设置Double
// javabean
variables.put("技师", new Person("admin", "admin"));
String taskId = result.getId();
// 存一个
taskService.setVariable(taskId, "请假原因", "55");
// 存多个
taskService.setVariables(taskId, variables);
taskService.complete(taskId);
}
2)工作流程中获取变量的2种方式
1:runtimeService获取变量
// runtimeService获取变量
@Test
public void runTimeServiceTangTest() throws Exception {
// 获取大管家
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 拿到任务服务对象实例
RuntimeService runtimeService = processEngine.getRuntimeService();
// 拿到查询对象
ExecutionQuery executionQuery = runtimeService.createExecutionQuery();
// 做事情
Execution execution = executionQuery.processInstanceId("2501")
.activityId("经理审批id")// 活动节点id
.singleResult();
// 取一个变量 要转
String executionId = execution.getId();
String name = (String) runtimeService.getVariable(executionId, "请假原因");
System.out.println("取一个要转:" + name);
// 取一个变量 不转
String executionId2 = execution.getId();
String name2 = runtimeService.getVariable(executionId, "呵呵", String.class);
System.out.println("取一个不转:" + name2);
// 取全部
Map<String, Object> variables = runtimeService.getVariables(executionId);
System.out.println("取全部变量:" + variables);
// 取出部分变量
Map<String, Object> variables2 = runtimeService.getVariables(executionId, Arrays.asList("请假天数", "3"));
System.out.println("取部分:" + variables2);
}
2:taskService获取变量
// tang经理审批完成任务时 TaskService获取变量
@Test
public void taskTangTest() throws Exception {
// 获取大管家
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 拿到任务服务对象实例
TaskService taskService = processEngine.getTaskService();
// 设置查询条件
Task task = taskService.createTaskQuery()
.taskAssignee("tang")
.processInstanceId("2501")
.singleResult();
String taskId = task.getId();// 任务id
String variableName = "请假原因";
// 执行任务 取出变量 但要强转 取一个
String varName = (String) taskService.getVariable(taskId, variableName);
System.out.println("取一个要强转:" + varName);
// 取一个但无需强转
String varName2 = taskService.getVariable(taskId, variableName, String.class);
System.out.println("取一个变量不转:" + varName);
// 取全部
Map<String, Object> variables = taskService.getVariables(taskId);
System.out.println("取全部变量:" + variables);
// 取出部分变量
Map<String, Object> variables2 = taskService
.getVariables(taskId, Arrays.asList("请假天数", "3"));
System.out.println("取部分" + variables2);
}
3)流程变量数据库的设计原理
1)对于变量的存储在数据库以多个数据类型存储的,满足存储多种数据类型的需求;
ACT_RU_VARIABLE:运行时流程变量数据表
1. ID_:标识 2. REV_:版本号
3. TYPE_:数据类型 4. NAME_:变量名
5. EXECUTION_ID_: 执行实例id 6. PROC_INST_ID_: 流程实例id
7. TASK_ID_: 任务id 8. BYTEARRAY_ID_:
9. DOUBLE_:若数据类型为double ,保存数据在此列
10. LONG_: 若数据类型为Long保存数据到此列
11. TEXT_: string 保存到此列 12. TEXT2_:
4)流程定义语言BPMN
1)概念:业务流程建模与标注(Business Process Model and Notation,BPMN),解释了流程是由基本符号和图元组合成的业务流程图;
2)流程(Process):bpmn是一个流程的根元素,一个工作流就是一个工作流;
3)顺序流(SequenceFlow)
概念:顺序流是连接流程节点的线,是一个节点的出口;
顺序流结构:
Id: 唯一标示,用来区分不同的顺序流
sourceRef:连线的源头节点ID
targetRef:连线的目标节点ID
name:连线的名称,不涉及业务,主要用于显示。多出口原则要设置
并发流的使用(驳回or同意)
工作流程图驳回还是通过(condition ${flag==true/false})
代码(在完成任务时设置flag的开关)
package com.yyg.activiti_02.sequenceflow_02;
import static org.junit.Assert.*;
import java.util.HashMap;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;
import com.yyg.activiti_02.base.Basebpmn;
public class SequenceFlowTest extends Basebpmn {
// 部署流程
@Test
public void deployTest() throws Exception {
Deployment deploy = deploy("LeaveProcess", "员工离职流程申请_v01");
System.out.println(deploy);
}
//开启流程
@Test
public void startProcess() throws Exception {
String processDefinitionKey = "leaveProcess";
ProcessInstance processInstance = startProcess(processDefinitionKey);
System.out.println(processInstance);// 2501
}
// 查看yang私有任务
@Test
public void queryYangPersonalTaskTest() throws Exception {
Task queryPrivateTask = queryPrivateTask("yang", "2501");
// Task[id=2504, name=员工申请]
// 第二次 驳回 Task[id=7503, name=员工申请]
// 第三次 null 通过 没有任务
System.out.println(queryPrivateTask);
}
@Test
public void queryYangPersonalTaskTest() throws Exception {
Task queryPrivateTask = queryPrivateTask("yang", "2501");
// Task[id=2504, name=员工申请]
// 第二次 驳回 Task[id=7503, name=员工申请]
// 第三次 null 通过 没有任务
System.out.println(queryPrivateTask);
}
//查看yang的私有任务
@Test
public void complateYangPersonalTaskTest() throws Exception {
complatePersonalTask("yang", "2501");
}
// 查看tang的私有任务
@Test
public void queryTangPersonalTaskTest() throws Exception {
Task queryPrivateTask = queryPrivateTask("tang", "2501");
// Task[id=5002, name=经理批准]
//驳回第二次 Task[id=10002, name=经理批准]
System.out.println(queryPrivateTask);
}
// tang经理驳回申请操作测试
@Test
public void tangNoPassTest() throws Exception {
String taskId = queryPrivateTask("tang", "2501").getId();
HashMap<String, Object> variables = new HashMap<>();// 设置变量
variables.put("flag", false);
taskService.complete(taskId, variables);
}
// tang经理通过申请操作测试
@Test
public void tangPassTest() throws Exception {
String taskId = queryPrivateTask("tang", "2501").getId();
HashMap<String, Object> variables = new HashMap<>();// 设置变量
variables.put("flag", true);
taskService.complete(taskId, variables);
}
// 测试状态
@Test
public void testProcessState() throws Exception {
showProcessState("2501");
}}
4)节点
1)节点类型:
- 开始节点 结束节点
- 任务节点 网关节点 监听器节点
2)开始事件节点(startEvent):开始事件对应节点
3)结束事件节点(endEvent):结束事件对应节点
4)任务节点 (Task)
- 接收任务节点 (receiveTask)
- 接收任务节点概念:不需要人工参与,接收任务会等待信号,任务创建后,节点流程会进入等待状态,引擎收到single信号才继续执行(收到信号触发)
- 接收任务节点使用
- 流程图
代码实现
package com.yyg.activiti_02.receiveTask_03;
import static org.junit.Assert.*;
import java.util.HashMap;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.junit.Test;
import com.yyg.activiti_02.base.Basebpmn;
public class ReceiveTaskTest extends Basebpmn{
//部署流程
@Test
public void deployTest() throws Exception {
Deployment deployment = deploy("ReceiveRequestProcess", "接收任务流程_v1");
//DeploymentEntity[id=1, name=接收任务流程_v1]
System.out.println(deployment);
}
//启动流程
@Test
public void startProcessTest() throws Exception {
ProcessInstance startProcess = startProcess("receiveTaskProcess");
//ProcessInstance[2501]
System.out.println(startProcess);
}
//计算今日销售额 第一个节点
@Test
public void countTotalTest() throws Exception {
//今天的销售额 应该是调用Mapper查询方法计算从数据库
double total=6666.66; 模拟的数据
Execution execution = getExecution("2501", "销售额今日计算id");
String executionId=execution.getId();
//把总额设置到变量 节点要拿到
HashMap<String, Object> variables = new HashMap<>();
variables.put("total", total);
//向接收任务节点发送信号
runtimeService.signal(executionId, variables);
}
//发送短信 第二个节点
@Test
public void sendMsgTest() throws Exception {
Execution execution = getExecution("2501", "发送短信给老板id");
String executionId=execution.getId();
// 1 从流程变量种获取销售额
Double total = runtimeService.getVariable(executionId, "total", Double.class);
//应该是调用第三方接口发送短信
// 2 把销售额发送给老板
String message="很开心的一天 盈利了"+total+"元";
System.out.println(message);
// 3 让流程继续往下走 给接收任务节点发送消息
runtimeService.signal(executionId);
}
//4 判断流程结束
@Test
public void isEnd() throws Exception {
showProcessState("2501");//已结束
}
}
用户任务节点 userTask (需要人工参与的节点)
流程图
代码实现
package com.yyg.activiti_02.receiveTask_03;
import java.util.HashMap;
import java.util.Map;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;
import com.yyg.activiti_02.base.Basebpmn;
public class UserTaskTest extends Basebpmn{
@Test
public void test2() {
//部署
deploy("UserTaskProcess", "人工处理任务节点");
//启动时要设置第一个节点的办理者
String processDefinitionKey = "userTaskProcessid";
Map<String, Object> variables = new HashMap<>();
//第一个节点办理者
String assignee = "yang";//当前登录用户名称
variables.put("apply", assignee);
ProcessInstance pi = startProcess(processDefinitionKey,variables);
//获取写死办理的任务
Task task = queryPrivateTask(assignee, pi.getId());
//Task[id=9, name=计算今日销售额]
System.out.println(task);
}
//要把第一个节点走下去
/**
* 使用流程变量设置
* @throws Exception
*/
@Test
public void test3Pre() throws Exception {
//启动时要设置第一个节点的办理者
String processDefinitionKey = "userTaskProcessid";
Map<String, Object> variables = new HashMap<>();
//第一个节点办理者
String assignee = "yang";//当前登录用户名称
variables.put("apply", assignee);
ProcessInstance pi = startProcess(processDefinitionKey,variables);
//获取写死办理的任务
Task task = queryPrivateTask(assignee,pi.getId());
//id:2505,name:计算今日销售额,assignee:yang
System.out.println(task);
taskService.complete(task.getId());
}
//上一个任务完成设置下一个任务的办理者,没法做,没有办法直接获取下一个任务并设置
//当前任务创建时,再指定办理者
@Test
public void test3() throws Exception {
String assignee ="tang";
String processInstanceId="2501";
Task task = queryPrivateTask(assignee, processInstanceId);
//Task[id=2508, name=发送短信]
System.out.println(task);
//完成第二个任务
taskService.complete(task.getId());
//判断流程是否结束
showProcessState(processInstanceId);//流程已结束
}
}
监听器类设置办理人ManagerSettingListener
/**
* ①写一个类实现监听器类-TaskListener
* ②把写好类绑定到对应节点
* ③实现监听器逻辑
* @author 阳彦刚
*/
public class ManagerSettingListener implements TaskListener{
@Override
public void notify(DelegateTask delegateTask) {
System.out.println(delegateTask.getName());
//1 获取申请人
String apply = delegateTask.getVariable("apply", String.class);
//2 通过申请人获取审批人 通过申请人获取部门经理
String manager = apply+"审批人";
//3 设置办理者
delegateTask.setAssignee(manager);
}
}
5)监听器的使用
创建:写一个类实现某个监听器接口,重写方法配置自定义监听器;
1)activiti任务监听器TaskListener
用途:人工任务节点办理者的动态设置,只能监听人工任务节点
流程图(第一个无需监听,根据第一个节点在第二个节点设置办理人)
代码实现
package com.yyg.activiti_02.tasklistener_05;
import static org.junit.Assert.*;
import java.util.HashMap;
import java.util.Map;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;
import com.yyg.activiti_02.base.Basebpmn;
public class MyTaskListenerTest extends Basebpmn{
//部署
@Test
public void deployTest() throws Exception {
Deployment deployment = deploy("TaskProcessTest2","任务监听流程_v02");
//DeploymentEntity[id=1, name=任务监听流程_v02]
System.out.println(deployment);
}
//启动
@Test
public void startProcessTest() throws Exception {
String processDefinitionKey="taskProcessid";
Map<String, Object> variables=new HashMap<>();
variables.put("applyUser", "狗蛋儿");
ProcessInstance processInstance = startProcess(processDefinitionKey, variables);
//ProcessInstance[2501]
System.out.println(processInstance);
}
//第一个节点 查看狗蛋儿的私有任务
@Test
public void queryPersionalTaskTest() throws Exception {
Task task = queryPrivateTask("狗蛋儿", "2501");
//Task[id=2505, name=员工申请]
System.out.println(task);
}
//狗蛋儿完成第一个任务
@Test
public void complateGDTaskTest() throws Exception {
taskService.complete(queryPrivateTask("狗蛋儿", "2501").getId());
}
//查看qian的私有任务
@Test
public void queryQianPersionalTaskTest() throws Exception {
Task task = queryPrivateTask("qian", "2501");
//Task[id=5002, name=部门审批]
System.out.println(task);
}
//第二个节点qian完成第二个任务
@Test
public void complateQianTaskTest() throws Exception {
taskService.complete(queryPrivateTask("qian", "2501").getId());
}
//查看状态
@Test
public void idEnd() throws Exception {
showProcessState("2501");//已结束
}
}
任务监听器MyTaskListener:
package com.yyg.activiti_02.tasklistener_05;
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;
/**
* @author Administrator
* 只能绑定到用户任务节点
* 可用于用户节点办理者的动态设置,操作日志等,可以从数据库查询出数据为下一节点设置受理人等
*/
public class MyTaskListener implements TaskListener{
@Override
public void notify(DelegateTask task) {
//通过上一个节点查询出当前节点的办理人
//获取到上一个节点的办理人
//流程变量用起来
//查询数据库,得到第一个节点的办理人zhang的部门经理是qian
String name = "qian";//zhang是通过数据库查询出来的办理人
System.out.println("设置了当前任务节点的办理人");
//设置qian为当前任务节点的办理人
task.setAssignee(name);
}
}
2)activiti执行监听器ExecutionListener
用途:可以用来修改开始和结束的状态,可以监听所有节点,可以监听所有节点
执行监听器应用:
流程图
开始执行监听器的方法
结束执行监听器的方法
代码(启动测试即可可以看到执行开始、执行结束、改变状态)
package com.yyg.activiti_02.executionlistener_04;
import static org.junit.Assert.*;
import java.util.HashMap;
import java.util.Map;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.junit.Test;
import com.yyg.activiti_02.base.Basebpmn;
public class MyExecutionListenerTest extends Basebpmn {
// 部署人工节点流程
@Test
public void deployTest() throws Exception {
Deployment deploy = deploy("TaskProcessTest", "人工节点流程监听器_v01");
// DeploymentEntity[id=1, name=人工节点流程监听器_v01]
System.out.println(deploy);
}
// 启动流程
@Test
public void startProcessTest() throws Exception {
String processDefinitionKey = "taskProcessTestIid";
ProcessInstance processInstance = startProcess(processDefinitionKey);
//ProcessInstance[2501]
System.out.println(processInstance);
}
// yang完成私有方法
@Test
public void complateYangTest() throws Exception {
taskService.complete(queryPrivateTask("yang", "2501").getId());
}
}
6)网关节点
用途:控制流程的流向
排它网关
概念:排他网关流出的顺序流都有个conditionExpression元素,在内部维护返回boolean类型的决策结果决策网关只会返回一条结果如果没有任何一个出口符合条件则抛出异常
流程图
并行网关(parallelGateWay)
概念:多个分支要一起执行完,网关可以表示流程中的并行情况,可以把多条分支 汇聚到一起
流程图