快速入门Zookeeper
Zookeeper
ZooKeeper作为一个强大的开源分布式协调服务,扮演着分布式系统中至关重要的角色。它提供了一个中心化的服务,用于维护配置信息、命名、提供分布式同步以及提供组服务等。通过其高性能和可靠的特性,ZooKeeper能够确保在复杂的分布式环境中,各个节点和服务之间的协调和通信得以顺利进行。无论是在大规模的Web服务、云基础设施管理,还是大数据处理框架中,ZooKeeper都是实现服务发现、负载均衡、数据发布/订阅等关键功能的首选工具。它的出现极大地简化了分布式系统设计中的一致性问题,使得开发者可以更加专注于业务逻辑的实现。

安装配置
学习笔记:快速入门ZooKeeper技术
zookeeper命令操作
zookeeper数据模型

服务端命令操作
• 启动 ZooKeeper 服务: ./zkServer.sh start
• 查看 ZooKeeper 服务状态: ./zkServer.sh status
• 停止 ZooKeeper 服务: ./zkServer.sh stop
• 重启 ZooKeeper 服务: ./zkServer.sh restart
客户端命令操作

连接ZooKeeper服务端:
./zkCli.sh –server ip:port

断开链接
quit

查看节点信息
ls /dubbo

创建节点并赋值(没有加任何参数就是持久化的)
create /节点path value

设置节点值
set /节点path value

删除节点值
delete /path

不能重复创建节点,但是可以创建子节点往下延申
create /app1/p1
create /app1/p2

子节点存在的时候,不允许直接删除父节点
直接删除子节点的节点
deleteall /节点path

创建临时顺序节点
create -e /节点path value
退出会话,重新打开xshell查询会发现临时节点没有了
创建持久化顺序节点
create -s /节点path value
如果生成多次,会发现顺序产生多个节点

查看创建顺序临时节点
create -es /节点路径


查看节点详细信息
ls -s /节点path(ls2 /)
之前使用过Dubbo,这里可以看一下服务提供方的ip地址


JAVA API操作
注意
因为Curator是ZooKeeper的Java客户端库,所以二者的版本要对应起来可以看下官网的说明。
Zookeeper 3.5X 的版本可以用Curator4.0版本
低版本的Curator不能用高版本的Zookeeper,反之则可以。
导入pom.xml
<dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.10</version><scope>test</scope></dependency><!--curator--><dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>4.0.0</version></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>4.0.0</version></dependency><!--日志--><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.21</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.21</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.1</version><configuration><source>1.8</source><target>1.8</target></configuration></plugin></plugins></build>
建立链接
public class CuratorTest {/*** 建立连接*/@Testpublic void testConnection() {// 1.第一种方式// 重试策略,该策略重试设定的次数,每次重试之间的睡眠时间都会增加/*** 参数:* baseSleepTimeMs – 重试之间等待的初始时间量* 最大重试 次数 – 重试的最大次数*/RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);/*** Create a new client** @param connectString list of servers to connect to 连接字符串,地址+端口 例如“192. 168.149.135:2181, 192.168.149.135”* @param sessionTimeoutMs session timeout 会话超时时间 单位毫秒* @param connectionTimeoutMs connection timeout 连接超时时间 单位毫秒* @param retryPolicy retry policy to use 策略* @return client*/CuratorFramework client =CuratorFrameworkFactory.newClient("192. 168.149.135:2181", 60 * 1000, 15 * 1000, retryPolicy);client.start();}
}
/*** 建立连接 方式二*/@Testpublic void testConnection2() {RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);// 第二种方式CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder().connectString("192. 168.149.135:2181").sessionTimeoutMs(60 * 1000).connectionTimeoutMs(15 * 1000).retryPolicy(retryPolicy).namespace("itheima");;builder.build().start();}
注意这里建议把namespace加上,相当于是根目录

添加节点
public class CuratorTest {// 声明为成员变量 private CuratorFramework client;/*** 建立连接 方式二*/@Beforepublic void testConnection2() {RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);// 第二种方式client = CuratorFrameworkFactory.builder().connectString("192. 168.149.135:2181").sessionTimeoutMs(60 * 1000).connectionTimeoutMs(15 * 1000).retryPolicy(retryPolicy).namespace("itheima").build();client.start();}/*** 创建节点* 持久、临时、顺序* 设置数据* <p>* 1.基本创建* 2.创建节点,带有数据* 3.设置节点的类型* 4.创建多级节点*/@Testpublic void testCreate() throws Exception {// client操作}@After/*** 关闭连接*/public void close() {if (null != client) {client.close();}}
}
(1).创建一个基础的节点
我们先创建一个基础的节点
CuratorTest.java
@Testpublic void testCreate() throws Exception {String path = client.create().forPath("/app4");System.out.println(path);}
(2).创建一个带有数据的节点
CuratorTest.java
@Testpublic void testCreateValue() throws Exception {String path = client.create().forPath("/app5", "heima".getBytes());System.out.println(path);}
(3).设置节点的类型
CuratorTest.java
创建临时节点
/*** 设置节点类型** @throws Exception*/@Testpublic void testCreateType() throws Exception {String path = client.create().withMode(CreateMode.EPHEMERAL).forPath("/app6", "number6".getBytes());System.out.println(path);}
(4).创建多级节点
CuratorTest.java
/*** 多级节点** @throws Exception*/@Testpublic void testCreateManyTypes() throws Exception {// creatingParentsIfNeeded()如果父节点不存在,就创建一个节点String path = client.create().creatingParentsIfNeeded().forPath("/app8/p8", "number8".getBytes());System.out.println(path);}
查询节点
(1).查询数据
CuratorTest.java
/*** 获取、查询* 1.查询数据* 2.查询子节点* 3.查询节点的状态 ls -s*/@Testpublic void testGet() throws Exception {byte[] bytes = client.getData().forPath("/app7");System.out.println(new String(bytes));}
(2).查询子节点
CuratorTest.java
/*** 获取、查询* 2.查询子节点*/@Testpublic void testGetSon() throws Exception {List<String> path = client.getChildren().forPath("/app8");System.out.println(path);}
(3).查询节点的状态 ls -s
CuratorTest.java
/*** 3.查询节点的状态 ls -s*/@Testpublic void testGetStatus() throws Exception {Stat stat = new Stat();System.out.println("查询前:" + stat);client.getData().storingStatIn(stat).forPath("/app8/p8");System.out.println("查询后:" + stat);}
修改节点
修改数据
修改前用Zookeeper查询
/*** 修改数据** @throws Exception*/@Testpublic void testSet() throws Exception {client.setData().forPath("/app7", "dong77".getBytes());}
根据版本修改数据⭐(推荐)
CuratorTest.java
/*** 按照版本修改** @throws Exception*/@Testpublic void testSetForVersion() throws Exception {int version = 0;Stat stat = new Stat();client.getData().storingStatIn(stat).forPath("/app7");version = stat.getVersion();System.out.println("当前version是:" + version);client.setData().withVersion(version).forPath("/app7", "luka7".getBytes());}
删除节点
/*** 1.删除单个节点** @throws Exception*/@Testpublic void testDelete() throws Exception {client.delete().forPath("/app5");}
删除带有子节点的节点
删除前节点app7是有子节点的
/*** 2.删除带有子节点的节点** @throws Exception*/@Testpublic void testDeleteWithSon() throws Exception {client.delete().deletingChildrenIfNeeded().forPath("/app7");}
必须成功的删除节点⭐(推荐):防止网络抖动,本质抖动。
删除前app4还在
/*** 3.必须成功的删除节点** @throws Exception*/@Testpublic void testDeleteSucceed() throws Exception {client.delete().guaranteed().forPath("/app4");}
回调
删除前有节点
/*** 4.回调** @throws Exception*/@Testpublic void testDeleteReturnFun() throws Exception {BackgroundCallback callback = new BackgroundCallback() {@Overridepublic void processResult(CuratorFramework client, CuratorEvent event) throws Exception {System.out.println("我被删除了");System.out.println(event);}};client.delete().inBackground(callback).forPath("/app8");}
Watch事件监听

(1).NodeCache给指定一个节点注册监听器
用代码实现一下:
命名空间下面可能没有子节点的话,过一会儿就会删除命名空间
CuratorTest.java
/*** NodeCache : 只是监听某一个特定的节点** @throws Exception*/@Testpublic void testNodeCache() throws Exception {while (true) {/*** Params:* client – curztor client 客户端* path – the full path to the node to cache 要缓存的节点的完整路径* dataIsCompressed – if true, data in the path is compressed 如果为 true,则路径中的数据被压缩,默认不压缩*/// 1.创建NodeCache对象NodeCache nodeCache = new NodeCache(client, "/app1");// 2.注册监听8nodeCache.getListenable().addListener(new NodeCacheListener() {@Overridepublic void nodeChanged() throws Exception {System.out.println("节点变化了");}});// 3.开启监听 如果为 true,将在此方法返回之前调用, rebuild() 以便获得节点的初始视图nodeCache.start(true);}}
现在想知道节点变成了什么,这里需要修改代码
CuratorTest.java
/*** NodeCache : 只是监听某一个特定的节点** @throws Exception*/@Testpublic void testNodeCache() throws Exception {/*** Params:* client – curztor client 客户端* path – the full path to the node to cache 要缓存的节点的完整路径* dataIsCompressed – if true, data in the path is compressed 如果为 true,则路径中的数据被压缩,默认不压缩*/// 1.创建NodeCache对象NodeCache nodeCache = new NodeCache(client, "/app1");// 2.注册监听nodeCache.getListenable().addListener(new NodeCacheListener() {@Overridepublic void nodeChanged() throws Exception {System.out.println("节点变化了");// 获取修改节点后的数据byte[] data = nodeCache.getCurrentData().getData();System.out.println("修改后数据是:" + new String(data));}});// 3.开启监听 如果为 true,将在此方法返回之前调用, rebuild() 以便获得节点的初始视图nodeCache.start(true);while (true) {}}
(2).PathChildrenCache(监听某个节点的子节点们 )
测试前先给app1节点创建3个子节点
/*** PathChildrenCache : 监控一个ZNode的所有子节点.** @throws Exception*/@Testpublic void testPathChildrenCache() throws Exception {/*** 如果为 true,则除了统计信息之外,还会缓存节点内容*/// 1.创建监听对象PathChildrenCache pathChildrenCache = new PathChildrenCache(client, "/app1", true);// 2.绑定监听器pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {@Overridepublic void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {System.out.println("子节点变化了");System.out.println(event);}});pathChildrenCache.start();while (true) {}}
那现在我想看到具体子节点的变化情况和变化的值呢。修改CuratorTest.java修改PathChildrenCache构造函数,最后一个值是false,然后输出监听信息。
/*** PathChildrenCache : 监控一个ZNode的所有子节点.** @throws Exception*/@Testpublic void testPathChildrenCache() throws Exception {/*** 如果为 true,则除了统计信息之外,还会缓存节点内容*/// 1.创建监听对象PathChildrenCache pathChildrenCache = new PathChildrenCache(client, "/app1", false);// 2.绑定监听器pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {@Overridepublic void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {System.out.println("子节点变化了");System.out.println(event);// 1.获取类型PathChildrenCacheEvent.Type type = event.getType();// 2.判断类型是否是updateif (type.equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)) {byte[] bytes = event.getData().getData();System.out.println("数据被更新了:" + new String(bytes));} else if (type.equals(PathChildrenCacheEvent.Type.CHILD_ADDED)) {byte[] bytes = event.getData().getData();System.out.println("数据被添加了:" + new String(bytes));} else if (type.equals(PathChildrenCacheEvent.Type.CHILD_REMOVED)) {byte[] bytes = event.getData().getData();System.out.println("数据被删除了:" + new String(bytes));}}});pathChildrenCache.start();while (true) {}}
(3).TreeCache(监听某个节点自己和所有的子节点们)
CuratorTest.java
/*** TreeCache : 可以监控整个树上的所有节点,类似于PathChildrenCache和NodeCache的组合** @throws Exception*/@Testpublic void testTreeCache() throws Exception {TreeCache treeCache = new TreeCache(client, "/app1");treeCache.getListenable().addListener(new TreeCacheListener() {@Overridepublic void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception {System.out.println("整个树节点有变化");System.out.println(event);}});treeCache.start();while (true) {}}
也想输出树节点的信息,继续修改CuratorTest.java
/*** TreeCache : 可以监控整个树上的所有节点,类似于PathChildrenCache和NodeCache的组合** @throws Exception*/@Testpublic void testTreeCache() throws Exception {TreeCache treeCache = new TreeCache(client, "/app1");treeCache.getListenable().addListener(new TreeCacheListener() {@Overridepublic void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception {System.out.println("整个树节点有变化");System.out.println(event);TreeCacheEvent.Type type = event.getType();if (type.equals(TreeCacheEvent.Type.NODE_UPDATED)) {byte[] bytes = event.getData().getData();System.out.println("树节点数据被更新了:" + new String(bytes));} else if (type.equals(TreeCacheEvent.Type.NODE_ADDED)) {byte[] bytes = event.getData().getData();System.out.println("树节点数据被添加了:" + new String(bytes));} else if (type.equals(TreeCacheEvent.Type.NODE_REMOVED)) {byte[] bytes = event.getData().getData();System.out.println("树节点数据被删除了:" + new String(bytes));} else {System.out.println("树节点无操作");}}});treeCache.start();while (true) {}}
分布式锁

原理
当客户端想要获得锁,则创建节点,使用完锁,则删除该节点。

模拟12306售票案例


创建一个测试类LockTest.java
package com.itheima;/*** @ClassName: LockTest* @Description:* @Author: wty* @Date: 2023/3/14*/public class LockTest {public static void main(String[] args) {Tick12306 tick12306 = new Tick12306();// 创建客户端Thread t1 = new Thread(tick12306, "携程");Thread t2 = new Thread(tick12306, "飞猪");Thread t3 = new Thread(tick12306, "去哪儿");t1.start();t2.start();t3.start();}
}
创建实体类模拟12306抢票操作
package com.itheima;/*** @ClassName: Tick12306* @Description:* @Author: wty* @Date: 2023/3/14*/public class Tick12306 implements Runnable {// 数据库的票数private int tickets = 100;@Overridepublic void run() {while (true) {if (tickets > 0) {System.out.println("线程:" + Thread.currentThread().getName() + "买走了票,剩余" + (--tickets));}}}
}
解决方案:用分布式锁解决
添加工具类ClientConnection.java
public class ClientConnection {public static CuratorFramework getConnection() {ExponentialBackoffRetry retry = new ExponentialBackoffRetry(3000, 10);CuratorFramework client = CuratorFrameworkFactory.builder().connectString("192. 168.149.135:2181").sessionTimeoutMs(60 * 1000).connectionTimeoutMs(15 * 1000).retryPolicy(retry).build();client.start();return client;}
}
修改Tick12306.java
public class Tick12306 implements Runnable {private InterProcessMutex lock;// 数据库的票数private int tickets = 100;public Tick12306() {CuratorFramework client = ClientConnection.getConnection();lock = new InterProcessMutex(client, "/itheima/lock");}@Overridepublic void run() {while (true) {// 获取锁try {lock.acquire(3, TimeUnit.SECONDS);if (tickets > 0) {System.out.println("线程:" + Thread.currentThread().getName() + "买走了票,剩余" + (--tickets));Thread.sleep(100);}} catch (Exception e) {e.printStackTrace();} finally {// 释放锁try {lock.release();} catch (Exception e) {e.printStackTrace();}}}}
}
zookeeper 集群




配置每一个Zookeeper 的dataDir 和 clientPort 分别为2181 2182 2183
修改/usr/local/zookeeper-cluster/zookeeper-1/conf/zoo.cfg





模拟集群异常
(1)首先我们先测试如果是从服务器挂掉,会怎么样
把3号服务器停掉,观察1号和2号,发现状态并没有变化。


由此得出结论,3个节点的集群,从服务器挂掉,集群正常
(2)我们再把1号服务器(从服务器)也停掉,查看2号(主服务器)的状态,发现已经停止运行了。

由此得出结论,3个节点的集群,2个从服务器都挂掉,主服务器也无法运行。因为可运行的机器没有超过集群总数量的半数。
(3)我们再次把1号服务器启动起来,发现2号服务器又开始正常工作了。而且依然是领导者。

(4)我们把3号服务器也启动起来,把2号服务器停掉,停掉后观察1号和3号的状态。

(5)我们再次测试,当我们把2号服务器重新启动起来启动后,会发生什么?2号服务器会再次成为新的领导吗?结果2号服务器启动后依然是跟随者(从服务器),3号服务器依然是领导者(主服务器),没有撼动3号服务器的领导地位。由此我们得出结论,当领导者产生后,再次有新服务器加入集群,不会影响到现任领导者。
集群角色

相关文章:
快速入门Zookeeper
Zookeeper ZooKeeper作为一个强大的开源分布式协调服务,扮演着分布式系统中至关重要的角色。它提供了一个中心化的服务,用于维护配置信息、命名、提供分布式同步以及提供组服务等。通过其高性能和可靠的特性,ZooKeeper能够确保在复杂的分布式…...
Filter and Search 筛选和搜索
Goto Data Grid 数据网格 Filter and Search 筛选和搜索 Filter Drop-down Menus (Excel-style) 筛选器下拉菜单(Excel 样式) 要调用列的筛选器下拉菜单,请单击列标题中的筛选器图标。在 “Values” 选项卡中,用户可以从 Data …...
spark的学习-06
SparkSQL读写数据的方式 1)输入Source 方式一:给定读取数据源的类型和地址 spark.read.format("json").load(path) spark.read.format("csv").load(path) spark.read.format("parquet").load(path) 方式二:…...
Linux C/C++ Socket 编程
本文目录 Linux C语言 socket 编程 client 端头文件 unistd.h & arpa/inet.h1. **unistd.h**2. **arpa/inet.h** socket() 创建套接字sockaddr_in 结构体inet_pton()connect()send()recv()send() 和 recv() 中的 flags 参数**默认行为(flags 0)的特…...
Flutter错误: uses-sdk:minSdkVersion 16 cannot be smaller than version 21 declared
前言 今天要做蓝牙通信的功能,我使用了flutter_reactive_ble这个库,但是在运行的时候发现一下错误 Launching lib/main.dart on AQM AL10 in debug mode... /Users/macbook/Desktop/test/flutter/my_app/android/app/src/debug/AndroidManifest.xml Err…...
Spark 的容错机制:保障数据处理的稳定性与高效性
Spark 的介绍与搭建:从理论到实践_spark环境搭建-CSDN博客 Spark 的Standalone集群环境安装与测试-CSDN博客 PySpark 本地开发环境搭建与实践-CSDN博客 Spark 程序开发与提交:本地与集群模式全解析-CSDN博客 Spark on YARN:Spark集群模式…...
TCP可靠连接的建立和释放,TCP报文段的格式,UDP简单介绍
TCP连接的建立(三次握手) 建立连接使用的三报文 SYN 报文仅用于 TCP 三次握手中的第一个和第二个报文(SYN 和 SYN-ACK),用于初始化连接的序列号。数据传输阶段不再使用 SYN 标志。 SYN 报文通常只携带连接请求信息&a…...
LLMs之PDF:zeroX(一款PDF到Markdown 的视觉模型转换工具)的简介、安装和使用方法、案例应用之详细攻略
LLMs之PDF:zeroX(一款PDF到Markdown 的视觉模型转换工具)的简介、安装和使用方法、案例应用之详细攻略 目录 zeroX的简介 1、支持的文件类型 zeroX的安装和使用方法 T1、Node.js 版本: 安装 使用方法 使用文件 URL: 使用本地路径&…...
开源数据库 - mysql - mysql-server-8.4(gtid主主同步+ keepalived热切换)部署方案
前置条件 假设主从信息 mysqlhostport主192.168.1.13306从192.168.1.23306vip192.168.1.3 部署流程 导出测试环境表结构与数据 使用mysqldump ./mysqldump -ulzzc -p -S /tmp/mysql3306.sock --single-transaction --database lzzc > databaseLZZCxxxx.sql查看gtid号 …...
Java全栈体系路线
Java全栈体系路线 摘要 Java 是一门广泛应用于企业级开发的语言,具有强大的生态系统和丰富的工具支持。成为一名 Java 全栈开发工程师不仅需要掌握后端开发技能,还需要具备前端开发和数据库管理的能力。本文将详细介绍 Java 全栈开发的学习路线&#x…...
【Unity基础】Unity中如何导入字体?
在Unity中,不能像其他软件一样直接使用字体文件,需要通过FontAssetCreator将其转换成Texture的Asset文件,然后才能使用。 本文介绍了使用FontAssetCreator导入字体的过程,并对其参数设置进行了说明。 Font Asset Creator 是 Uni…...
使用NVIDIA GPU加速FFmpeg视频压制:完全指南
引言 在视频处理领域,FFmpeg是一个强大的工具。结合NVIDIA的硬件编码器NVENC,我们可以实现快速高效的视频压制。本文将详细解析一个实用的视频压制命令,帮助你理解每个参数的作用。 核心命令 ffmpeg -i input.mp4 -vf scale640:360 -c:v h…...
Python学习:scipy是什么?
文章目录 一、Scipy简介二、Scipy的组成部分1. 基础功能:2. 特殊函数:3. 优化:4. 积分:5. 插值:6. 信号处理:7. 图像处理:8. 统计分布:9. 空间数据结构和算法:10. 稀疏矩…...
spark的学习-05
SparkSql 结构化数据与非结构化数据 结构化数据就类似于excel表中的数据(统计的都是结构化的数据)一般都使用sparkSql处理结构化的数据 结构化的文件:JSON、CSV【以逗号分隔】、TSV【以制表符分隔】、parquet、orc 结构化的表:…...
SQL注入(SQL Injection)详解
SQL注入(SQL Injection)是一种代码注入技术,它通过在应用程序的输入字段中插入或“注入”恶意的SQL语句,从而操控后端数据库服务器执行非预期的命令。这种攻击方式常用于绕过应用程序的安全措施,未经授权地访问、修改或…...
深入解析 OpenHarmony 构建系统-2-目录结构与核心组件
引言 OpenHarmony作为一款面向全场景的分布式操作系统,其构建系统在开发过程中扮演着至关重要的角色。本文将详细介绍OpenHarmony构建系统的目录结构和核心组件,帮助开发者更好地理解和使用这一强大的工具。 目录结构概览 以下是OpenHarmony构建系统的目录结构,每个目录和…...
网络安全应急响应(归纳)
目录 一、概述二、理论 系统排查 系统基本信息 windowsLinux用户信息 WindowsLinux启动项:开机系统在前台或者后台运行的程序,是病毒等实现持久化驻留的常用方法。 WindowsLinux任务计划:由于很多计算机都会自动加载“任务计划”,…...
【网络协议栈】网络层(上)网络层的基本理解、IP协议格式、网络层分组(内附手画分析图 简单易懂)
绪论 “It does not matter how slowly you go as long as you do not stop.”。本章是自上而下的进入网络协议栈的第三个篇幅–网络层–,本章我将带你了解网络层,以及网络层中非常重要的IP协议格式和网络层的分片组装问题,后面将持续更新网…...
数据库类型介绍
1. 关系型数据库(RDBMS) 关系型数据库是最常见的一类数据库,它们通过表(Table)来存储数据,表之间通过关系(如主键和外键)来关联。 • MySQL:开源的关系型数据库管理系统&…...
一步一步从asp.net core mvc中访问asp.net core WebApi
"从asp.net core mvc中访问asp.net core WebApi"看到这个标题是不是觉得很绕口啊,但的确就是要讲一讲这样的访问。前面我们介绍了微信小程序访问asp.net core webapi(感兴趣的童鞋可以看看前面的博文有关WEBAPI的搭建),这里我们重点不关心如何…...
label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...
C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...
python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...
html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...
