Camunda工作流引擎简记

news2025/8/9 13:04:54

本文转载自玩转Camunda之实战篇-赶紧收藏起来吧_哔哩哔哩_bilibili

其中部分内容,经过本人修改

一、工作流相关介绍

BPM(BusinessProcessManagement),业务流程管理是一种管理原则,通常也可以代指BPMS(BusinessProcessManagementSuite),是一个实现整合不同系统和数据的流程管理软件套件.

BPMN(BusinessProcessModelandNotation)是基于流程图的通用可视化标准。该流程图被设计用于创建业务流程操作的图形化模型。业务流程模型就是图形化对象的网状图,包括活动和用于定义这些活动执行顺序的流程设计器。BPMN2.0正式版本于2011年1月3日发布,常见的工作流引擎如:Activiti、Flowable、jBPM 都基于 BPMN 2.0 标准。

然后来看看BPM的发展历程:

二、Camunda介绍

官网地址:https://camunda.com/

中文站点:http://camunda-cn.shaochenfeng.com/

下载:https://downloads.camunda.cloud/release/camunda-bpm/run/7.15/

案例地址:Congratulation! | docs.camunda.org

前期准备工作: JAVA1.8以上的JRE或JDK

2.1 Camunda Modeler

Camunda Modeler 是Camunda 官方提供的一个流程设计器,用于编辑流程图以及其他模型【表单】,也就是一个流程图的绘图工具。可以官方下载,也可以在提供给大家的资料中获取。获取后直接解压缩即可,注意:解压安装到非中文目录中!!!

启动的效果:

2.2 Camunda BPM

下载地址 https://camunda.com/download/

Camunda BPM 是Camunda官方提供的一个业务流程管理平台,用来管理,部署的流程定义、执行任务,策略等。下载安装一个Camunda平台,成功解压 Camunda 平台的发行版后,执行名为start.bat(对于 Windows 用户)或start.sh(对于 Unix 用户)的脚本。此脚本将启动应用程序服务器。

打开您的 Web 浏览器并导航到http://localhost:8080/以访问欢迎页面,Camunda的管理平台。

登录成功的主页:

2.3 入门案例

创建简单流程

我们先通过 Modeler 来绘制一个简单流程

1.) 创建流程:选择 BPMN diagram (Camunda Platform)

2.) 创建开始节点:并设定节点名称

3.) 创建服务节点:设置处理方式

我们切换节点的类型为 service Task

然后我们需要配置刷卡付款节点,服务类型有很多执行的方法,这次我们使用“external(外部)”任务模式。

具体配置内容为

4.) 添加结束节点

5.) 配置流程参数

点击画布的空白处,右侧的面板会显示当前流程本身的参数,这里我们修改id为payment-retrieval,id是区分流程的标识然后修改Name 为“付款流程”最后确保 Executable是勾选的,只有Executable被勾选,流程才能执行

外部任务

在上面设计的流程图,刷卡付款节点的处理是外部任务,Camunda 可以使多种语言实现业务逻辑,我们以Java为例来介绍。

添加相关的依赖:

<dependencies>
	<dependency>
		<groupId>org.camunda.bpm</groupId>
		<artifactId>camunda-external-task-client</artifactId>
		<version>${camunda.external-task-client.version}</version>
	</dependency>
	<dependency>
		<groupId>org.slf4j</groupId>
		<artifactId>slf4j-simple</artifactId>
		<version>1.7.36</version>
	</dependency>
	<dependency>
		<groupId>javax.xml.bind</groupId>
		<artifactId>jaxb-api</artifactId>
		<version>2.3.1</version>
	</dependency>
</dependencies>

编写处理的业务逻辑的代码

import org.camunda.bpm.client.ExternalTaskClient;

import java.awt.*;
import java.net.URI;

public class Demo01 {
    public static void main(String[] args) {
        ExternalTaskClient client = ExternalTaskClient.create()
                .baseUrl("http://localhost:8080/engine-rest")
                .asyncResponseTimeout(10000) // 长轮询超时时间
                .build();
        // 订阅指定的外部任务
        client.subscribe("charge-card")
                .lockDuration(1000)
                .handler(((externalTask, externalTaskService) -> {
                    // 获取流程变量
                    String item = (String) externalTask.getVariable("item");
                    Long amount = (Long) externalTask.getVariable("amount");
                    System.out.println("item--->"+item + "  amount-->" + amount);
                    try {
                        Desktop.getDesktop().browse(new URI("https://docs.camunda.org/get-started/quick-start/complete"));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    // 完成任务
                    externalTaskService.complete(externalTask);
                })).open();
    }
}

运行该方法即可,当流程处理时会执行相关逻辑。

部署流程

接下来我们就可以来部署上面定义的流程了。使用 Camunda Modeler 部署流程,点击工具栏中的部署按钮可以将当前流程部署到流程引擎,点击部署按钮,输入Deployment Name 为 “Payment” ,输入下方REST Endpoint 为http://localhost:8080/engine-rest ,然后点击右下角Deploy部署

部署操作:

部署的时候报错:原因是安装路径中有中文

部署成功:

然后在BPM中我们可以查看部署的流程:

启动流程

我们使用Rest API发起流程,所以需要一个接口测试工具(例如:Postman),或者也可以使用电脑自带的curl

curl执行如下命令

curl -H "Content-Type: application/json" -X POST -d '{"variables": {"amount": {"value":555,"type":"long"}, "item": {"value":"item-xyz"} } }' http://localhost:8080/engine-rest/process-definition/key/payment-retrieval/start

postman方式处理

在url中输入:http://localhost:8080/engine-rest/process-definition/key/payment-retrieval/start 通过POST方式提交,提交的方式是JSON 数据,具体内容为:

{
	"variables": {
		"amount": {
			"value":555,
			"type":"long"
		},
		"item": {
			"value": "item-xyz"
		}
	}
}

然后我们点击发送,操作成功可以看到如下的返回信息

同时任务执行后我们在控制台可以看到相关的信息

三、案例扩展

上面的案例过于简单,我们添加不同的任务节点和网关来丰富下

3.1 用户任务

添加节点

我们在上面的案例中添加一个用户任务来处理流程。

点击刚刚创建的批准付款节点,然后通过扳手设置节点的类型为用户任务(User Task)

然后设置节点的审批人为demo

配置表单

用户节点处我们绑定表单数据。然后创建表单相关的字段,并添加对应的描述信息。

通过File > New File > Form创建一个form, 并且以 payment-form作为该form的编号。

三个字段

  1. 金额
    • Type: Number
    • Key: amount
    • Field Label: Amount
  2. 物品
    • Type: Text Field
    • Key: item
    • Field Label: Item
  3. 是否审批
    • Type: Checkbox
    • Key: approved
    • Label: Approved?

部署流程

流程定义好之后我们就可以部署流程了。直接在Camunda Modeler工具栏上的上传按钮将流程上传到流程引擎中。部署后在Camunda Web中查看部署的流程。

测试流程

打开任务列表(http://localhost:8080/camunda/app/tasklist/),使用 demo / demo 登录。点击右上角的 Start process ,在弹出的对话框中选择“付款流程”.

这时会弹出编辑流程变量的对话框,可以通过点击 Add a variable 按钮添加变量,这次我们先不添加,直接点击右下角Start启动流程。

这时,在任务列表应该就能看到刚创建的人工任务了,如果没有可以手动刷新一下

到这儿这个用户任务节点的人工审核就应该要处理了,我们在下一个案例中继续这个案例,我们加入排他网关来处理。

3.2 排他网关

我们将使用排他网关(Exclusive Gateways),为流程添加分支,仅在金额足够大的时候进行人工审核.

添加网关节点

首先打开Camunda Modeler ,在左侧的工具架中找到网关(菱形),将它拖动到“付款请求”和“刷卡付款”之间,将“批准付款”向下移动再添加一个网关,调整流程,最后看起来类似这样:

配置网关

接下来,我们选择“<1000”的连线,打开属性面板,选择“Condition Type”为“Expression”,这里我们使用JAVA统一表达式语言编写条件,这里要做的是在金额小于1000时直接刷卡付款,则输入表达式 ${amount<1000}

同样的,对另一条线也进行配置,表达式为${amount>=1000}

然后是否批准的排他网关节点我们也需要处理下

部署流程

部署流程和上面的操作是一样的。

测试操作

打开任务列表(http://localhost:8080/camunda/app/tasklist/),使用 demo / demo 登录,点击右上角的 Start process ,在弹出的对话框中选择“付款流程”,上面例子中,我们直接点击 Start,但这次我们要增加几个变量来测试动态的流程。

试着更改 amount 的值,查看对流程执行顺序的影响

3.3 决策自动化

在上面的案例中我们在审批时是通过用户任务结合表单来做的审批,本案例我们来看看我们通过DMN为流程添加一个业务规则来处理

添加业务规则

打开 Camunda Modeler,点击 “批准付款”,在右面的扳手菜单中,将类型改为“Business Rule Task ”(业务规则任务)

下一步,将属性面板中的 Implementation 选择为DMN,输入 Decision Ref 为 approve-payment,为了将决策的结果存入流程变量,我们还需要编辑结果变量Result Variable 为approved,结果类型 Map Decision Result 选择为 singleEntry ,最后结果如下:

创建DMN表

点击 File > New File > DMN Diagram创建一个新的DMN,现在画布上已经存在一个决策元素了,选择它,然后在右侧属性面板中更改IdName,这里的Id需要和流程中的Decision Ref属性一致,这次我们输入Id为approve-payment

接下来,点击决策元素左上角的表格按钮,创建新的DMN表.

编辑DMN表

首先编辑输入参数,在本例中,为了简单,我们依据项目名进行判断,规则可以使用 FEEL 表达式JUEL或者 Script 书写,详情可以阅读 https://docs.camunda.org/manual/latest/user-guide/dmn-engine/expressions-and-scripts/

双击表格中的Input,编辑第一个输入参数

下面,设置输入参数,双击Output编辑

下面,我们点击左侧的蓝色加号,添加一些规则,最后类似这样:

部署DMN表

点击底部的部署按钮,将DMN部署到流程引擎中

流程案例测试

现在打开 http://localhost:8080/camunda/app/cockpit/ ,使用demo/demo登录,可以看到决策定义增加了一个,点击进去可以看到刚才编辑的DMN.

点击进去可以看到对应的决策信息

然后我们按照之前的操作,多启动几个流程,再去看具体的决策结果即可

四、IDEA引入流程设计器

在工作流引擎中流程设计器是一个非常重要的组件,而InterlliJ IDEA是Java程序员用到的最多的编程工具了。前面在基础篇的介绍中我们都在通过Camunda提供的流程设计器绘制好流程图,然后需要单独的拷贝到项目中,要是调整修改不是很方便,这时我们可以在IDEA中和流程设计器绑定起来。这样会更加的灵活。

4.1 下载Camunda Model

第一步肯定是需要下载Camunda Model 这个流程设计器,我们前面有介绍。就是之前解压好的目录了。

4.2 IDEA中配置

我们先进入settings中然后找到tools,继续找到External Tool.

最终效果

4.3 编辑bpmn文件

找到您想打开的bpmn文件, 点击右键, 找到External Tools 运行camunda modler即可进行文件编写.

搞定~

五、SpringBoot整合Camunda

5.1 官方案例说明

接下来我们看看怎么在我们的实际项目中来使用Camunda了。方式有多种,首先我们可以参考官网提供的整合案例。

但是这里有个比较头疼的问题就是Camunda和SpringBoot版本的兼容性问题,虽然官方也给出了兼容版本的对照表。

但是如果不小心还是会出现各种问题,比如:

上面就是典型的版本不兼容的问题了。

5.2 官方Demo

为了能让我们的案例快速搞定,我们可以通过Camunda官方提供的网站来创建我们的案例程序。地址:https://start.camunda.com/

生成代码后,解压后我们通过idea打开项目,项目结构

相关的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>com.boge.workflow</groupId>
  <artifactId>camunda-project-demo</artifactId>
  <version>1.0.0-SNAPSHOT</version>

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

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

      <dependency>
        <groupId>org.camunda.bpm</groupId>
        <artifactId>camunda-bom</artifactId>
        <version>7.15.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>

    <dependency>
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
    </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>2.4.3</version>
      </plugin>
    </plugins>
  </build>

</project>

属性文件的配置信息

spring.datasource.url: jdbc:h2:file:./camunda-h2-database

camunda.bpm.admin-user:
  id: demo
  password: demo

然后通过启动类启动程序

访问服务:http://localhost:8080/

5.3 MySQL数据库

上面的例子我们数据存储在了H2这个内存型数据库,我们可以切换到MySQL数据库。首先我们需要导入相关的SQL脚本。位置就在我们之前下载的Camunda Web服务中。

执行创建所有必需的表和默认索引的SQL DDL脚本。上面两个脚本都要执行。

生成的相关表结构比较多,因为本身就是基于Activiti演变而来,所以有Activiti基础的小伙伴会非常轻松了。简单介绍下相关表结构的作用。

  • ACT_RE :'RE’表示 repository。 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。
  • ACT_RU:'RU’表示 runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。 Flowable只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表可以一直很小速度很快。
  • ACT_HI:'HI’表示 history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。
  • ACT_GE: GE 表示 general。 通用数据, 用于不同场景下
  • ACT_ID: ’ID’表示identity(组织机构)。这些表包含标识的信息,如用户,用户组,等等。

具体的表结构的含义:

表分类表名解释
一般数据
[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]用户表

然后我们在SpringBoot项目中导入MySql的依赖,然后修改对应的配置信息

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
    </dependency>

修改application.yaml。添加数据源的相关信息。

# spring.datasource.url: jdbc:h2:file:./camunda-h2-database

camunda.bpm.admin-user:
  id: demo
  password: demo
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/camunda1?serverTimezone=Asia/Shanghai
    username: root
    password: 123456
camunda:
  bpm:
    database:
      type: mysql
      schema-update: true
    auto-deployment-enabled: false # 自动部署 resources 下的 bpmn文件

然后启动项目,发现数据库中有了相关记录,说明操作成功

六、Camunda专题讲解

用了整合的基础我们就可以来完成一个流程审批的案例了

6.1 部署流程

@RestController
@RequestMapping("/flow")
public class FlowController {

    @Autowired
    private RepositoryService repositoryService;

    @GetMapping("/deploy")
    public String deplopy(){
        Deployment deploy = repositoryService.createDeployment()
                .name("部署的第一个流程") // 定义部署文件的名称
                .addClasspathResource("process.bpmn") // 绑定需要部署的流程文件
                .deploy();// 部署流程
        return deploy.getId() + ":" + deploy.getName();
    }
}

启动后访问接口即可

6.2 启动流程

启动流程我们通过单元测试来操作

package com.boge.workflow;


import org.camunda.bpm.engine.RepositoryService;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.TaskService;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.engine.task.Task;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest(classes = Application.class)
public class ApplicationTest {

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    /**
     * 启动流程的案例
     */
    @Test
    public void startFlow(){
        // 部署流程
        ProcessInstance processInstance = runtimeService
                .startProcessInstanceById("1a880f27-2e57-11ed-80d9-c03c59ad2248");
        // 部署的流程实例的相关信息
        System.out.println("processInstance.getId() = " + processInstance.getId());
        System.out.println("processInstance.getProcessDefinitionId() = " + processInstance.getProcessDefinitionId());
    }


}

6.3 查询待办

查询待办也就是查看当前需要审批的任务,通过TaskService来处理

    /**
     * 查询任务
     *    待办
     *
     *  流程定义ID:processDefinition : 我们部署流程的时候会,每一个流程都会产生一个流程定义ID
     *  流程实例ID:processInstance :我们启动流程实例的时候,会产生一个流程实例ID
     */
    @Test
    public void queryTask(){
        List<Task> list = taskService.createTaskQuery()
                //.processInstanceId("eff78817-2e58-11ed-aa3f-c03c59ad2248")
                .taskAssignee("demo1")
                .list();
        if(list != null && list.size() > 0){
            for (Task task : list) {
                System.out.println("task.getId() = " + task.getId());
                System.out.println("task.getAssignee() = " + task.getAssignee());
            }
        }
    }

6.4 完成任务

   /**
     * 完成任务
     */
    @Test
    public void completeTask(){
        // 根据用户找到关联的Task
        Task task = taskService.createTaskQuery()
                //.processInstanceId("eff78817-2e58-11ed-aa3f-c03c59ad2248")
                .taskAssignee("demo")
                .singleResult();
        if(task != null ){
            taskService.complete(task.getId());
            System.out.println("任务审批完成...");
        }
    }

七、参考

  1. Modeler Download Center
  2. Run Download Center
  3. Quick Start Camunda | docs.camunda.org
  4. Camunda Platform Initializr

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

火山引擎 DataTester 应用故事:一个A/B测试,将产品DAU提升了数十万

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 疫情让线下的需求大量转移到线上&#xff0c;催生出了远程办公、网络授课、线上健身等新的生态现象。如何更好地为用户服务&#xff0c;提升用户体验&#xff0c;成…

计算机的组成

文章目录五大部件1) 输入设备2) 存储器3) CPU&#xff08;中央处理器&#xff09;4) 输出设备五大部件 所有类型的计算机&#xff0c;其本质都是接收用户输入的原始数据&#xff0c;并将其加工、处理成对用户有用的数据&#xff0c;它们都支持执行如表 1 所示的 5 项基本操作。…

SpringCloud Sentinel 使用

哈喽~大家好&#xff0c;SpringCloud Sentinel 使用。 &#x1f947;个人主页&#xff1a;个人主页​​​​​ &#x1f948; 系列专栏&#xff1a;【微服务】 &#x1f949;推荐专栏&#xff1a; JavaEE框架 目录 一、前言 1、什么是Sentinel&…

时间复杂度和空间复杂度【一学就会】

目录 &#x1f947;1.算法效率 &#x1f50e;2.时间复杂度 &#x1f4d7;2.1 大O渐进表示法 &#x1f4d8;2.2 时间复杂度的练习&#xff08;没有说明即最坏情况&#xff09; &#x1f511;3.空间复杂度 &#x1f308;如何评价一个代码呢&#xff1f;它的效率高不高&#…

美创科技发布数据安全综合评估系统|推进安全评估高效开展

数字化深入的今天&#xff0c;数据价值和风险相伴相生&#xff0c;让数据要素发挥更大价值&#xff0c;提高风险预见预判&#xff0c;数据安全评估日益紧迫和必要。《数据安全法》提出&#xff1a;“重要数据处理者应对其数据处理活动定期开展风险评估&#xff0c;并向有关主管…

精彩回顾|关系网络赋能银行数字化转型的应用与实践

本文是根据11月10日Galaxybase图创课堂&#xff1a;乘金融科技之风&#xff1a;关系网络赋能银行数字化转型的应用与实践整理&#xff0c;错过的小伙伴们可以观看回放&#xff1a;https://uao.so/pct862806 精彩回顾 近年&#xff0c;知识图谱的重要性和实际应用逐步呈上升趋…

十大排序(总结+算法实现)

十大排序&#xff08;总结算法实现&#xff09; 十大排队的性能分析 冒泡排序 使用冒泡排序&#xff0c;时间复杂度为O(n^2),空间复杂度为O(1) 像气泡一样从低往上浮现 vector<int> bubbleSort(vector<int>nums) {int lengthnums.size();for(int i0;i<lengt…

PreScan快速入门到精通第三十七讲PreScan中使用深度摄像机

深度相机提供了一个 "相机"图像,其中包含深度值,而不是颜色。它提供的地面真实数据可用于校准或验证立体相机的深度计算。 对象配置 系统选项卡 变量 描述 …

antd——a-tree-select 树形选择控件 与 a-cascader 级联选择器 的对比——技能提升

在遇到 省市区多级联动数据的时候&#xff0c;经常会用到的就是 a-cascader级联选择器。 1.级联选择器的使用方法 1.1 需要指定数据源——options 数据结构是 对象数组嵌套——value/label/children <a-cascader :options"options" placeholder"Please sele…

SpringBoot3 正式发布:有哪些新玩法?

SpringBoot 3.0现已正式发布&#xff0c;可以在Maven Central中找到。 这是自四年前发布2.0以来的第一个主要版本。 它也是SpringBoot的第一个GA版本&#xff0c;提供了对Spring Framework 6.0和GraalVM的支持。 一文详解&#xff5c;从JDK8飞升到JDK17&#xff0c;再到未来…

Tesla M40 下Ubuntu anaconda pycharm安装

显卡&#xff1a;Tesla M40 24GB (2张&#xff09; 显卡驱动版本(推荐)&#xff1a;470.57.02 cuda版本&#xff1a;11.4 安装前需要&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;禁用nouveau驱动&#xff01;&#xff01;&#xff01;&#xff01;&#x…

php中通用的excel导出方法实例

一.普遍导出方法 excel导出的方法网上有很多&#xff0c;在crm或是oa系统中导出excel是常有的事&#xff0c;做过的此功能人都知道&#xff0c;其主要操作其实是循环数据列表&#xff0c;然后一格一格地添加数据到固定的单元格中。只要做好了一次&#xff0c;其后只要复制相关…

外汇天眼:2022 年世界杯已经开始,但这将如何影响外汇交易?

关于 2022 年世界杯 2022年世界杯于2022年11月20日在卡塔尔拉开帷幕&#xff0c;将持续到2022年12月18日。2022年国际足联世界杯是由国际足联成员协会的男子国家队和第22届国际足联世界杯举办的国际足球锦标赛。这是第一次在阿拉伯世界举办的世界杯。 关于中东 尽管经历了疫情…

MCE | KRAS 突变型肺癌耐药性探索

KRAS 是一种致癌基因&#xff0c;编码 KRAS 蛋白 (一种 small GTPase 转导蛋白)。KRAS 通过结合 GTP/GDP 控制其活跃状态&#xff0c;进而控制其信号传递和下游级联反应。致癌性 KRAS 突变会破坏 GTPase 活性&#xff0c;进而使 KRAS 蛋白锁定在活跃状态下&#xff0c;从而使启…

【面试题】JS基础-异步

1. 异步 1.1 为什么要异步&#xff1f; JS是单线程语言&#xff0c;只能同时做一件事。JS和DOM渲染共用同一个线程&#xff0c;因为JS可修改DOM结构。当遇到等待的情况时&#xff0c;例如网络请求、定时任务&#xff0c;程序不能卡住。所以需要异步来解决JS单线程等待的问题&…

学完Spring框架回头再来看反射你会发现真的不一样

文章目录前言一.什么是反射&#xff1f;二.如何实现反射&#xff1f;2.1java.lang.Class2.2通过反射创建对象2.3通过反射获取类成员三.反射的性能四.反射是如何破坏单例模式的&#xff1f;五.如何避免单例模式被反射破坏&#xff1f;前言 你还记得你的Spring入门案例吗&#x…

查询利器—索引

目录 索引的优缺点 常见索引分类 MySQL数据操作的宏观过程 认识磁盘 正式理解索引结构 采用B树的原因 聚簇索引与非聚簇索引 索引操作 索引创建原则 索引的优缺点 优点&#xff1a;提高一个海量数据的检索速度 缺点&#xff1a;查询速度的提高是以插入、更新、删除…

pdf生成:wkhtmltopdf

wkhtmltopdf是开源&#xff08;LGPLv3&#xff09;命令行工具&#xff0c;使用Qt WebKit渲染引擎将HTML渲染为PDF和各种图像格式。这些完全以“headless”模式运行&#xff0c;不需要显示或显示服务wkhtmltoimage。建议&#xff1a; 不要将wkhtmltopdf与任何不受信任的HTML一起…

sqli-labs/Less-61

这一关的欢迎界面提示我们尝试机会为5次 然后要以id为注入点 首先先判断一下是否为数字型 输入id1 and 12 回显如下 所以属于字符型 然后输入1 回显如下 出现了报错信息 说明可以进行报错注入 也说明了注入类型 佐证一下 输入一个1))--回显如下 这道题我还是使用报错注入 首…

使用Python查询国内 COVID-19 疫情

有时我们只是想要一个速的工具来告诉当前疫情的情况&#xff0c;我们只需要最少的数据。 使用Python语言和tkinter图形化显示数据。 首先&#xff0c;我们使用 Tkinter 库使我们的脚本可以图形化显示。 使用 requests 库从 丁香园 获取数据。 然后我们将在这种情况下显示我们…