WebSocket Day03 : SpringMVC整合WebSocket

news2024/11/26 13:38:33

前言

在现代Web应用程序中,实时性和即时通信变得越来越重要。传统的HTTP请求-响应模式无法满足实时数据传输和双向通信的需求。随着技术的发展,WebSocket成为了一种强大而灵活的解决方案。 WebSocket是HTML5提供的一种新的通信协议,它通过一个持久化的、双向的连接,在客户端和服务器之间实现了实时的数据传输和双向通信。相比传统的HTTP请求-响应模式,WebSocket能够提供更低的延迟、更高的效率和更好的用户体验。 本文是“WebSocket 教程”系列的第三篇,将介绍如何将WebSocket与SpringMVC框架整合起来,以实现基于WebSocket的实时通信功能。我们将使用SpringMVC作为Web应用程序的基础框架,利用其强大的功能和易用的开发模式,结合WebSocket的优势,构建一个实时通信的应用程序。

一、WebSocket和SpringMVC的基本概念和原理

WebSocket是HTML5提供的一种通信协议,它允许在客户端和服务器之间建立一个持久化的、双向的连接,实现实时的数据传输和双向通信。相比传统的HTTP请求-响应模式,WebSocket具有以下特点:

  1. 双向通信:WebSocket允许客户端和服务器之间进行双向通信,而不仅仅是单向的请求-响应模式。这意味着服务器可以主动发送消息给客户端,而不需要客户端发起请求。

  2. 持久连接:一旦WebSocket连接建立成功,它将保持持久性的连接状态,不像HTTP请求-响应模式那样需要在每次请求后关闭连接。这样可以减少因频繁建立和关闭连接而产生的额外开销。

  3. 低延迟:由于WebSocket使用了长连接,数据传输的延迟相对较低。这使得实时性要求高的应用场景,如聊天应用、股票行情等,能够更好地满足用户的需求。

SpringMVC是一个基于Java的开源MVC(Model-View-Controller)框架,用于构建Web应用程序。它提供了强大的功能和灵活的开发模式,使得开发者可以轻松构建可扩展、可维护的Web应用程序。在整合WebSocket时,SpringMVC提供了对WebSocket的支持,简化了WebSocket的使用和管理。

SpringMVC框架中与WebSocket相关的几个核心概念包括:

  1. WebSocketHandler:WebSocketHandler是一个处理WebSocket连接和消息的接口,开发者需要实现该接口来处理不同类型的WebSocket消息。

  2. WebSocketSession:WebSocketSession代表一个WebSocket连接,它提供了一些方法来发送消息、关闭连接等操作。

  3. WebSocketConfigurer:WebSocketConfigurer是一个配置接口,用于配置WebSocket相关的参数和处理器。

  4. @EnableWebSocket:@EnableWebSocket注解用于启用WebSocket支持,将WebSocketConfigurer实例注册到SpringMVC的配置中。

通过使用SpringMVC提供的WebSocket支持,我们可以更方便地使用WebSocket,并且与SpringMVC的其他功能进行无缝整合。这使得开发者能够更加高效地构建实时通信的Web应用程

二、前期准备

1、新建项目,结构如下

2、导入依赖
<!-- websocket 依赖 -->
        <dependency>
            <groupId>javax.websocket</groupId>
            <artifactId>javax.websocket-api</artifactId>
            <version>1.1</version>
            <scope>provided</scope>
        </dependency>

        <!-- 打印日志 -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.3.8</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
        </dependency>

      
        <!-- ch03 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.23</version>
        </dependency>
        <!-- 在 spring 4.0 开始支持-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-websocket</artifactId>
            <version>5.3.23</version>
        </dependency>

 这些依赖项在Spring MVC项目中具有以下用途:

  1. javax.websocket-api:这个依赖项提供了WebSocket API的规范,包括用于创建和管理WebSocket连接的接口和类。它是WebSocket开发的基本依赖项。

  2. logback-classic:这是Logback日志框架的经典模块,用于记录应用程序的日志。它可以在开发过程中帮助调试和跟踪问题。

  3. lombok:Lombok是一个Java库,通过注解的方式简化了Java代码的编写。它提供了各种实用的注解,如@Data、@Getter、@Setter等,可以减少样板代码的编写。

  4. spring-webmvc:这是Spring MVC框架的核心模块,提供了处理Web请求的基本功能,包括控制器、视图解析器、数据绑定等。

  5. spring-websocket:这是Spring框架提供的WebSocket支持模块。它为Spring MVC应用程序启用了WebSocket功能,包括配置和管理WebSocket连接、处理WebSocket消息等。

以上是这些依赖项的常见用途。通过添加这些依赖项,您可以在Spring MVC项目中使用WebSocket,并处理来自客户端的实时消息。

三、在SpringMVC中配置和启用WebSocket支持 

 1、WebSocket 配置类

@Configuration
// 启用 WebSocket 支持
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    /**
     * 装配服务端
     * @return
     */
    @Bean
    public WebSocketHandler webSocketHandler(){
        return new ChatServer();
    }

    /**
     * 装配 HttpSession 的拦截器,这样就可以在握手阶段
     * 获取 HttpSession 的内容,在使用 WebSocketSession 时
     * 就能直接得到 HttpSession 的数据
     * @return
     */
    @Bean
    public HandshakeInterceptor handshakeInterceptor(){
        return new HttpSessionHandshakeInterceptor();
    }

    /**
     * 给服务端注册请求的端点(映射连接地址)
     * @param registry
     */
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        // 给 CharServer 设置连接的 url
        registry.addHandler(webSocketHandler(), "/connect")
        // 设置握手拦截器
        .addInterceptors(handshakeInterceptor());
    }
}

WebSocket的配置类,用于启用WebSocket支持并配置WebSocket相关的参数。

首先,我们使用@Configuration注解将该类标记为配置类。

然后,我们使用@EnableWebSocket注解启用WebSocket支持。

接下来,我们实现WebSocketConfigurer接口,并实现其中的方法。

registerWebSocketHandlers()方法中,我们通过registry.addHandler()方法注册一个WebSocket处理器(ChatServer)并指定连接的URL为"/connect"。同时,我们通过addInterceptors()方法添加一个握手拦截器(HttpSessionHandshakeInterceptor),这样就可以在握手阶段获取HttpSession的内容。

最后,我们使用@Bean注解分别装配了ChatServerHttpSessionHandshakeInterceptor的实例,并将其返回。

2、MvcConfig 配置类
@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

MVC的配置类,用于启用Spring MVC并配置默认的Servlet处理。

首先,我们使用@Configuration注解将该类标记为配置类。

然后,我们使用@EnableWebMvc注解启用Spring MVC支持。

接下来,我们实现了WebMvcConfigurer接口,并重写了其中的configureDefaultServletHandling()方法。

configureDefaultServletHandling()方法中,我们通过调用configurer.enable()方法启用默认的Servlet处理。这意味着将会使用Servlet容器提供的默认Servlet来处理静态资源,而不是通过DispatcherServlet来处理。

通常情况下,Spring MVC会使用DispatcherServlet作为前端控制器,负责处理所有的请求和响应。但有时候我们可能希望使用Servlet容器提供的默认Servlet来处理一些静态资源,例如图片、样式表和JavaScript文件等。通过调用configurer.enable()方法,我们可以启用默认的Servlet处理来处理这些静态资源。

3、AppConfig 配置类
@Configuration
@ComponentScan(basePackages = "edu.nf.ch03")
@Import({MvcConfig.class,WebSocketConfig.class})
public class AppConfig {
}

 首先,我们使用@Configuration注解将该类标记为配置类。

然后,我们使用@ComponentScan注解指定要扫描的基础包路径为edu.nf.ch03。这意味着Spring将会自动扫描该包及其子包下的所有组件,例如控制器、服务类、存储库等,并进行相应的装配和管理。

接下来,我们使用@Import注解导入了两个配置类:MvcConfigWebSocketConfig。通过将其他配置类导入到当前配置类中,可以实现不同配置之间的组合和共享。

最后,我们定义了一个AppConfig类作为整个应用的配置入口点。

4、WebConfig 配置类
public class WebConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[0];
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{AppConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

 这段代码是一个Web应用的配置类,用于初始化DispatcherServlet并指定配置类和URL映射。

首先,我们定义了一个名为WebConfig的类,并继承自AbstractAnnotationConfigDispatcherServletInitializer类。这是Spring提供的一个方便的初始化器类,用于在Java配置中使用注解配置DispatcherServlet。

然后,我们重写了getRootConfigClasses()方法,返回一个空数组。这意味着我们不需要在根应用上下文中加载其他的配置类,因为我们已经在getServletConfigClasses()方法中指定了要加载的配置类。

接下来,我们重写了getServletConfigClasses()方法,返回一个包含AppConfig.class的数组。这样就指定了要在DispatcherServlet的应用上下文中加载的配置类,即AppConfig

最后,我们重写了getServletMappings()方法,返回一个包含"/"的字符串数组。这样就指定了DispatcherServlet的URL映射为根路径/,表示所有请求都会被DispatcherServlet处理。

四、实现登录

1、新建 controller ,实现登录

@Controller
public class UserController {

    /**
     * 简单的用户登录
     * @param userName
     * @param session
     * @return
     */
    @PostMapping("/user/login")
    public String login(String userName, HttpSession session){
        // 将用户信息保存到会话作用域
        session.setAttribute("user",userName);

        // 重定向到聊天的首页
        return "redirect:/static/chat.html";
    }

}

这是一个基于Spring MVC的控制器类,用于处理用户登录请求。该类包含了一个login方法,该方法通过@PostMapping注解将请求映射到/user/login路径。

参数说明:

  • userName:表示用户输入的用户名。
  • session:表示HttpSession对象,用于保存用户信息。

方法逻辑:

  1. 将用户信息保存到会话作用域中,使用session.setAttribute("user", userName),其中"user"是属性名,userName是属性值。
  2. 通过返回"redirect:/static/chat.html"实现重定向到聊天首页。

总结:该login方法实现了用户登录的逻辑,并将用户信息保存到会话中,然后重定向到聊天首页。在实际应用中,需要进一步处理用户登录的验证、错误处理等逻辑。

 2、新建一个登录页面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>用户登录</h1>
<form name="f1" method="post" action="../user/login">
Name:<input type="text" name="userName"/>
<input type="submit" value="登录">
</form>
</body>
</html>

该页面包含了以下元素:

  1. <form>:HTML表单,用于向服务器端发送请求。
    • name="f1":表单的名称,用于JavaScript访问。
    • method="post":使用POST方法提交请求。
    • action="../user/login":指定表单提交的目标地址,即UserController类中的login方法的映射路径。
  2. <input type="text" name="userName"/>:用于输入用户名的文本框。
    • type="text":指定输入框的类型为文本框。
    • name="userName":指定输入框的名称,用于后台获取用户输入的用户名。
  3. <input type="submit" value="登录">:用于提交表单的按钮。
    • type="submit":指定按钮的类型为提交按钮。
    • value="登录":指定按钮上的文本为“登录”。

五、实现服务端发送信息

1、新建一个消息对象 Message

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Message {

    private String fromUser;
    private String sendTime;
    private String content;

}
 2、实现服务端聊天

public class ChatServer extends TextWebSocketHandler {

    /**
     * 用户列表
     * 每一个用户连接时都会创建一个 WebSocket 对象
     */
    private static final Map<String, WebSocketSession> users = new HashMap<>();

    /**
     * 客户端建立连接后执行的方法,等效于 onOpen 方法
     * @param session
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        // 获取登录的用户信息
        String userName = (String) session.getAttributes().get("user");
        // 保存到用户列表
        users.put(userName,session);
    }

    /**
     * 接受客户端的消息,等效于 onMessage 方法
     * @param session
     * @param message
     * @throws Exception
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        // 获取消息载体,也就是客户端发送的文本内容
        String msgContent = message.getPayload();
        // 获取发送人
        String fromUser = (String) session.getAttributes().get("user");
        // 发送时间
        String sendTime = new SimpleDateFormat("hh:mm").format(new Date());
        // 封装消息对象
        Message msg = new Message(fromUser,sendTime,msgContent);
        // 序列化为 JSON 字符串
        String json = new ObjectMapper().writeValueAsString(msg);
        // 群发给所有人
        for( String userName : users.keySet()){
            WebSocketSession s = users.get(userName);
            // 发送消息,必须是一个 TextMessage 的对象
            s.sendMessage(new TextMessage(json));
        }

    }

    /**
     * 连接关闭后执行的方法
     * @param session
     * @param status
     * @throws Exception
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        String userName = (String) session.getAttributes().get("user");
        // 将用户移除在线列表
        users.remove(userName);
    }
}

这是一个简单的聊天服务器的示例代码,使用WebSocket来实现客户端之间的即时通信。让我们逐行解析这段代码的功能和实现细节:

  1. Map<String, WebSocketSession> users:用于保存用户列表,每个用户连接时都会创建一个WebSocketSession对象。

  2. afterConnectionEstablished方法:在客户端与服务器建立连接后执行的方法。它从WebSocketSession中获取登录的用户信息,并将其保存到用户列表中。

  3. handleTextMessage方法:接收客户端发送的消息并进行处理。它从WebSocketSession中获取消息内容和发送人信息,然后封装成一个Message对象,并将其序列化为JSON字符串。接着,它通过遍历用户列表,将消息发送给所有在线用户。

  4. afterConnectionClosed方法:在客户端与服务器断开连接后执行的方法。它从WebSocketSession中获取断开连接的用户信息,并将其从用户列表中移除。

以上就是这段代码的主要功能和实现逻辑。需要注意的是,这只是一个简单的示例,实际的聊天服务器可能还需要处理更多的业务逻辑和异常情况。此外,这段代码使用了Spring框架提供的TextWebSocketHandler类,你需要确保正确地配置Spring WebSocket相关的依赖和配置文件。

3、新建聊天页面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="js/JQuery文件.txt.js"></script>
</head>
<body>
<h1>聊天室</h1>
<div id="msg">

    <input type="text" id="message"/>
    <input type="button" value="发送"/><br>


</div>

<script>

    // 创建 WebSocket 对象
    var ws = new WebSocket("ws://localhost:8080/connect");

    // 接受服务端的信息
    ws.onmessage = function (event) {
        // 将消息填充到 div 中
        let data = event.data;
        // 将 json 字符串 转换为 json 对象
        data = $.parseJSON(data);
        $('#msg').append(data.fromUser + " : " + data.sendTime + "<br>");
        $('#msg').append(data.content + "<br>");
    }


    $(function () {
        $(':button').on('click',function () {
            let msg = $('#message').val();
            // 发送消息
            ws.send(msg);

            // 发送完之后清空消息框
            $('#message').val('');
        })
    })


</script>

</body>
</html>

这是一个简单的聊天室的前端代码示例。让我们逐行解析这段代码的功能和实现细节:

  1. <div id="msg">:消息显示区域。

  2. <input type="text" id="message"/>:文本输入框,用于输入发送的消息内容。

  3. <input type="button" value="发送"/><br>:发送按钮。

  4. <script>:JavaScript脚本区域。

  5. var ws = new WebSocket("ws://localhost:8080/connect");:创建WebSocket对象,连接到服务器的地址是"ws://localhost:8080/connect"。

  6. ws.onmessage:监听WebSocket对象的onmessage事件,当接收到来自服务器的消息时执行相应的操作。

  7. let data = event.data;:获取接收到的消息数据。

  8. data = $.parseJSON(data);:将接收到的JSON字符串转换为JSON对象。

  9. $('#msg').append(data.fromUser + " : " + data.sendTime + "<br>");:将发送人和发送时间添加到消息显示区域。

  10. $('#msg').append(data.content + "<br>");:将消息内容添加到消息显示区域。

  11. $('button').on('click',function () {...}):监听发送按钮的点击事件。

  12. let msg = $('#message').val();:获取文本输入框中的消息内容。

  13. ws.send(msg);:通过WebSocket对象发送消息到服务器。

  14. $('#message').val('');:发送完消息后清空文本输入框。

以上就是这段前端代码的主要功能和实现逻辑。需要注意的是,这个示例代码使用了jQuery库来简化DOM操作和事件处理。你需要确保正确地引入jQuery库,并根据自己的实际情况修改WebSocket连接地址和其他相关代码。

 

 4、运行效果

六、gitee案例

地址:ch03 · qiuqiu/WebSocket-study - 码云 - 开源中国 (gitee.com)

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

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

相关文章

基于蛇优化算法的无人机航迹规划-附代码

基于蛇优化算法的无人机航迹规划 文章目录 基于蛇优化算法的无人机航迹规划1.蛇优化搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用蛇优化算法来优化无人机航迹规划。 1.蛇优化…

在jupyter中使用R

如果想在Jupyter Notebook中使用R语言&#xff0c;以下几个步骤操作可行&#xff1a; 1、启动Anaconda Prompt 2、进入R的安装位置&#xff0c;切换到R的安装位置&#xff1a;D:\Program Files\R\R-3.4.3\bin&#xff0c;启动R&#xff0c;具体代码操作步骤如下&#xff0c;在…

noip模拟赛多校第八场 T4 不要翻墙 (矩阵乘法优化DP, 动态DP)

题目描述 简要题意&#xff1a;太长了&#xff0c;就不总结了&#xff0c;自己看吧。 分析 我们首先考虑 m 1 m 1 m1 的情况&#xff1a; T > 0 T > 0 T>0 时&#xff0c;显然我们可以 O ( n ) O(n) O(n) 的维护一个 前缀积 和 前缀积的逆元&#xff0c…

基于鹈鹕算法的无人机航迹规划-附代码

基于鹈鹕算法的无人机航迹规划 文章目录 基于鹈鹕算法的无人机航迹规划1.鹈鹕搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用鹈鹕算法来优化无人机航迹规划。 1.鹈鹕搜索算法 …

x86汇编代码学习-计算机工作原理1

文章目录 前言1.CPU架构2.8086寄存器3. 指令流水线4.内存模型5.总线6.硬盘7 计算机启动过程BIOS8.BootLoader9.地址映射10.为什么boot loader要放在0x7c00这个位置&#xff1f;11 显卡是如何显示的12.汇编指令1.环境搭建 12 程序13 x86 汇编指令介绍 前言 x86汇编 详解x86汇编…

虚拟机联网 | 虚拟机连接Xshell

目录 一&#xff0c;打开网络虚拟编辑器二&#xff0c;打开网络设置三&#xff0c;最终设置四&#xff0c;测试有没有连上网五&#xff0c;测试连接工具Xshell 一&#xff0c;打开网络虚拟编辑器 1. 点击"编辑"&#xff0c;打开"虚拟网络编译器" 2. 选择更…

SHEIN要求卖家完成德国EPR合规,逾期将强制下架——站斧浏览器

EPR是卖家在欧盟自由销售的通行证之一&#xff0c;如果没有&#xff0c;是不允许在欧盟国家销售产品的。 近期根据SHEIN官方邮件通知&#xff0c;卖家需要在收到邮件后5天内完成申报&#xff0c;逾期申报产品将会在德国站点下架。 因此&#xff0c;建议卖家尽快通过合规的服务…

第八章《搞懂算法:逻辑回归是怎么回事》笔记

8.1 如何理解逻辑回归 逻辑回归根据给定的自变量数据集来估计事件的发生概率&#xff0c;由于结果是一个概率&#xff0c;因此因变量的范围在 0 和 1 之间。 逻辑回归的与线性回归一样&#xff0c;也是以线性函数为基础的&#xff1b;而与线性回归不同的是&#xff0c;逻辑回…

智能安全配电装置在银行配电系统中的应用

【摘要】银行是国家重点安全保护部分&#xff0c;关系到社会资金的稳定&#xff0c;也是消防重点单位&#xff0c;消防安全保障工作是银行工作的重要方面。智能安全配电装置应用在银行配电系统中&#xff0c;可以提升银行智能化管控水平和有效防范电气火灾的发生。 【关键词】…

【QT】QT自定义C++类

在使用Qt的ui设计时&#xff0c;Qt为我们提供了标准的类&#xff0c;但是在很多复杂工程中&#xff0c;标准的类并不能满足所有的需求&#xff0c;这时就需要我们自定义C类。 下面以自定义的QPushButton作一个很简单的例子。 先新建默认Qt Widgets Application项目 一、自定义…

从传统货架到智能货架电子标签PTL仓储亮灯系统的革新

在现代物流仓储行业中&#xff0c;仓库的管理和物料的寻找一直是一个难题。仓库内物料数量种类繁多&#xff0c;寻找物料耗时长、困难大&#xff0c;盘点更是耗费人力多、成本高、速度慢。此外&#xff0c;货物存储位置不清晰&#xff0c;经常性找不到物料。多发、少发、错料现…

首个流体力学大模型背后,是昇腾的大模型“造林”逻辑

作者 | 曾响铃 文 | 响铃说 一个飞机模型在试验风洞里&#xff0c;空气从它的机翼与机身流过&#xff0c;形成一层又一层稳定的气流&#xff0c;当风速加快&#xff0c;空气的流线开始波浪式摆动&#xff0c;最终随着速度增大而相互混合、形成不再能分辨的湍流&#xff0c;看…

大模型的实践应用5-百川大模型(Baichuan-13B)的模型搭建与模型代码详细介绍,以及快速使用方法

大家好,我是微学AI,今天给大家介绍一下大模型的实践应用5-百川大模型(Baichuan-13B)的模型搭建与模型代码详细介绍,以及快速使用方法。 Baichuan-13B 是由百川智能继 Baichuan-7B 之后开发的包含 130 亿参数的开源可商用的大规模语言模型,在权威的中文和英文 benchmark 上均…

【寒武纪(3)】媒体处理系统的系统控制、视频输入和后处理子系统

系统控制 文章目录 系统控制1、配置视频缓存池Video Pool2、配置硬件IP为在线工作&#xff08;不通过DDR数据交互&#xff09;/ 离线工作&#xff08;写入DDR&#xff09;模式3、硬IP可以使用 非Video Block &#xff08;VB&#xff09;内存4、配置是否启动内存传递的压缩 视频…

Elasticsearch:搜索架构

Elasticsearch 全文检索的复杂性 为了理解为什么全文搜索是一个很难解决的问题&#xff0c;让我们想一个例子。 假设你正在托管一个博客发布网站&#xff0c;其中包含数亿甚至数十亿的博客文章&#xff0c;每个博客文章包含数百个单词&#xff0c;类似于 CSDN。 执行全文搜索…

c++-红黑树

文章目录 前言一、红黑树1、红黑树的概念2、红黑树的性质3、红黑树节点的定义4、红黑树结点插入4.1 情况1&#xff1a;cur为红&#xff0c;p为红&#xff0c;g为黑&#xff0c;存在且为红4.2 情况2&#xff1a;cur为红&#xff0c;p为红&#xff0c;g为黑&#xff0c;u不存在/u…

Unity之NetCode多人网络游戏联机对战教程(6)--NetworkTransform组件

文章目录 前言NetworkTransform是什么玩家移动脚本NetworkTransform字段讲解Synchronizing ("Syncing")ThresholdsLocal spaceInterpolationSlerp PositionUse Quaternion SynchronizationUse Quaternion CompressionUse Half Float PrecisionAuthority modesServer …

银河E8,吉利版Model 3:5米大车身、45寸大屏、首批8295座舱芯

作者 | Amy 编辑 | 德新 吉利银河E8在曝光后多次引爆热搜&#xff0c;李书福更是赞誉有加&#xff0c;称其为「买了就直接享受」。这款备受瞩目的车型于 10月30日晚首次亮相。 虽然新车外观在今年上海车展上早已曝光&#xff0c;但这次的发布会却带来了不少惊喜。新车架构以及…

pytorch安装1

用豆瓣源安装pytorch1.5.1&#xff08;速度很快&#xff09;-CSDN博客 详情请参考这位神仙的博客 我真的哭死&#xff0c;原来torch都安装好了&#xff0c;好不容易全部加载好了&#xff0c;但是&#xff0c;gpu配不上去&#xff0c;后来发现还是版本的问题版本不匹配具体版本…

Element对象_属性

Element对象对应网页的HTML元素。每一个HTML元素&#xff0c;在DOM树上都会转化成一个Element节点对象&#xff08;以下简称元素节点&#xff09; 1、Element.id Element.id属性返回指定元素的id属性&#xff0c;该属性可读写 2、Element.className className属性用来读写当前…