LiteFlow逻辑流引擎集成验证

news2024/12/22 15:12:27

本文将介绍开源逻辑流组件LiteFlow的架构、设计思想和适用场景,如何基于springboot集成LiteFlow,并验证DSL多种逻辑流程,以及逻辑流设计器的开发思路。

一、逻辑流解决什么问题

在每个公司的系统中,总有一些拥有复杂业务逻辑的系统,这些系统承载着核心业务逻辑,几乎每个需求都和这些核心业务有关,这些核心业务业务逻辑冗长,涉及内部逻辑运算,缓存操作,持久化操作,外部资源调取,内部其他系统RPC调用等等。时间一长,项目几经易手,维护成本就会越来越高。

如果你要对复杂业务逻辑进行新写或者重构,用LiteFlow最合适不过。它是一个编排式的规则引擎框架,组件编排,帮助解耦业务代码,让每一个业务片段都是一个组件。利用LiteFlow,你可以将瀑布流式的代码,转变成以组件为核心概念的代码结构,这种结构的好处是可以任意编排,组件与组件之间是解耦的,组件可以用脚本来定义,组件之间的流转全靠规则来驱动。LiteFlow拥有开源规则引擎最为简单的DSL语法。十分钟就可上手。

LiteFlow适用于拥有复杂逻辑的业务,比如说价格引擎,下单流程等,这些业务往往都拥有很多步骤,这些步骤完全可以按照业务粒度拆分成一个个独立的组件,进行装配复用变更。使用LiteFlow,你会得到一个灵活度高,扩展性很强的系统。因为组件之间相互独立,也可以避免改一处而动全身的这样的风险。然而,对于基于角色任务流转的场景,LiteFlow并非最佳选择,推荐使用Flowable、Activiti、Camunda等专门的流程引擎。关于开源工作流引擎介绍参考:https://lowcode.blog.csdn.net/article/details/116405594

有的时候大家把LiteFlow叫做规则引擎,其实,逻辑引擎和规则引擎还是不一样,我认为LiteFlow是逻辑流引擎,它偏向于组件级接口的编排,粒度更细更底层,而规则引擎(比如:drools),它更偏向于业务规则计算,比如决策树、决策表等,解决某一个特定的业务需求,比如:保险行业投保规则计算。

二、LiteFlow的设计思想

LiteFlow是基于工作台模式进行设计的,何谓工作台模式?

n个工人按照一定顺序围着一张工作台,按顺序各自生产零件,生产的零件最终能组装成一个机器,每个工人只需要完成自己手中零件的生产,而无需知道其他工人生产的内容。每一个工人生产所需要的资源都从工作台上拿取,如果工作台上有生产所必须的资源,则就进行生产,若是没有,就等到有这个资源。每个工人所做好的零件,也都放在工作台上。

这个模式有几个好处:

每个工人无需和其他工人进行沟通。工人只需要关心自己的工作内容和工作台上的资源。这样就做到了每个工人之间的解耦和无差异性。

即便是工人之间调换位置,工人的工作内容和关心的资源没有任何变化。这样就保证了每个工人的稳定性。

如果是指派某个工人去其他的工作台,工人的工作内容和需要的资源依旧没有任何变化,这样就做到了工人的可复用性。

因为每个工人不需要和其他工人沟通,所以可以在生产任务进行时进行实时工位更改:替换,插入,撤掉一些工人,这样生产任务也能实时的被更改。这样就保证了整个生产任务的灵活性。

这个模式映射到LiteFlow框架里,工人就是组件,工人坐的顺序就是流程配置,工作台就是上下文,资源就是参数,最终组装的这个机器就是这个业务。正因为有这些特性,所以LiteFlow能做到统一解耦的组件和灵活的装配。

三、LiteFlow强大的编排能力


LiteFlow的编排语法强大到可以编排出任何你想要的逻辑流程。如下图复杂的语法,如果使用瀑布式的代码去写,那种开发以及维护难度可想而知,但是使用LiteFlow你可以轻松完成逻辑流程的编排,易于维护。

四、LiteFlow使用mysql持久化

LiteFlow支持本地yml文件、mysql等关系型数据库、zookeeper、nacos、Etcd、redis等多种数据持久化方式。

以下介绍用mysql数据库如何持久化LiteFlow的逻辑流。

在mysql数据库中创建2张表:liteflow_chain(逻辑流表)和liteflow_script(脚本节点表)

DROP TABLE IF EXISTS `liteflow_chain`;
CREATE TABLE `liteflow_chain`  (
  `id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键',
  `application_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用名称',
  `chain_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '逻辑流程名称',
  `chain_desc` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '逻辑流描述',
  `el_data` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '逻辑流内容',
  `chain_flow` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '逻辑流图',
  `enable` tinyint NULL DEFAULT NULL COMMENT '是否有效',
  `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人',
  `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
  `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '修改人',
  `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间',
  `sys_org_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '所属部门',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

DROP TABLE IF EXISTS `liteflow_script`;
CREATE TABLE `liteflow_script`  (
  `id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键',
  `application_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用名称',
  `script_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '脚本ID',
  `script_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '脚本名称',
  `script_data` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '脚本内容',
  `script_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '脚本类型',
  `script_language` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '脚本语言',
  `enable` tinyint NULL DEFAULT NULL COMMENT '是否有效',
  `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人',
  `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
  `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '修改人',
  `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间',
  `sys_org_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '所属部门',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

数据库表创建完成后,插入逻辑流测试数据:

INSERT INTO `liteflow_chain` VALUES ('1', 'demo', 'chain1', '串行流', '  THEN(a, b, c);', NULL, 1, NULL, '2024-03-22 09:45:15', NULL, NULL, NULL);
INSERT INTO `liteflow_chain` VALUES ('2', 'demo', 'chain2', '并行流', ' WHEN(a, b, c);', NULL, 1, NULL, '2024-03-22 09:48:07', NULL, NULL, NULL);
INSERT INTO `liteflow_chain` VALUES ('3', 'demo', 'chain3', '串行并行流', '        THEN(\r\n            a, b, WHEN(c,d)\r\n        );', NULL, 1, NULL, '2024-03-22 09:48:07', NULL, NULL, NULL);
INSERT INTO `liteflow_chain` VALUES ('4', 'demo', 'chain4', '串行并行流', '        THEN(\r\n            a,\r\n            WHEN(b, c),\r\n            d\r\n        );', NULL, 1, NULL, '2024-03-22 09:48:07', NULL, NULL, NULL);
INSERT INTO `liteflow_chain` VALUES ('5', 'demo', 'chain5', '串并串行流', '        THEN(\r\n            a,\r\n            WHEN(b, THEN(c, d)),\r\n            e\r\n        );', NULL, 1, NULL, '2024-03-22 09:48:07', NULL, NULL, NULL);
INSERT INTO `liteflow_chain` VALUES ('6', 'demo', 'chain6', '选择流', 'THEN(a, SWITCH(s1).to(b, c, d));', NULL, 1, NULL, '2024-03-22 09:48:07', NULL, NULL, NULL);
INSERT INTO `liteflow_chain` VALUES ('7', 'demo', 'chain7', '循环流', 'THEN(a, FOR(s2).DO(THEN(b, c)));', NULL, 1, NULL, '2024-03-22 09:48:07', NULL, NULL, NULL);
INSERT INTO `liteflow_chain` VALUES ('8', 'demo', 'chain8', '串并串流程', '        THEN(\r\n            a,\r\n            WHEN( THEN(b, c), d),\r\n            e\r\n        );', NULL, 1, NULL, '2024-03-22 14:56:32', NULL, NULL, NULL);
INSERT INTO `liteflow_script` VALUES ('1', 'demo', 's1', '选择脚本', '  var count = defaultContext.getData(\"count\");\r\n                if(count < 100){\r\n                    return \"b\";\r\n                }else if( count > 100 && count < 500 ){\r\n                    return \"c\";\r\n                }else{\r\n                  return \"d\";\r\n                }', 'switch_script', 'js', 1, NULL, '2024-03-22 11:35:39', NULL, NULL, NULL);
INSERT INTO `liteflow_script` VALUES ('2', 'demo', 's2', '循环脚本', '                var count = 2;\r\n                return count;', 'for_script', 'js', 1, NULL, '2024-03-22 11:36:35', NULL, NULL, NULL);

插入数据的表如下:

五、Springboot集成LiteFlow

  1. 新建一个springboot工程,在pom.xml中引入如下Jar:
<dependency>
    <groupId>com.yomahub</groupId>
    <artifactId>liteflow-spring-boot-starter</artifactId>
    <version>2.11.4.2</version>
</dependency>
<dependency>
    <groupId>com.yomahub</groupId>
    <artifactId>liteflow-rule-sql</artifactId>
    <version>2.11.4.2</version>
</dependency>
<dependency>
    <groupId>com.yomahub</groupId>
    <artifactId>liteflow-script-groovy</artifactId>
    <version>2.11.4.2</version>
</dependency>
<dependency>
    <groupId>com.yomahub</groupId>
    <artifactId>liteflow-script-graaljs</artifactId>
    <version>2.11.4.2</version>
</dependency>

2、application.yaml文件中增加对liteflow的配置

server:
  port: 8080
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/camunda719?characterEncoding=UTF-8&useUnicode=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
liteflow:
  rule-source-ext-data-map:
    applicationName: demo
    #以下是chain表的配置,这个一定得有
    chainTableName: liteflow_chain
    chainApplicationNameField: application_name
    chainNameField: chain_name
    elDataField: el_data
    chainEnableField: enable
    #以下是script表的配置,如果你没使用到脚本,下面可以不配置
    scriptTableName: liteflow_script
    scriptApplicationNameField: application_name
    scriptIdField: script_id
    scriptNameField: script_name
    scriptDataField: script_data
    scriptTypeField: script_type
    scriptLanguageField: script_language
    scriptEnableField: enable
    #以下是轮询机制的配置
    pollingEnabled: true
    pollingStartSeconds: 0
    pollingIntervalSeconds: 30


3、新建逻辑流节点处理类

liteflow中的组件分普通组件、选择组件、条件组件等,需要分别继承NodeComponent、NodeSwitchComponent、NodeIfComponent等类需要你自己去定义一个类去继承这些父类。这样一方面造成了耦合,另一方面由于java是单继承制,所以使用者就无法再去继承自己的类了,在自由度上就少了很多玩法。

LiteFlow提供了声明式组件方式。声明式组件这一特性允许你自定义的组件不继承任何类和实现任何接口,普通的类也可以依靠注解来完成LiteFlow组件的声明。以下的测试类采用了组件声明方式。

为了方便模拟多种逻辑测试,分别建ACmp、BCmp、CCmp、DCmp、ECmp共5个类,每个类中线程睡眠500毫秒,模拟实际业务耗时。

ACmp.java类:

package com.yuncheng.logicflow;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import com.yomahub.liteflow.enums.NodeTypeEnum;
import com.yomahub.liteflow.slot.DefaultContext;

@LiteflowComponent
public class ACmp  {
    @LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "a", nodeName = "组件a",  nodeType = NodeTypeEnum.COMMON)
    public void process(NodeComponent bindCmp) {
        //do your business
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        DefaultContext context = bindCmp.getContextBean(DefaultContext.class);
        context.setData("key1","hello");
        context.setData("count",200);
        User user = new User();
        user.setName("张三");
        user.setAge(28);
        context.setData("user",user);
        System.out.println("==============执行a: " );
    }
}


 

BCmp.java类:

package com.yuncheng.logicflow;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import com.yomahub.liteflow.enums.NodeTypeEnum;
import com.yomahub.liteflow.slot.DefaultContext;

@LiteflowComponent
public class BCmp {

    @LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "b", nodeName = "组件b",  nodeType = NodeTypeEnum.COMMON)
    public void process(NodeComponent bindCmp) {
        //do your business
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        DefaultContext context = bindCmp.getContextBean(DefaultContext.class);
        User user = context.getData("user");
        System.out.println("==============执行b: ");
        System.out.println("==============执行b:key1= " + context.getData("key1"));
        System.out.println("==============执行b:count= " + context.getData("count"));
        System.out.println("==============执行b:user= " + user.getName());
    }
}

CCmp.java类:

package com.yuncheng.logicflow;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import com.yomahub.liteflow.enums.NodeTypeEnum;
import com.yomahub.liteflow.slot.DefaultContext;

@LiteflowComponent
public class CCmp{

    @LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "c", nodeName = "组件c",  nodeType = NodeTypeEnum.COMMON)
    public void process(NodeComponent bindCmp) {
        //do your business
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        DefaultContext context = bindCmp.getContextBean(DefaultContext.class);
        System.out.println("==============执行c: ");
        System.out.println("==============执行c:key1= " + context.getData("key1"));
        System.out.println("==============执行c:count= " + context.getData("count"));
    }
}

DCmp.java类:

package com.yuncheng.logicflow;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import com.yomahub.liteflow.enums.NodeTypeEnum;

@LiteflowComponent
public class DCmp {

    @LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "d", nodeName = "组件d",  nodeType = NodeTypeEnum.COMMON)
    public void process(NodeComponent bindCmp) {
        //do your business
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("==============执行d: " );
    }
}

ECmp.java类:

package com.yuncheng.logicflow;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import com.yomahub.liteflow.enums.NodeTypeEnum;

@LiteflowComponent
public class ECmp {

    @LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "e", nodeName = "组件e",  nodeType = NodeTypeEnum.COMMON)
    public void process(NodeComponent bindCmp) {
        //do your business
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("==============执行e: ");
    }
}

LogicController.java,模拟测试的REST服务类:

package com.yuncheng.logicflow;

import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.flow.LiteflowResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.Date;

@RestController
@RequestMapping
public class LogicController {
    @Resource
    private FlowExecutor flowExecutor;

    /**
     * 浏览器里访问:http://localhost:8080/logicTest/chain1
     * @param key 逻辑流定义的key
     * @return
     */
    @GetMapping(value = "/logicTest/{key}")
    public String logicTest(@PathVariable("key") String key) {
        long begin = new Date().getTime();
        LiteflowResponse response = flowExecutor.execute2Resp(key, "arg");
        long end = new Date().getTime();
        long hs = end - begin;
        System.out.println("====================执行耗时:" + hs);
        return response.getSlot().getExecuteStepStr() + ",执行耗时: " + hs;
    }

}

LogicFlowApplication.java,springboot应用启动类:

package com.yuncheng;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.Environment;

@SpringBootApplication
public class LogicFlowApplication {
    public static void main(String... args) {
        ConfigurableApplicationContext application =  SpringApplication.run(LogicFlowApplication.class, args);
        Environment env = application.getEnvironment();
        String port = env.getProperty("server.port");
        String path = env.getProperty("server.servlet.context-path");
        if (path == null || "".equals(path)) {
            path = "/";
        }
        System.out.println("\n----------------------------------------------------------\n" +
                "\tLogicFlowApplication is running!\n" +
                "\tPort:\t" + port + "\n" +
                "\tPath:\t" + path + "\n" +
                "----------------------------------------------------------");
    }
}

启动springboot工程:

启动成功,并发现LiteFlow定时查询liteflow_chain(逻辑流表)和liteflow_script(脚本节点表),说明LiteFlow使用mysql数据库持久化是成功的。

六、测试验证LiteFlow规则

1、串行流验证

逻辑流表达式:THEN(a, b, c);

浏览器地址栏输入:http://localhost:8080/logicTest/chain1

返回结果:a[组件a]==>b[组件b]==>c[组件c],执行耗时: 1528

2、并行流验证

逻辑流表达式: WHEN(a, b, c);

浏览器地址栏输入:http://localhost:8080/logicTest/chain2

返回结果:a[组件a]==>b[组件b]==>c[组件c],执行耗时: 550

3、串并流验证

逻辑流表达式: THEN( a, b, WHEN(c,d));

浏览器地址栏输入:http://localhost:8080/logicTest/chain3

返回结果:a[组件a]==>b[组件b]==>c[组件c]==>d[组件d],执行耗时: 1527

4、选择流验证

逻辑流表达式: THEN(a, SWITCH(s1).to(b, c, d));

浏览器地址栏输入:http://localhost:8080/logicTest/chain6

返回结果:a[组件a]==>s1[选择脚本]==>c[组件c],执行耗时: 2468

5、循环流验证

逻辑流表达式:THEN(a, FOR(s2).DO(THEN(b, c)));

浏览器地址栏输入:http://localhost:8080/logicTest/chain7

返回结果:a[组件a]==>s2[循环脚本]==>b[组件b]==>c[组件c]==>b[组件b]==>c[组件c],执行耗时: 2605

七、逻辑流设计器开发思路

开源逻辑流LiteFlow只有后端引擎,没有前端逻辑流设计器,需要使用者自行开发设计器。可使用滴滴开源的LogicFlow前端逻辑流设计器进行二次开发实现。

LogicFlow 是一款滴滴开源的流程图编辑框架,提供了一系列流程图交互、编辑所必需的功能和灵活的节点自定义、插件等拓展机制。LogicFlow支持前端研发自定义开发各种逻辑编排场景,如流程图、ER图、BPMN流程等。在工作审批配置、机器人逻辑编排、无代码平台流程配置都有较好的应用。体验地址:https://site.logic-flow.cn/


LogicFlow 虽然提供了可视化图形编排框架,但LiteFlow逻辑流设计器开发有个技术难点,就是如何把图形化的节点编排转换为LiteFlow可执行的逻辑流表达式。云程低代码平台(http://www.yunchengxc.com)开发团队目前正在开发LiteFlow逻辑流设计器,初步思路借鉴图论中的有向无环图算法解决,通过节点的流向和度数,计算生成LiteFlow逻辑流表达式,开发完成后考虑把逻辑流设计器开源。

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

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

相关文章

regexp_substr()

1、基本语法 REGEXP_SUBSTR(String, pattern, position,occurrence, modifier) String&#xff1a;需要进行处理的字符串。 pattern&#xff1a;正则表达式。 position&#xff1a;起始位置&#xff08;从字符串的第几个开始&#xff0c;默认为1&#xff0c;注&#xff1a;…

C++多重继承与虚继承

多重继承的原理 多重继承(multiple inheritance)是指从多个直接基类中产生派生类的能力。 多重继承的派生类继承了所有父类的属性。 在面向对象的编程中&#xff0c;多重继承意味着一个类可以从多个父类继承属性和方法。 就像你有一杯混合果汁&#xff0c;它是由多种水果榨取…

任务2.1 一元二次方程(顺序结构版)

在这个任务中&#xff0c;我们编写了一个Java程序来解决一元二次方程。程序接受用户输入的系数a、b、c&#xff0c;并计算出方程的根。通过计算判别式delta的值&#xff0c;我们可以确定方程有两个不相等实根、两个相等实根还是没有实数根。这个程序遵循了IPO模式&#xff0c;即…

Linux split分割xls或csv文件

文件名&#xff1a;test.xls split -a 2 -d -l 100 test.xls test-a 2&#xff1a;后缀是2位 -d&#xff1a;后缀数字 -l 100 &#xff1a;每100行一个文件 test.xls&#xff1a;需要分割的文件名 test&#xff1a;分割后的文件前缀批量修改文件后缀 for i in test*; do mv $…

探索多种数据格式:JSON、YAML、XML、CSV等数据格式详解与比较

title: 探索多种数据格式&#xff1a;JSON、YAML、XML、CSV等数据格式详解与比较 date: 2024/3/28 17:34:03 updated: 2024/3/28 17:34:03 tags: 数据格式JSONYAMLXMLCSV数据交换格式比较 1. 数据格式介绍 数据格式是用于组织和存储数据的规范化结构&#xff0c;不同的数据格…

蓝桥杯每日一题(floyd算法)

4074 铁路与公路 如果两个城市之间有铁路t11&#xff0c;公路就会t2>1,没铁路的时候t1>1,公路t21。也就是公路铁路永远都不会相等。我们只需要计算通过公路和铁路从1到n最大的那个即可。 floyd是直接在数组上更新距离。不需要新建dis数组。另外一定要记得把邻接矩阵初始…

探索云原生时代:技术驱动的业务架构革新

一、引言 在数字化浪潮中&#xff0c;云原生技术已成为推动企业快速创新的重要动力。本文将深入探讨云原生的核心理念、技术架构以及其在实际业务环境中的应用&#xff0c;带领读者深入理解云原生技术的复杂性和优势。 云原生技术的定义 云原生&#xff08;Cloud Native&#x…

慧天[HTWATER]:采用CUDA框架实现耦合模型并行求解

慧天[HTWATER]软件简介 针对城市排水系统基础设施数据管理的需求&#xff0c;以及水文、水力及水质模拟对数据的需求&#xff0c;实现了以数据库方式对相应数据的存储。可以对分流制排水系统及合流制排水系统进行地表水文、管网水力、水质过程的模拟计算。可以对城市低影响开发…

“人工智能+”国家战略会带来哪些机会?

一、“人工智能”战略背景 2024年的中国政府工作报告首次引入了“人工智能”的概念&#xff0c;这是国家层面对于人工智能技术和各行业深度融合的重要战略举措。这一概念的提出意味着我国将进一步深化人工智能技术的研发应用&#xff0c;并积极推动人工智能与经济社会各领域的…

ida调试技巧-通过修改zf寄存器的值绕过简单反调试

参考本篇->OllyDbg笔记-对标志寄存器中ZF的理解&#xff08;逆向方面&#xff09;_零标志位zf怎么判断-CSDN博客 不想看也没关系&#xff0c;蒟蒻博主概述一下&#xff0c;总之&#xff0c;在机器执行汇编指令时&#xff0c;标志&#xff08;flag&#xff09;寄存器中的一个…

C++自主点餐系统

一、 题目 设计一个自助点餐系统&#xff0c;方便顾客自己点餐&#xff0c;并提供对餐厅销售情况的统计和管理功能。 二、 业务流程图 三、 系统功能结构图 四、 类的设计 五、 程序代码与说明 头文件1. SystemMap.h #pragma once #ifndef SYSTEMMAP #define SYSTEMMAP #in…

kubernetes(K8S)学习(一):K8S集群搭建(1 master 2 worker)

K8S集群搭建&#xff08;1 master 2 worker&#xff09; 一、环境资源准备1.1、版本统一1.2、k8s环境系统要求1.3、准备三台Centos7虚拟机 二、集群搭建2.1、更新yum&#xff0c;并安装依赖包2.2、安装Docker2.3、设置hostname&#xff0c;修改hosts文件2.4、设置k8s的系统要求…

常见的三种办公室租赁方式各自优缺点

商业办公的租赁市场。找商业办公地点&#xff0c;跟找住宅租房有点像&#xff0c;但目的和要求不同。主要也是三种方式&#xff1a;直接找房东租、接手别人的转租&#xff0c;或者找中介帮忙。每种方式都有它的小窍门和注意事项。 直租 直租商业办公&#xff0c;就是直接和办公…

YoloV5改进策略:Neck和Head改进|ECA-Net:用于深度卷积神经网络的高效通道注意力|多种改进方法|附结构图

摘要 本文使用ECA-Net注意力机制加入到YoloV5Neck和Head中。我尝试了多种改进方法&#xff0c;并附上改进结果&#xff0c;方便大家了解改进后的效果&#xff0c;为论文改进提供思路。&#xff08;改进中。。。。&#xff09; 论文&#xff1a;《ECA-Net&#xff1a;用于深度…

Python实现一个简单的银行管理系统GUI应用

介绍 在本教程中&#xff0c;我们将创建一个基本的银行管理系统GUI应用&#xff0c;用户可以通过图形界面执行各种银行操作。我们将使用Python编程语言和Tkinter库来实现此应用。 使用说明 需要安装Python解释器&#xff0c;以及PythonCharm &#x1f449; 点我去下载 效果图…

Mysql的连接与存储

目录 一、mysql的连接查询 1、连接的分类&#xff1a; 1.1 内连接 1.2左连接 1.3 右连接 二、存储过程 1、简介 2、优点 3、语法 4、参数分类 5、带参数的存储过程 6、修改存储过程 7、删除存储过程 三、总结 一、mysql的连接查询 mysql的连接查询&#xff0c;通…

tomcat和Servlet开发小案例

在上篇文章中,我已经正确安装了tomcat和利用servlet写了个基础的hello world程序,明白了这两个东西到底是啥玩意. 接下来,需要写个登录的小案例来进一步熟悉下基于servlet开发的流程. 一,新建项目 我们新建的maven项目其实里面是空的。所以我们需要给他变成一个servlet项目。 …

vue3全局引入element-plus使用Message教程

文章目录 安装引入 Element Plus和组件样式示例注意安装与引入&#xff1a;按需引入&#xff1a;API 使用&#xff1a;样式问题&#xff1a;组件上下文&#xff1a;版本兼容性&#xff1a;错误处理&#xff1a; 这是 Element UI 的 Vue 3 版本。ElMessage 是 Element Plus 中的…

编程语言|C语言——C语言变量的存储方式

前言 变量是程序中数据的存储空间的抽象。变量的存储方式可分为静态存储和动态存储两种。 静态存储变量通常是在程序编译时就分配一定的存储空间并一直保持不变&#xff0c;直至整个程序结束。在上一部分中介绍的全局变量的存储方式即属于此类存储方式。 动态存储变量是在程序执…

黑马鸿蒙笔记1

这里与前端类似。