Activiti实战——Springboot整合Activiti

news2024/12/31 4:04:31

目录

一、Activiti数据库表名说明

 二、Spring boot整合activiti

1. 创建springboot项目

2. 引入activiti依赖及项目依赖

3. 配置数据源

(1)创建数据源配置文件

(2)配置文件

4. 配置Acitviti引擎

5. 启动项目

 三、Activiti接口

1. 流程引擎API和服务

 2. 使用Activiti服务

(1)绘制流程图,生成bpmn文件

(2)部署流程定义

 (3)启动流程

(4)查询待办任务列表

(5)完成任务

 (6)暂停和激活流程定义

(7)查询接口

(8)EUL表达式

 四、BPMN2.0简介

1. 定义一个过程

 五、查询历史

 1. 历史过程实例查询

 2. 历史变量实例查询

 3. 历史活动实例查询

 4. 历史细节查询

5. 历史任务实例查询

6. 历史配置


Activiti官方文档:Activiti User Guide

本篇博客代码地址:https://gitee.com/zhangyin_0116/springboot-activiti-learn.git

一、Activiti数据库表名说明

Activiti 的数据库名称都以 ACT_ 开头。第二部分是表用例的双字符标识。此用例也将大致匹配服务 API。

  • ACT_RE_*:RE 代表 。具有此前缀的表包含静态信息,例如流程定义和流程资源(图像、规则等)。repository

  • ACT_RU_*:RU 代表 。这些是包含流程实例、用户任务、变量、作业等的运行时数据的运行时表。Activiti 仅在流程实例执行期间存储运行时数据,并在流程实例结束时删除记录。这使运行时表保持小而快速。runtime

  • ACT_ID_*:ID 代表 。这些表包含标识信息,例如用户、组等。identity

  • ACT_HI_*:HI 代表 。这些是包含历史数据的表,例如过去的流程实例、变量、任务等。history

  • ACT_GE_*:数据,用于各种用例。general

 二、Spring boot整合activiti

1. 创建springboot项目

2. 引入activiti依赖及项目依赖

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

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
        
        <!-- Mysql驱动包 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.26</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.8</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.activiti/activiti-spring-boot-starter -->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-spring-boot-starter</artifactId>
            <version>7.1.0.M6</version>
        </dependency>
    </dependencies>

        通过引入activiti-spring-boot-starter依赖项,可以轻松地在Spring Boot应用程序中集成和配置Activiti引擎,而无需手动配置所有的Activiti相关组件和依赖项。

        该依赖项提供了一系列自动配置类和默认配置,使得Activiti的集成变得更加简单。它会自动配置数据库连接、事务管理器、流程引擎以及与Spring Boot框架的其他集成。

        使用activiti-spring-boot-starter依赖项,可以通过@Autowired注解轻松注入Activiti的各种服务接口(如RepositoryService、RuntimeService、TaskService等),并使用它们操作流程引擎。

        此外,该依赖项还提供了一些自定义属性配置,您可以通过在application.properties或application.yml文件中进行相应配置来定制Activiti的行为。 

3. 配置数据源

(1)创建数据源配置文件

@Configuration
public class DruidConfig {

    @Value("${spring.datasource.url}")
    private String url;

    @Value("${spring.datasource.username}")
    private String username;

    @Value("${spring.datasource.password}")
    private String password;

    @Value("${spring.datasource.driver-class-name}")
    private String driverClassName;

    @Bean
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setDriverClassName(driverClassName);
        // 其他 Druid 相关配置,如最大连接数、初始连接数等
        return dataSource;
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource());
    }

}

(2)配置文件

# 数据源配置
spring:
  datasource:
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/activiti-learn?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true
    username: root
    password: 123456

4. 配置Acitviti引擎

@Configuration
public class ActivitiConfiguration {
    @Autowired
    private DataSource dataSource;
    @Autowired
    private PlatformTransactionManager platformTransactionManager;

    public ActivitiConfiguration() {
    }

    //通过@Bean注解将SpringProcessEngineConfiguration实例声明为Spring Bean,使其可供其他组件注入和使用
    @Bean
    public SpringProcessEngineConfiguration springProcessEngineConfiguration() {
        SpringProcessEngineConfiguration spec = new SpringProcessEngineConfiguration();
        //设置数据源,将注入的数据源设置到SpringProcessEngineConfiguration实例中
        spec.setDataSource(this.dataSource);
        //设置事务管理器将注入的事务管理器设置到SpringProcessEngineConfiguration实例中
        spec.setTransactionManager(this.platformTransactionManager);
        //设置数据库模式更新策略 true表示在启动时自动创建或更新Activiti引擎所需的数据库表结构
        spec.setDatabaseSchemaUpdate("true");
        Resource[] resources = null;
        //配置流程部署资源
        //使用PathMatchingResourcePatternResolver从classpath中的bpmn目录下加载所有以.bpmn为扩展名的文件作为流程定义资源,
        // 并将它们设置到SpringProcessEngineConfiguration实例中。
        try {
            resources = (new PathMatchingResourcePatternResolver()).getResources("classpath*:bpmn/*.bpmn");
        } catch (IOException var4) {
            var4.printStackTrace();
        }

        spec.setDeploymentResources(resources);
        return spec;
    }
}

5. 启动项目

启动项目,可以看到对应的数据库中自动生成了与Activiti相关的表。

 三、Activiti接口

1. 流程引擎API和服务

从 ProcessEngine 中,可以获取包含工作流/BPM 方法的各种服务。

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

RuntimeService runtimeService = processEngine.getRuntimeService();
RepositoryService repositoryService = processEngine.getRepositoryService();
TaskService taskService = processEngine.getTaskService();
ManagementService managementService = processEngine.getManagementService();
IdentityService identityService = processEngine.getIdentityService();
HistoryService historyService = processEngine.getHistoryService();
FormService formService = processEngine.getFormService();
DynamicBpmnService dynamicBpmnService = processEngine.getDynamicBpmnService();

 2. 使用Activiti服务

(1)绘制流程图,生成bpmn文件

这里是一个请假的流程定义bpmn文件:

<?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.kafeitu.me/activiti/leave">
  <process id="leave" name="请假流程-普通表单" isExecutable="true">
    <documentation>请假流程演示</documentation>
    <startEvent id="startevent1" name="提交申请" activiti:initiator="applyUserId"></startEvent>
    <userTask id="deptLeaderVerify" name="部门领导审批" activiti:candidateGroups="deptLeader" ></userTask>
    <exclusiveGateway id="exclusivegateway5"></exclusiveGateway>
    <userTask id="modifyApply" name="调整申请" activiti:assignee="${applyUserId}">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <userTask id="hrVerify" name="人事审批" activiti:candidateGroups="hr"></userTask>
    <exclusiveGateway id="exclusivegateway6"></exclusiveGateway>
    <userTask id="reportBack" name="销假" activiti:assignee="${applyUserId}">

    </userTask>
    <endEvent id="endevent1" name="结束"></endEvent>
    <exclusiveGateway id="exclusivegateway7"></exclusiveGateway>
    <sequenceFlow id="flow2" sourceRef="startevent1" targetRef="deptLeaderVerify"></sequenceFlow>
    <sequenceFlow id="flow3" sourceRef="deptLeaderVerify" targetRef="exclusivegateway5"></sequenceFlow>
    <sequenceFlow id="flow6" sourceRef="hrVerify" targetRef="exclusivegateway6"></sequenceFlow>
    <sequenceFlow id="flow8" sourceRef="reportBack" targetRef="endevent1"></sequenceFlow>
    <sequenceFlow id="flow11" sourceRef="modifyApply" targetRef="exclusivegateway7"></sequenceFlow>
    <sequenceFlow id="flow5" name="同意" sourceRef="exclusivegateway5" targetRef="hrVerify">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${pass}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow4" name="不同意" sourceRef="exclusivegateway5" targetRef="modifyApply">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${!pass}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow7" name="同意" sourceRef="exclusivegateway6" targetRef="reportBack">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${pass}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow9" name="不同意" sourceRef="exclusivegateway6" targetRef="modifyApply">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${!pass}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow12" name="结束流程" sourceRef="exclusivegateway7" targetRef="endevent1">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${!pass}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow10" name="重新申请" sourceRef="exclusivegateway7" targetRef="deptLeaderVerify">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${pass}]]></conditionExpression>
    </sequenceFlow>
  </process>

(2)部署流程定义

部署流程定义的方法有很多种,这里只介绍一种实际项目中最常用的。

    @Autowired
    private ProcessEngine processEngine;

    @Autowired
    private RepositoryService repositoryService;

    @Test
    void deployProcessDefinition() throws FileNotFoundException {
        String processDefinitionFilePath = "D:\\Java_Dev\\IDEA_Projects\\Personal_project\\springboot-activiti-learn\\src\\main\\resources\\leave.bpmn";
        Deployment deploy = this.repositoryService.createDeployment()
                .addInputStream(processDefinitionFilePath, new FileInputStream(processDefinitionFilePath))
                .deploy();
        System.out.println("部署流程定义成功:"+ deploy);
    }

查看数据库表 act_re_procdef

可以看到已经部署成功

 (3)启动流程

启动流程的方法也有很多种,这里介绍的方法是比较常用的启动流程的方法,需要传递三个参数,分别是:

processDefinitionKey(流程定义key), businessKey(业务key), variables(参数)

这里我们使用流程定义的id去查询流程定义的key,用流程定义的key来启动流程

    @Test
    void startProcessInstance() {

        //启动流程时传递的参数列表 这里根据实际情况 也可以选择不传
        Map<String, Object> variables = new HashMap<String, Object>();
        variables.put("姓名", "张三");
        variables.put("请假天数", new Integer(4));
        variables.put("请假原因", "我很累!");

        // 根据流程定义ID查询流程定义  leave:1:10004是我们刚才部署的流程定义的id
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId("leave:1:10004")
                .singleResult();

        // 获取流程定义的Key
        String processDefinitionKey = processDefinition.getKey();

        //定义businessKey  businessKey一般为流程实例key与实际业务数据的结合
        //假设一个请假的业务 在数据库中的id是1001
        String businessKey = processDefinitionKey + ":" + "1001";
        //设置启动流程的人
        Authentication.setAuthenticatedUserId("xxyin");
        ProcessInstance processInstance = this.runtimeService
                .startProcessInstanceByKey(processDefinitionKey, businessKey, variables);
        System.out.println("流程启动成功:" + processInstance);
    }

查看数据库表 act_hi_procinst:

(4)查询待办任务列表

    @Test
    void findTodoTask() {
        TaskQuery taskQuery = ((TaskQuery)taskService.createTaskQuery().orderByTaskCreateTime()).asc();
        // <userTask id="deptLeaderVerify" name="部门领导审批" activiti:assignee="zhangsan" ></userTask>
        //添加查询条件 查询指派给 zhangsan 的任务  假设这个任务指派给了zhangsan
        taskQuery.taskAssignee("zhangsan");
        //添加查询条件 查询流程定义key为 leave 的任务
        taskQuery.processDefinitionKey("leave");
        List<Task> tasks = taskQuery.list();
        // 处理查询结果
        for (Task task : tasks) {
            System.out.println("Task ID: " + task.getId());
            System.out.println("Task Name: " + task.getName());
            // 其他任务属性的获取和处理
        }
    }

运行结果:

Task ID: 15010
Task Name: 部门领导审批

(5)完成任务

通过查询可以看到当前流转到的任务是“部门领导审批”,可以在表act_ru_task中看到:

 

    @Test
    void complete() {
        //这里模拟传进来的参数
        String taskId = "15010";
        String assignee = "zhangsan";
        Map<String, Object> variables = new HashMap<>();
        variables.put("pass",true);
        variables.put("comment","同意请假");

        //根据任务id获取到当前的任务
        TaskQuery query = this.taskService.createTaskQuery();
        Task task = (Task)((TaskQuery)query.taskId(taskId)).singleResult();

        //将参数列表的评论赋值给comment
        String taskComment = variables.remove("comment").toString();
        //向特定的任务添加评论
        if (!taskComment.equals("")) {
            taskService.addComment(taskId, task.getProcessInstanceId(), taskComment);
        }
        //如果当前任务没有指派人,需要先使用 claim() 方法领取任务
        taskService.claim(taskId,assignee);
        //如果有指派人,直接完成任务
        taskService.complete(taskId,variables);
    }

完成该任务后,再次查看 act_ru_task 表,可以看到任务已经流转到了“人事审批”:

查看评论表act_hi_comment,可以看到任务评论已经添加到对应的任务上:

 (6)暂停和激活流程定义

可以挂起进程定义。挂起流程定义时,无法创建新的流程实例(将引发异常)。暂停进程定义是通过 :RepositoryService

    @Test
    void suspendProcessDefinition() {
        repositoryService.suspendProcessDefinitionByKey("leave");
        try {
            runtimeService.startProcessInstanceByKey("leave");
        } catch (ActivitiException e) {
            e.printStackTrace();
        }
    }

 运行结果:

2023-05-21 21:10:08.425 ERROR 29036 --- [           main] o.a.e.impl.interceptor.CommandContext    : Error while closing command context

org.activiti.engine.ActivitiException: Cannot start process instance. Process definition 请假流程-普通表单 (id = leave:1:10004) is suspended

如果想要激活,执行:

repositoryService.activateProcessDefinitionByKey("leave");

(7)查询接口

有两种方式可以从引擎查询数据,查询API和native查询

  • 查询 API

        允许使用流畅的 API 对完全类型安全的查询进行编程,例如:

List<Task> tasks = taskService.createTaskQuery()
    .taskAssignee("zhangsan")
    .processVariableValueEquals("name", "zhangsan")
    .orderByDueDate().asc()
    .list();
  • native查询

         允许您编写自己的 SQL 查询。返回类型由您使用的 Query 对象定义,数据映射到正确的对象中,例如 Task、ProcessInstance、Execution 等。由于查询将在数据库中触发,因此必须使用数据库中定义的表名和列名;

这个是查询任务名为“人事审批”的任务:

    @Test
    void nativeAPI() {
        // 创建原生任务查询对象 查询任务名为 人事审批 的任务
        NativeTaskQuery nativeTaskQuery = taskService.createNativeTaskQuery()
                .sql("SELECT * FROM " + managementService.getTableName(Task.class) + " T WHERE T.NAME_ = #{taskName}")
                .parameter("taskName", "人事审批");

        // 执行查询并获取结果
        List<Task> tasks = nativeTaskQuery.list();

        // 处理查询结果
        for (Task task : tasks) {
            System.out.println("Task ID: " + task.getId());
            System.out.println("Task Name: " + task.getName());
            // 其他任务属性的获取和处理
        }
    }

这个是查询任务id为 35006 ,并且没有指派人的任务:

    @Test
    void nativeAPI2() {
        // 创建原生任务查询对象
        NativeTaskQuery nativeTaskQuery = taskService.createNativeTaskQuery()
                .sql("SELECT * FROM " + managementService.getTableName(Task.class) +
                        " T WHERE T.ID_ = #{taskId} AND T.ASSIGNEE_ = #{assignee}" )
                .parameter("taskId","35006")
                .parameter("assignee", "");

        // 执行查询并获取结果
        List<Task> tasks = nativeTaskQuery.list();

        // 处理查询结果
        for (Task task : tasks) {
            System.out.println("Task ID: " + task.getId());
            System.out.println("Task Name: " + task.getName());
            // 其他任务属性的获取和处理
        }
    }
}

运行结果:

Task ID: 35006
Task Name: 人事审批

(8)EUL表达式

Activiti 使用 UEL 进行表达式解析。UEL 代表统一表达式语言,是 EE6 规范的一部分。分为两种:值表达式和方法表达式

  • 值表达式:解析为一个。默认情况下,所有流程变量都可供使用。
${myVar}
${myBean.myProperty}
  •  方法表达式:调用方法,带或不带参数。调用不带参数的方法时,请确保在方法名称后添加空括号(因为这会将表达式与值表达式区分开来)。传递的参数可以是文本值或自行解析的表达式。例子:
${printer.print()}
${myBean.addNewOrder('orderName')}
${myBean.doSomething(myVar, execution)}

在所有流程变量之上,还有一些默认对象可用于表达式:

  • execution:保存有关正在进行的执行的其他信息的 。DelegateExecution

  • task:保存有关当前任务的其他信息的 。注意:仅适用于从任务侦听器计算的表达式。DelegateTask

  • authenticatedUserId:当前经过身份验证的用户的 ID。如果没有用户经过身份验证,则该变量不可用。

 四、BPMN2.0简介

1. 定义一个过程

  • process:有两个属性 id 和 name。
<definitions
  xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
  xmlns:activiti="http://activiti.org/bpmn"
  targetNamespace="Examples">

  <process id="myProcess" name="My First Process">
    ..
  </process>

</definitions>
  • sequenceFlow:序列流
    <sequenceFlow id="flow5" name="同意" sourceRef="exclusivegateway5" targetRef="hrVerify">
      <conditionExpression xsi:type="tFormalExpression">
        <![CDATA[${pass}]]>
      </conditionExpression>
    </sequenceFlow>
<conditionExpression xsi:type="tFormalExpression">
  <![CDATA[${order.price > 100 && order.price < 250}]]>
</conditionExpression>
  • exclusiveGateway 排他网关

在XML中的表示:

<exclusiveGateway id="exclusiveGw" name="Exclusive Gateway" />

<sequenceFlow id="flow2" sourceRef="exclusiveGw" targetRef="theTask1">
  <conditionExpression xsi:type="tFormalExpression">${input == 1}</conditionExpression>
</sequenceFlow>

<sequenceFlow id="flow3" sourceRef="exclusiveGw" targetRef="theTask2">
  <conditionExpression xsi:type="tFormalExpression">${input == 2}</conditionExpression>
</sequenceFlow>

<sequenceFlow id="flow4" sourceRef="exclusiveGw" targetRef="theTask3">
  <conditionExpression xsi:type="tFormalExpression">${input == 3}</conditionExpression>
</sequenceFlow>
  •  parallelGateway:并行网关

 XML定义如下:

<startEvent id="theStart" />
<sequenceFlow id="flow1" sourceRef="theStart" targetRef="fork" />

<parallelGateway id="fork" />
<sequenceFlow sourceRef="fork" targetRef="receivePayment" />
<sequenceFlow sourceRef="fork" targetRef="shipOrder" />

<userTask id="receivePayment" name="Receive Payment" />
<sequenceFlow sourceRef="receivePayment" targetRef="join" />

<userTask id="shipOrder" name="Ship Order" />
<sequenceFlow sourceRef="shipOrder" targetRef="join" />

<parallelGateway id="join" />
<sequenceFlow sourceRef="join" targetRef="archiveOrder" />

<userTask id="archiveOrder" name="Archive Order" />
<sequenceFlow sourceRef="archiveOrder" targetRef="theEnd" />

<endEvent id="theEnd" />

 五、查询历史

在 API 中,可以查询所有 5 个历史记录实体:

 1. 历史过程实例查询

    @Test
    void historyAPI1() {
        List<HistoricProcessInstance> processInstances = historyService.createHistoricProcessInstanceQuery()
                .processDefinitionKey("leave")
                .orderByProcessInstanceDuration()
                .desc()
                .listPage(0, 10);
        System.out.println("ProcessInstance: "+ processInstances);
    }

 2. 历史变量实例查询

    @Test
    void historyAPI2() {
        List<HistoricVariableInstance> historicVariableInstances = historyService.createHistoricVariableInstanceQuery()
                .processInstanceId("60002")
                .orderByVariableName().desc()
                .list();
        System.out.println("historicVariableInstances: "+ historicVariableInstances);
    }

 3. 历史活动实例查询

查询已经完成的任务(用户任务):

    @Test
    void historyAPI3() {
        List<HistoricActivityInstance> userTask = historyService.createHistoricActivityInstanceQuery()
                .activityType("userTask")
                .processDefinitionId("leave:1:10004")
                .finished()
                .orderByHistoricActivityInstanceEndTime()
                .desc()
                .listPage(0, 1);
        System.out.println("userTask: "+ userTask);
    }

 4. 历史细节查询

    @Test
    void historyAPI4() {
        List<HistoricDetail> historicDetails = historyService.createHistoricDetailQuery()
                .variableUpdates()
                .processInstanceId("60002")
                .orderByVariableName().asc()
                .list();
        System.out.println("historicDetails: "+ historicDetails);
    }

5. 历史任务实例查询

查询已完成的任务:

    @Test
    void historyAPI5() {
        List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery()
                .finished()
                .orderByHistoricTaskInstanceDuration()
                .desc()
                .listPage(0, 10);
        System.out.println("historicTaskInstances: "+ historicTaskInstances);
    }

 查询未完成的任务:

    @Test
    void historyAPI6() {
        List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery()
                .unfinished()
                .orderByHistoricTaskInstanceDuration()
                .desc()
                .listPage(0, 10);
        System.out.println("historicTaskInstances: "+ historicTaskInstances);
    }

6. 历史配置

  • none:跳过所有历史记录存档。这是运行时进程执行的最高性能,但没有历史信息可用。

  • activity:存档所有流程实例和活动实例。在流程实例结束时,顶级流程实例变量的最新值将被复制到历史变量实例中。不会存档任何详细信息。

  • audit:这是默认值。它存档所有流程实例、活动实例,使变量值持续同步以及提交的所有表单属性,以便通过表单进行的所有用户交互都是可追溯的并且可以审核的。

  • full:这是历史存档的最高级别,因此速度最慢。此级别存储级别中的所有信息以及所有其他可能的详细信息,主要是过程变量更新。audit

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

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

相关文章

【MySQL 数据库】1、MySQL 的 DDL、DML、DQL 语句

目录 一、MySQL 应该掌握哪些知识点 &#xff1f;二、数据库相关概念三、主流关系型数据库管理系统四、关系型数据库五、SQL 语句的分类六、DDL(1) 数据库操作(2) 表操作(3) 字段的数据类型(4) 创建员工表(5) 修改表结构(6) 删除某一张表 七、DML八、DQL(1) 员工表(2) distinct…

经典神经网络(4)Nin-Net及其在Fashion-MNIST数据集上的应用

经典神经网络(4)Nin-Net及其在Fashion-MNIST数据集上的应用 1 Nin-Net的简述 1.1 Nin-Net的概述 LeNet、AlexNet和VGG都有⼀个共同的设计模式&#xff1a;通过⼀系列的卷积层与汇聚层来提取空间结构特征&#xff1b;然后通过全连接层对特征的表征进⾏处理。AlexNet和VGG对Le…

线程池的创建与使用

void execute(Runnable run)方法处理Runnbale任务 Future<> submit(Callable<> task)方法处理Callable任务 void shutdown()结束线程池 List<\Runnable> shutdownNow()立即结束线程池&#xff0c;不管任务是否执行完毕 //创建线程池的一种方式 ExecutorServi…

基于WebApi实现ModbusTCP数据服务

在上位机开发过程中&#xff0c;有时候会遇到需要提供数据接口给MES或者其他系统&#xff0c;今天跟大家分享一下&#xff0c;如何在Winform等桌面应用程序中&#xff0c;开发WebApi接口&#xff0c;提供对外数据服务。 为了更好地演示应用场景&#xff0c;本案例以读取Modbus…

Leetcode 209. 长度最小的子数组——go语言实现

文章目录 一、题目描述二、代码实现方法一&#xff1a;暴力法解题思路代码实现复杂度分析 方法二&#xff1a;滑动窗口 双指针解题思路代码实现复杂度分析 方法三&#xff1a;前缀和 二分查找解题思路代码实现复杂度分析 一、题目描述 给定一个含有 n 个正整数的数组和一个正…

STM32 10个工程篇:1.IAP远程升级(四)

在前三篇博客中主要介绍了IAP远程升级的应用背景、下位机的实现原理、以及基于STM32CubeMX对STM32F103串口DMA的基本配置&#xff0c;第四篇博客主要想介绍Labview端上位机和下位机端的报文定义和通信等。 当笔者工作上刚接触到STM32 IAP升级的时候&#xff0c;实事求是地说存在…

【科普】电压和接地真的存在吗?如何测试?

经常在实验室干活的&#xff0c;难免不被电击过&#xff0c;尤其是在干燥的北方&#xff0c;“被电”是常有的事情&#xff0c;我记得有一次拿着射频线往仪表上拧的时候&#xff0c;遇到过一次严重的电火花&#xff0c;瞬间将仪表的射频口边缘烧出了一个疤&#xff0c;实验室遭…

LeetCode83. 删除排序链表中的重复元素

写在前面&#xff1a; 题目链接&#xff1a;LeetCode83. 删除排序链表中的重复元素 编程语言&#xff1a;C 题目难度&#xff1a;简单 一、题目描述 给定一个已排序的链表的头 head &#xff0c; 删除所有重复的元素&#xff0c;使每个元素只出现一次 。返回 已排序的链表 。 …

Java中异常的处理及捕获

Java中异常的处理及捕获 一、异常的概述 &#xff08;1&#xff09;Java中异常的作用&#xff1a;增强程序的健壮性 &#xff08;2&#xff09;在Java中所有的Error&#xff08;错误&#xff09;和异常&#xff08;Exception&#xff09;都继承了同一个父类Throwable 二、异…

postgresql内核源码分析-删除表drop table流程

专栏内容&#xff1a;postgresql内核源码分析个人主页&#xff1a;我的主页座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物&#xff0e; 目录 前言 调用关系 概要流程 详细流程 创建对象列表空间 删除多个指定的数据库…

【蓝桥杯国赛真题27】Scratch LED屏幕 少儿编程scratch图形化编程 蓝桥杯国赛真题讲解

目录 scratch LED屏幕 一、题目要求 编程实现 二、案例分析 1、角色分析

C#中使用git将项目代码上传到远程仓库的操作

一、远程仓库创建操作&#xff08;远程仓库使用的是gitHub&#xff09; 1、登录GitHub官网&#xff0c;注册登录账号后&#xff0c;点击创建仓库 2、仓库名称命名&#xff0c;如下所示&#xff1a; 3、创建成功如下所示&#xff1a;获得https协议&#xff08;https://github.c…

Android开发不可缺少的辅助工具

目录 jadxandroid_toolscrcpy-guiCode CraftsSQLite Expert Personal jadx jadx是一款apk反编译工具。 PS&#xff1a;部分版本安装&#xff0c;无法打开类文件&#xff0c;需换个版本。 开源地址&#xff1a;https://github.com/skylot/jadx android_tool android_tool可以通…

【瑞萨RA_FSP】SCL UART 串口通信

文章目录 一、串口通信协议简介1. 物理层2. 协议层 二、SCI 简介三、SCI的结构框图四、UART波特率计算 一、串口通信协议简介 串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式&#xff0c;因为它简单便捷&#xff0c;因此大部分电子设备都支持该通讯方式&a…

SNAT和DNAT策略

文章目录 1.SNAT策略及应用1.1 SNAT原理与应用1.2 SNAT策略的工作原理1.3 实验步骤 2.DNAT策略2.1 DNAT策略的概述2.1 DNAT原理与应用2.3 实验步骤 3.规则的导出、导入4. 总结 1.SNAT策略及应用 1.1 SNAT原理与应用 SNAT 应用环境&#xff1a;局域网主机共享单个公网IP地址接…

【利用AI让知识体系化】关于浏览器内核的基础知识

I. 介绍 什么是浏览器内核 浏览器内核&#xff08;Browser Engine&#xff09;&#xff0c;也叫浏览器渲染引擎&#xff08;Rendering Engine&#xff09;&#xff0c;是浏览器的核心组成部分&#xff0c;它负责将 HTML、CSS、JavaScript 等代码经过解析和渲染后&#xff0c;…

End-to-End Object Detection with Transformers 论文学习

论文地址&#xff1a;End-to-End Object Detection with Transformers 1. 解决了什么问题&#xff1f; 现有的目标检测算法需要大量的人为先验的设计&#xff0c;如 anchor 和 NMS&#xff0c;整体架构并不是端到端的。现有的检测方法为了去除重叠框&#xff0c;一般会利用 p…

企业级信息系统开发——初探Spring - 利用组件注解符精简Spring配置文件

文章目录 一、打开项目二、利用组件注解符精简Spring配置文件&#xff08;一&#xff09;创建新包&#xff08;二&#xff09;复制四个类&#xff08;三&#xff09;修改杀龙任务类&#xff08;四&#xff09;修改救美任务类&#xff08;五&#xff09;修改勇敢骑士类&#xff…

NEEPU Sec 2023 公开赛 writeup

文章目录 WebCute CirnoCute Cirno(Revenge) RevHow to use ida?BaseHow to use python?IKUN检查器junk code CryptoFunnyRsaLossloud Misc吉林第一站倒影Shiro重生之我是CTFer 问卷 Web Cute Cirno 学艺不精的我脑袋要炸了 在Cirno界面的源代码中发现任意读 考虑之前的比…

在Ubuntu20.04部署Flink1.17实现基于Flink GateWay的Hive On Flink的踩坑记录(一)

在Ubuntu20.04部署Flink1.17实现基于Flink GateWay的Hive On Flink的踩坑记录&#xff08;一&#xff09; 前言 转眼间&#xff0c;Flink1.14还没玩明白&#xff0c;Flink已经1.17了&#xff0c;这迭代速度还是够快。。。 之前写过一篇&#xff1a;https://lizhiyong.blog.c…