工作流引擎Camunda

一,什么是Camunda?

Camunda是一个开源的工作流引擎和业务流程管理平台,基于Java和Spring框架构建。它支持BPMN 2.0标准,允许用户通过图形界面或编程方式定义复杂的工作流和业务流程。Camunda可以嵌入到任何Java应用程序中,也可以作为独立的服务运行,为开发者提供了极大的灵活性。

1、什么是工作流

工作流(Workflow),是对工作流程及其各操作步骤之间业务规则的抽象、概括描述。指在组织中,多个任务、活动或过程之间的顺序和控制流。这些任务通常涉及多个参与者、系统或部门,工作流的目标是将复杂的业务逻辑分解为多个可管理的逻辑段,并统一控制这些逻辑段的执行条件、执行顺序以及相互通信,从而实现业务逻辑的解耦与优化。这种方式不仅提高了业务流程的灵活性和可维护性,还促进了各个环节之间的协同工作。

2、为什么要使用工作流

提高效率:通过自动化和标准化重复性任务,减少人工干预,提升整体工作效率。
增强透明度:工作流提供清晰的任务分配和进度跟踪,使团队成员能够实时了解工作状态,促进协作。
降低错误率:通过预定义的流程和自动化步骤,减少人为错误,提高数据准确性。
灵活性和适应性:可以根据业务需求快速调整和优化流程,适应变化的市场环境。
优化资源管理:通过有效分配和调度资源,确保任务按时完成,提高资源利用率。
监控和分析:提供实时监控和数据分析功能,帮助识别瓶颈和改进机会,持续优化业务流程。
合规性和标准化:确保业务流程符合行业标准和法规要求,提高合规性,减少风险。

二,Camunda应用架构

Camunda是一个基于 Java 的分布式应用架构,主要包括以下几个核心组件:

1、Camunda BPM 引擎

核心功能:执行 BPMN 2.0 流程、CMMN 案例和 DMN 决策模型。
高性能:经过优化,支持高并发和复杂业务逻辑的执行。
集成:可嵌入到 Java 应用中,或通过 REST API 与外部系统交互。

2、建模工具

Camunda Modeler:图形化工具,用于设计和编辑 BPMN、CMMN 和 DMN 模型,便于业务用户进行流程建模。

3、用户任务管理

Tasklist:Web 应用,用户可以在此管理和处理任务,查看分配的任务并通过表单完成。

4、监控与分析工具

Cockpit:用于实时监控流程执行,提供流程实例状态、性能指标和历史数据分析,帮助识别瓶颈和优化流程。

5、REST API

接口服务:提供全面的 RESTful API,支持流程的启动、任务查询、用户管理等操作,便于与其他系统集成。

6、外部任务

任务处理:支持外部任务模式,将任务分配给外部服务或微服务,提高灵活性和可扩展性。

7、事件处理

事件驱动:支持处理多种事件(如消息、信号、定时器),实现复杂的事件驱动工作流。

8、多租户支持

多租户架构:支持在同一引擎实例中管理多个租户,确保数据隔离和安全性,适合 SaaS 解决方案。

9、前端用户界面

Cockpit:流程监控和管理界面。

Tasklist:任务管理和审批界面。

Admin:系统管理和配置界面。

三、camunda使用实例

本实例中我们实现以下功能:1.工作流程设计 2.工作流中包含用户任务和服务任务 3.工作流中使用网关  4.工作流和外部服务结合实现任务执行前提醒任务执行者 5.实现工作流实例的启动  6.实现工作流实例启动时设置各个任务的执行人 7.实现代办任务获取和已办任务获取。

项目环境:JDK(openJDK17)、SpringBoot3.2.2、Camunda7.20.0

1.下载camunda流程设计器

下载地址:Releases · camunda/camunda-modeler · GitHub

Download The Camunda BPMN / DMN Process Modeler | Camunda

2个地址都可以下载流程设计器,github上可以下载历史版本。

流程设计器下载、解压后可直接使用。

2.创建camunda流程引擎服务

自动创建服务地址:Camunda Automation Platform 7 Initializr

3.使用流程设计器设计业务流程

流程设计器选择匹配的camunda版本。

流程开始

新建运单任务

货物入仓任务

排他网关

分支条件1

分支条件2

货物收运任务

流程结束

4.camunda引擎项目结构及代码

项目结构

pom.xml

<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">

  <modelVersion>4.0.0</modelVersion>

  <groupId>infosky</groupId>
  <artifactId>camnuda-engine</artifactId>
  <version>1.0</version>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>3.2.2</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>

      <dependency>
        <groupId>org.camunda.bpm</groupId>
        <artifactId>camunda-bom</artifactId>
        <version>7.20.0</version>
        <scope>import</scope>
        <type>pom</type>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>org.camunda.bpm.springboot</groupId>
      <artifactId>camunda-bpm-spring-boot-starter-rest</artifactId>
    </dependency>

    <dependency>
      <groupId>org.camunda.bpm.springboot</groupId>
      <artifactId>camunda-bpm-spring-boot-starter-webapp</artifactId>
    </dependency>

    <dependency>
      <groupId>org.camunda.bpm</groupId>
      <artifactId>camunda-engine-plugin-spin</artifactId>
    </dependency>

    <dependency>
      <groupId>org.camunda.spin</groupId>
      <artifactId>camunda-spin-dataformat-all</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- mysql驱动 -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.27</version>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>

  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <version>3.2.2</version>
      </plugin>
    </plugins>
  </build>

</project>

application.yaml

server:
  port: 9999

spring:
  datasource:
    url: jdbc:mysql://172.20.220.114:3306/lt?nullDatabaseMeansCurrent=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false
    username: aaaaa
    password: bbbbbbbbb
    driverClassName: com.mysql.cj.jdbc.Driver

camunda:
  bpm:
    database:
      type: mysql
    auto-deployment-enabled: false
    admin-user:
      id: demo
      password: demo

Application.java

package infosky;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * springboot启动类
 */
@SpringBootApplication
public class Application {
  static Logger logger = LoggerFactory.getLogger(Application.class);
  public static void main(String... args) {
    try {
      SpringApplication.run(Application.class, args);
      logger.info("★★★★★★★★★★★★★★★★★★★★启动正常★★★★★★★★★★★★★★★★★★★★");
    } catch (Exception e) {
      logger.error("■■■■■■■■■■■■■■■■■■启动异常", e);
    }
  }
}
FlowController.java
package infosky.controller;

import org.camunda.bpm.engine.HistoryService;
import org.camunda.bpm.engine.RepositoryService;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.TaskService;
import org.camunda.bpm.engine.history.HistoricTaskInstance;
import org.camunda.bpm.engine.repository.Deployment;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * camunda流程
 */
@RestController
@RequestMapping("/flow")
public class FlowController {
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private HistoryService historyService;

    /**
     * 部署流程
     * @return
     */
    @RequestMapping("/deploy")
    public String deploy(){
        Deployment dm = repositoryService.createDeployment()
                .name("运单流程")                        //定义部署文件的名称
                .addClasspathResource("bpmn/awb.bpmn") //绑定需要部署的流程文件
                .deploy();                                //部署流程
        return dm.getName() + "|" + dm.getId();
    }

    /**
     * 启动流程
     */
    @RequestMapping("/startFlow")
    public String startFlow(){
        //定义map集合,存储相关流程的变量信息
        Map<String,Object> map = new HashMap<>();
        map.put("user1","wangwu");
        map.put("user2","lisi");
        //启动流程
        //  启动流程可以根据id或者key,其中id是唯一的它由3部分组成(流程定义的key:版本号:自动生成的id)
        //    id例=>   Process_awb:3:d9afa57b-dfbb-11ef-818c-4e5f7046682e
        //    key例=>  Process_awb  ■key对应的流程定义不唯一,同一个key的流程定义可以有多个版本。
        //  流程启动时可指定key和对应的版本 例=>runtimeService.startProcessInstanceByKey("Process_awb","3");
        //  流程启动时也可只指定key,此时默认启动该key的最新版本 例=>runtimeService.startProcessInstanceByKey("Process_awb");
        //  根据id启动流程 例=>runtimeService.startProcessInstanceById("Process_awb:3:d9afa57b-dfbb-11ef-818c-4e5f7046682e");
        //  以上指的id和key及版本存储在表[ACT_RE_PROCDEF]  另外,此处的key是在流程设计器中的[流程ID]
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("Process_awb",map);

        //返回流程实例id
        return processInstance.getId();
    }

    @RequestMapping("/completeTask")
    public void completeTask(){
        //获取任务 可根据流程实例id或者taskid,对应表[ACT_RU_TASK]
        //  ■任务执行完后将清除[ACT_RU_TASK]表中对应的task数据
        Task task = taskService.createTaskQuery()
                .processInstanceId("c2861623-e044-11ef-aa57-4e5f7046682e")
//                .taskId("6db24541-dfbc-11ef-98b5-4e5f7046682e")
                .singleResult();

        //判断任务是否存在
        if(task != null){
            System.out.println("==================");
            //完成任务   参数:taskID
            taskService.complete(task.getId());
        }
    }

    /**
     * 查询任务(代办)
     *
     *  流程定义ID:processDefinition =>流程部署时产生的ID,一个流程部署多次每次都会产生一个ID
     *  流程实例ID:processInstance   =>启动流程实例时产生的实例ID
     * @return
     */
    @RequestMapping("/queryTaskByHandle")
    public void queryTaskByHandle(){
        List<Task> list = taskService.createTaskQuery()
                .taskAssignee("lisi")
                .list();
        for (Task task : list) {
            System.out.println("#############:" + task.getId());
        }
    }

    /**
     * 查询已完成任务
     * [ACT_HI_TASKINST]
     */
    @RequestMapping("/queryTaskByHistory")
    public void queryTaskByHistory(){
        List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
                .taskAssignee("wangwu")
                .finished()
                .list();
        for (HistoricTaskInstance hti : list) {
            System.out.println("#############:" + hti.getProcessDefinitionKey() + "|" + hti.getName() + "|" + hti.getStartTime() + "|" + hti.getEndTime());
        }
    }
}
NewawbStartListener.java
package infosky.listener;

import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.ExecutionListener;
import org.springframework.stereotype.Component;

/**
 * 监听器
 *   用于给对应处理人发送消息
 *   可将消息存储到DB中或者发送到MQ中
 */
@Component
public class NewawbStartListener implements ExecutionListener {
    @Override
    public void notify(DelegateExecution delegateExecution) throws Exception {
        Object user1 = delegateExecution.getVariable("user1");
        System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&:" + user1);
    }
}
FohService.java
package infosky.service;

import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate;
import org.springframework.stereotype.Service;

/**
 * 货物入仓处理
 */
@Service("fohService")
public class FohService implements JavaDelegate {
    @Override
    public void execute(DelegateExecution delegateExecution) throws Exception {
        //处理完成后设置网关变量
        delegateExecution.setVariable("aaa",1);
        System.out.println("$$$$$$$$$$$$$$$$$完成任务");
    }
}

5.项目启动后会自动将camunda需要的表生成到对应的数据库中(共49张表)

6.部署流程

将流程设计器中导出的流程文件(awb.bpmn),复制到项目的bpmn文件夹下

启动项目,执行/flow/deploy,部署对应流程。

7.启动流程

8.执行新建运单任务

9.执行货物收运任务

任务完成后,task表中删除对应的记录。

以上处理中在流程启动时设置了变量user1,user2。在执行新建运单任务前,向执行人发送信息这里用监听器[NewawbStartListener]中方法[notify]模拟实现消息发送。在任务货物入仓中设置流程执行变量aaa的值,从而控制网关的执行方向。代办任务和已完成任务在FlowController.java中均已实现,具体可参考代码。

附:参考资料

camunda中文网站:Camunda 中文站 | docs.camunda.org

camunda生成项目网站:Camunda Automation Platform 7 Initializr

camunda下载流程设计器:Download The Camunda BPMN / DMN Process Modeler | Camunda

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/963020.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++,STL,【目录篇】

文章目录 一、简介二、内容提纲第一部分&#xff1a;STL 概述第二部分&#xff1a;STL 容器第三部分&#xff1a;STL 迭代器第四部分&#xff1a;STL 算法第五部分&#xff1a;STL 函数对象第六部分&#xff1a;STL 高级主题第七部分&#xff1a;STL 实战应用 三、写作风格四、…

【已解决】黑马点评项目Redis版本替换过程的数据迁移

黑马点评项目Redis版本替换过程的数据迁移 【哭哭哭】附近商户中需要用到的GEO功能只在Redis 6.2以上版本生效 如果用的是老版本&#xff0c;美食/KTV的主页能正常返回&#xff0c;但无法显示内容 上次好不容易升到了5.0以上版本&#xff0c;现在又用不了了 Redis 6.2的windo…

文献阅读 250201-The carbon budget of China: 1980–2021

The carbon budget of China: 1980–2021 来自 <https://www.sciencedirect.com/science/article/pii/S2095927323007703> 中国碳预算&#xff1a;1980–2021 年 ## Abstract: Using state-of-the-art datasets and models, this study comprehensively estimated the an…

《OpenCV》——图像透视转换

图像透视转换简介 在 OpenCV 里&#xff0c;图像透视转换属于重要的几何变换&#xff0c;也被叫做投影变换。下面从原理、实现步骤、相关函数和应用场景几个方面为你详细介绍。 原理 实现步骤 选取对应点&#xff1a;要在源图像和目标图像上分别找出至少四个对应的点。这些对…

条件变量 实现2生产者2消费者模型

1个生产者在生产的时候&#xff0c;另个生产者不能生产(生产者之间互斥) 条件变量用于线程同步&#xff0c;线程挂起/被唤醒。 条件变量和互斥锁共同保证生产者之间互斥生产者和消费者的同步。 思路&#xff1a; 1 定义、初始化共享资源 a 缓冲区&#xff1a;存储物品…

一个开源 GenBI AI 本地代理(确保本地数据安全),使数据驱动型团队能够与其数据进行互动,生成文本到 SQL、图表、电子表格、报告和 BI

一、GenBI AI 代理介绍&#xff08;文末提供下载&#xff09; github地址&#xff1a;https://github.com/Canner/WrenAI 本文信息图片均来源于github作者主页 在 Wren AI&#xff0c;我们的使命是通过生成式商业智能 &#xff08;GenBI&#xff09; 使组织能够无缝访问数据&…

使用C#开发一款通用数据库管理工具

由于经常使用各种数据库&#xff0c;笔者自己动手丰衣足食&#xff0c;使用C#开发了一款通用数据库管理工具&#xff0c;支持Mysql、Oracle、Sqlite、SQL Server等数据库的表、视图、存储过程、函数管理功能&#xff0c;并支持导入导出、数据字典生成、拖拽式跨机器跨库数据一键…

sqli-labs靶场通关

sqli-las通关 mysql数据库5.0以上版本有一个自带的数据库叫做information_schema,该数据库下面有两个表一个是tables和columns。tables这个表的table_name字段下面是所有数据库存在的表名。table_schema字段下是所有表名对应的数据库名。columns这个表的colum_name字段下是所有…

DNS缓存详解(DNS Cache Detailed Explanation)

DNS缓存详解 清空DNS缓存可以让网页访问更快捷。本文将从什么是DNS缓存、为什么清空DNS缓存、如何清空DNS缓存、清空DNS缓存存在的问题四个方面详细阐述DNS缓存清空的相关知识。 一、什么是DNS缓存 1、DNS缓存的定义&#xff1a; DNS缓存是域名系统服务在遇到DNS查询时自动…

【VM】VirtualBox安装CentOS8虚拟机

阅读本文前&#xff0c;请先根据 VirtualBox软件安装教程 安装VirtualBox虚拟机软件。 1. 下载centos8系统iso镜像 可以去两个地方下载&#xff0c;推荐跟随本文的操作用阿里云的镜像 centos官网&#xff1a;https://www.centos.org/download/阿里云镜像&#xff1a;http://…

2024第十五届蓝桥杯网安赛道省赛题目--rc4

rc4 一、查壳 无壳&#xff0c;32位 二、IDA分析 1.main 2.sub_401005 根据题目以及该函数的内容都可以让我们确定这是个rc4加密题。 所以

区块链项目孵化与包装设计:从概念到市场的全流程指南

区块链技术的快速发展催生了大量创新项目&#xff0c;但如何将一个区块链项目从概念孵化成市场认可的产品&#xff0c;是许多团队面临的挑战。本文将从孵化策略、包装设计和市场落地三个维度&#xff0c;为你解析区块链项目成功的关键步骤。 一、区块链项目孵化的核心要素 明确…

【机器学习】自定义数据集 使用scikit-learn中svm的包实现svm分类

一、支持向量机(support vector machines. &#xff0c;SVM)概念 1. SVM 绪论 支持向量机&#xff08;SVM&#xff09;的核心思想是找到一个最优的超平面&#xff0c;将不同类别的数据点分开。SVM 的关键特点包括&#xff1a; ① 分类与回归&#xff1a; SVM 可以用于分类&a…

电信传输基本理论/5G网络层次架构——超三万字详解:适用期末考试/考研/工作

电信传输的基本概念 信息、通信、电信、电信传输的定义 信息 信息指的是消息中的有效信息量 通信 通信指的是利用传输媒质将信息从一段传输到另一端 电信 电信的意思是利用电子技术来将信息从一段传输到另一端 电信传输 电信传输的概念就是将含有信息的电信号进行传输…

代码练习3

1 #include <stdio.h>void draw(int n) {for (int i n; i > 1; i--) {// 打印空格for (int j 0; j < n - i; j) {printf(" ");}// 打印星号for (int j 0; j < 2 * i - 1; j) {printf("*");}// 换行printf("\n");} }int main()…

好用的翻译工具

最近看到个好用的翻译工具&#xff0c;叫沉浸式翻译 沉浸式翻译 - 双语对照网页翻译插件 | PDF翻译 | 视频字幕翻译 我下载的是谷歌插件 点击下载插件会跳转到使用文档&#xff0c;跟着一步步操作即可 翻译的效果&#xff0c;我这里用的是免费版的&#xff0c;如果需要加强&…

Linux-CentOS的yum源

1、什么是yum yum是CentOS的软件仓库管理工具。 2、yum的仓库 2.1、yum的远程仓库源 2.1.1、国内仓库 国内较知名的网络源(aliyun源&#xff0c;163源&#xff0c;sohu源&#xff0c;知名大学开源镜像等) 阿里源:https://opsx.alibaba.com/mirror 网易源:http://mirrors.1…

el-table组件样式如何二次修改?

文章目录 前言一、去除全选框按钮样式二、表头颜色的修改 前言 ElementUI中的组件el-table表格组件提供了丰富的样式&#xff0c;有一个全选框的el-table组件&#xff0c;提供了全选框和多选。 一、去除全选框按钮样式 原本默认是有全选框的。假如有一些开发者&#xff0c;因…

一起学SysML v2规范(01)

1 00:00:01,560 --> 00:00:05,840 今天我们开始一个新的系列 2 00:00:06,690 --> 00:00:08,190 一起学SysML v2 3 00:00:08,200 --> 00:00:09,570 规范 4 00:00:15,770 --> 00:00:17,040 这里说一起学 5 00:00:17,050 --> 00:00:18,920 就是说我和大家一起学…

(9)下:学习与验证 linux 里的 epoll 对象里的 EPOLLIN、 EPOLLHUP 与 EPOLLRDHUP 的不同。小例子的实验

&#xff08;4&#xff09;本实验代码的蓝本&#xff0c;是伊圣雨老师里的课本里的代码&#xff0c;略加改动而来的。 以下是 服务器端的代码&#xff1a; 每当收到客户端的报文时&#xff0c;就测试一下对应的 epoll 事件里的事件标志&#xff0c;不读取报文内容&#xff0c;…