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 {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String userName = req.getParameter("userName");// 将用户名保存到 HttpSessionreq.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 响应对象*/@Overridepublic 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 则是每一个客户端的 Sessionprivate static Map<String,Session> users = new HashMap<>();@OnOpenpublic void onOpen(Session session){// 添加用户到用户列表String userName = (String) session.getUserProperties().get("user");// 添加到用户列表中users.put(userName,session);}@OnMessagepublic void onMessage(String message,Session session) throws Exception {// 获取发送人String formUser = (String) session.getUserProperties().get("user");// 创建发送时间String sendTime = new SimpleDateFormat("hh:mm").format(new Date());// 封装消息对象并序列化为 JSONMessage 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);}}@OnClosepublic 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)

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

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

相关文章

Ipswitch WS_FTP 12 安裝

Ipswitch WS.FTP.Professional.12.6.rar_免费高速下载|百度网盘-分享无限制 This works but quite difficult to figure out. It didnt allow me to replace the wsftpext.dll at 1st and had to test lots of ways how to replace it. This is how I did: 1. Follow the instr…

【qemu逃逸】D3CTF2021-d3dev

前言 题目给的是一个 docker 环境&#xff0c;所以起环境非常方便&#xff0c;但是该怎么调试呢&#xff1f;有无佬教教怎么在 docker 中调试&#xff1f; 我本来想着直接起一个环境进行调试&#xff0c;但是缺了好的库&#xff0c;所以就算了&#xff0c;毕竟本题也不用咋调…

3+单细胞+代谢+WGCNA+机器学习

今天给同学们分享一篇生信文章“Identification of new co-diagnostic genes for sepsis and metabolic syndrome using single-cell data analysis and machine learning algorithms”&#xff0c;这篇文章发表Front Genet.期刊上&#xff0c;影响因子为3.7。 结果解读&#x…

微服务架构——笔记(1)

微服务架构——笔记&#xff08;1&#xff09; 文章来源B站视频 尚硅谷SpringCloud框架开发教程(SpringCloudAlibaba微服务分布式架构丨Spring Cloud)教程 own process 独立部署 &#xff08;1.微服务架构零基础理论&#xff09; 叙述 马丁福勒 架构模式&#xff0c;倡导将单…

图片批量归类:告别混乱,实现高效文件管理

在日常生活中&#xff0c;我们经常需要处理大量的图片文件。这些图片可能来自于不同的设备、不同的目录&#xff0c;甚至不同的存储介质。随着时间的推移&#xff0c;这些图片文件会越来越多&#xff0c;管理起来也会越来越困难。如何高效地整理这些图片文件&#xff0c;告别混…

Bytedance揭秘OpenAI大模型: GPT-3到GPT-4进化路径

文章目录 探秘GPT-3到GPT-4进化之路1、SFT&#xff1a;早期GPT进化的推动者2、RLHF和SFT&#xff1a;编码能力提升的功臣3、代码加入预训练&#xff0c;对推理帮助最大4、“跷跷板”现象 论文地址项目链接Reference GPT-Fathom: Benchmarking Large Language Models to Deciphe…

大数据毕业设计选题推荐-智慧小区大数据平台-Hadoop-Spark-Hive

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

差生文具多之(一)eBPF

前言 在问题排查过程中, 通常包含: 整体观测, 数据采集, 数据分析这几个阶段. 对于简单问题的排查, 可以跳过前两个步骤, 无需额外收集数据, 直接通过分析日志中的关键信息就可以定位根因; 而对于复杂问题的排查, 为了对应用的行为有更完整的了解, 可以通过以下形式收集更多的…

【MATLAB】基于灰狼优化算法优化BP神经网络 (GWO-BP)的数据回归预测

文章目录 效果一览文章概述订阅专栏只能获取一份代码部分源码参考资料效果一览 文章概述 【MATLAB】基于灰狼优化算法优化BP神经网络 (GWO-BP)的数据回归预测 在MATLAB中,基于灰狼优化算法优化BP神经网络(GWO-BP)进行数据回归预测的步骤如下: 数据准备:首先,将用于回归预…

深度学习_9_图片分类数据集

散装代码&#xff1a; import matplotlib.pyplot as plt import torch import torchvision from torch.utils import data from torchvision import transforms from d2l import torch as d2ld2l.use_svg_display()# 通过ToTensor实例将图像数据从PIL类型变换成32位浮点数格式…

城市内涝怎么预警?万宾科技内涝积水监测仪

在城市运行过程中&#xff0c;城市内涝问题频繁出现&#xff0c;影响城市管理水平的提升&#xff0c;也会进一步减缓城市基础设施建设。尤其近几年来&#xff0c;城市内涝灾害频繁出现&#xff0c;在沿海地区内涝所带来的安全隐患成为城市应急管理部门的心头大患。城市内涝的背…

Java 正则表达式分组匹配

前几篇文章都是简单判断是否满足匹配规则&#xff0c;当需要提取匹配结果时就用到分组匹配。 分组匹配 可以判断是否满足正则表达式&#xff0c;然后提取出子串。 有些时候电话号码是以 123-4567-8899 这样显示的&#xff0c;我们要判断某个字符串是这种形式的并分别提起三段…

从NetSuite Payment Link杂谈财务自动化、数字化转型

最近在进行信息化的理论学习&#xff0c;让我有机会跳开软件功能&#xff0c;用更加宏大的视野&#xff0c;来审视我们在哪里&#xff0c;我们要到哪去。 在过去20多年&#xff0c;我们的财务软件经历了电算化、网络化、目前处于自动化、智能化阶段。从NetSuite这几年的功能发…

【vue2高德地图api】04-poi搜索

系列文章目录 文章目录 系列文章目录前言一、高德地图文档入口二、使用步骤1.创建文件以及路由2.编写页面代码3.样式4变量以及方法5.编写查询方法 总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 本篇要实现的功能&#xff0c;看下图 提示&#x…

【从零开始学习Redis | 第五篇】基于布隆过滤器解决Redis的穿透问题

前言&#xff1a; 在如今的开发中&#xff0c;使用缓存中间件Redis已经成为一项很广泛的技术&#xff0c;Redis的高性能大大优化了我们的服务器性能&#xff0c;缓解了在高并发的情况下服务器的压力。它基于缓存的形式&#xff0c;在内存中保存数据&#xff0c;减少对磁盘的IO操…

制造行业数字化运维破局之道

项目背景 某大型汽车制造集团&#xff0c;致力于通过数字化、智能化运营手段为用户提升提供高品质的汽车产品和服务。IT部门不仅为内外部持续提供服务&#xff0c;同时为业务运营与核心系统运行提供重要支撑。数字化运维作为数字化转型的核心基础&#xff0c;不但要保障数据安…

网络编程 - HTTP协议

目录 HTTP协议格式 一&#xff0c;请求格式 1.1 URL的基本格式 1.2 方法(method) 1.3 请求头header 二&#xff0c;响应格式 2.1 状态码 HTTP协议格式 HTTP协议与之前讲的TCP/IP协议不同&#xff0c;HTTP协议要分为两个部分——请求和响应&#xff0c;也就是一种"一…

尚硅谷Docker基础篇和Dockerfile超详细整合笔记

Docker基础篇DockerFile Docker&#xff1a;您要如何确保应用能够在这些环境中运行和通过质量检测&#xff1f;并且在部署过程中不出现令人头疼的版本、配置问题&#xff0c;也无需重新编写代码和进行故障修复&#xff1f;而这个就是使用容器。Docker解决了运行环境和配置问题…

linux 创建git项目并提交到gitee(保姆式教程)

01、git安装与初始化设置 mhzzjmhzzj-virtual-machine:~/work/skynetStudy$ apt install mhzzjmhzzj-virtual-machine:~/work/skynetStudy$ git config --global user.name "用户名" mhzzjmhzzj-virtual-machine:~/work/skynetStudy$ git config --global user.ema…

Java 8 新特性 Stream 的使用场景(不定期更新)

方便在写代码的过程中直接使用&#xff0c;好记性不如好文章&#xff0c;直接 CV 改了直接用。提高 办&#xff08;摸&#xff09;公&#xff08;鱼&#xff09;效&#xff08;时&#xff09;率&#xff08;间&#xff09;&#xff0c; 不然就直接问 GPT 也不是说不行。 只符合…