WebSocket Day02 : 握手连接

前言

        握手连接是WebSocket建立通信的第一步,通过客户端和服务器之间的一系列握手操作,确保了双方都支持WebSocket协议,并达成一致的通信参数。握手连接的过程包括客户端发起握手请求、服务器响应握手请求以及双方完成握手连接。完成握手连接后,客户端和服务器之间建立了一个持久性的双向通信链路,可以进行实时的数据传输。

       本次案例,使用 servlet 实现一个用户登录进入聊天室聊天。

一、前期准备

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>

        <!-- ch02 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.14.2</version>
        </dependency>

 让我逐个解释这些依赖项的作用:

  1. javax.websocket-api: 这是Java WebSocket API的依赖项,用于在Java应用程序中实现WebSocket通信。

  2. logback-classic: 这是Logback日志框架的经典实现,用于打印日志。

  3. lombok: 这是一个Java库,用于通过注解减少Java代码的样板代码量,提高代码的可读性和简洁性。

  4. javax.servlet-api: 这是Java Servlet API的依赖项,用于开发基于Java的Web应用程序。

  5. jackson-databind: 这是Jackson JSON处理库的依赖项,用于在Java应用程序中进行JSON数据的序列化和反序列化操作。

二、使用 servlet 实现登录功能

1、新建一个 loginServlet
/**
 * @Date 2023-11-01
 * @Author qiu
 * 用户登录
 */
@WebServlet("/login")
public class LoginServlet extends HttpServlet {


    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String userName = req.getParameter("userName");

        // 将用户名保存到 HttpSession
        req.getSession().setAttribute("user",userName);

        // 重定向到聊天的首页
        resp.sendRedirect("chat.html");

    }
}

让我来逐行解释这段代码的功能:

  1. @WebServlet("/login"):这是一个Servlet注解,指定了该Servlet对应的URL路径为"/login"。当客户端发送带有"/login"路径的请求时,Servlet容器将调用该Servlet来处理请求。

  2. public class LoginServlet extends HttpServlet:这是一个命名为LoginServlet的Java类,它继承自HttpServlet类,表示它是一个Servlet。

  3. protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException:这是Servlet的service方法,它负责处理客户端的请求并返回响应。HttpServletRequest对象提供了关于HTTP请求的信息,而HttpServletResponse对象用于设置HTTP响应。

  4. String userName = req.getParameter("userName");:从HTTP请求中获取名为"userName"的参数值,并将其存储在一个名为userName的字符串变量中。这里假设前端通过HTTP请求将用户名作为参数传递给后端。

  5. req.getSession().setAttribute("user",userName);:使用HttpServletRequest的getSession()方法获取当前会话的HttpSession对象,并使用setAttribute()方法将用户名存储在名为"user"的属性中。这样,在整个会话期间,可以通过getAttribute()方法来访问和使用该属性。

  6. resp.sendRedirect("chat.html");:使用HttpServletResponse的sendRedirect()方法将响应重定向到"chat.html"页面。这意味着登录成功后,用户将被重定向到聊天页面。

以上就是这段代码的功能。它通过获取用户输入的用户名,并将其保存到会话中,实现了用户登录的功能。然后,通过重定向将用户导航到聊天页面。

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

让我来逐行解释这段代码的功能: 

  1. <form name="f1" method="post" action="login">:这是一个表单(form标签),用于接收用户输入的登录信息,并将其提交到名为"login"的URL路径。

  2. Name:<input type="text" name="userName"/>:这是一个文本输入框(input标签),用于用户输入用户名。name属性指定了该输入框的名称为"userName",以便后端能够通过该名称获取用户输入的值。

  3. <input type="submit" value="登录">:这是一个提交按钮(input标签),用于提交表单数据。当用户点击该按钮时,表单中的数据将被发送到服务器进行处理。

三、握手连接

1、新建一个 消息对象 实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Message {

    /**
     * 发送人
     */
    private String fromUser;

    /**
     * 发送时间
     */
    private String sendTime;

    /**
     * 发送内容
     */
    private String content;

}

让我来逐行解释这段代码的功能:

  1. @Data:这是一个Lombok注解,自动生成getter、setter、equals、hashCode和toString方法等常见的代码。

  2. @AllArgsConstructor:这是一个Lombok注解,自动生成一个包含所有属性的构造函数。

  3. @NoArgsConstructor:这是一个Lombok注解,自动生成一个无参构造函数。

  4. public class Message:这是一个命名为Message的Java类。

  5. private String fromUser;:这是一个私有的字符串类型变量,表示消息的发送人。

  6. private String sendTime;:这是一个私有的字符串类型变量,表示消息的发送时间。

  7. private String content;:这是一个私有的字符串类型变量,表示消息的内容。

以上就是这段代码的功能。它定义了一个Message类,用于表示一条消息的数据结构。该类包含了发送人、发送时间和发送内容三个属性,并使用Lombok注解简化了相应的代码编写工作。通过创建Message对象,可以方便地操作和传递消息的相关信息。

2、握手连接处理类

public class WebSocketHandshake extends Configurator {

    /**
     * 重写握手处理方法
     * @param sec
     * @param request  请求对象
     * @param response 响应对象
     */
    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
        // 获取 HttpSession 对象
        HttpSession httpSession = (HttpSession)request.getHttpSession();

        // 获取用户名
        String userName = (String) httpSession.getAttribute("user");

        // 将用户名保存到当前用户连接 websocket 的 session 中
        sec.getUserProperties().put("user",userName);

    }


}

让我来逐行解释这段代码的功能:

  1. public class WebSocketHandshake extends Configurator:这是一个命名为WebSocketHandshake的Java类,继承了Configurator类。

  2. @Override:这是一个注解,表示该方法重写了父类或接口的方法。

  3. public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response):这是一个公共的无返回值方法,用于修改WebSocket握手过程中的处理逻辑。它接受三个参数:

    • sec:ServerEndpointConfig对象,用于配置WebSocket端点。
    • request:HandshakeRequest对象,表示握手请求。
    • response:HandshakeResponse对象,表示握手响应。
  4. HttpSession httpSession = (HttpSession)request.getHttpSession();:获取握手请求中的HttpSession对象,用于获取用户相关的会话信息。

  5. String userName = (String) httpSession.getAttribute("user");:从HttpSession对象中获取名为"user"的属性,即用户名。

  6. sec.getUserProperties().put("user",userName);:将获取到的用户名保存到当前用户连接WebSocket的session中。通过sec.getUserProperties()可以获取到与当前用户连接相关的会话属性,这里将用户名保存在"user"属性中。

以上就是这段代码的功能。它通过重写WebSocket握手处理方法,在握手过程中获取并保存了用户名,以便后续在WebSocket连接中使用。

1)为什么需要这个类握手处理类

这个类是用于在WebSocket握手过程中获取并保存用户名的。WebSocket是一种基于TCP协议的全双工通信协议,它通过在客户端和服务器之间建立持久连接,实现实时的双向通信。

在实际应用中,往往需要对连接WebSocket的用户进行身份验证和权限控制。而在WebSocket握手过程中,可以通过HTTP协议传递一些额外的信息,比如用户的身份信息。为了在后续的WebSocket连接中能够对用户进行身份验证和权限控制,我们需要将用户相关的信息保存起来。

这个WebSocketHandshake类的作用就是在WebSocket握手过程中,获取用户的身份信息(这里是用户名),并将其保存到当前用户连接的WebSocket会话中。通过在握手过程中获取用户名,并将其保存在WebSocket的session中,我们可以在后续的WebSocket连接中使用这个信息进行身份验证和权限控制。

因此,这个类的存在是为了方便在WebSocket应用中获取和保存用户信息,以便后续进行进一步的处理和控制。

3、服务端

@Slf4j
@ServerEndpoint(value = "/connect",configurator = WebSocketHandshake.class)
public class ChatServer {
    // 用户列表,key 为用户 id 或者是 name,
    // value 则是每一个客户端的 Session
    private static Map<String,Session> users = new HashMap<>();

    @OnOpen
    public void onOpen(Session session){
        // 添加用户到用户列表
        String userName = (String) session.getUserProperties().get("user");
        // 添加到用户列表中
        users.put(userName,session);
    }

    @OnMessage
    public void onMessage(String message,Session session) throws Exception {
        // 获取发送人
        String formUser = (String) session.getUserProperties().get("user");
        // 创建发送时间
        String sendTime = new SimpleDateFormat("hh:mm").format(new Date());
        // 封装消息对象并序列化为 JSON
        Message msg = new Message(formUser,sendTime,message);
        String jsonMessage = new ObjectMapper().writeValueAsString(msg);
        log.info(jsonMessage);
        // 群发给所有人
        for (String userName : users.keySet()){
            Session s = users.get(userName);
            s.getBasicRemote().sendText(jsonMessage);
        }
    }

    @OnClose
    public void onClose(Session session){
        // 将用户移除在线列表
        String userName = (String) session.getUserProperties().get("user");
        users.remove(userName);
    }

}

这是一个基于Java实现的WebSocket聊天室后端代码。

首先,在websocket包下,使用了@ServerEndpoint(value = "/connect")注解声明了一个WebSocket服务端,对应的WebSocket地址为/connect

接下来,代码中定义了一个静态变量users,用来存储所有连接到该WebSocket服务端的用户Session。在用户连接WebSocket服务器时,通过@OnOpen注解声明的方法将用户Session添加到用户列表中。

@OnMessage注解声明的方法中,当WebSocket服务端接收到客户端发送的消息时,先获取发送人和发送时间,然后封装成一个Message对象并序列化成JSON格式。然后遍历用户列表,将消息发送给每一个客户端。

最后,在@OnClose注解声明的方法中,当一个用户关闭连接时,将其从用户列表中移除。

需要注意的是,在上述代码中还使用了@ServerEndpoint注解的configurator参数,通过自定义WebSocketHandshake类实现了WebSocket握手过程的一些特殊处理。具体可查看WebSocketHandshake类的实现。

总的来说,这是一个简单的WebSocket聊天室后端实现,通过Java提供的WebSocket API完成了对WebSocket连接的管理和消息的广播。

4、新建一个客户端聊天页面
<!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>

这是一个简单的前端实现,用于创建一个基本的聊天室界面,并通过WebSocket协议与服务器进行通信。下面逐行详细讲解代码的功能和实现。

  1. <script src="js/JQuery文件.txt.js"></script>:引入一个JavaScript文件,其中包含了JQuery库的代码。

  2. <h1>聊天室</h1>:在页面中插入一个标题,显示为"聊天室"。

  3. <div id="msg">:定义一个div元素,用于显示聊天消息。

  4. <input type="text" id="message"/>:创建一个文本输入框,用户可以在其中输入消息。

  5. <input type="button" value="发送"/><br>:创建一个按钮,用于发送消息。

  6. <script>:JavaScript代码的开始标签。

  7. var ws = new WebSocket("ws://localhost:8080/connect");:创建一个WebSocket对象,连接到指定的服务器地址(这里是"ws://localhost:8080/connect")。

  8. ws.onmessage:WebSocket对象的onmessage事件,用于接收从服务器发送的消息。

  9. let data = event.data;:将接收到的消息内容存储在变量data中。

  10. data = $.parseJSON(data);:使用JQuery库中的parseJSON函数,将接收到的json格式消息转换为json对象。

  11. $('#msg').append(data.fromUser + " : " + data.sendTime + "<br>");:将消息发送者和发送时间显示在页面上。

  12. $('#msg').append(data.content + "<br>");:将消息内容显示在页面上。

  13. $('button').on('click', function () {:当用户点击按钮时触发一个匿名函数。

  14. let msg = $('#message').val();:获取文本输入框中的消息内容,并存储在变量msg中。

  15. ws.send(msg);:通过WebSocket发送消息给服务器。

  16. $('#message').val('');:清空文本输入框。

  17. </script>:JavaScript代码的结束标签。

总体来说,这段代码实现了一个简单的聊天室界面,用户可以在文本输入框中输入消息,点击发送按钮后,消息会通过WebSocket协议发送给服务器。同时,页面会接收服务器返回的消息并将其显示在页面上。但需要注意的是,这只是前端部分的实现,后端代码和服务器的支持是实现完整聊天室功能的必要条件。

5、运行效果

本次案例就是通过实现用户的登录,然后把用户名保存到作用域中,然后再从作用域中获取用户名实现的一个多人聊天案例。通过登录去获取到进入聊天室的人是谁。 

四、gitee 案例

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

优雅的 Dockerfile 是怎样炼成的?

Docker 简介 目前&#xff0c;Docker 主要有两个形态&#xff1a;Docker Desktop 和 Docker Engine。 Docker Desktop 是专门针对个人使用而设计的&#xff0c;支持 Mac&#xff08;已支持arm架构的M系芯片&#xff09; 和 Windows 快速安装&#xff0c;具有直观的图形界面&a…

【教3妹学编程-算法题】117. 填充每个节点的下一个右侧节点指针 II

2哥 : 3妹&#xff0c;听说你昨天去面试了&#xff0c;怎么样啊&#xff1f; 3妹&#xff1a;嗨&#xff0c;别提了&#xff0c;让我回去等通知&#xff0c;估计是没有通知了&#xff0c; 还浪费我请了一天假。 2哥 : 你又请假了啊&#xff0c; 你是怎么跟你那个严厉的老板请假…

微服务架构之路1,服务如何拆分?使用微服务的注意事项?

目录 一、前言二、单体服务的弊端三、微服务化四、服务如何拆分&#xff1f;1、拆分原则2、拆分时机和拆分方法3、拆分实践 五、使用微服务的注意事项1、确保相关业务和利益相关者的支持2、确定微服务的拆分粒度3、遵循微服务架构的原则4、确保接口的稳定性5、关注数据一致性6、…

postMessage

A:端口3000 import React, { useEffect } from react;function App() {useEffect(() > {const childWindow document.getElementById(child).contentWindow;const sendMessageToChild () > {childWindow.postMessage("主页面消息", "http://localhost:…

【QT5之QFtp模块】编译及使用

下载 传送门&#xff1a;https://github.com/qt/qtftp 或者 git clone https://github.com/qt/qtftp.git 下载ZIP&#xff0c;解压待用。 编辑 使用QtCreator打开qtftp.pro; 修改如下&#xff1a; qtftp.pro中&#xff0c;将第21行注释; src/qftp.pro中&#xff0c;将第4行…

Java程序设计2023-第四次上机练习

8-1 三子棋 编写程序&#xff0c;实现简单的三子棋游戏。在三子棋中&#xff0c;双方在33的棋盘中轮流下棋&#xff0c;一方用*示&#xff0c;另一方用O表示。如果一方的3个棋子占据了同一行&#xff0c;同一列或者对角线&#xff0c;则该方获胜。如果棋盘已被棋子占满&#x…

设置DevC++支持c++11标准

1.点击编译选项 2. 设置语言标准 3.点击确认 4.测试代码 使用auto成功 测试&#xff01;

【漏洞复现】Apache_HTTPD_多后缀解析漏洞

感谢互联网提供分享知识与智慧&#xff0c;在法治的社会里&#xff0c;请遵守有关法律法规 文章目录 1.1、漏洞描述1.2、漏洞复现1、基础环境2、漏洞验证 1.3、深度利用GetShell 1.4、修复建议 1.1、漏洞描述 Apache HTTPD 支持一个文件拥有多个后缀&#xff0c;并为不同后缀执…

统计学习方法 条件随机场

文章目录 统计学习方法 条件随机场随机场马尔可夫随机场定义因子分解 条件随机场定义参数化形式简化形式矩阵形式 概率预测问题前向-后向算法概率的计算期望值的计算 学习问题改进的迭代尺度法拟牛顿法 解码问题 统计学习方法 条件随机场 学习李航的《统计学习方法》时&#x…

STM32 IAP应用开发--bootloader升级程序

STM32 IAP应用开发--bootloader升级程序 Chapter1 STM32 IAP应用开发——通过串口/RS485实现固件升级&#xff08;方式2&#xff09;前言什么是IAP&#xff1f;什么是BootLoader&#xff1f; 方案介绍&#xff1a;1&#xff09;bootloader部分&#xff1a;2&#xff09;APP部分…

基于单片机的胎压监测系统的设计

收藏和点赞&#xff0c;您的关注是我创作的动力 文章目录 概要 一、系统整体设计方案二、 系统设计4.1 主流程图 三 系统仿真5.1 系统仿真调试实物 四、 结论 概要 本文以STC89C52单片机为控制核心&#xff0c;通过气压传感器模块对汽车各轮胎的胎压进行实时数据的采集与处理&…

【数据结构】树与二叉树(二):树的表示C语言:树形表示法、嵌套集合表示法、嵌套括号表示法 、凹入表示法

文章目录 5.1 树的基本概念5.1.1 树的定义5.1.2 森林的定义5.1.3 树的术语5.1.4 树的表示1&#xff0e;树形表示法2&#xff0e;嵌套集合表示法结构体创建树主函数 3&#xff0e;嵌套括号表示法结构体创建树嵌套括号表示法主函数 4&#xff0e;凹入表示法结构体创建树凹入表示法…

IDEA 设置代码注释模板

功能简介&#xff1a; 每次看别人代码时&#xff0c;面对毫无注释的类&#xff0c;除了头大还是头大&#xff0c; 以下提供了一种代码类注释模板 新建java类的时候&#xff0c;自动增加类注释&#xff0c;养成代码开发好习惯 效果展示&#xff1a; 代码模板&#xff1a; #if (…

多媒体应用设计师 2023年(含答案回忆版)

以下是小红书上的回忆版 软考考完疯狂回忆&#xff0c;多媒体应用设计师选择题 1.pattern 2.effective 3.merge 4.applications 5.graphic 6.udp 7.rtp 8.rtsp 9.10cm 10.永久 11…97 12.工作技术管理标准 13.管理型元数据 14.premiere 15.wave 16.500km/h 17.3M 18.44000 19.…

Capto2024专为Mac电脑设计的屏幕录制和视频编辑软件

不得不说视频编辑功能&#xff1a;Capto提供了多种视频编辑功能&#xff0c;例如剪辑、旋转、裁剪、调整音频和视频的音量、加入水印、添加注释等&#xff0c;你能够使用Capto编辑你的视频&#xff0c;使之更加专业和生动。有目共睹的是录制完成后&#xff0c;你能够使用Capto提…

深入理解WPF中的依赖注入和控制反转

在WPF开发中&#xff0c;依赖注入&#xff08;Dependency Injection&#xff09;和控制反转&#xff08;Inversion of Control&#xff09;是程序解耦的关键&#xff0c;在当今软件工程中占有举足轻重的地位&#xff0c;两者之间有着密不可分的联系。今天就以一个简单的小例子&…

Paddle炼丹炉炸了Unexpected BUS error encountered in DataLoader worker

Paddle训练报错&#xff0c;内存不足 python train.py -c config/ResNet_W18.yaml修改配置文件config/ResNet_W18.yaml # 原配置 loader:num_workers: 4use_shared_memory: True# 修改后 loader:num_workers: 2use_shared_memory: False

数据分析实战 | 关联规则分析——购物车分析

目录 一、数据及分析对象 二、目的及分析任务 三、方法及工具 四、数据读入 五、数据理解 六、数据预处理 七、生成频繁项集 八、计算关联度 九、可视化 一、数据及分析对象 数据集链接&#xff1a;Online Retail.xlsx 该数据集记录了2010年12月01日至2011年12月09日…

ChinaSoft 论坛巡礼 | 安全攸关软件的智能化开发方法论坛

2023年CCF中国软件大会&#xff08;CCF ChinaSoft 2023&#xff09;由CCF主办&#xff0c;CCF系统软件专委会、形式化方法专委会、软件工程专委会以及复旦大学联合承办&#xff0c;将于2023年12月1-3日在上海国际会议中心举行。 本次大会主题是“智能化软件创新推动数字经济与社…

贝锐向日葵亮相阿里云“云栖大会”:独创专利算法赋能全新云桌面

2023年10月31日-11月2日&#xff0c;一年一度的云栖大会如期举办&#xff0c;国产远程连接服务创领者贝锐受邀参与。活动现场&#xff0c;贝锐CTO张小峰进行了分享&#xff0c;宣布贝锐旗下国民级远程控制品牌“贝锐向日葵”与无影展开合作&#xff0c;同时全新的“云桌面”将于…