ZooKeeper 实战(三) SpringBoot整合Curator-开发使用篇

文章目录

  • ZooKeeper 实战(三) SpringBoot整合Curator-开发使用篇
      • 0. ZooKeeper客户端
    • 1. Curator
      • 1.1. 简介
      • 1.2. 应用场景
      • 1.3. 优势
      • 1.4. 依赖说明
    • 2. 依赖导入
    • 3. 配置类
      • 3.1. 重试策略
      • 3.2. 实现代码
      • 3.3. 总结
    • 4. Curator中的基本API
      • 4.1. 创建节点
      • CreateMode中的节点类型
      • 4.2. 查询节点
      • 4.3. 更新节点
      • 4.4. 删除节点
      • 4.6. 异步调用
    • 5. 总结

ZooKeeper 实战(三) SpringBoot整合Curator-开发使用篇

0. ZooKeeper客户端

目前,Zookeeper服务器有三种Java客户端: Zookeeper、Zkclient和Curator。

  1. Zookeeper: Zookeeper是官方提供的原生java客户端
  2. Zkclient: 是在原生zookeeper客户端基础上进行扩展的开源第三方Java客户端
  3. Curator: Netflix公司在原生zookeeper客户端基础上开源的第三方Java客户端

由于 Curator 较于其他两种客户端操作更简单,功能更丰富,可以说是当前最好用,最流行的ZooKeepe的客户端。所以接下来我们将以Curator作为Zookeeper客户端为例,进行整合开发。

1. Curator

1.1. 简介

Curator是Apache软件基金会下的一个开源框架,目前是Apache下的顶级项目。Curator起初是 Netflix公司开源的一套ZooKeeper客户端框架,后捐献给Apache。和 ZkClient一样,它解决了非常底层的细节开发工作,包括连接、重连、反复注册Watcher的问题以及 NodeExistsException异常等。

1.2. 应用场景

Curator可以提供支持常见的ZooKeeper应用场景:

  • 配置管理:实现分布式系统的配置管理,通过在ZooKeeper集群中存储和管理配置信息,可以实现配置的集中管理和动态更新。
  • 服务注册与发现:实现服务注册与发现机制,通过在ZooKeeper集群中注册和发现服务节点,可以实现分布式系统中的服务发现和负载均衡。
  • 命名服务:实现分布式系统中的命名服务,通过在ZooKeeper集群中分配和管理工作空间,可以实现分布式系统中资源的唯一标识和集中管理。
  • 协调与同步:实现分布式系统中的协调与同步机制,通过在ZooKeeper集群中达成一致协议,可以实现分布式系统中的任务分配、状态同步和协调控制。
  • 分布式锁:实现分布式系统中的锁机制,通过在ZooKeeper集群中分配锁资源,可以实现分布式系统中的互斥访问和协同操作。
  • 消息队列:实现基于ZooKeeper的分布式消息队列系统,通过在ZooKeeper集群中存储消息队列的元数据和消息内容,可以实现分布式的消息传递和异步通信。

1.3. 优势

  • 简单易用:Curator提供了一个简单易用的API,使得开发人员可以轻松地与ZooKeeper集群进行交互,并实现各种分布式应用场景。
  • 高性能:Curator优化了与ZooKeeper集群的通信性能,通过使用异步操作和批量操作等技术,提高了与ZooKeeper集群的交互速度。
  • 灵活的监视机制:Curator提供了灵活的监视机制,开发人员可以通过监视ZooKeeper集群中的节点变化,实现分布式系统的实时监控和通知。
  • 原子操作:Curator提供了原子操作的支持,这些操作可以在ZooKeeper集群中以原子方式执行,以确保操作的可靠性。
  • 强大的抽象:Curator提供了一组抽象接口,使得开发人员可以轻松地与ZooKeeper集群进行交互,而无需了解ZooKeeper内部的具体实现细节。
  • 社区活跃:Curator是一个受欢迎的开源项目,拥有活跃的社区和广泛的应用场景,可以提供及时的技术支持和丰富的文档资源。

1.4. 依赖说明

curator它主要包含三个依赖(curator的依赖都已经放到maven仓库,你直接使用maven来构建它。对于大多数人来说,我们可能最常需要引入的是curator-recipes):

  • curator-recipes:依赖于framework和Client:最常用的是curator-recipes,它可以实现:
    • 锁:包括共享锁、共享可重入锁、读写锁等。
    • 选举:Leader选举算法。
    • Barrier:阻止分布式计算直至某个条件被满足的“栅栏”,可以看做JDK Concurrent包中Barrier的分布式实现。
    • 缓存:三种Cache及监听机制。
    • 持久化结点:连接或Session终止后仍然在ZooKeeper中存在的结点。
    • 队列:分布式队列、分布式优先级队列等。
  • curator-framework:包含了高层级的流式API,构建在Client之上如对节点的增删改查等。
  • curator-client:Zookeeper的基础客户端实现,如连接、重试、超时处理等。

注意:目前Curator2.x.x和3.x.x两个系列的版本,支持不同版本的Zookeeper。其中Curator 2.x.x兼容Zookeeper的3.4.x和3.5.x。而Curator 3.x.x只兼容Zookeeper 3.5.x,并且提供了一些诸如动态重新配置、watch删除等新特性。

最新版本Curator4.0十分依赖Zookeeper3.5.X。Curator4.0在软兼容模式下支持Zookeeper3.4.X,但是需要依赖排除zookeeper。

2. 依赖导入

<?xml version="1.0" encoding="UTF-8"?>
<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>org.example.ahao</groupId><artifactId>ahao_zookeeper</artifactId><version>1.0-SNAPSHOT</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.8</version><relativePath/></parent><properties><maven.compiler.source>11</maven.compiler.source><maven.compiler.target>11</maven.compiler.target><!-- 编码字符集 --><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!-- SpringBoot --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- SpringBoot 测试包 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!-- ZooKeeper客户端 curator --><dependency><groupId>org.apache.curator</groupId><artifactId>curator-client</artifactId><version>4.0.1</version></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>4.0.1</version></dependency></dependencies></project>

3. 配置类

3.1. 重试策略

在开始配置之前,简单了解一下Curator提供的几种常用的重试策略实现类:

  1. ExponentialBackoffRetry:这是Curator中最常用的重试策略实现类,它使用指数退避的方法来逐渐增加重试的间隔时间。根据失败次数和当前尝试次数来动态调整间隔时间,以便更好地平衡系统的性能和稳定性。
  2. SleepingSingleRetry:这种实现类会在连接失败时让线程休眠一段时间,然后再尝试重新连接。这种方法适用于那些不需要自动切换到其他可用节点的场景。
  3. FailoverRetry:这种实现类会在连接失败时尝试切换到另一个可用的Zookeeper节点,直到所有节点都成功连接或达到最大重试次数。这种方法适用于那些需要自动切换到其他可用节点的场景,以避免单点故障。

3.2. 实现代码

配置文件

# 端口号
server:port: 8888# zookeeper配置
apache:zookeeper:# 服务器连接地址,集群模式则使用逗号分隔如:ip1:host,ip2:hostconnect-url: 127.0.0.1:2180# 会话超时时间:单位mssession-timeout: 10000# 连接超时时间:单位msconnection-timeout: 10000# ACL权限控制,验证策略scheme: auth# 验证内容idauth_id: admin:123456# 重试策略retry-policy:# 初始化间隔时间base-sleep-time: 1000# 最大重试次数max-retries: 5# 最大重试间隔时间max-sleep: 30000

重试策略配置类

package com.ahao.demo.config;import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;/*** @Name: CuratorRetryPolicy* @Description: 重试策略参数* @Author: ahao* @Date: 2024/1/10 6:23 PM*/
@ConfigurationProperties(prefix = "apache.retry-policy")
@Configuration
@Getter
@Setter
public class CuratorRetryPolicy {// 初始化间隔时间private Integer baseSleepTime;// 最大重试次数private Integer maxRetries;// 最大重试间隔时间private Integer maxSleep;}

客户端配置类

package com.ahao.demo.config;import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @Name: ZkClientConfig* @Description: Curator客户端配置类* @Author: ahao* @Date: 2024/1/10 3:52 PM*/
@Configuration
@ConfigurationProperties(prefix = "apache.zookeeper")
@Setter
@Slf4j
public class ZkClientConfig {// 服务器连接地址,集群模式则使用逗号分隔如:ip1:host,ip2:hostprivate String connectUrl;// 会话超时时间:单位msprivate Integer sessionTimeout;// 连接超时时间:单位msprivate Integer connectionTimeout;// ACL权限控制,验证策略private String scheme;// 验证内容idprivate String authId;@Autowiredprivate CuratorRetryPolicy curatorRetryPolicy;@Beanpublic CuratorFramework curatorFramework(){CuratorFramework curatorFramework = CuratorFrameworkFactory.builder().connectString(connectUrl).sessionTimeoutMs(sessionTimeout).connectionTimeoutMs(connectionTimeout)// 权限认证//.authorization(scheme,authId.getBytes(StandardCharsets.UTF_8))// 重试策略.retryPolicy(new ExponentialBackoffRetry(curatorRetryPolicy.getBaseSleepTime(),curatorRetryPolicy.getMaxRetries(),curatorRetryPolicy.getMaxSleep())).build();// 启动客户端curatorFramework.start();return curatorFramework;}}

3.3. 总结

现在客户端已经配置好了,启动CuratorDemoApplication.class,观察一下是否能够正常启动。

在这里插入图片描述

观察输出日志,显示如下信息表示客户端连接成功。

在这里插入图片描述

4. Curator中的基本API

4.1. 创建节点

为了偷懒,我没有写相关业务层代码,在启动类中通过ApplicationRunner的run方法在容器启动后直接执行。

代码如下

创建默认节点(持久节点):client.create().forPath("路径")

创建默认节点,带初始内容:client.create().forPath("路径","内容".getBytes())

创建临时节点:client.create().withMode(CreateMode.EPHEMERAL).forPath("路径")

递归方式创建节点(父节点可以不存在):client.create().creatingParentsIfNeeded().forPath("路径")

package com.ahao.demo;import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.zookeeper.CreateMode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;/*** @Name: CuratorDemoApplication* @Description:* @Author: ahao* @Date: 2024/1/10 3:29 PM*/
@Slf4j
@SpringBootApplication
public class CuratorDemoApplication implements ApplicationRunner{@Autowiredprivate CuratorFramework client;public static void main(String[] args) {SpringApplication.run(CuratorDemoApplication.class,args);}@Overridepublic void run(ApplicationArguments args) throws Exception {log.info("。。。。。。。。。。。。。容器初始化完毕。。。。。。。。。。。。。。");TimeUnit.SECONDS.sleep(3);// 创建节点。如果没有设置节点属性,节点创建模式默认为持久化节点,内容默认为空client.create()// 如果需要,递归创建节点.creatingParentsIfNeeded()// 指定创建节点类型.withMode(CreateMode.EPHEMERAL)// 节点路径和数据.forPath("/ahao/test","this is a book".getBytes(StandardCharsets.UTF_8));}
}

通过./zkCli.sh启动的客户端终端,查看节点信息,起初没有/ahao/test节点,在启动容器后,执行新增节点方法。本来没有新增/ahao节点(没有父节点,直接创建子节点会失败),由于指定递归方式(.creatingParentsIfNeeded()),所以先完成了/ahao父节点的新增,然后再新增/ahao/test。观察/ahao和/ahao/test节点的数据:/ahao节点数据为空,/ahao/test节点数据就是我们在代码中传递的数据。最后,停止CuratorDemoApplication,观察节点信息发现,/ahao/test节点(临时节点)被删除了,而/ahao(持久节点)仍存在。

在这里插入图片描述

CreateMode中的节点类型

  • PERSISTENT: 持久化节点,数据在Curator客户端重启后仍然存在。
  • PERSISTENT_SEQUENTIAL: 持久化顺序节点,数据在Curator客户端重启后仍然存在,并且按照顺序排列。
  • EPHEMERAL: 临时节点,Curator客户端重启后,这些节点将消失。
  • EPHEMERAL_SEQUENTIAL: 临时顺序节点,类似于EPHEMERAL,但数据是按照顺序写入的。
  • CONTAINER: 容器节点,用于存储其他节点。
  • PERSISTENT_WITH_TTL: 带有时间生存期的持久化节点。当达到指定的生存期后,数据将被自动删除。
  • PERSISTENT_SEQUENTIAL_WITH_TTL: 持久化顺序节点,带有时间生存期。当达到指定的生存期后,数据将被自动删除并按照顺序排列。

4.2. 查询节点

判断某个节点是否存在:client.checkExists().forPath()

获取某个节点的数据:client.getData().forPath()

获取某个节点下的子节点:client.getChildren().forPath()

    @Overridepublic void run(ApplicationArguments args) throws Exception {log.info("。。。。。。。。。。。。。容器初始化完毕。。。。。。。。。。。。。。");TimeUnit.SECONDS.sleep(3);log.info("新增节点");// 创建节点client.create()// 如果需要,递归创建节点.creatingParentsIfNeeded()// 指定创建节点类型.withMode(CreateMode.EPHEMERAL)// 节点路径和数据.forPath("/ahao/test","this is a book".getBytes(StandardCharsets.UTF_8));// 睡眠1sTimeUnit.SECONDS.sleep(1);// 读取节点的数据内容byte[] bytes = client.getData().forPath("/ahao/test");String s = new String(bytes,StandardCharsets.UTF_8);log.info("读取到的数据内容:{}",s);// 判断节点是否存在并返回节点状态信息Stat stat = client.checkExists().forPath("/ahao/test");log.info("读取节点状态信息:{}", stat);// 获取子节点List<String> list = client.getChildren().forPath("/ahao");log.info("读取子节点:{}", list);}

日志输出如下:在这里插入图片描述

4.3. 更新节点

更新节点内容:client.setData().forPath()

    @Overridepublic void run(ApplicationArguments args) throws Exception {log.info("。。。。。。。。。。。。。容器初始化完毕。。。。。。。。。。。。。。");TimeUnit.SECONDS.sleep(3);log.info("新增节点");// 创建节点client.create()// 如果需要,递归创建节点.creatingParentsIfNeeded()// 指定创建节点类型.withMode(CreateMode.EPHEMERAL)// 节点路径和数据.forPath("/ahao/test","this is a book".getBytes(StandardCharsets.UTF_8));// 睡眠1sTimeUnit.SECONDS.sleep(1);// 读取节点的数据内容byte[] bytes = client.getData().forPath("/ahao/test");String s = new String(bytes,StandardCharsets.UTF_8);log.info("读取到的数据内容:{}",s);// 更新节点client.setData().forPath("/ahao/test","这是一本书".getBytes(StandardCharsets.UTF_8));// 再次读取节点的数据内容byte[] bytes2 = client.getData().forPath("/ahao/test");String s2 = new String(bytes2,StandardCharsets.UTF_8);log.info("读取到的数据内容:{}",s2);}

日志输出如下:

在这里插入图片描述

4.4. 删除节点

删除节点:client.delete().forPath()

递归方式删除节点及其子节点:client.delete().deletingChildrenIfNeeded().forPath()

		@Overridepublic void run(ApplicationArguments args) throws Exception {log.info("。。。。。。。。。。。。。容器初始化完毕。。。。。。。。。。。。。。");TimeUnit.SECONDS.sleep(3);log.info("新增节点");// 创建节点client.create()// 如果需要,递归创建节点.creatingParentsIfNeeded()// 指定创建节点类型.withMode(CreateMode.EPHEMERAL)// 节点路径和数据.forPath("/ahao/test","this is a book".getBytes(StandardCharsets.UTF_8));// 睡眠1sTimeUnit.SECONDS.sleep(1);// 删除/ahao节点// 直接删除会报错KeeperErrorCode = Directory not empty for /ahao因为/ahao下有子节点// client.delete().forPath("/ahao");// 正确方式删除/ahao节点// client.delete().deletingChildrenIfNeeded().forPath("/ahao");// 删除/ahao/test节点client.delete().forPath("/ahao/test");}

4.6. 异步调用

Curator使用BackgroundCallback接口实现有关服务端返回的结果信息处理。

public interface BackgroundCallback
{/*** Called when the async background operation completes** @param client 当前客户端实例* @param event operation result details 服务端事件操作结果,包含事件类型和响应码* @throws Exception errors*/public void processResult(CuratorFramework client, CuratorEvent event) throws Exception;
}

事件类型 在枚举类org.apache.curator.framework.api.CuratorEventType中有列举。

public enum CuratorEventType
{/*** Corresponds to {@link CuratorFramework#create()}*/CREATE,/*** Corresponds to {@link CuratorFramework#delete()}*/DELETE,/*** Corresponds to {@link CuratorFramework#checkExists()}*/EXISTS,/*** Corresponds to {@link CuratorFramework#getData()}*/GET_DATA,/*** Corresponds to {@link CuratorFramework#setData()}*/SET_DATA,/*** Corresponds to {@link CuratorFramework#getChildren()}*/CHILDREN,/*** Corresponds to {@link CuratorFramework#sync(String, Object)}*/SYNC,/*** Corresponds to {@link CuratorFramework#getACL()}*/GET_ACL,/*** Corresponds to {@link CuratorFramework#setACL()}*/SET_ACL,/*** Corresponds to {@link CuratorFramework#transaction()}*/TRANSACTION,/*** Corresponds to {@link CuratorFramework#getConfig()}*/GET_CONFIG,/*** Corresponds to {@link CuratorFramework#reconfig()}*/RECONFIG,/*** Corresponds to {@link Watchable#usingWatcher(Watcher)} or {@link Watchable#watched()}*/WATCHED,/*** Corresponds to {@link CuratorFramework#watches()} ()}*/REMOVE_WATCHES,/*** Event sent when client is being closed*/CLOSING
}

代码实现

    @Overridepublic void run(ApplicationArguments args) throws Exception {log.info("。。。。。。。。。。。。。容器初始化完毕。。。。。。。。。。。。。。");TimeUnit.SECONDS.sleep(3);log.info("新增节点");// 创建节点client.create()// 如果需要,递归创建节点.creatingParentsIfNeeded()// 指定创建节点类型.withMode(CreateMode.EPHEMERAL)// 节点路径和数据.forPath("/ahao/test","this is a book".getBytes(StandardCharsets.UTF_8));// 睡眠1sTimeUnit.SECONDS.sleep(1);// 异步回调BackgroundCallback callback = new BackgroundCallback() {@Overridepublic void processResult(CuratorFramework client, CuratorEvent event) throws Exception {log.info("时间类型:{}",event.getType());}};// 删除/ahao/test节点client.delete().deletingChildrenIfNeeded().inBackground(callback).forPath("/ahao/test");}

日志输出中可以发现,不再是main线程:

在这里插入图片描述

5. 总结

本篇我们介绍了如何SpringBoot整合Curator客户端,并讲解了部分基本API的使用,有关更高级的用法如分布式锁、事件监听、分布式消息队列等功能将在下篇博客介绍。

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

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

相关文章

基于MATLAB计算无线通信覆盖(一)环境准备

一、环境 MATLAB 2022b 注&#xff1a;开始仿真前需部署地理坐标区和地理图&#xff0c;最好采用第三种&#xff0c;直接把底图数据下载到本地&#xff0c;防止连接不上网络时只能显示darkwater的底图。 可用于地理坐标区和地理图的底图如下表所示 二、下载底图并安装 工具&…

【数据结构和算法】奇偶链表

其他系列文章导航 Java基础合集数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一、题目描述 二、题解 2.1 方法一&#xff1a;分离节点后合并 三、代码 3.1 方法一&#xff1a;分离节点后合并 四、复杂度分…

java版微信小程序商城 免 费 搭 建 java版直播商城平台规划及常见的营销模式有哪些?电商源码/小程序/三级分销

涉及平台 平台管理、商家端&#xff08;PC端、手机端&#xff09;、买家平台&#xff08;H5/公众号、小程序、APP端&#xff08;IOS/Android&#xff09;、微服务平台&#xff08;业务服务&#xff09; 2. 核心架构 Spring Cloud、Spring Boot、Mybatis、Redis …

经典网络 循环神经网络(一) | RNN结构解析,代码实现

文章目录 1 提出背景2 RNN2.1 RNN结构2.2 RNN代码实现2.3 代码简洁实现 1 提出背景 为什么要引入RNN呢&#xff1f; 非常简单&#xff0c;之前我们的卷积神经网络CNN&#xff0c;全连接神经网络等都是单个神经元计算 但在序列模型中&#xff0c;前一个神经元往往对后面一个神…

为什么使用 atan2(sin(z), cos(z)) 进行角度归一化?

文章目录 为什么使用 atan2(sin(z), cos(z)) 进行归一化&#xff1f;为什么归一化后的角度等于原始角度&#xff1f; atan2 方法返回 -π 到 π 之间的值&#xff0c;代表点 (x, y) 相对于正X轴的偏移角度。这个角度是逆时针测量的&#xff0c;以弧度为单位。关于 atan2 函数为…

YOLOv5姿态估计:HRnet实时检测人体关键点

前言&#xff1a; Hello大家好&#xff0c;我是Dream。 今天来学习一下利用YOLOv5进行姿态估计&#xff0c;HRnet与SimDR检测图片、视频以及摄像头中的人体关键点&#xff0c;欢迎大家一起前来探讨学习~ 本文目录&#xff1a; 一、项目准备1Pycharm中克隆github上的项目2.具体步…

【Linux实用篇】Linux软件安装 JDK Tomcat MySQL lrzsz

1. 软件安装 1.1 软件安装方式 在Linux系统中&#xff0c;安装软件的方式主要有四种&#xff0c;这四种安装方式的特点如下&#xff1a; 安装方式特点二进制发布包安装软件已经针对具体平台编译打包发布&#xff0c;只要解压&#xff0c;修改配置即可rpm安装软件已经按照red…

微信好友批量自动添加:快捷方式解密

对于一些希望扩大社交圈子或者推广业务的人来说&#xff0c;手动添加好友可能是一个耗时且繁琐的任务。 不过&#xff0c;别担心&#xff0c;今天给大家种草一个能够批量自动添加好友的微信管理工具&#xff0c;让你轻松地扩展好友列表。 首先&#xff0c;当微信在个微管理系…

Python数据分析案例31——中国A股的月份效应研究(方差分析,虚拟变量回归)

案例背景 本次案例是博主本科在行为金融学课程上做的一个小项目&#xff0c;最近看很多经管类的学生作业都很需要&#xff0c;我就用python来重新做了一遍。不弄那些复杂的机器学习模型了&#xff0c;经管类同学就用简单的统计学方法来做模型就好。 研究目的 有效市场假说是现…

VUE项目快速打包发布

VUE项目快速打包发布 首先在你的VS Code中新建一个终端 输入 npm run build 回车等运行结束之后会在你的项目中生成一个dist目录 此时再iis部署的时候把你添加的网站指定的目录指向dist即可

STM32CubeMX配置STM32G071UART+DMA收发数据(HAL库开发)

时钟配置HSI主频配置64M 配置好串口&#xff0c;选择异步模式 配置DMA TX,RX,选择循环模式。 NVIC中勾选使能中断 勾选生成独立的.c和h文件 配置好需要的开发环境并获取代码 串口重定向勾选Use Micro LIB main.c文件修改 增加头文件和串口重定向 #include <string.h&g…

spring常见漏洞(3)

CVE-2017-8046 Spring-Data-REST-RCE(CVE-2017-8046)&#xff0c;Spring Data REST对PATCH方法处理不当&#xff0c;导致攻击者能够利用JSON数据造成RCE。本质还是因为spring的SPEL解析导致的RCE 影响版本 Spring Data REST versions < 2.5.12, 2.6.7, 3.0 RC3 Spring Bo…

光学雨量监测站比传统雨量站有哪些优势

光学雨量监测站相比传统雨量站具有许多优势。首先&#xff0c;光学雨量监测站采用光学原理进行雨量监测&#xff0c;而传统雨量站则依靠传感器和机械部件进行测量。光学雨量监测站的结构相对简单&#xff0c;不需要频繁维护和校准&#xff0c;减少了运维成本和工作量。 其次&am…

【Emgu CV教程】5.1、几何变换之平移

图像的几何变换对于图像处理来说&#xff0c;也是最基础的那一档次&#xff0c;包括平移、旋转、缩放、透视变换等等&#xff0c;也就是对图像整理形状的改变&#xff0c;用到的函数都比较简单&#xff0c;理解起来也很容易。但是为了凑字数&#xff0c;还是一个函数一个函数的…

如何通过企业司法协助信息API识别潜在的不良合作伙伴

引言 在商业合作中&#xff0c;合作伙伴的信誉和合规性是至关重要的。然而&#xff0c;在选择合作伙伴时&#xff0c;我们往往面临信息不对称的问题。如何有效地识别潜在的不良合作伙伴&#xff0c;避免潜在的风险呢&#xff1f;通过企业司法协助信息API&#xff0c;我们可以快…

mysql简单操作集成数据模型使用方法

查看表信息&#xff0c;其中包括字段信息以及创表信息 DESCRIBE asset; show COLUMNS FROM asset; SHOW CREATE TABLE asset; 常规操作表 --查询 select * FROM device_template --插入 INSERT into asset_package (protocol,project_code,lease_id,station_name,device_id,…

Qt点击按钮在附近弹出下拉框

效果 MainWindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include"toollayout.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACEclass MainWindow : public QMainWindow {Q_OBJECTpublic:MainWindow…

vue3+vite项目构建时报错npm ERR! code EPERMnpm ERR! syscall mkdir...

vscode终端中输入npm create vitelatest vueviteproject1 -- --vue命令后报错 具体报错如下&#xff1a; PS D:\project> npm create vitelatest vueviteproject1 -- --vue >> npm ERR! code EPERM npm ERR! syscall mkdir npm ERR! path D:\node\node_cache\_cac…

C语言:自定义类型——联合和枚举

一、联合体 1.1 联合体类型的声明 像结构体⼀样&#xff0c;联合体也是由⼀个或者多个成员构成&#xff0c;这些成员可以是不同的类型。 声明方式如下图&#xff1a; 那联合体和结构体究竟有什么区别呢&#xff1f;&#xff1f; 下面将重点讲解联合体的特点&#xff01;&am…

判断交叉编译工具是否支持C++20的标准

写个任意的测试程序hello_world 执行 arm-linux-gnueabihf-g -stdc14 main.cpp arm-linux-gnueabihf-g -stdc17 main.cpp arm-linux-gnueabihf-g -stdc20 main.cpp没报错则代表支持&#xff0c;报错则不支持.