camunda中流程变量如何使用

news/2024/7/6 21:45:28/文章来源:https://www.cnblogs.com/hibpm/p/18282866

本文章介绍camunda流程引擎中变量的概念。流程变量可用于向流程运行时状态添加数据,或者更具体地说,向变量作用域添加数据。更改这些实体状态的各种 API 方法允许更新附加的变量。通常,变量由名称和值组成。该名称用于跨流程构造进行标识。例如,如果一个活动设置了一个名为 var 的变量,则后续活动可以使用此名称访问它。变量的值是一个 Java 对象。

1、流程变量作用域和可见性

所有可以具有变量的实体都称为变量作用域。这些是执行(包括流程实例)和任务。如概念部分所述,流程实例的运行时状态由执行树表示。比如以下流程模型,其中红点标记的活动任务:

此流程的运行时结构如下:

因为有网关节点,这个流程实例就是一个两个子执行(execution)的流程实例,每个子执行都创建了一个任务。所有这五个实体都是可变作用域,箭头标记父子关系。在父作用域上定义的变量可以在每个子作用域中访问,除非子作用域定义了同名的变量。反之,子变量不能从父作用域访问。直接附加到相关作用域的变量称为局部变量。请考虑以下变量分配给作用域:

在这种情况下,在处理任务 1 时,变量 worker 和 customer 是可访问的。请注意,由于作用域的结构,变量 worker 可以定义两次,以便任务1访问与任务2不同的工作线程变量。但是,两者都共享变量 customer,这意味着如果其中一个任务更新了该变量,则此更改对另一个任务也可见。

这两个任务都可以访问两个变量,而这些变量都不是局部变量。所有三个执行(execution)都有一个局部变量。

现在,假设我们在任务1上设置了一个局部变量 customer:

虽然仍然可以从任务 1 访问名为 customer 和 worker 的两个变量,但执行 1 上的 customer 变量是隐藏的,因此可访问的客户变量是任务 1 的局部变量。

通常,变量在以下情况下是可访问的:

  • 实例化流程
  • 传递消息
  • 任务生命周期转换
  • 设置/获取外部变量
  • 在委托(Delegate)中设置/获取变量
  • 流程模型中的表达式
  • 流程模型中的脚本
  • (历史性)变量查询

2、设置和检索流程变量

为了设置和检索变量,流程引擎提供了一个 Java API,它允许从 Java 对象中设置变量并以setting 的形式检索它们。在内部,引擎将变量保存到数据库,因此应用序列化。对于大多数应用来说,这是一个无关紧要的细节。但是,有时,在使用自定义 Java 类时,变量的序列化值是值得关注的。想象一下,一个管理许多流程应用程序的监控应用程序。它与这些应用程序的类分离,因此无法访问其 Java 表示中的自定义变量。对于这些情况,流程引擎提供了一种检索和操作序列化值的方法。这归结为两个 API:

  • Java 对象值 API(Java Object Value API):变量表示为 Java 对象。这些对象可以直接设置为值并以相同的形式检索。这是更简单的 API,是将代码作为流程应用程序的一部分实现,推荐使用这种方法。
  • 类型化值 API(Typed Value API:):变量值包装在用于设置和检索变量的所谓类型化值中。类型化值提供对元数据的访问,例如引擎序列化变量的方式,以及变量的序列化表示形式(具体取决于类型)。元数据还包含变量是否为瞬态的信息。

例如,以下代码使用这两个 API 检索和设置两个整数变量:

// Java Object API: Get Variable

Integer val1 = (Integer) execution.getVariable("val1");

// Typed Value API: Get Variable

IntegerValue typedVal2 = execution.getVariableTyped("val2");

Integer val2 = typedVal2.getValue();

Integer diff = val1 - val2;

// Java Object API: Set Variable

execution.setVariable("diff", diff);

// Typed Value API: Set Variable

IntegerValue typedDiff = Variables.integerValue(diff);

execution.setVariable("diff", typedDiff);

2.1、将变量设置为特定范围

可以从脚本(scripts)、输入\输出映射(input\output mapping)、侦听器(listeners )和服务任务(service tasks)中将变量设置到特定范围内。此功能的实现使用活动 ID 来标识目标范围,如果找不到用于设置变量的范围,则会引发异常。此外,一旦找到目标作用域,将在其中本地设置变量,这意味着即使目标作用域没有具有给定 id 的变量,也不会执行到父作用域的传播。

以下是脚本 executionListener 的示例用法:

<camunda:executionListener event="end">

<camunda:script scriptFormat="groovy"><![CDATA[execution.setVariable("aVariable", "aValue","aSubProcess");]]></camunda:script>

</camunda:executionListener>

另一个用法示例是输入\输出映射,使用DelegateVariableMapping实现

public class SetVariableToScopeMappingDelegate implements DelegateVariableMapping {

@Override

public void mapInputVariables(DelegateExecution superExecution, VariableMap subVariables) {

}

@Override

public void mapOutputVariables(DelegateExecution superExecution, VariableScope subInstance) {

superExecution.setVariable("aVariable","aValue","aSubProcess");

}

}

here 变量将在“aSubProcess”中本地设置,即使变量未事先在“aSubProcess”中本地设置,也不会传播到父范围。

3、支持的变量值

流程引擎支持以下变量值类型:

根据变量的实际值,分配不同的类型。在可用类型中,有九种原始值( primitive value)类型,这意味着它们存储简单标准 JDK 类的值,而无需其他元数据:

  • boolean:实例java.lang.Boolean
  • bytes:实例byte[]
  • short:实例java.lang.Short
  • integer:实例java.lang.Integer
  • long:实例java.lang.Long
  • double:实例java.lang.Double
  • date:实例java.util.Date
  • string:实例java.lang.String
  • null:引用null

原始值( primitive value)与其他变量值的不同之处在于,它们可以在 API 查询(如流程实例查询)中用作筛选条件。

file类型可用于存储文件或输入流的内容以及元数据,例如文件名、编码和文件内容对应的 MIME 类型。

object值类型表示定制 Java 对象。当此类变量被保留时,其值将根据序列化流程进行序列化。这些流程是可配置和可交换的。

3.1、字符串长度限制

string值存储在数据库的列(n)varchar类型中,长度限制为 4000(Oracle 为 2000)。根据正在使用的数据库和配置的字符集,此长度限制可能会导致不同数量的实数字符。变量值长度不会在 Camunda 引擎中进行验证,但值会“按原样”发送到数据库,如果超过长度限制,将引发数据库级异常。如果需要验证,可以单独实现,并且必须在调用用于设置变量的 Camunda API 之前进行。

流程变量可以存储为 Camunda Spin 插件提供的 JSON 和 XML 等格式。Spin 为object类型的变量提供序列化程序,以便 Java 变量可以以这些格式保存到数据库中。此外,可以通过值类型XML和JSON将JSON和XML文档直接存储为Spin对象。与普通字符串变量相反,Spin对象提供了一个流畅的API来对此类文档执行常见操作,如读取和写入属性。

3.2、对象值序列化

当将对象值传递给流程引擎时,可以指定序列化格式来告诉流程引擎以特定格式存储该值。基于这种格式,引擎查找一个序列化程序。序列化程序能够将Java对象序列化为指定的格式,并从该格式的表示中将其反序列化。这意味着,对于不同的格式可能有不同的序列化程序,并且可以实现自定义序列化程序以便以特定格式存储自定义对象。

流程引擎为formatapplication/x-java-serialized-object提供了一个内置的对象序列化程序。它能够序列化实现接口Java.io.Serializable的Java对象,并应用标准Java对象序列化。

使用类型值API设置变量时,可以指定所需的序列化格式:

CustomerData customerData = new CustomerData();

ObjectValue customerDataValue = Variables.objectValue(customerData)

.serializationDataFormat(Variables.SerializationDataFormats.JAVA)

.create();

execution.setVariable("someVariable", customerDataValue);

除此之外,流程引擎配置还有一个选项defaultSerializationFormat,当没有请求特定格式时使用该选项。此选项默认为application/x-java-serialized-object。

4、Java 对象 API

使用 Java 中的流程变量最方便的方法是使用它们的 Java 对象表示。只要流程引擎提供变量访问,就可以在此表示形式中访问流程变量,因为对于自定义对象,引擎知道所涉及的类。例如,以下代码设置并检索给定流程实例的变量:

com.example.Order order = new com.example.Order();

runtimeService.setVariable(execution.getId(), "order", order);

com.example.Order retrievedOrder = (com.example.Order) runtimeService.getVariable(execution.getId(), "order");

此代码将变量设置在变量作用域层次结构中可能的最高点。这意味着,如果变量已经存在(无论是在此次执行中还是在其任何父作用域中),它都会被更新。如果变量还不存在,则在最高范围(即流程实例)中创建该变量。如果一个变量应该在提供的执行中准确设置,那么可以使用本地方法。例如

com.example.Order order = new com.example.Order();

runtimeService.setVariableLocal(execution.getId(), "order", order);

com.example.Order retrievedOrder = (com.example.Order) runtimeService.getVariable(execution.getId(), "order");

com.example.Order retrievedOrder = (com.example.Order) runtimeService.getVariableLocal(execution.getId(), "order");

// both methods return the variable

每当在其 Java 表示中设置变量时,流程引擎都会自动确定合适的值序列化程序,或者如果提供的值无法序列化,则引发异常。

5、类型化值 API

在访问变量的序列化表示很重要,或者必须提示引擎以某种格式序列化值的情况下,可以使用基于类型值的API。与基于Java-Object的API相比,它将变量值封装在所谓的TypedValue中。这样的类型化值允许更丰富地表示变量值。

为了方便地构造类型化的值,Camunda平台提供了org.Camunda.bpm.engine.variable类。变量。此类包含静态方法,这些方法允许创建单一类型的值以及以流畅的方式创建类型值的映射。

6、流程变量值类型

6.1、基元值类型(Primitive Values)

以下代码通过将单个String变量指定为类型化值来设置该变量:

StringValue typedStringValue = Variables.stringValue("a string value");

runtimeService.setVariable(execution.getId(), "stringVariable", typedStringValue);

StringValue retrievedTypedStringValue = runtimeService.getVariableTyped(execution.getId(), "stringVariable");

String stringValue = retrievedTypedStringValue.getValue(); // equals "a string value"

请注意,使用此 API,变量值周围还有一个抽象级别。因此,为了获得真实值,有必要解开实际值。

6.2、文件值类型(File Values)

对于普通的String值,基于Java-Object的API更加简洁。因此,让我们考虑更丰富的数据结构的价值。

文件可以作为BLOB持久存在数据库中。文件值类型允许存储其他元数据,如文件名和mime类型。以下示例代码从文本文件创建文件值:

FileValue typedFileValue = Variables

.fileValue("addresses.txt")

.file(new File("path/to/the/file.txt"))

.mimeType("text/plain")

.encoding("UTF-8")

.create();

runtimeService.setVariable(execution.getId(), "fileVariable", typedFileValue);

FileValue retrievedTypedFileValue = runtimeService.getVariableTyped(execution.getId(), "fileVariable");

InputStream fileContent = retrievedTypedFileValue.getValue(); // a byte stream of the file contents

String fileName = retrievedTypedFileValue.getFilename(); // equals "addresses.txt"

String mimeType = retrievedTypedFileValue.getMimeType(); // equals "text/plain"

String encoding = retrievedTypedFileValue.getEncoding(); // equals "UTF-8"

更改文件File值.要更改或更新文件值,您必须创建一个具有相同名称和新内容的新FileValue,因为所有类型化的值都是不可变的:

InputStream newContent = new FileInputStream("path/to/the/new/file.txt");

FileValue fileVariable = execution.getVariableTyped("addresses.txt");

Variables.fileValue(fileVariable.getName()).file(newContent).encoding(fileVariable.getEncoding()).mimeType(fileVariable.getMimeType()).create();

6.3、对象值

自定义Java对象可以使用值类型对象进行序列化。使用类型化值API的示例:

com.example.Order order = new com.example.Order();

ObjectValue typedObjectValue = Variables.objectValue(order).create();

runtimeService.setVariableLocal(execution.getId(), "order", typedObjectValue);

ObjectValue retrievedTypedObjectValue = runtimeService.getVariableTyped(execution.getId(), "order");

com.example.Order retrievedOrder = (com.example.Order) retrievedTypedObjectValue.getValue();

这又等同于基于 Java 对象的 API。但是,现在可以告诉引擎在保留值时要使用哪种序列化格式。例如:

ObjectValue typedObjectValue = Variables

.objectValue(order)

.serializationDataFormat(Variables.SerializationDataFormats.JAVA)

.create();

创建一个值,该值由引擎的内置Java对象序列化程序序列化。此外,检索到的ObjectValue实例还提供了其他变量详细信息:

// returns true

boolean isDeserialized = retrievedTypedObjectValue.isDeserialized();

// returns the format used by the engine to serialize the value into the database

String serializationDataFormat = retrievedTypedObjectValue.getSerializationDateFormat();

// returns the serialized representation of the variable; the actual value depends on the serialization format used

String serializedValue = retrievedTypedObjectValue.getValueSerialized();

// returns the class com.example.Order

Class<com.example.Order> valueClass = retrievedTypedObjectValue.getObjectType();

// returns the String "com.example.Order"

String valueClassName = retrievedTypedObjectValue.getObjectTypeName();

当调用应用程序不拥有实际变量值的类(即com.example.Order未知)时,序列化详细信息非常有用。在这些情况下,runtimeService.getVariableTyped(execution.getId(),“order”)将引发异常,因为它会立即尝试反序列化变量值。在这种情况下,可以使用调用runtimeService.getVariableTyped(execution.getId(),“order”,false)。附加布尔参数告诉流程引擎不要尝试反序列化。在这种情况下,调用isDeserialized()将返回false,而像getValue()和getObjectType()这样的调用将引发异常。尽管如此,调用getValueSerialized()和getObjectTypeName()是访问变量的一种方式。

同样,也可以从变量的序列化表示中设置变量:

String serializedOrder = "...";

ObjectValue serializedValue =

Variables

.serializedObjectValue(serializedOrder)

.serializationDataFormat(Variables.SerializationDataFormats.JAVA)

.objectTypeName("com.example.Order")

.create();

runtimeService.setVariableLocal(execution.getId(), "order", serializedValue);

ObjectValue retrievedTypedObjectValue = runtimeService.getVariableTyped(execution.getId(), "order");

com.example.Order retrievedOrder = (com.example.Order) retrievedTypedObjectValue.getValue();

不一致的变量状态

设置序列化变量值时,不检查序列化值的结构是否与变量值应为其实例的类兼容。在设置上述示例中的变量时,所提供的序列化值不会根据com.example的结构进行验证。顺序因此,只有在调用runtimeService#getVariableTyped时才会检测到无效的变量值。

Java 序列化格式

在使用变量的序列化表示时,默认情况下禁止使用Java序列化格式。您应该使用另一种格式(JSON或XML),或者在javaSerializationFormatEnabled配置标志的帮助下显式启用Java序列化。

6.4、JSON 和 XML 值

Camunda Spin插件为JSON和XML文档提供了一个抽象,有助于它们的处理和操作。这通常比将此类文档存储为纯字符串变量更方便。有关存储JSON文档和存储XML文档的详细信息,请参阅Camunda SPIN上的文档。

6.5、瞬态变量

只有通过基于类型值的API(typed-value-based API)才能声明瞬态变量。它们不会保存到数据库中,并且仅在当前事务期间存在。流程实例执行过程中的每个等待状态都会导致所有瞬态变量的丢失。这通常发生在外部服务当前不可用、用户任务已到达或进程执行正在等待消息、信号或条件时。请小心使用此功能。

任何类型的变量都可以使用Variables类声明为transient,并将参数isTransient设置为true。

// primitive values

TypedValue typedTransientStringValue = Variables.stringValue("foobar", true);

// object value

com.example.Order order = new com.example.Order();

TypedValue typedTransientObjectValue = Variables.objectValue(order, true).create();

// file value

TypedValue typedTransientFileValue = Variables.fileValue("file.txt", true)

.file(new File("path/to/the/file.txt"))

.mimeType("text/plain")

.encoding("UTF-8")

.create();

瞬态变量可以通过 REST API 使用,例如在启动新的流程实例时:https://docs.camunda.org/rest/camunda-bpm-platform/7.19/#tag/Process-Definition/operation/startProcessInstance

6.6、设置多个类型化值

类似于基于Java-Object的API,也可以在一个API调用中设置多个类型化的值。Variables类提供了一个流畅的API来构造类型化值的映射:

com.example.Order order = new com.example.Order();

VariableMap variables =

Variables.createVariables()

.putValueTyped("order", Variables.objectValue(order).create())

.putValueTyped("string", Variables.stringValue("a string value"))

.putValueTyped("stringTransient", Variables.stringValue("foobar", true));

runtimeService.setVariablesLocal(execution.getId(), "order", variables);

7、API 的可互换性

两个API在相同的实体上提供不同的视图,因此可以根据需要进行组合。例如,使用基于Java-Object的API设置的变量可以作为类型化值检索,反之亦然。由于类VariableMap实现了Map接口,所以也可以将普通Java对象和类型化的值放入该映射中。

您应该使用哪种API?最适合你的目的。当您确信您始终可以访问所涉及的值类时,例如在流程应用程序(如JavaDelegate)中实现代码时,则基于Java-Object的API更易于使用。当您需要访问值特定的元数据(如序列化格式)或将变量定义为瞬态时,那么基于类型值的API就是您的选择。

8、输入/输出变量映射

为了提高源代码和业务逻辑的可重用性,Camunda平台提供了流程变量的输入/输出映射。这可以用于任务、事件和子流程。

为了使用变量映射,必须将Camunda扩展元素inputOutput添加到元素中。它可以包含多个inputParameter和outputParameter元素,用于指定应映射的变量。inputParameter的name属性表示活动内部的变量名(要创建的局部变量),而outputParameter的name属性表示活动外部的变量名。

输入/输出参数的内容指定映射到相应变量的值。它可以是一个简单的常量字符串或表达式。一个空体将变量设置为null值。

<camunda:inputOutput>

<camunda:inputParameter name="x">foo</camunda:inputParameter>

<camunda:inputParameter name="willBeNull"/>

<camunda:outputParameter name="y">${x}</camunda:outputParameter>

<camunda:outputParameter name="z">${willBeNull == null}</camunda:outputParameter>

</camunda:inputOutput>

甚至可以使用List和Map等复杂结构。两者也可以嵌套。

<camunda:inputOutput>

<camunda:inputParameter name="x">

<camunda:list>

<camunda:value>a</camunda:value>

<camunda:value>${1 + 1}</camunda:value>

<camunda:list>

<camunda:value>1</camunda:value>

<camunda:value>2</camunda:value>

<camunda:value>3</camunda:value>

</camunda:list>

</camunda:list>

</camunda:inputParameter>

<camunda:outputParameter name="y">

<camunda:map>

<camunda:entry key="foo">bar</camunda:entry>

<camunda:entry key="map">

<camunda:map>

<camunda:entry key="hello">world</camunda:entry>

<camunda:entry key="camunda">bpm</camunda:entry>

</camunda:map>

</camunda:entry>

</camunda:map>

</camunda:outputParameter>

</camunda:inputOutput>

脚本也可以用于提供变量值。有关如何指定脚本,请参阅脚本一章中相应的部分。

输入/输出映射好处的一个简单例子是复杂的计算,它应该是多个过程定义的一部分。此计算可以作为独立的委托代码或脚本开发,并在每个进程中重复使用,即使进程使用不同的变量集也是如此。输入映射用于将不同的过程变量映射到复杂计算活动所需的输入参数。因此,输出映射允许在进一步的过程执行中利用计算结果。

更详细地说,让我们假设这样的计算是由Java Delegate类org.camunda.bpm.example实现的。ComplexCalculation。此委托需要一个userId和一个costSum变量作为输入参数。然后,它计算三个值,悲观预测、现实预测和乐观预测,这三个值是对客户面临的未来成本的不同预测。在第一个过程中,两个输入变量都可用作过程变量,但名称不同(id、sum)。从这三个结果来看,流程仅使用realisticForecast,它在后续活动中依赖于名称预测。相应的输入/输出映射如下所示:

<serviceTask camunda:class="org.camunda.bpm.example.ComplexCalculation">

<extensionElements>

<camunda:inputOutput>

<camunda:inputParameter name="userId">${id}</camunda:inputParameter>

<camunda:inputParameter name="costSum">${sum}</camunda:inputParameter>

<camunda:outputParameter name="forecast">${realisticForecast}</camunda:outputParameter>

</camunda:inputOutput>

</extensionElements>

</serviceTask>

在第二个过程中,让我们假设costSum变量必须根据三个不同映射的属性进行计算。此外,该过程还取决于变量avgForecast作为三个预测的平均值。在这种情况下,映射如下所示:

<serviceTask camunda:class="org.camunda.bpm.example.ComplexCalculation">

<extensionElements>

<camunda:inputOutput>

<camunda:inputParameter name="userId">${id}</camunda:inputParameter>

<camunda:inputParameter name="costSum">

${mapA[costs] + mapB[costs] + mapC[costs]}

</camunda:inputParameter>

<camunda:outputParameter name="avgForecast">

${(pessimisticForecast + realisticForecast + optimisticForecast) / 3}

</camunda:outputParameter>

</camunda:inputOutput>

</extensionElements>

</serviceTask>

Camunda工作流体验环境:http://www.yunchengxc.com

Camunda7.19官方文档:https://docs.camunda.org/manual/7.19/user-guide/process-engine/variables/

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ubuntu apt update 提示 The repository ‘http://xxx Release‘ does not have a Release file

sudo apt update && sudo apt upgrade -y提示 报错 E: The repository ‘http://xxx Release‘ does not have a Release file.编辑文件 /etc/apt/sources.list, 添加下面代码保存 deb http://nl3.archive.ubuntu.com/ubuntu jammy main restricted universe multivers…

处理器SDK Linux软件开发

处理器SDK Linux软件开发 https://software-dl.ti.com/jacinto7/esd/processor-sdk-linux-edgeai/TDA4VM/08_06_01/exports/docs/devices/TDA4VM/linux/index.html 1.概述 欢迎使用处理器SDK Linux版TDA4VM! SDK提供软件和工具,让用户在德州仪器的边缘人工智能应用处理器上有…

jira修改RoadMap里的时间格式,硬核日期格式化

jira修改roadMap里的时间格式 在插件目录找到portfolio-plugin-9.16.1.jar将他下载到本地 使用zip解压软件解压jar包 全局搜索 DD/MM/YY 将其替换YYYY/MM/DD修改后效果图全局搜索 return${l()(o.getUTCDate().toString(),2,"0")}/${t} 替换 return ${o.getUTCMonth()…

不同网站检测到的ip不同

背景 最近在使用某个接口时出现了问题,大致是根据ip查询地址。 于是使用查询ip的网站,发现ip各有不同。大致上是有三种ip。 探讨 经过查询,比较合理的解释是,运营商有多个网络出口,根据访问的网站不同,使用的网络出口也不同,因此不同的网站分别使用了不同的ip去访问,因…

全网最适合入门的面向对象编程教程:08 类和对象的Python实现-@property装饰器:把方法包装成属性

本文主要对@property 装饰器的基本定义、使用场景和使用方法进行了介绍,同时介绍了setter装饰器和deleter装饰器的应用场景和语法。全网最适合入门的面向对象编程教程:08 类和对象的 Python 实现-@property 装饰器:把方法包装成属性 摘要: 本文主要对@property 装饰器的基本…

Java 异常 随机数 包装类

异常,随机数,包装类,日期类正如 “人无完人”一样,程序也不是完美的,它总会存在这样那样的问题,而有些问题并不是能够通过程序员开发更好的代码来解决的,如果我们忽视它,可能就会造成程序的终止,甚至是系统的崩溃。因此,我们需要想办法来合理的解决它,这就是Java中异常…

DataWhale暑期夏令营第一期——大模型技术方向task2笔记

Task 2 笔记 数据分析 可以先通过对标签中各个项进行数据分析(使用values_count方法),可以得到主要任务的各个指标的值分布情况。 我认为这一步的作用:帮助理解数据。 大模型的本质还是概率生成,通过prompt提示词去进行生成Baseline优化思路 1.数据处理角色合并:将同一个…

基于Bootstrap Blazor开源的.NET通用后台权限管理系统

前言 今天大姚给大家分享一个基于Bootstrap Blazor开源的.NET通用后台权限管理系统,后台管理页面兼容所有主流浏览器,完全响应式布局(支持电脑、平板、手机等所有主流设备),可切换至 Blazor 多 Tabs 模式,权限控制细化到网页内任意元素(按钮、表格、文本框等等):Boots…

03-立即执行函数

JS中的立即执行函数01 立即执行函数的定义 立即执行函数有自己的作用域,因此可以防止全局变量之间的污染02 应用场景 <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible…

初体验Sonar10.6 之 从部署到实战

Sonar介绍及下载 Sonar是一个代码质量管理的开源平台,用于管理源代码的质量。 SonarLint IDE插件安装 https://plugins.jetbrains.com/plugin/7973-sonarlint https://marketplace.visualstudio.com/items?itemName=SonarSource.sonarlint-vscode sonar scanner下载地址 http…

charles使用

一,下载 去官网下载charles,如果有破解版的更好,不用花钱,但是一般也有30天试用期 二,安装 按照步骤安装即可 三,使用 1,首先,安装本地证书。按照指引一步一步安装。(注意:保存的时候最好放到受信任的证书目录中)2,安装移动端证书:它会告诉你ip和port。 首先你需要…

算法金 | 致敬深度学习三巨头:不愧是腾讯,LeNet问的巨细。。。

​大侠幸会,在下全网同名「算法金」 0 基础转 AI 上岸,多个算法赛 Top 「日更万日,让更多人享受智能乐趣」抱个拳,送个礼 读者参加面试,竟然在 LeNet 这个基础算法上被吊打~ LeNet 确实经典,值得好好说道说道 更多内容,见微*公号往期文章:有史以来最详细的卷积神经网络…

[大疆航线] 系列(3) 无人机多角度航线规划软件μMAPLE

关键词:无人机航线、航点动作,航线软件 作者:ludwig1860 日期:2024.7.3 1. 多角度航线规划软件μMAPLE的编写 我们研究团队编写了一个名为μMAPLE (uav-based Multi-Angular flight PLannEr)的多角度航线规划软件。当然,我们也很乐意协助研究人员们开发符合各自需求的航线…

Windows Terminal 中设置常用命令的别名

Windows Terminal 中设置常用命令的别名 ‍ E:\zhpj\Desktop>cmd /? 启动 Windows 命令解释器的一个新实例 . . . 如果 /D 未在命令行上被指定,当 CMD.EXE 开始时,它会寻找 以下 REG_SZ/REG_EXPAND_SZ 注册表变量。如果其中一个或 两个都存在,这两个变量会先被执行。HKE…

ssrf结合python反序列化

存储session对象时 当然不能直接存储对象 需要转换成有规律的字符串 这一过程就涉及到了序列化 将对象转换成字符串这一过程称之为序列化 PYTHON反序列化漏洞 本文中就涉及到了pickle这一序列化模块导致的反序列化漏洞 在反序列化结束时 会触发__reduce__魔术方法 类似于php中的…

Web基础知识扫盲

1、中间件 定义:中间件是一种独立的系统软件服务程序,分布式应用软件借助这种软件在不同的技术之间共享资源,中间件位于客户机服务器的操作系统之上,管理计算资源和网络通信。常见的中间件:IIS、Apache、Nginx、Tomcat 2、NAT网络地址转换 这里只介绍动态转换一种 动态转换…

MySQL-16.MVCC(多版本并发控制)

C-16.多版本并发控制 1.什么是MVCCMVCC(Multiversion Concurrency Control),多版本并发控制。顾名思义,MVCC是通过数据行的多个版本管理来实现数据库的并发控制。这项技术使得在InnoDB的事务隔离级别下执行一致性读操作有了保证。换言之,就是为了查询一些正在被另一事务更…

[JLU] 数据结构与算法上机题解思路分享-课程设计第一次与第二次上机

这是吉林等通知大学数据结构与算法上机题的题解思路,没有精妙的解法,只是一个记录罢前言 首先,请务必自己尽全力尝试实现题目,直接看成品代码,思维就被拘束了,也很容易被查重。 这里只是思路解析的博客,代码仓库在 JLU_Data_Structures_Record 希望你能在这里找到你想要…

【Python】GUI开发笔记

一、环境搭建: 1、Pycharm开发工具pycharm历史版本 https://www.jetbrains.com/pycharm/download/other.html破解插件 https://blog.csdn.net/weixin_50737119/article/details/135628513 2、PYENV 版本管理 Python也有对应的版本管理工具,叫pyenv 这个东西挺奇怪的,直接发…

Day1| 704. 二分查找 27. 移除元素

704.二分查找 题目链接 : https://leetcode.cn/problems/binary-search/description/ 思路😗*切记二分查找要基于排序好的数组或者数据,否则二分查找必不能使用!!!!!!!!! ** 双指针写最简单,一个头指针从0开始,一个尾指针从数组长度-1开始,中间指针是头+尾/2,每次比较头尾中间…