最全面的SpringMVC教程(六)——WebSocket

article/2025/8/24 3:14:35

前言

在这里插入图片描述

本文为 【SpringMVC教程】WebSocket 相关知识介绍,具体将对WebSocket进行简介,并通过实战案例对WebSocket的使用进行详尽介绍~

📌博主主页:小新要变强 的主页
👉Java全栈学习路线可参考:【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~
👉算法刷题路线可参考:算法刷题路线总结与相关资料分享,内含最详尽的算法刷题路线指南及相关资料分享~
👉Java微服务开源项目可参考:企业级Java微服务开源项目(开源框架,用于学习、毕设、公司项目、私活等,减少开发工作,让您只关注业务!)

↩️本文上接:最全面的SpringMVC教程(五)——文件上传与下载


目录

文章标题

  • 前言
  • 目录
  • 一、WebSocket 简介
  • 二、WebSocket实战案例
  • 后记

在这里插入图片描述

一、WebSocket 简介

WebSocket 协议提供了一种标准化方式,可通过单个 TCP 连接在客户端和服务器之间建立全双工、双向通信通道。它是与 HTTP 不同的 TCP 协议,但旨在通过 HTTP 工作,使用端口 80 和 443。

WebSocket 交互以 HTTP 请求开始,HTTP请求中包含Upgrade: websocket 时,会切换到 WebSocket 协议。以下示例显示了这样的交互:

GET /spring-websocket-portfolio/portfolio HTTP/1.1
Host: localhost:8080
Upgrade: websocket 
Connection: Upgrade 
Sec-WebSocket-Key: Uc9l9TMkWGbHFD2qnFHltg==
Sec-WebSocket-Protocol: v10.stomp, v11.stomp
Sec-WebSocket-Version: 13
Origin: http://localhost:8080

成功握手后,HTTP 升级请求底层的 TCP 套接字保持打开状态,客户端和服务器都可以继续发送和接收消息。

🍀(1)HTTP 与 WebSocket

尽管 WebSocket 被设计为与 HTTP 兼容并从 HTTP 请求开始,但这两种协议会产生不同的架构和应用程序编程模型。

在 HTTP 和 REST 中,一个应用程序被建模为多个 URL。为了与应用程序交互,客户端访问这些 URL,请求-响应样式。服务器根据 HTTP URL、方法和请求头将请求路由到适当的处理程序。而在 WebSocket中,通常只有一个 URL 用于初始连接。随后,所有应用程序消息都在同一个 TCP 连接上流动。

我们现在有一个需求,就是页面要实时显示当前的库存信息:

短轮询方式:

最简单的一种方式,就是你用JS写个死循环(setInterval),不停的去请求服务器中的库存量是多少,然后刷新到这个页面当中,这其实就是所谓的短轮询。

这种方式有明显的坏处,那就是你很浪费服务器和客户端的资源。客户端还好点,现在PC机配置高了,你不停的请求还不至于把用户的电脑整死,但是服务器就很蛋疼了。如果有1000个人停留在某个商品详情页面,那就是说会有1000个客户端不停的去请求服务器获取库存量,这显然是不合理的。

长轮询方式:

长轮询这个时候就出现了,其实长轮询和短轮询最大的区别是,短轮询去服务端查询的时候,不管库存量有没有变化,服务器就立即返回结果了。而长轮询则不是,在长轮询中,服务器如果检测到库存量没有变化的话,将会把当前请求挂起一段时间(这个时间也叫作超时时间,一般是几十秒)。在这个时间里,服务器会去检测库存量有没有变化,检测到变化就立即返回,否则就一直等到超时为止。

而对于客户端来说,不管是长轮询还是短轮询,客户端的动作都是一样的,就是不停的去请求,不同的是服务端,短轮询情况下服务端每次请求不管有没有变化都会立即返回结果,而长轮询情况下,如果有变化才会立即返回结果,而没有变化的话,则不会再立即给客户端返回结果,直到超时为止。

这样一来,客户端的请求次数将会大量减少(这也就意味着节省了网络流量,毕竟每次发请求,都会占用客户端的上传流量和服务端的下载流量),而且也解决了服务端一直疲于接受请求的窘境。

但是长轮询也是有坏处的,因为把请求挂起同样会导致资源的浪费,假设还是1000个人停留在某个商品详情页面,那就很有可能服务器这边挂着1000个线程,在不停检测库存量,这依然是有问题的。

🍀(2)何时使用 WebSocket

WebSockets 可以使网页具有动态性和交互性。但是,在许多情况下,Ajax 和 HTTP 长轮询的组合可以提供简单有效的解决方案。

例如,新闻、邮件和社交提要需要动态更新,但每隔几分钟更新一次可能也完全没问题。另一方面,协作、游戏和金融应用程序需要更接近实时。

延迟本身并不是决定因素。如果消息量相对较低(例如监控网络故障),HTTP轮询可以提供有效的解决方案。低延迟、高频率和高容量的组合是使用 WebSocket 的最佳案例。

二、WebSocket实战案例

Spring Framework 提供了一个 WebSocket API,我们可以使用它来编写处理 WebSocket 消息的客户端和服务器端应用程序。

🍀(1)引入依赖

<dependency><groupId>org.springframework</groupId><artifactId>spring-websocket</artifactId><version>5.2.18.RELEASE</version>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-messaging</artifactId><version>5.2.18.RELEASE</version>
</dependency>  

🍀(2)创建 WebSocket 服务器需要实现WebSocketHandler接口或者直接扩展TextWebSocketHandlerBinaryWebSocketHandler这两个类,使用起来相对简单一点。以下示例使用TextWebSocketHandler

public class MessageHandler extends TextWebSocketHandler {Logger log = LoggerFactory.getLogger(MessageHandler.class);//用来保存连接进来sessionprivate List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();/*** 关闭连接进入这个方法处理,将session从 list中删除*/@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {sessions.remove(session);log.info("{} 连接已经关闭,现从list中删除 ,状态信息{}", session, status);}/*** 三次握手成功,进入这个方法处理,将session 加入list 中*/@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {sessions.add(session);log.info("用户{}连接成功.... ",session);}/*** 处理客户发送的信息,将客户发送的信息转给其他用户*/@Overridepublic void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {log.info("收到来自客户端的信息: {}",message.getPayload());session.sendMessage(new TextMessage("当前时间:"+LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss")) +",收到来自客户端的信息!"));for(WebSocketSession wss : sessions)if(!wss.getId().equals(session.getId())){wss.sendMessage(message);}}
}

🍀(3)有专用的 WebSocket Java 配置和 XML 命名空间支持,用于将前面的 WebSocket 处理程序映射到特定的 URL,如以下示例所示

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer{@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(new MessageHandler(), "/message").addInterceptors(new HttpSessionHandshakeInterceptor()).setAllowedOrigins("*"); //允许跨域访问}
}

以下示例显示了与前面示例等效的 XML 配置:

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:websocket="http://www.springframework.org/schema/websocket"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/websockethttps://www.springframework.org/schema/websocket/spring-websocket.xsd"><websocket:handlers><websocket:mapping path="/message" handler="myHandler"/><websocket:handshake-interceptors><bean class="org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor"/></websocket:handshake-interceptors></websocket:handlers><bean id="myHandler" class="com.wang.MessageHandler"/></beans>

🍀(4)使用原生js,用来访问websocket

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>websocket调试页面</title>
</head>
<body>
<div style="float: left; padding: 20px"><strong>location:</strong> <br /><input type="text" id="serverUrl" size="35" value="" /> <br /><button onclick="connect()">connect</button><button onclick="wsclose()">disConnect</button><br /> <strong>message:</strong> <br /> <input id="txtMsg" type="text" size="50" /><br /><button onclick="sendEvent()">发送</button>
</div><div style="float: left; margin-left: 20px; padding-left: 20px; width: 350px; border-left: solid 1px #cccccc;"> <strong>消息记录</strong><div style="border: solid 1px #999999;border-top-color: #CCCCCC;border-left-color: #CCCCCC; padding: 5px;width: 100%;height: 172px;overflow-y: scroll;" id="echo-log"></div><button onclick="clearLog()" style="position: relative; top: 3px;">清除消息</button>
</div></div>
</body>
<!-- 下面是h5原生websocket js写法 -->
<script type="text/javascript">let output ;let websocket;function connect(){ //初始化连接output = document.getElementById("echo-log")let inputNode = document.getElementById("serverUrl");let wsUri = inputNode.value;try{websocket = new WebSocket(wsUri);}catch(ex){console.log(ex)alert("对不起websocket连接异常")}connecting();window.addEventListener("load", connecting, false);}function connecting(){websocket.onopen = function(evt) { onOpen(evt) };websocket.onclose = function(evt) { onClose(evt) };websocket.onmessage = function(evt) { onMessage(evt) };websocket.onerror = function(evt) { onError(evt) };}function sendEvent(){let msg = document.getElementById("txtMsg").valuedoSend(msg);}//连接上事件function onOpen(evt){writeToScreen("CONNECTED");doSend("WebSocket 已经连接成功!");}//关闭事件function onClose(evt){writeToScreen("连接已经断开!");}//后端推送事件function onMessage(evt){writeToScreen('<span style="color: blue;">服务器: ' + evt.data+'</span>');}function onError(evt){writeToScreen('<span style="color: red;">异常信息:</span> ' + evt.data);}function doSend(message){writeToScreen("客户端A: " + message);websocket.send(message);}//清除div的内容function clearLog(){output.innerHTML = "";}//浏览器主动断开连接function wsclose(){websocket.close();}function writeToScreen(message){let pre = document.createElement("p");pre.innerHTML = message;output.appendChild(pre);}
</script>
</html>
ws:127.0.0.1:8088/app/message

我们可以看到在websocket的请求中有这样的首部信息:
在这里插入图片描述

而且我们多次发送消息,并没有新的请求产生:

在这里插入图片描述

小知识: 我们经常看到有很多地方使用sockjs完成websocket的建立,原因是一些浏览器中缺少对WebSocket的支持。SockJS是一个浏览器JavaScript库,它提供了一个连贯的、跨浏览器的Javascript API,它在浏览器和web服务器之间创建了一个低延迟、全双工、跨域通信通道。


后记

在这里插入图片描述
👉Java全栈学习路线可参考:【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~
👉算法刷题路线可参考:算法刷题路线总结与相关资料分享,内含最详尽的算法刷题路线指南及相关资料分享~


http://chatgpt.dhexx.cn/article/pVb7LChw.shtml

相关文章

SpringMVC教程(三)

SpringMVC&#xff1a;Hello,SpringMVC HelloSpringMVC 配置版 新建一个Moudle &#xff0c; 添加web的支持&#xff01;确定导入了SpringMVC 的依赖&#xff01; 配置web.xml &#xff0c; 注册DispatcherServlet <?xml version"1.0" encoding"UTF-8&quo…

史上最全最细的SpringMVC教程

SpringMVC是强大的Web开发框架&#xff0c;基于Spring。 课程从基础开始逐步讲解SpringMVC框架Web应用的相关技术点。涵盖了SpringMVC基础内容以及与Spring框架集成(如IoC容器、AOP等)等高级内容。 学习该课程后可以让我们能非常简单的设计出干净的Web层和薄薄的Web层。掌握强…

黑马程序员--SpringMVC详细教程

一、SpringMVC概述 SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架&#xff0c;属于 SpringFrameWork 的后续产品&#xff0c;已经融合在 Spring Web Flow 中。 SpringMVC 已经成为目前最主流的MVC框架之一&#xff0c;并且随着Spring3.0 的发…

史上最全的SpringMVC教程,终于整理出来了

1. 为啥要学 SpringMVC&#xff1f; 1.1 SpringMVC 简介 在学习 SpringMVC 之前我们先看看在使用 Servlet 的时候我们是如何处理用户请求的&#xff1a; 配置web.xml <?xml version"1.0" encoding"UTF-8"?> <web-app xmlns"http://xml…

史上最全面最易懂的,Spring框架学习教程

Spring通过PlatformTransactionManager平台事务管理器接口对事务的管理进行高度抽象&#xff0c;但是该接口下具体的实现是由各个平台自己实现&#xff0c;Spring并不直接管理事务&#xff0c;而是提供了多种事务管理器&#xff0c;也就是对各个平台的事务管理进行封装&#xf…

Spring 入门教程

Spring 入门教程 1、参考资料 尚硅谷-Spring5框架最新版教程&#xff08;idea版&#xff09;雷丰阳spring、springmvc、mybatis、spring一站式学习 项目地址&#xff1a;Oneby / spring-learn 2、Spring 概述 2.1、Spring 框架概述 Spring 是轻量级的开源的 JavaEE 框架 Sp…

spring框架教程

Spring框架 一、spring简介 简介&#xff1a;spring框架是一个轻量级的控制反转和面向切面的容器框架&#xff0c;用来解决项目开发中的复杂度问题–解耦 轻量级&#xff1a;体积小&#xff0c;对代码没有侵入性&#xff08;代码侵入性&#xff1a;指的是业务代码中不会调用sp…

一文学会Spring,Spring最简单的入门教程(万字好文)

1.Spring概述 1.1 Spring框架是什么 ​ Spring是与2003年兴起的一个轻量级的Java开发框架&#xff0c;它是为了解决企业应用开发的复杂性而创建的。Spring的核心是控制反转(IOC)和面向切面编程(AOP)。Spring是可以在Java SE/EE中使用的轻量级开源框架。 ​ Spring的主要作用…

lcx 内网转发

把放置到已经控制的内网主机 执行 内网主机输入命令lcx.exe -slave 外网ip 外网端口 内网ip 内网端口lcx.exe -slave 30.1.85.55 2222 127.0.0.1 3389 外网主机输入命令lcx.exe -listen 2222 3388 打开 mstsc ip&#xff1a;3388

lcx使用

lcx使用 win7 192.168.5.101 win 10 192.168.0.31 kali 192.168.5.102 lcx 本机: lcx -listen 2222 3333 2222为转发端口&#xff0c;3333为本机任意未被占用的端口 肉鸡&#xff1a;lcx -slave 2.2.2.2 2222 127.0.0.1 3389 2.2.2.2 为本机IP,2222为转发端口&#xff0c;…

lcx实现端口转发

LCX转发实验一 环境&#xff1a;内网3389端口不对外开放&#xff0c;但是1234端口对外开放&#xff08;正向连接&#xff09; lcx .exe –tran 1234 127.0.0.1 3389过程&#xff1a;192.168.1.105: 1234 -> 3389 LCX转发实验二 环境&#xff1a;内网主机可以访问外网80端口…

端口转发lcx工具+nc反弹工具使用

一、lcx工具 lcx.exe是一个端口转发工具&#xff0c;有Windows版和Linux版两个版本&#xff0c;Windows版是lcx.exe,Linux版为portmap&#xff0c; Windows版使用方法如下&#xff1a; 1、 lcx 内网端口转发 本机IP:192.168.1.10 目标机IP&#xff1a;192.168.1.5 本机运行…

lcx的使用-内网穿透

lcx有两个功能映射(slave)和转发(tran) 简单看个列子&#xff1a; 映射(slave) 第一步&#xff1a; 我在攻击机上执行此命令 lcx -listen 3333 2222此命令表示我监听3333端口&#xff0c;并把3333端口映射到2222端口 第二步&#xff1a; 我在靶机上执行此命令&#xff1a; …

流量映射端口反弹(lcx,ew)

转载自西梅哥的有道云&#xff1a; https://note.youdao.com/ynoteshare1/index.html?ida6bf797cce0b6087cb78b44818dca69f&typenote 内网应用 一、端口转发工具&#xff1a; 1.LCX&#xff08;支持双系统&#xff09; A、window&#xff08;LCX&#xff09; 上传一些…

利用lcx作端口映射

端口映射 端口映射就是将内网中的主机的一个端口映射到外网主机的一个端口&#xff0c;提供相应的服务。 当用户访问外网IP的这个端口时&#xff0c;服务器自动将请求映射到对应局域网内部的机器上。比如&#xff0c;我们在内网中有一台Web服务器&#xff0c;但是外网中的用户…

Lcx端口转发初探

最近写了一个简单的威胁分析专家系统Gui图形界面工具&#xff0c;可以快速判断失陷主机&#xff0c;给出失陷隶属度&#xff0c;非常人性化&#xff0c;压缩包大小有20M。实际上&#xff0c;这个小工具可以帮助一线驻场人员&#xff0c;快速定位高危主机&#xff0c;并给所有主…

隐藏隧道通信:lcx 端口转发

郑重声明&#xff1a; 本笔记编写目的只用于安全知识提升&#xff0c;并与更多人共享安全知识&#xff0c;切勿使用笔记中的技术进行违法活动&#xff0c;利用笔记中的技术造成的后果与作者本人无关。倡导维护网络安全人人有责&#xff0c;共同维护网络文明和谐。 隐藏隧道通信…

lcx端口转发linux_技术干货 | 内网渗透之代理转发

1 前言 谈到内网转发&#xff0c;在我们日常的渗透测试过程中经常会用到端口转发&#xff0c;可以利用代理脚本将内网的流量代理到本地进行访问&#xff0c;这样极大的方便了我们对内网进行横向渗透。 那为什么不直接通过登陆服务器来对内网中其他机器进行渗透&#xff0c;而是…

lcx用法

lcx.exe是一个端口转发工具&#xff0c;有Windows版和Linux版两个版本&#xff0c;Windows版是lcx.exe,Linux版为portmap Windows版使用方法如下&#xff1a; lcx有两大功能&#xff1a; 1&#xff09;端口转发(listen和slave成对使用) 2&#xff09;端口映射(tran) 1、lcx 内网…

lcx端口转发

lcx端口转发&#xff1a; 本文主要通过讲解lcx的本地端口及远程端口转发&#xff0c;让能熟练使用lcx端口转发工具&#xff0c;对端口转发知识有更加深入了解&#xff0c;本次实验靶场来源于暗月(moonsec)师傅,本文内容全由本人通过学习理解编制&#xff0c;文中若有错处&…