首页
统计
关于
Search
1
Sealos3.0离线部署K8s集群
1,079 阅读
2
类的加载
740 阅读
3
Spring Cloud OAuth2.0
725 阅读
4
SpringBoot自动装配原理
690 阅读
5
集合不安全问题
583 阅读
笔记
Java
多线程
注解和反射
JVM
JUC
设计模式
Mybatis
Spring
SpringMVC
SpringBoot
MyBatis-Plus
Elastic Search
微服务
Dubbo
Zookeeper
SpringCloud
Nacos
Sentinel
数据库
MySQL
Oracle
PostgreSQL
Redis
MongoDB
工作流
Activiti7
Camunda
消息队列
RabbitMQ
前端
HTML5
CSS
CSS3
JavaScript
jQuery
Vue2
Vue3
Linux
容器
Docker
Kubernetes
Python
登录
Search
标签搜索
Java
CSS
mysql
RabbitMQ
JavaScript
Redis
JVM
Mybatis-Plus
Camunda
多线程
CSS3
Python
Spring Cloud
注解和反射
Activiti
工作流
SpringBoot
Mybatis
Spring
html5
蘇阿細
累计撰写
388
篇文章
累计收到
4
条评论
首页
栏目
笔记
Java
多线程
注解和反射
JVM
JUC
设计模式
Mybatis
Spring
SpringMVC
SpringBoot
MyBatis-Plus
Elastic Search
微服务
Dubbo
Zookeeper
SpringCloud
Nacos
Sentinel
数据库
MySQL
Oracle
PostgreSQL
Redis
MongoDB
工作流
Activiti7
Camunda
消息队列
RabbitMQ
前端
HTML5
CSS
CSS3
JavaScript
jQuery
Vue2
Vue3
Linux
容器
Docker
Kubernetes
Python
页面
统计
关于
搜索到
18
篇与
的结果
2024-07-05
任务分配
1. 固定分配在绘制流程时直接指定 Assignee测试package com.sw.camundademo; import org.camunda.bpm.engine.RepositoryService; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.TaskService; import org.camunda.bpm.engine.repository.Deployment; import org.camunda.bpm.engine.runtime.ProcessInstance; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; /** * @Author Suaxi * @Date 2024/7/3 22:11 * @Description */ @SpringBootTest public class AssigneeTest { @Autowired private RepositoryService repositoryService; @Autowired private RuntimeService runtimeService; @Autowired private TaskService taskService; @Test public void deploy() { Deployment deploy = repositoryService.createDeployment() .name("请假流程-固定分配") .addClasspathResource("flow/01.任务分配-固定分配.bpmn") .deploy(); System.out.println(deploy.getId()); } @Test public void startProcess() { ProcessInstance processInstance = runtimeService.startProcessInstanceById("Process_0sa1c18:1:db75f76f-3946-11ef-9303-a8a1592cf182"); System.out.println("processInstance.getId() = " + processInstance.getId()); } @Test public void completeTask() { taskService.complete("44488821-3947-11ef-98ee-a8a1592cf182"); } } 2. 值表达式通过 ${value} 的形式来设置 Assignee测试package com.sw.camundademo; import org.camunda.bpm.engine.RepositoryService; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.TaskService; import org.camunda.bpm.engine.repository.Deployment; import org.camunda.bpm.engine.runtime.ProcessInstance; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.HashMap; import java.util.Map; /** * @Author Suaxi * @Date 2024/7/3 22:11 * @Description */ @SpringBootTest public class AssigneeTest { @Autowired private RepositoryService repositoryService; @Autowired private RuntimeService runtimeService; @Autowired private TaskService taskService; @Test public void deploy() { Deployment deploy = repositoryService.createDeployment() .name("请假流程-值表达式") .addClasspathResource("flow/02.任务分配-值表达式.bpmn") .deploy(); System.out.println(deploy.getId()); } @Test public void startProcess() { Map<String, Object> variables = new HashMap<>(4); variables.put("user1", "admin"); ProcessInstance processInstance = runtimeService.startProcessInstanceById("Process_0nn4skb:1:cfb647fa-3949-11ef-83c2-a8a1592cf182", variables); System.out.println("processInstance.getId() = " + processInstance.getId()); } @Test public void completeTaskVariables() { Map<String, Object> variables = new HashMap<>(4); variables.put("user2", "admin"); taskService.complete("34ca22b2-394a-11ef-896b-a8a1592cf182", variables); } } 3. 方法表达式与值表达式类似,当调用无参的方法时,要在表达式方法名的末尾添加括号(与值表达式做区分),如:# assigneeService是容器中的bean对象,通过调用getAssignee()方法来设置 Assignee ${assigneeService.getAssignee()} ${assigneeService.getAssignee("method expression test")}测试package com.sw.camundademo.service; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; /** * @Author Suaxi * @Date 2024/7/3 22:46 * @Description */ @Slf4j @Service public class AssigneeService { public String getAssignee() { log.info("getAssignee方法执行了"); return "admin"; } } package com.sw.camundademo; import org.camunda.bpm.engine.RepositoryService; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.TaskService; import org.camunda.bpm.engine.repository.Deployment; import org.camunda.bpm.engine.runtime.ProcessInstance; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.HashMap; import java.util.Map; /** * @Author Suaxi * @Date 2024/7/3 22:11 * @Description */ @SpringBootTest public class AssigneeTest { @Autowired private RepositoryService repositoryService; @Autowired private RuntimeService runtimeService; @Autowired private TaskService taskService; @Test public void deploy() { Deployment deploy = repositoryService.createDeployment() .name("请假流程-方法表达式") .addClasspathResource("flow/03.任务分配-方法表达式.bpmn") .deploy(); System.out.println(deploy.getId()); } @Test public void startProcess() { ProcessInstance processInstance = runtimeService.startProcessInstanceById("Process_128tk93:1:0316ac79-394c-11ef-b118-a8a1592cf182"); System.out.println("processInstance.getId() = " + processInstance.getId()); } @Test public void completeTask() { taskService.complete("3858dc36-394c-11ef-bc0e-a8a1592cf182"); } } 4. 监听器配置可以通过自定义的监听器配置来指定 Assignee监听器(根据流程实例的事件类型 create 设置 Assignee)package com.sw.camundademo.listener; import lombok.extern.slf4j.Slf4j; import org.camunda.bpm.engine.delegate.DelegateTask; import org.camunda.bpm.engine.delegate.TaskListener; /** * @Author Suaxi * @Date 2024/7/3 23:07 * @Description */ @Slf4j public class AssigneeListener implements TaskListener { @Override public void notify(DelegateTask delegateTask) { if (EVENTNAME_CREATE.equals(delegateTask.getEventName())) { log.info("自定义监听器触发了..."); delegateTask.setAssignee("admin"); } } } 流程图绘制(在 Listener 选项卡下配置 Event Type 和具体的监听器全路径类名)测试方法同理以上其他的任务分配方式
2024年07月05日
30 阅读
0 评论
0 点赞
2024-07-05
SpringBoot整合Camunda
1. 根据官方文档https://docs.camunda.org/get-started/spring-boot/2. 自定义(1)新建springboot项目pom.xml配置<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.5.RELEASE</version> <relativePath/> </parent> <groupId>com.sw</groupId> <artifactId>camunda-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>camunda-demo</name> <description>camunda-demo</description> <properties> <java.version>1.8</java.version> <camunda.version>7.15.0</camunda.version> <camunda.spin.dataformat.version>1.14.4</camunda.spin.dataformat.version> <mysql.version>8.0.33</mysql.version> <lombok.version>1.18.32</lombok.version> </properties> <dependencies> <!-- camunda bom --> <dependency> <groupId>org.camunda.bpm</groupId> <artifactId>camunda-bom</artifactId> <version>${camunda.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- camunda starter rest --> <dependency> <groupId>org.camunda.bpm.springboot</groupId> <artifactId>camunda-bpm-spring-boot-starter-rest</artifactId> <version>${camunda.version}</version> </dependency> <!-- camunda starter webapp --> <dependency> <groupId>org.camunda.bpm.springboot</groupId> <artifactId>camunda-bpm-spring-boot-starter-webapp</artifactId> <version>${camunda.version}</version> </dependency> <!-- camunda engine plugin spin --> <dependency> <groupId>org.camunda.bpm</groupId> <artifactId>camunda-engine-plugin-spin</artifactId> <version>${camunda.version}</version> </dependency> <!-- camunda spin --> <dependency> <groupId>org.camunda.spin</groupId> <artifactId>camunda-spin-dataformat-all</artifactId> <version>${camunda.spin.dataformat.version}</version> </dependency> <!-- spring web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- jdbc --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <!-- lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> (2)修改数据库为MySQL解压 camunda-bpm-run-7.15.0.zip 压缩包,在 camunda-bpm-run-7.15.0\configuration\sql\create 路径下找到 mysql_engine_7.15.0.sql,mysql_identity_7.15.0.sql两个文件,在数据库创建 camunda-demo 库,并执行刚才的两个sql文件(3)修改数据源配置文件application.ymlserver: port: 8088 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/camunda-demo?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false username: root password: 123456 camunda.bpm.admin-user: id: admin password: 123456 camunda: bpm: database: type: mysql schema-update: true #自动部署resources下的bpmn文件 auto-deployment-enabled: false项目启动成功之后可访问 http://localhost:8088(4)表说明与Activity类似 表名解释一般数据 [ACT_GE_BYTEARRAY]通用的流程定义和流程资源 [ACT_GE_PROPERTY]系统相关属性流程历史记录 [ACT_HI_ACTINST]历史的流程实例 [ACT_HI_ATTACHMENT]历史的流程附件 [ACT_HI_COMMENT]历史的说明性信息 [ACT_HI_DETAIL]历史的流程运行中的细节信息 [ACT_HI_IDENTITYLINK]历史的流程运行过程中用户关系 [ACT_HI_PROCINST]历史的流程实例 [ACT_HI_TASKINST]历史的任务实例 [ACT_HI_VARINST]历史的流程运行中的变量信息流程定义表 [ACT_RE_DEPLOYMENT]部署单元信息 [ACT_RE_MODEL]模型信息 [ACT_RE_PROCDEF]已部署的流程定义运行实例表 [ACT_RU_EVENT_SUBSCR]运行时事件 [ACT_RU_EXECUTION]运行时流程执行实例 [ACT_RU_IDENTITYLINK]运行时用户关系信息,存储任务节点与参与者的相关信息 [ACT_RU_JOB]运行时作业 [ACT_RU_TASK]运行时任务 [ACT_RU_VARIABLE]运行时变量表用户用户组表 [ACT_ID_BYTEARRAY]二进制数据表 [ACT_ID_GROUP]用户组信息表 [ACT_ID_INFO]用户信息详情表 [ACT_ID_MEMBERSHIP]人与组关系表 [ACT_ID_PRIV]权限表 [ACT_ID_PRIV_MAPPING]用户或组权限关系表 [ACT_ID_PROPERTY]属性表 [ACT_ID_TOKEN]记录用户的token信息 [ACT_ID_USER]用户表
2024年07月05日
156 阅读
0 评论
0 点赞
2024-07-05
IDEA引入流程设计器
以 Camunda 7.15.0 版本为例1. 下载Camunda Modelhttps://downloads.camunda.cloud/release/camunda-bpm/run/7.15/camunda-bpm-run-7.15.0.ziphttps://downloads.camunda.cloud/release/camunda-modeler/4.12.0/camunda-modeler-4.12.0-win-x64.zip2. 在IDEA中配置idea ---> file ---> setting ---> tools ---> external tools ---> 点击添加---> tool settings ---> programs ---> 选择刚刚下载的压缩包解压之后的camunda modeler.exe ---> ok3. 编辑BPMN文件启动 camunda-modeler
2024年07月05日
47 阅读
0 评论
0 点赞
2023-05-27
工作流 - 网关
1. 排他网关 ExclusiveGateway(1)概念排他网关,用来在流程中实现决策。 当流程执行到这个网关,所有分支都会判断条件是否为true,如果 为true则执行该分支,排他网关只会选择一个为true的分支执行,如果有两个分支条件都为true,排他网关会选择id值较小的一条分支去执行当从网关出去的线所有条件都不满足时则会抛出异常org.activiti.engine.ActivitiException: No outgoing sequence flow of the exclusive gateway 'exclusivegateway' could be selected for continuing the process at org.activiti.engine.impl.bpmn.behavior.ExclusiveGatewayActivityBehavior.leave(ExclusiveGatewayActivityBehavior.java:85)(2)测试public class ExclusiveTest { @Test public void deploy() { //1.获取ProcessEngine对象 ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); //2.获取RepositoryService RepositoryService service = engine.getRepositoryService(); //3.部署 Deployment deploy = service.createDeployment() .addClasspathResource("bpmn/evection-exclusive.bpmn") .addClasspathResource("bpmn/evection-exclusive.png") .name("出差申请流程-排他网关") .deploy(); System.out.println("id: " + deploy.getId()); System.out.println("name: " + deploy.getName()); //service.deleteDeployment("57501", true); } @Test public void startProcess() { ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); RuntimeService runtimeService = engine.getRuntimeService(); Evection evection = new Evection(); evection.setNum(4d); Map<String, Object> map = new HashMap<>(); map.put("evection", evection); ProcessInstance instance = runtimeService.startProcessInstanceByKey("evection-exclusive", map); System.out.println("流程定义id:" + instance.getProcessDefinitionId()); } @Test public void completeTask() { String userId = "lisi"; ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = engine.getTaskService(); Task task = taskService.createTaskQuery().processDefinitionKey("evection-exclusive").taskAssignee(userId).singleResult(); if (task != null) { Evection evection = new Evection(); evection.setNum(2d); Map<String, Object> map = new HashMap<>(); map.put("evection", evection); taskService.complete(task.getId(), map); System.out.println("任务:" + task.getId() + "完成"); } } }2. 并行网关ParallelGateway(1)概念并行网关允许将流程分成多条分支,也可以把多条分支汇聚到一起,并行网关的功能是基于进入和外出顺序流的:fork分支: 并行后的所有外出顺序流,为每个顺序流都创建一个并发分支join汇聚: 所有到达并行网关,在此等待的进入分支,直到所有进入顺序流的分支都到达以后,流程就会通过汇聚网关注意,如果同一个并行网关有多个进入和多个外出顺序流,它就同时具有分支和汇聚功能,这时,网关会先汇聚所有进入的顺序流,然后再切分成多个并行分支,并行网关与其他网关的主要区别是,并行网关不会解析条件,即使顺序流中定义了条件,在流程流转时也会被忽略(2)测试public class 8ParallelTest { @Test public void deploy() { //1.获取ProcessEngine对象 ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); //2.获取RepositoryService RepositoryService service = engine.getRepositoryService(); //3.部署 Deployment deploy = service.createDeployment() .addClasspathResource("bpmn/evection-parallel.bpmn") //.addClasspathResource("bpmn/evection-exclusive.png") .name("出差申请流程-并行网关") .deploy(); System.out.println("id: " + deploy.getId()); System.out.println("name: " + deploy.getName()); //service.deleteDeployment("57501", true); } @Test public void startProcess() { ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); RuntimeService runtimeService = engine.getRuntimeService(); Evection evection = new Evection(); evection.setNum(4d); Map<String, Object> map = new HashMap<>(); map.put("evection", evection); ProcessInstance instance = runtimeService.startProcessInstanceByKey("evection-parallel", map); System.out.println("流程定义id:" + instance.getProcessDefinitionId()); } @Test public void completeTask() { String userId = "lisi"; ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = engine.getTaskService(); Task task = taskService.createTaskQuery().processDefinitionKey("evection-parallel").taskAssignee(userId).singleResult(); if (task != null) { taskService.complete(task.getId()); System.out.println("任务:" + task.getId() + "完成"); } } }流程流转至网关处,可查看 act_ru_task 表对应的数据,有两个正在执行的任务查看 act_ru_execution 表,有多个分支正在运行并行任务执行不分先后,由任务的负责人去执行即可,处理完一个任务则 act_ru_task 减少一条记录(负责人为技术经理对应的任务)有并行网关的汇聚结点,则说明有一个分支已经到汇聚,等待其它的分支到达当所有分支任务都完成,都到达汇聚结点后,查看 act_ru_task 表,执行流程实例已经变为总经理审批(出差天数大于等于3),说明流程执行已经通过并行网关(即所有分支到达汇聚结点,并行网关执行完成)3. 包含网关InclusiveGateway(1)概念包含网关可以看做是排他网关和并行网关的结合体,和排他网关一样,你可以在外出顺序流上定义条件,包含网关会解析它们,但其主要的区别是包含网关可以选择多于的一条顺序流,这和并行网关一样,包含网关的功能是基于进入和外出顺序流的:分支: 所有外出顺序流的条件都会被解析,结果为true的顺序流会以并行方式继续执行,会为每个顺序流创建 一个分支汇聚: 所有并行分支到达包含网关会进入等待状态,直到每个进入顺序流的分支都到达,这是与并行网关最大的不同(包含网关只会等待被选中且执行了的进入顺序流,在汇聚之后, 流程会穿过包含网关继续执行)(2)测试public class InclusiveTest { @Test public void deploy() { //1.获取ProcessEngine对象 ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); //2.获取RepositoryService RepositoryService service = engine.getRepositoryService(); //3.部署 Deployment deploy = service.createDeployment() .addClasspathResource("bpmn/evection-inclusive.bpmn") //.addClasspathResource("bpmn/evection-inclusive.png") .name("出差申请流程-包含网关") .deploy(); System.out.println("id: " + deploy.getId()); System.out.println("name: " + deploy.getName()); } @Test public void startProcess() { ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); RuntimeService runtimeService = engine.getRuntimeService(); Evection evection = new Evection(); evection.setNum(4d); Map<String, Object> map = new HashMap<>(); map.put("evection", evection); ProcessInstance instance = runtimeService.startProcessInstanceByKey("evection-inclusive", map); System.out.println("流程定义id:" + instance.getProcessDefinitionId()); } @Test public void completeTask() { String userId = "zhangsan"; ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = engine.getTaskService(); Task task = taskService.createTaskQuery().processDefinitionKey("evection-inclusive").taskAssignee(userId).singleResult(); if (task != null) { taskService.complete(task.getId()); System.out.println("任务:" + task.getId() + "完成"); } } }执行流程a. 当流程执行到第一个包含网关后,会根据条件判断,当前要走哪几个分支act_ru_task 表信息技术经理审批、人事经理审批都是当前并行执行的任务act_ru_execution 表信息第一条记录代表包含网关分支,第二、三条记录代表要执行的分支如果有一个分支执行先走到汇聚结点的分支,要在此等待其它执行分支b. 先执行技术经理审批,然后查看当前任务表 act_ru_task,还剩人事经理的任务查看 act_ru_execution 表信息人事经理的分支还在,技术经理的分支已走到汇聚节点c. 人事经理进行任务处理,然后查看当前任务表 act_ru_task,任务来到了总经理这边查看 act_ru_execution 表信息包含网关执行完成,分支和汇聚就从 act_ru_execution 删除注:如果包含网关中设置的条件在流程变量中不存在,则会抛出异常分支需要判断条件,只有符合条件的分支才会执行,符合条件的分支最终才进行汇聚4. 事件网关EventGateway事件网关允许根据事件判断流向,网关的每个外出顺序流都要连接到一个中间捕获事件,当流程到达一个基于事件网关时,网关会进入等待状态(即暂停执行),与此同时,会为每个外出顺序流创建相对应的事件订阅,事件网关的外出顺序流和普通顺序流不同,这些顺序流不会真的"执行",相反它们让流程引擎去决定执行到事件网关的流程需要订阅哪些事件,同时还要考虑以下条件:事件网关必须有两条或以上外出顺序流事件网关后,只能使用 intermediateCatchEvent 类型(activiti不支持基于事件网关后连接 ReceiveTask)连接到事件网关的中间捕获事件必须只有一个入口顺序流intermediateCatchEvent 类型:Message Event 消息事件Singal Event 信号事件Timer Event 定时事件
2023年05月27日
153 阅读
0 评论
0 点赞
2023-05-26
工作流 - 组任务
1. 组任务处理流程(1)查询组任务指定候选人,查询该候选人当前的待办任务,候选人不能立即办理任务(2)拾取(claim)任务该组任务的所有候选人都能拾取将候选人的组任务,变成个人任务,原来候选人就变成了该任务的负责人如果拾取后不想办理该任务时怎么办?需要将已经拾取的个人任务归还到组里边,将个人任务变成了组任务(即设置assignee为null)(3)查询个人任务查询方式同理个人任务部分,根据assignee查询用户负责的个人任务(4)办理个人任务同理任务处理2. 查询组任务根据候选人查询组任务@Test public void queryGroupTask() { String key = "evection1"; String candidateUser = "zhangsan"; ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = engine.getTaskService(); List<Task> list = taskService.createTaskQuery() .processDefinitionKey(key) .taskCandidateUser(candidateUser) //.taskCandidateOrAssigned(candidateUser) .list(); for (Task task : list) { System.out.println("流程实例id:" + task.getProcessInstanceId()); System.out.println("任务id:" + task.getId()); System.out.println("任务名称:" + task.getName()); System.out.println("负责人:" + task.getAssignee()); } }3. 拾取组任务候选人员拾取组任务后该任务变为自己(即指定候选人)的个人任务@Test public void claimTask() { String taskId = "45002"; String userId = "zhangsan"; ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = engine.getTaskService(); Task task = taskService.createTaskQuery().taskId(taskId).taskCandidateUser(userId).singleResult(); if (task != null) { taskService.claim(taskId, userId); System.out.println("任务拾取成功"); } }4. 查询个人待办任务查询方式同理个人任务查询@Test public void queryGroupTask() { String key = "evection1"; String candidateUser = "zhangsan"; ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = engine.getTaskService(); List<Task> list = taskService.createTaskQuery() .processDefinitionKey(key) //.taskCandidateUser(candidateUser) //.taskCandidateOrAssigned(candidateUser) .taskAssignee(candidateUser) .list(); for (Task task : list) { System.out.println("流程实例id:" + task.getProcessInstanceId()); System.out.println("任务id:" + task.getId()); System.out.println("任务名称:" + task.getName()); System.out.println("负责人:" + task.getAssignee()); } }5. 办理个人任务@Test public void completeTask() { ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = engine.getTaskService(); taskService.complete("42505"); System.out.println("任务完成"); }6. 归还组任务设置 assignee 为 null 即可@Test public void taskBack() { String taskId = "45002"; String userId = "zhangsan"; ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = engine.getTaskService(); Task task = taskService.createTaskQuery().taskId(taskId).taskAssignee(userId).singleResult(); if (task != null) { //设置userId为null,则归还组任务 taskService.setAssignee(taskId, null); System.out.println("归还任务成功"); } }7. 任务交接将任务负责人设置为其他用户@Test public void setOtherUserId() { String taskId = "45002"; String userId = "zhangsan"; ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = engine.getTaskService(); Task task = taskService.createTaskQuery().taskId(taskId).taskAssignee(userId).singleResult(); if (task != null) { //设置新的任务负责人 taskService.setAssignee(taskId, "sunxiaocuan"); System.out.println("任务交接成功"); } }8. 数据库表操作查询当前任务执行表SELECT * FROM act_ru_task任务执行表记录当前执行的任务信息,由于该任务当前是组任务,所有assignee为空,当拾取任务后该字段就是拾取用户的 id查询任务参与者SELECT * FROM act_ru_identitylink该表记录当前任务用户或组,当前任务如果设置了候选人,会向该表插入候选人记录,有 几个候选人就插入几个与 act_ru_identitylink 对应的还有一张历史表 act_hi_identitylink,向 act_ru_identitylink 插入记录的同时也会向历史表插入对应的记录
2023年05月26日
43 阅读
0 评论
0 点赞
2023-05-26
工作流 - 流程变量
1. 概念流程变量在 activiti 中是一个非常重要的角色,流程运转有时需要靠流程变量,业务系统和 activiti 结合时少不了流程变量,流程变量就是 activiti 在管理工作流时根据管理需要而设置的变量。 如:在出差申请流程流转时如果出差天数大于 3 天则由总经理审核,否则由人事直接审核, 出差天数就可以设置为流程变量,在流程流转时使用。 注:虽然流程变量中可以存储业务数据,可以通过activiti的api查询流程变量从而实现查询业务数据, 但是不建议这样使用,因为业务数据查询由业务系统负责,activiti设置流程变量是为了流程执行需要而创建的。2. 流程变量类型如果将 pojo 存储到流程变量中,必须实现序列化接口 serializable,为了防止由于新增字段无法反序列化,需要生成 serialVersionUID3. 流程变量作用域流程变量的作用域可以是一个流程实例(processInstance),或一个任务(task),或一个执行实例 (execution)global变量流程变量的默认作用域是流程实例,当一个流程变量的作用域为流程实例时,可以称为 global 变量注:Global变量:userId(变量名)、xxx(变量值) global 变量中变量名不允许重复,设置相同名称的变量,后设置的值会覆盖前设置的变量值local变量任务和执行实例仅仅是针对一个任务和一个执行实例范围,范围没有流程实例大, 称为 local 变量。Local 变量由于在不同的任务或不同的执行实例中,作用域互不影响,变量名可以相同没有影响。Local 变量名也可以和 global 变量名相同,也是没有影响的4. 流程表变量的使用方法(1)在属性上使用UEL表达式可以在 assignee 处设置 UEL 表达式,表达式的值为任务的负责人,比如: ${assignee}, assignee 就 是一个流程变量名称, Activiti获取UEL表达式的值,即流程变量assignee的值 ,将assignee的值作为任务的负责人进行任务分配(2)在连线上使用UEL表达式可以在连线上设置UEL表达式,决定流程走向。 比如:${price<10000} ,price就是一个流程变量名称,uel表达式结果类型为布尔类型, 如果UEL表达式是true,则决定流程执行走向(即流程走这条连线)5. 使用流程变量例:员工创建出差申请单,由部门经理审核,部门经理申请通过后3天以下由财务直接申批,3天以上先由总经理审批,总经理审批通过后再由财务审批(1)流程定义先通过UEL-value来设置负责人然后在分支线上来设置条件注:此处还可以通过对象参数命名,比如 evection.num另一根线对应的设置设置完成之后即可部署流程(2)使用global变量创建pojo对象public class Evection implements Serializable { /** * id */ private long id; /** * 名称 */ private String evectionName; /** * 出差天数 */ private double num; /** * 开始日期 */ private Date startDate; /** * 结束日期 */ private Date endDate; /** * 目的地 */ private String destination; /** * 事由 */ private String reason; public Evection() { } public Evection(long id, String evectionName, double num, Date startDate, Date endDate, String destination, String reason) { this.id = id; this.evectionName = evectionName; this.num = num; this.startDate = startDate; this.endDate = endDate; this.destination = destination; this.reason = reason; } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getEvectionName() { return evectionName; } public void setEvectionName(String evectionName) { this.evectionName = evectionName; } public double getNum() { return num; } public void setNum(double num) { this.num = num; } public Date getStartDate() { return startDate; } public void setStartDate(Date startDate) { this.startDate = startDate; } public Date getEndDate() { return endDate; } public void setEndDate(Date endDate) { this.endDate = endDate; } public String getDestination() { return destination; } public void setDestination(String destination) { this.destination = destination; } public String getReason() { return reason; } public void setReason(String reason) { this.reason = reason; } @Override public String toString() { return "Evection{" + "id=" + id + ", evectionName='" + evectionName + '\'' + ", num=" + num + ", startDate=" + startDate + ", endDate=" + endDate + ", destination='" + destination + '\'' + ", reason='" + reason + '\'' + '}'; } }部署流程@Test public void deploy() { //1.获取ProcessEngine对象 ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); //2.获取RepositoryService RepositoryService service = engine.getRepositoryService(); //3.部署 Deployment deploy = service.createDeployment() .addClasspathResource("bpmn/evection-variable.bpmn") .addClasspathResource("bpmn/evection-variable.png") .name("出差申请流程-Variable") .deploy(); System.out.println("id: " + deploy.getId()); System.out.println("name: " + deploy.getName()); }设置流程变量a. 启动流程时设置,变量的作用域是整个流程实例通过startProcessInstanceByKey方法设置流程变量的作用域是一个流程实例,流程变量使用Map存储,同一个流程实例map中的key相同时,后者会覆盖前者@Test public void startAndSet() { ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); RuntimeService runtimeService = engine.getRuntimeService(); String key = "evection-variable"; Map<String, Object> variables = new HashMap<>(); Evection evection = new Evection(); evection.setNum(2d); variables.put("evection", evection); variables.put("assignee0", "zhangsan"); variables.put("assignee1", "lisi"); variables.put("assignee2", "wangwu"); variables.put("assignee3", "xiaoming"); ProcessInstance instance = runtimeService.startProcessInstanceByKey(key, variables); System.out.println("流程实例名称:" + instance.getName()); System.out.println("流程定义id:" + instance.getProcessDefinitionId()); }处理任务@Test public void completeTask() { String key = "evection-variable"; String assignee = "lisi"; ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = engine.getTaskService(); Task task = taskService.createTaskQuery().processDefinitionKey(key).taskAssignee(assignee).singleResult(); if (task != null) { taskService.complete(task.getId()); System.out.println("任务:" + task.getId() + "," + task.getName() + ",完成"); } }b. 处理任务时设置在完成任务时设置流程变量,该流程变量只有在该任务完成后其它结点才可使用该变量,它的作用域是整个流程实例,如果设置的流程变量的key在流程实例中已存在相同的名字则后设置的变量会替换前边设置的变量@Test public void startProcess() { ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); RuntimeService runtimeService = engine.getRuntimeService(); String key = "evection-variable"; Map<String, Object> variables = new HashMap<>(); variables.put("assignee0", "zhangsan"); variables.put("assignee1", "lisi"); variables.put("assignee2", "wangwu"); variables.put("assignee3", "xiaoming"); ProcessInstance instance = runtimeService.startProcessInstanceByKey(key, variables); System.out.println("流程实例名称:" + instance.getName()); System.out.println("流程定义id:" + instance.getProcessDefinitionId()); }处理时设置@Test public void doingSet() { String taskId = "1404"; ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = processEngine.getTaskService(); Map<String, Object> variables = new HashMap<>(); Evection evection = new Evection(); evection.setNum(3d); variables.put("evection", evection); taskService.setVariablesLocal(taskId, variables); taskService.complete(taskId); }注: 通过当前任务设置流程变量,需要指定当前任务id,如果当前执行的任务id不存在则抛出异常(任务办理时也是通过map设置流程变量,一次可以设置多个变量)c. 当前流程实例设置通过流程实例id设置全局变量,该流程实例必须未执行完成(即该流程实例还没有走完/结束)@Test public void setLocalVariableByTaskId(){ String taskId="1404"; ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = processEngine.getTaskService(); Evection evection = new Evection (); evection.setNum(3d); taskService.setVariableLocal(taskId, "evection", evection); // 可以通过map一次设置多个值 //taskService.setVariablesLocal(taskId, variables) }注:任务id必须是当前待办的任务id,act_ru_task中存在,如果该任务已结束,会抛出异常,同时也可以通过 taskService.getVariable() 方法获取流程变量(3)设置local变量a. 任务办理时设置任务办理时设置local流程变量,当前运行的流程实例只能在该任务结束前使用,任务结束该变量无法在 当前流程实例使用,可以通过查询历史任务查询@Test public void completTask() { //任务id String taskId = "1404"; //获取processEngine ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = processEngine.getTaskService(); //定义流程变量 Map<String, Object> variables = new HashMap<String, Object>(); Evection evection = new Evection (); evection.setNum(3d); //定义流程变量 Map<String, Object> variables = new HashMap<>(); //变量名是evection,变量值是evection对象 variables.put("evection", evection); //设置local变量,作用域为该任务 taskService.setVariablesLocal(taskId, variables); //完成任务 taskService.complete(taskId); }注:作用域为当前任务,每个任务可以设置同名的变量,互不影响b. 通过当前任务设置@Test public void setLocalVariableByTaskId(){ String taskId="1404"; ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = processEngine.getTaskService(); Evection evection = new Evection (); evection.setNum(3d); taskService.setVariableLocal(taskId, "evection", evection); // 可以通过map一次设置多个值 //taskService.setVariablesLocal(taskId, variables) }注:同理全局变量设置时的前提条件,即当前任务不能执行完/结束c. 补充部门经理审核、总经理审核、财务审核时设置local变量,可通过historyService查询每个历史任务时一起将流程变量的值也查询出来@Test public void queryHistoryInfo() { //创建历史任务查询对象 HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery(); //查询结果包括local变量 historicTaskInstanceQuery.includeTaskLocalVariables(); for (HistoricTaskInstance historicTaskInstance : list) { System.out.println("=============================="); System.out.println("任务id:" + historicTaskInstance.getId()); System.out.println("任务名称:" + historicTaskInstance.getName()); System.out.println("任务负责人:" + historicTaskInstance.getAssignee()); System.out.println("任务local变量:"+ historicTaskInstance.getTaskLocalVariables()); }
2023年05月26日
73 阅读
0 评论
0 点赞
2023-05-25
工作流 - 个人任务
1. 分配任务负责人(1)固定分配在进行业务流程设计的时候指定固定的任务负责人Properties ---> Main Config ---> Assignee(2)表达式分配在Activiti中支持使用UEL表达式,UEL表达式是Java EE6 规范的一部分, UEL(Unified Expression Language) 即统一表达式语言Activiti支持两种UEL表达式: UEL-value 和 UEL-methodUEL-value创建一个新的流程使用表达式之后的几个负责人以 ${assignee0}, ${assignee1}...的形式以此类推流程绘制完成之后,进行部署,在启动流程实例时给 UEL 表达式赋值@Test public void deploy() { //1.获取ProcessEngine对象 ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); //2.获取RepositoryService RepositoryService service = engine.getRepositoryService(); //3.部署 Deployment deploy = service.createDeployment() .addClasspathResource("bpmn/evection-uel.bpmn") .addClasspathResource("bpmn/evection-uel.png") .name("出差申请流程-UEL") .deploy(); System.out.println("id: " + deploy.getId()); System.out.println("name: " + deploy.getName()); } @Test public void createProcess() { ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); RuntimeService service = engine.getRuntimeService(); //设置assignee Map<String, Object> map = new HashMap<>(); map.put("assignee0", "zhangsan"); map.put("assignee1", "lisi"); map.put("assignee2", "wangwu"); map.put("assignee3", "xiaoming"); service.startProcessInstanceByKey("evection-uel", map); }启动成功后,可在 act_ru_variable 表中查找对应的赋值信息UEL-methodUserBean即注册到Spring容器中的Bean,表示调用该对象的 getUserId 方法UEL-method 与 UEL-value 结合如: ${userService.findManager(emp)}userService 是 Spring 容器的一个bean,findManager 是该 bean 的一个方法,emp 是 activiti 流程变量, emp作为参数传到 userService.findManager 方法中其他表达式支持解析基础类型、 bean、 list、 array 和 map,也可作为条件判断,如: ${order.price > 100 && order.price < 250}(3)分配监听器使用监听器来完成负责人的指定,在流程设计的时候就不需要指定assignee Event选项Event分类:create:任务创建后触发assignment:任务分配后触发Delete:任务完成后触发All:所有事件都触发自定义监听器package com.sw.listener; import org.activiti.engine.delegate.DelegateTask; public class TaskListener implements org.activiti.engine.delegate.TaskListener { @Override public void notify(DelegateTask delegateTask) { if ("创建请假单".equals(delegateTask.getName()) && "create".equals(delegateTask.getEventName())) { //指定任务负责人 delegateTask.setAssignee("zhangsan-listener"); } } }测试@Test public void deploy() { //1.获取ProcessEngine对象 ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); //2.获取RepositoryService RepositoryService service = engine.getRepositoryService(); //3.部署 Deployment deploy = service.createDeployment() .addClasspathResource("bpmn/evection-listener.bpmn") .addClasspathResource("bpmn/evection-listener.png") .name("出差申请流程-Listener") .deploy(); System.out.println("id: " + deploy.getId()); System.out.println("name: " + deploy.getName()); } @Test public void createProcess() { ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); RuntimeService service = engine.getRuntimeService(); service.startProcessInstanceByKey("evection-listener"); }(4)查询任务查询指定任务负责人的待办任务@Test public void queryPersonalTaskList() { //流程定义key String processDefinitionKey = "evection"; //任务负责人 String assignee = "lisi"; ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = engine.getTaskService(); List<Task> list = taskService.createTaskQuery().processDefinitionKey(processDefinitionKey).taskAssignee(assignee).list(); if (list != null && list.size() > 0) { for (Task task : list) { System.out.println("----------------------"); System.out.println("流程实例id:" + task.getProcessInstanceId()); System.out.println("任务id:" + task.getId()); System.out.println("任务负责人:" + task.getAssignee()); System.out.println("任务名称:" + task.getName()); } } }关联 businessKey在 activiti 实际应用中,查询待办任务的同时可能还要显示出和业务系统相关的数据,如:查询待审批出差任务列表需要将出差单的日期、 出差天数等信息显示出来,出差天数等信息在业务系统中存在,而并没有在 activiti 数据库中,所以无法通过 activiti 的 api 查询到出差相关的信息。 实现: 在查询待办任务时,通过 businessKey(业务标识 )关联查询业务系统的出差信息表单,从而查询出出差天数等信息@Test public void queryProcessInstance() { ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); //查询流程实例id TaskService taskService = engine.getTaskService(); Task task = taskService.createTaskQuery().processDefinitionKey("evection").taskAssignee("lisi").singleResult(); String instanceId = task.getProcessInstanceId(); //根据流程实例id查询businessKey RuntimeService runtimeService = engine.getRuntimeService(); ProcessInstance instance = runtimeService.createProcessInstanceQuery().processInstanceId(instanceId).singleResult(); System.out.println("businessKey: " + instance.getBusinessKey()); }(5)办理任务@Test public void completeTask() { //任务id String taskId = "10005"; //任务负责人 String assignee = "zhansan"; ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = engine.getTaskService(); Task task = taskService.createTaskQuery().taskId(taskId).taskAssignee(assignee).singleResult(); if (task == null) { throw new IllegalArgumentException(assignee + " 无权限处理该任务!"); } taskService.complete(taskId); System.out.println("任务:" + taskId + ",已完成"); }注:在实际应用中,完成任务前需要校验任务的负责人是否具有该任务的办理权限
2023年05月25日
51 阅读
0 评论
0 点赞
2023-05-25
工作流 - 流程实例
1. 概念流程实例(ProcessInstance)代表流程定义的执行实例一个流程实例包括了所有的运行节点,可以通过这个对象来了解当前流程实例的进度等信息,例如:用户或者程序按照流程定义的内容发起了一个流程,这就是一个流程实例2. 业务管理流程定义部署在Activiti后,我们就可以在系统中通过Activiti去管理流程的执行,但是如果要将流程实例和业务数据关联,这时需要使用到Activiti中预留的BusinessKey(业务标识)来关联@Test public void associateBusinessKey() { //1.获取ProcessEngine对象 ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); //2.RuntimeService RuntimeService service = engine.getRuntimeService(); //3.启动流程,添加businessKey ProcessInstance instance = service.startProcessInstanceByKey("evection", "10001"); System.out.println("businessKey: " + instance.getBusinessKey()); }3. 流程实例的挂起和激活在实际场景中可能由于流程变更需要将当前运行的流程暂停而不删除,流程暂停后将不能继续执行(1)全部流程挂起操作流程的定义为挂起状态,该流程定义下边所有的流程实例全部暂停。 流程定义为挂起状态时,该流程定义将不允许启动新的流程实例,同时该流程定义下的所有的流程实例都将全部挂起暂停执行@Test public void processSuspendOrActive() { //1.获取ProcessEngine对象 ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); //2.RepositoryService RepositoryService service = engine.getRepositoryService(); //3.查询流程定义的对象 ProcessDefinition definition = service.createProcessDefinitionQuery().processDefinitionKey("evection").singleResult(); //4.获取当前流程定义的状态 String id = definition.getId(); boolean suspended = definition.isSuspended(); //5.挂起 ---> 激活,否则反之 if (suspended) { service.activateProcessDefinitionById(id, true, null); System.out.println("流程:" + id + ",已激活"); } else { service.suspendProcessDefinitionById(id, true, null); System.out.println("流程:" + id + ",已挂起"); } }注:挂起流程定义后,实例对象中(数据库数据的状态)的状态会修改为 2,此时如果再去操作对应的流程实例会抛出异常,将挂起的流程转变为激活状态,则对应的状态值会从 2 更新为 1(即可以正常处理业务流程)4. 单个实例挂起针对单个流程执行挂起操作,则将指定的流程实例挂起,当前流程定义的其他流程实例不受干扰,此时如果去操作已挂起的该流程实例,同理会抛出异常@Test public void singleProcessSuspendOrActive() { //1.获取ProcessEngine对象 ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); //2.RuntimeService RuntimeService service = engine.getRuntimeService(); //3.查询流程实例对象 ProcessInstance instance = service.createProcessInstanceQuery().processInstanceId("2501").singleResult(); //4.获取相关状态 String id = instance.getId(); boolean suspended = instance.isSuspended(); //5.执行挂起/激活 if (suspended) { service.activateProcessInstanceById(id); System.out.println("流程实例:" + id + ",已激活"); } else { service.suspendProcessInstanceById(id); System.out.println("流程实例:" + id + ",已挂起"); } }
2023年05月25日
64 阅读
0 评论
0 点赞
1
2
3