Spring Boot进阶(89):Spring Boot和Zookeeper搭建分布式系统,提高系统可靠性

news2024/12/23 17:54:58

📣前言


  在当今信息化时代,互联网公司在面对海量访问请求时往往需要采用分布式系统来提高系统的可扩展性和可靠性。分布式系统具有多节点、相互协作的特性,不仅可以提高系统的吞吐量,而且还能在某个节点出现故障时自动切换到其他节点,以保证系统的可靠性。

  本文主要介绍了如何使用Zookeeper作为分布式系统的协调者,并使用Spring Boot和Zookeeper来搭建一个分布式系统。本文首先介绍了Zookeeper的概念和原理,然后详细讲解了如何使用Spring Boot来集成Zookeeper,最后通过一个实际应用场景的案例,展示了如何使用Spring Boot和Zookeeper来搭建分布式系统。这将又会是干货满满的一期,全程无尿点不废话只抓重点教,具有非常好的学习效果,拿好小板凳准备就坐!希望学习的过程中大家认真听好好学,学习的途中有任何不清楚或疑问的地方皆可评论区留言或私信,bug菌将第一时间给予解惑,那么废话不多说,直接开整!Fighting!!

🌊环境说明

开发工具:IDEA 2021.3
JDK版本: JDK 1.8
Spring Boot版本:2.3.1 RELEASE
Maven版本:3.8.2


🏆本文收录于《Spring Boot从入门到精通》,专门攻坚指数提升,2023 年国内最系统+最强(更新中)。

本专栏致力打造最硬核 Spring Boot 从零基础到进阶系列学习内容,🚀均为全网独家首发,打造精品专栏,专栏持续更新中…欢迎大家订阅持续学习。 如果想快速定位学习,可以看这篇【SpringBoot教程导航帖】,你想学习的都被收集在内,快速投入学习!!两不误。

摘要

  本文主要介绍了如何使用Zookeeper作为分布式系统的协调者,并使用Spring Boot和Zookeeper来搭建一个分布式系统。本文首先介绍了Zookeeper的概念和原理,然后详细讲解了如何使用Spring Boot来集成Zookeeper,最后通过一个实际应用场景的案例,展示了如何使用Spring Boot和Zookeeper来搭建分布式系统。

正文

概述

  Zookeeper是一个分布式的协调者,可以用于在分布式系统中实现分布式应用的协调和管理。Zookeeper采用了类似于文件系统的树形结构,每个节点都可以存储一些数据,同时也可以在节点上注册一些监听器,当节点的数据发生变化时可以触发相应的事件。

  在分布式系统中,通常需要一个协调者来管理各个节点之间的状态和信息,例如:负载均衡、服务发现、配置管理等。在这些应用场景下,Zookeeper可以作为一个分布式协调者来实现。

  同时,Spring Boot是一个开发Web应用程序的框架,它简化了Java应用程序的开发过程,并提供了许多有用的功能,例如:自动配置、热部署、注解等。

搭建Spring Boot应用

  首先,我们先创建个基础的Spring Boot项目,如果还不会点这里,此处就不详细赘述啦。

Spring Boot集成教学

步骤1:引入依赖

在使用Spring Boot集成Zookeeper之前,我们需要在pom.xml文件中引入以下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>5.1.0</version>
</dependency>
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>5.1.0</version>
</dependency>

步骤2:创建Zookeeper客户端

在使用Zookeeper之前,我们需要创建一个Zookeeper客户端。可以通过以下方式创建:

@Configuration
public class ZookeeperConfig {
 
    @Value("${zookeeper.host}")
    private String host;
 
    @Value("${zookeeper.timeout}")
    private int timeout;
 
    @Bean
    public CuratorFramework curatorFramework() {
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
        CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient(host, timeout, 10000, retryPolicy);
        curatorFramework.start();
        return curatorFramework;
    }
}

步骤3:使用Zookeeper

在使用Zookeeper时,我们需要使用CuratorFramework对象来操作Zookeeper。例如:创建一个节点、获取节点数据、监听节点变化等操作。以下是一些常见的操作:

@Autowired
private CuratorFramework curatorFramework;

public void createNode(String path, byte[] data) throws Exception {
    curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(path, data);
}

public byte[] getNodeData(String path) throws Exception {
    return curatorFramework.getData().forPath(path);
}

public void setData(String path, byte[] data) throws Exception {
    curatorFramework.setData().forPath(path, data);
}

public void addListener(String path, NodeCacheListener listener) throws Exception {
    NodeCache nodeCache = new NodeCache(curatorFramework, path);
    nodeCache.getListenable().addListener(listener);
    nodeCache.start(true);
}

步骤4:启动Spring Boot应用程序

  在完成上述步骤之后,我们可以启动Spring Boot应用程序,并通过浏览器访问http://localhost:8080/来测试程序是否运行正常。

应用场景案例

以下是一个应用场景案例,它演示了如何使用Spring Boot和Zookeeper来搭建一个分布式系统:

案例背景

在这个案例中,我们将实现一个简单的在线聊天室,用户可以在聊天室中发送消息并与其他用户交流。

系统架构

我们将使用分布式系统来搭建这个聊天室,在分布式系统中,每个节点都是相互独立的,并且可以自由地加入或退出系统。

实现步骤

步骤1:创建Zookeeper客户端

  我们需要在程序中创建一个Zookeeper客户端来连接Zookeeper服务器,可以使用CuratorFramework类来实现。具体代码如下:

@Configuration
public class ZookeeperConfig {
 
    @Value("${zookeeper.host}")
    private String host;
 
    @Value("${zookeeper.timeout}")
    private int timeout;
 
    @Bean
    public CuratorFramework curatorFramework() {
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
        CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient(host, timeout, 10000, retryPolicy);
        curatorFramework.start();
        return curatorFramework;
    }
}
步骤2:创建节点

我们需要在Zookeeper中创建三个节点:

  1. /message:用于存储聊天消息
  2. /users:用于存储在线用户
  3. /sequence:用于生成唯一的序列号

以下是创建节点的代码:

@PostConstruct
public void init() throws Exception {
    createNode("/message", "".getBytes());
    createNode("/users", "".getBytes());
    createNode("/sequence", "0".getBytes());
}

private void createNode(String path, byte[] data) throws Exception {
    if (curatorFramework.checkExists().forPath(path) == null) {
        curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(path, data);
    }
}
步骤3:处理聊天消息

在聊天室中,当用户发送消息时,我们需要将消息存储到Zookeeper中。具体代码如下:

@RestController
public class ChatController {
 
    @Autowired
    private CuratorFramework curatorFramework;

    @PostMapping("/message")
    public void sendMessage(String message) throws Exception {
        long sequence = getSequence();
        String path = "/message/message_" + sequence;
        curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(path, message.getBytes());
    }

    private long getSequence() throws Exception {
        String path = "/sequence";
        Stat stat = curatorFramework.setData().withVersion(-1).forPath(path, "1".getBytes());
        return stat.getVersion();
    }
}
步骤4:处理在线用户

当用户进入或退出聊天室时,我们需要将他们的信息存储到Zookeeper中。具体代码如下:

@RestController
public class ChatController {
 
    @Autowired
    private CuratorFramework curatorFramework;

    @PostMapping("/users")
    public void login(String username) throws Exception {
        String path = "/users/" + username;
        curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath(path);
    }

    @DeleteMapping("/users")
    public void logout(String username) throws Exception {
        String path = "/users/" + username;
        curatorFramework.delete().forPath(path);
    }

}
步骤5:监听节点变化

当聊天室中有新消息或用户加入或退出时,我们需要通过监听节点变化来获取最新的聊天消息和在线用户列表。具体代码如下:

@Component
public class ChatListener {

    @Autowired
    private CuratorFramework curatorFramework;

    @Autowired
    private SimpMessagingTemplate messagingTemplate;

    @PostConstruct
    public void init() throws Exception {
        addMessageListener();
        addUserListener();
    }

    private void addMessageListener() throws Exception {
        String path = "/message";
        NodeCacheListener listener = new NodeCacheListener() {
            @Override
            public void nodeChanged() throws Exception {
                byte[] data = curatorFramework.getData().forPath(path);
                String message = new String(data);
                messagingTemplate.convertAndSend("/topic/messages", message);
            }
        };
        addListener(path, listener);
    }

    private void addUserListener() throws Exception {
        String path = "/users";
        PathChildrenCacheListener listener = new PathChildrenCacheListener() {
            @Override
            public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent event) throws Exception {
                List<String> users = curatorFramework.getChildren().forPath(path);
                messagingTemplate.convertAndSend("/topic/users", users);
            }
        };
        addListener(path, listener);
    }

    private void addListener(String path, CuratorListener listener) throws Exception {
        PathChildrenCache pathChildrenCache = new PathChildrenCache(curatorFramework, path, true);
        pathChildrenCache.getListenable().addListener(listener);
        pathChildrenCache.start(PathChildrenCache.StartMode.BUILD_INITIAL_CACHE);
    }

}
步骤6:创建WebSocket控制器

我们需要创建一个WebSocket控制器来处理客户端的WebSocket连接请求。具体代码如下:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws").withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/topic");
    }

}
步骤7:创建前端页面

最后,我们需要创建一个前端页面来展示聊天室中的消息和在线用户列表。以下是前端页面的代码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Chat Room</title>
    <script src="/webjars/jquery/3.6.0/jquery.min.js"></script>
    <script src="/webjars/sockjs-client/1.5.0/dist/sockjs.min.js"></script>
    <script src="/webjars/stomp-websocket/2.3.3/dist/stomp.min.js"></script>
</head>
<body>
    <h1>在线用户列表</h1>
    <ul id="users">

    </ul>
    <hr>
    <h1>聊天消息</h1>
    <ul id="messages">

    </ul>
    <input type="text" id="message" placeholder="发送消息">
    <button id="send">发送</button>

    <script>
        var stompClient = Stomp.over(new SockJS('/ws'));
        stompClient.connect({}, function (frame) {
            console.log('Connected: ' + frame);

            stompClient.subscribe('/topic/users', function (response) {
                console.log(response);
                var users = JSON.parse(response.body);
                console.log(users);
                var userHtml = '';
                for (var i = 0; i < users.length; i++) {
                    userHtml += '<li>' + users[i] + '</li>';
                }
                $('#users').html(userHtml);
            });

            stompClient.subscribe('/topic/messages', function (response) {
                console.log(response);
                var message = response.body;
                $('#messages').append('<li>' + message + '</li>');
            });
        });

        $('#send').click(function () {
            var message = $('#message').val();
            stompClient.send('/app/message', {}, message);
        });
    </script>
</body>
</html>

测试步骤

这里提供一个简单的测试用例步骤:

  1. 启动Zookeeper服务;
  2. 创建一个Spring Boot项目,添加Curator和WebSocket的依赖;
  3. 编写ZookeeperConfig类,在其中创建CuratorFramework客户端;
  4. 编写ChatController类,在其中处理聊天消息和在线用户;
  5. 编写ChatListener类,在其中监听节点变化并发送消息到前端;
  6. 编写WebSocketConfig类,启用WebSocket和消息代理;
  7. 编写前端页面,并在其中连接到WebSocket并发送和接收消息;
  8. 启动Spring Boot应用,访问前端页面,在页面中输入用户名并发送消息即可。

具体实现可以参考之上的代码。

小结

  本文介绍了如何使用Spring Boot和Zookeeper来搭建一个分布式系统,并以一个在线聊天室的应用场景为例,演示了如何使用Zookeeper来实现在线用户管理和实时聊天功能。

  在实现过程中,我们使用了Zookeeper来作为分布式协调者,用于管理在线用户和聊天消息;使用了Spring Boot来简化Java应用程序的开发过程,并提供了自动配置和热部署等功能。

总结

  在当今互联网时代,分布式系统已经成为了很多企业必不可少的基础设施。Zookeeper作为一个分布式协调者,可以协助我们实现分布式应用的协调和管理,提高系统的可扩展性和可靠性。同时,Spring Boot作为一个开发Web应用程序的框架,可以简化Java应用程序的开发过程,提高开发效率和代码质量。

  结合Zookeeper和Spring Boot,可以快速地开发出高可靠、高性能的分布式系统,为企业的信息化建设提供有力的支持。

… …

  ok,以上就是我这期的全部内容啦,如果还想学习更多,你可以看看如下的往期热文推荐哦,每天积累一个奇淫小知识,日积月累下去,你一定能成为令人敬仰的大佬。

「赠人玫瑰,手留余香」,咱们下期拜拜~~

🌊 热文推荐

滴~如下推荐【Spring Boot 进阶篇】的学习大纲,请小伙伴们注意查收。

Spring Boot进阶(01):Spring Boot 集成 Redis,实现缓存自由

Spring Boot进阶(02):使用Validation进行参数校验

Spring Boot进阶(03):如何使用MyBatis-Plus实现字段的自动填充

Spring Boot进阶(04):如何使用MyBatis-Plus快速实现自定义sql分页

Spring Boot进阶(05):Spring Boot 整合RabbitMq,实现消息队列服务

Spring Boot进阶(06):Windows10系统搭建 RabbitMq Server 服务端

Spring Boot进阶(07):集成EasyPoi,实现Excel/Word的导入导出

Spring Boot进阶(08):集成EasyPoi,实现Excel/Word携带图片导出

Spring Boot进阶(09):集成EasyPoi,实现Excel文件多sheet导入导出

Spring Boot进阶(10):集成EasyPoi,实现Excel模板导出成PDF文件

Spring Boot进阶(11):Spring Boot 如何实现纯文本转成.csv格式文件?

Spring Boot进阶(12):Spring Boot 如何获取Excel sheet页的数量?

Spring Boot进阶(13):Spring Boot 如何获取@ApiModelProperty(value = “序列号“, name = “uuid“)中的value值name值?

Spring Boot进阶(14):Spring Boot 如何手动连接库并获取指定表结构?一文教会你

Spring Boot进阶(15):根据数据库连接信息指定分页查询表结构信息

Spring Boot进阶(16):Spring Boot 如何通过Redis实现手机号验证码功能?

Spring Boot进阶(17):Spring Boot如何在swagger2中配置header请求头等参数信息

Spring Boot进阶(18):SpringBoot如何使用@Scheduled创建定时任务?

Spring Boot进阶(19):Spring Boot 整合ElasticSearch

Spring Boot进阶(20):配置Jetty容器

Spring Boot进阶(21):配置Undertow容器

Spring Boot进阶(22):Tomcat与Undertow容器性能对比分析

Spring Boot进阶(23):实现文件上传

Spring Boot进阶(24):如何快速实现多文件上传?

Spring Boot进阶(25):文件上传的单元测试怎么写?

Spring Boot进阶(26):Mybatis 中 resultType、resultMap详解及实战教学

Spring Boot进阶(27):Spring Boot 整合 kafka(环境搭建+演示)

Spring Boot进阶(28):Jar包Linux后台启动部署及滚动日志查看,日志输出至实体文件保存

Spring Boot进阶(29):如何正确使用@PathVariable,@RequestParam、@RequestBody等注解?不会我教你,结合Postman演示

Spring Boot进阶(30):@RestController和@Controller 注解使用区别,实战演示

… …

  若想系统完整的从0到1的学习,可以参考这篇专栏总结《2023最新首发,全网最全 Spring Boot 学习宝典(附思维导图)》,本专栏致力打造最硬核 Spring Boot 进阶系列学习内容,🚀均为全网独家首发,打造精品专栏,专栏持续更新中。欢迎大家订阅持续学习。

  如果想快速定位学习,可以看这篇【教程导航帖】导航目录,你想学习的都被收集在内,快速投入学习!!两不误。

  在入门及进阶之途,我必助你一臂之力,系统性学习,从入门到精通,带你不走弯路,直奔终点;投资自己,永远性价比最高,都这么说了,你还不赶紧来学??

  本文涉及所有源代码,均已上传至GitHub开源,供同学们一对一参考 GitHub传送门,同时,原创开源不易,欢迎给个star🌟,想体验下被🌟的感jio,非常感谢❗

📣文末

我是bug菌,CSDN | 阿里云 | 华为云 | 51CTO 等社区博客专家,历届博客之星Top30,掘金年度人气作者Top40,51CTO年度博主Top12,掘金 | InfoQ | 51CTO等社区优质创作者,全网粉丝合计15w+ ;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板等海量资料。

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

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

相关文章

APC学习记录

文章目录 APC概念APC插入、执行过程逆向分析插入过程执行过程总结 代码演示参考资料 APC概念 APC全称叫做异步过程调用&#xff0c;英文名是 Asynchronous Procedure Call&#xff0c;在进行系统调用、线程切换、中断、异常时会进行触发执行的一段代码&#xff0c;其中主要分为…

【Bond随你温故Kubernetes之】壹图复盘service与内部通信

最近跟朋友聊到了k8s 我&#xff1a; “环境给了就只管用呗&#xff0c;副本自动管理地妥妥的&#xff0c;有啥可以复盘的&#xff1f;“ 朋友&#xff1a; “容器的通讯与服务暴露还是有点东西的” 我&#xff1a; “嗯&#xff5e;&#xff5e;&#xff08;抿嘴点…

Android S从桌面点击图标启动APP流程 (六)

系列文章 Android S从桌面点击图标启动APP流程 (一)Android S从桌面点击图标启动APP流程 (二) Android S从桌面点击图标启动APP流程 (三) Android S从桌面点击图标启动APP流程 (四) Android S从桌面点击图标启动APP流程 (五) Android 12的源码链接&#xff1a; android 1…

基于Or-Tools的指派问题建模求解(PythonAPI)

基于Or-Tools的指派问题建模求解&#xff08;PythonAPI&#xff09; 指派问题&#xff08;又称为分配问题&#xff0c;assignment problem&#xff09;基于Or-Tools的指派问题建模求解&#xff08;PythonAPI&#xff09;导入pywraplp库数据准备声明MIP求解器初始化决策变量初始…

自然语言处理 (NLP) 简介

自然语言处理 &#xff08;Natural Language Processing NLP&#xff09; 简介 本课程是关于NLP 101的4部分系列中的第1部分&#xff1a; 自然语言处理导论&#xff08;今天的教程&#xff09;BagofWords模型简介Word2Vec&#xff1a;自然语言处理中嵌入的研究BagofWords与Wo…

3年轻量:腾讯云轻量2核2G4M应用服务器366三年!

腾讯云轻量应用服务器三年特价&#xff0c;3年轻量2核2G4M服务器&#xff0c;2023双十一优惠价格366元三年&#xff0c;自带4M公网带宽&#xff0c;下载速度可达512KB/秒&#xff0c;300GB月流量&#xff0c;50GB SSD盘系统盘&#xff0c;阿腾云atengyun.com分享腾讯云轻量2核2…

apk反编译修改教程系列-----修改apk中的图片 任意更换apk桌面图片【三】

往期教程&#xff1a; apk反编译修改教程系列-----修改apk应用名称 任意修改名称 签名【一】 apk反编译修改教程系列-----任意修改apk版本号 版本名 防止自动更新【二】 这次实例演示下如何更换apk安装后的桌面图标图片。其实这个步骤前面我有一个教程贴。这次针对步骤做个补…

C++初阶-类和对象(中)1

类和对象&#xff08;中&#xff09;1 一、类的6个默认成员函数二、构造函数概念特性 三、析构函数概念特性 四、拷贝构造函数概念特征 一、类的6个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类。 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何…

ASP.NET WebApi 极简依赖注入

文章目录 环境服务类启动项注入使用依赖注入的优点 环境 .NET Core 7.0ASP.NET CoreVisual Studio 2022 服务类 public class T_TempService {public T_TempService(){}public void Test(){}}启动项注入 #region 依赖注入 builder.Services.AddTransient<T_TempService&g…

【LeetCode力扣】189 53 轮转数组 | 最大子数组和

目录 1、189. 轮转数组 1.1、题目介绍 1.2、解题思路 2、53. 最大子数组和 2.1、题目介绍 2.2、解题思路 1、189. 轮转数组 1.1、题目介绍 原题链接&#xff1a;189. 轮转数组 - 力扣&#xff08;LeetCode&#xff09; ​ 示例 1: 输入: nums [1,2,3,4,5,6,7], k 3输…

Android数据对象序列化原理与应用

序列化与反序列化 序列化是将对象转换为可以存储或传输的格式的过程。在计算机科学中&#xff0c;对象通常是指内存中的数据结构&#xff0c;如数组、列表、字典等。通过序列化&#xff0c;可以将这些对象转换为字节流或文本格式&#xff0c;以便在不同的系统之间进行传输或存…

ChineseChess4 2023.10.27

中国象棋残局&#xff1a;黑双卒压境&#xff0c;如何破黑中心卒 要么一将黑棋死棋&#xff0c;要么想法子把黑中卒干掉&#xff0c;而且干掉中卒&#xff0c;基本要想用车去抽&#xff0c;也不知道棋局有问题呢&#xff0c;还是怎么回事&#xff0c;没想到。 中国象棋残局模拟…

重要环节不可忽视,CSS性能优化引领用户体验!

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 ⭐ 专栏简介 &#x1f4d8; 文章引言 一、前…

【驱动开发】基于GPIO子系统编写LED驱动,编写应用程序进行测试设置定时器,5秒钟打印一次hello world

基于GPIO子系统编写LED驱动&#xff0c;编写应用程序进行测试&#xff0c;设置定时器&#xff0c;5秒钟打印一次hello world 驱动程序&#xff1a; #include <linux/init.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_gpio.…

Tensorflow2 中模型训练标签顺序和预测结果标签顺序不一致问题解决办法

本篇文章将详细介绍Tensorflow2.x中模型训练标签顺序和预测结果标签顺序不一致问题&#xff0c;这个问题如果考虑不周&#xff0c;或者标签顺序没有控制好的情况下会出现预测结果精度极其不准确的情况。 训练数据集的结构&#xff1a;数据集有超过10的类别数&#xff0c;这里包…

全网最详细的大数据架构搭建配置及说明文档

版本兼容 JDK1.8.0_211ZooKeeper3.4.14Hadoop3.2.1Hive3.1.2HBase2.2.1Scala2.13.1Spark2.4.4MySQL5.7.28 基本配置 修改ip和主机名 主机名IP地址JavaZookeeperHadoopHiveHBaseSparkMySQLhadoop192.168.137.201√√√√√√slave1192.168.137.202√√√√√√slave2192.168…

如何在《倩女幽魂》游戏中使用搭建工具

如何在《倩女幽魂》游戏中使用搭建工具 S5 一键搭建脚本 进行 游戏礼包销售。 首先&#xff0c;定义在《倩女幽魂》游戏中使用搭建工具 S5 一键搭建脚本 进行 游戏礼包销售&#xff0c;需要完成以下几个步骤&#xff1a; 准备工作&#xff1a;确保您已经安装了华科云商软件&am…

Vite+Vue3项目全局引入scss文件

前言 Sass 是世界上最成熟、最稳定、最强大的专业级CSS扩展语言&#xff01;在日常项目开发过程中使用非常广泛&#xff0c;今天主要讲一下 ViteVue3 项目中该如何全局引入 scss 文件&#xff0c;引入混合 mixin 文件的不同配置。捎带说一下 Vue2 中的引入方式做一下简单的对比…

力扣:143. 重排链表(Python3)

题目&#xff1a; 给定一个单链表 L 的头节点 head &#xff0c;单链表 L 表示为&#xff1a; L0 → L1 → … → Ln - 1 → Ln请将其重新排列后变为&#xff1a; L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → … 不能只是单纯的改变节点内部的值&#xff0c;而是需要实际的进…

8通道模数转换AD7091驱动代码SPI接口ADC,verilog

名称&#xff1a;8通道模数转换AD7091驱动代码 软件&#xff1a;QuartusII 语言&#xff1a;Verilog 代码功能&#xff1a; 使用verilog代码设计AD7091R-8驱动代码 控制接口为SPI接口&#xff0c;实现8通道模数转换&#xff0c;输出8通道数字信号。 FPGA代码Verilog/VHDL代码…