SpringBoot整合WebSocket详细教程

news/2024/10/18 2:28:58/

预期效果

在这里插入图片描述

在这里插入图片描述
共开启两个页面,实现一对一聊天。

服务端代码:https://gitee.com/lianaozhe/springboot-websocket.git

代码实现逻辑

服务端

导入相关依赖:

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency><!-- hutool 工具包,各种封装功能 一应俱全--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.5</version></dependency>

WebSocketConfig配置类:

package com.web.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** @ClassName WebSocketConfig* @Description TODO* @Author laz* @Date 2023/4/26 16:18* @Version 1.0*/
@Configuration
public class WebSocketConfig {/*** 	注入ServerEndpointExporter,* 	这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint*/@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}}

WebSocket操作类:

package com.web.websocket;import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;/*** @ClassName WebSocket* @Description TODO* @Author laz* @Date 2023/4/26 16:20* @Version 1.0*/
@Component
@Slf4j
@ServerEndpoint("/websocket/{userId}")
public class WebSocket {//与某个客户端的连接会话,需要通过它来给客户端发送数据private Session session;/*** 用户ID*/private String userId;/*** 用来存放每个客户端对应的MyWebSocket对象。*/private static CopyOnWriteArraySet<WebSocket> webSockets =new CopyOnWriteArraySet<>();// 用来存在线连接用户信息private static ConcurrentHashMap<String,Session> sessionPool = new ConcurrentHashMap<String,Session>();/*** 链接成功调用的方法*/@OnOpenpublic void onOpen(Session session, @PathParam(value="userId")String userId) {try {this.session = session;this.userId = userId;webSockets.add(this);sessionPool.put(userId, session);log.info("【websocket消息】有新的连接,用户id是【{}】总数为【{}】",userId,webSockets.size());} catch (Exception e) {}}/*** 链接关闭调用的方法*/@OnClosepublic void onClose() {try {webSockets.remove(this);sessionPool.remove(this.userId);log.info("【websocket消息】连接断开,总数为:"+webSockets.size());} catch (Exception e) {}}/*** 收到客户端消息后调用的方法** @param message* @param message*/@OnMessagepublic void onMessage(String message) {log.info("【websocket消息】收到客户端消息:"+message);JSONObject jsonObject = JSONUtil.parseObj(message);Object toUserId = jsonObject.get("toUserId");Session session = sessionPool.get(toUserId);session.getAsyncRemote().sendText(JSONUtil.toJsonStr(jsonObject.get("msg")));}/** 发送错误时的处理* @param session* @param error*/@OnErrorpublic void onError(Session session, Throwable error) {log.error("用户错误,原因:"+error.getMessage());error.printStackTrace();}// 此为广播消息public void sendAllMessage(String message) {log.info("【websocket消息】广播消息:"+message);for(WebSocket webSocket : webSockets) {try {if(webSocket.session.isOpen()) {webSocket.session.getAsyncRemote().sendText(message);}} catch (Exception e) {e.printStackTrace();}}}// 此为单点消息public void sendOneMessage(String userId, String message) {Session session = sessionPool.get(userId);if (session != null&&session.isOpen()) {try {log.info("【websocket消息】 单点消息:"+message);session.getAsyncRemote().sendText(message);} catch (Exception e) {e.printStackTrace();}}}// 此为单点消息(多人)public void sendMoreMessage(String[] userIds, String message) {for(String userId:userIds) {Session session = sessionPool.get(userId);if (session != null&&session.isOpen()) {try {log.info("【websocket消息】 单点消息:"+message);session.getAsyncRemote().sendText(message);} catch (Exception e) {e.printStackTrace();}}}}}

TestController测试接口类:

package com.web.controller;import com.web.websocket.WebSocket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** @ClassName TestController* @Description TODO* @Author laz* @Date 2023/4/26 16:23* @Version 1.0*/
@RestController
@RequestMapping("web")
public class TestController {@Autowiredprivate WebSocket webSocket;@RequestMapping("test")public String test(String userId,String msg){webSocket.sendOneMessage(userId,msg);return "成功";}
}

客户端

test.html文件:

<!doctype html>
<html lang="zh-CN"><head><!-- 必须的 meta 标签 --><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"><!-- Bootstrap 的 CSS 文件 --><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css"integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous"><title>WebSocket1</title><style>form {width: 820px;margin: auto;}.div1 {width: 820px;height: 500px;border: #000000;border-width: thin;border-style: solid;}.div2 {text-align: center;width: 800px;height: 50px;}</style><script>function clearData() {$("#div1").html("");}var socket;function openSocket() {if (typeof(WebSocket) == "undefined") {console.log("您的浏览器不支持WebSocket");} else {console.log("您的浏览器支持WebSocket");//websocket地址var socketUrl = "ws://localhost:8088/websocket/20";console.log(socketUrl);if (socket != null) {socket.close();socket = null;}socket = new WebSocket(socketUrl);//打开事件socket.onopen = function() {console.log("websocket已打开");$("#div1").append("websocket已打开" + "<br \>");};//获得消息事件socket.onmessage = function(msg) {console.log(msg.data);$("#div1").append("接收到消息:" + msg.data + "<br \>");};//关闭事件socket.onclose = function() {console.log("websocket已关闭");$("#div1").append("websocket已关闭" + "<br \>");};//发生了错误事件socket.onerror = function() {console.log("websocket发生了错误");$("#div1").append("websocket发生了错误" + "<br \>");}}}function sendMsg() {if (typeof(WebSocket) == "undefined") {console.log("您的浏览器不支持WebSocket");} else {console.log("您的浏览器支持WebSocket");console.log('{"toUserId":"' + $("#toUserId").val() + '","msg":"' + $("#msg").val() + '"}');socket.send('{"toUserId":"' + $("#toUserId").val() + '","msg":"' + $("#msg").val() + '"}');var msg = document.getElementById("msg").value;$("#div1").append("发送消息:" + msg + "<br \>");document.getElementById("msg").value = "";}}</script></head><body><h1 align="center">WebSocket测试Demo</h1><br /><form class="form-inline"><div class="form-group mx-sm-3 mb-2"><label for="toUserId" class="sr-only">toUserId</label><input type="text" class="form-control" id="toUserId" placeholder="toUserId"></div><div class="form-group mb-2"><label for="msg" class="sr-only">消息內容</label><input type="text" class="form-control" id="msg" placeholder="消息內容"></div><div class="form-group mx-sm-3 mb-2"><button type="button" class="btn btn-primary" onclick="openSocket()">开启socket</button></div><div class="form-group mx-sm-3 mb-2"><button type="button" class="btn btn-danger" onclick="sendMsg()">发送消息</button></div><div class="form-group mx-sm-3 mb-2"><button type="button" class="btn btn-secondary" onclick="clearData()">清空内容</button></div><div class="div2"></div><div class="div1" id="div1"></div></form></body><script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script><script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js"integrity="sha384-7ymO4nGrkm372HoSbq1OY2DP4pEZnMiA+E0F3zPr+JQQtQ82gQ1HPY3QIVtztVua" crossorigin="anonymous"></script></html>

在这里插入图片描述
复制test.html文件为test2.html文件,将上面的userId由’20’改为’10’,后面测试使用。

测试

测试一

运行服务端项目,打开test.html,点击’开启socket’按钮(一定要先开启socket连接,否则无法接收到消息)。

在这里插入图片描述

可以看到,服务端与客户端已建立了连接。

然后调用我们的测试接口:

在这里插入图片描述

然后观察test.html页面:

在这里插入图片描述
可以看到,客户端的用户20成功接收到服务端发来的信息。

测试二

打开test2.html,同样点击’开启socket’,与服务端建立连接。

此时用test2.html给test.html发送一条消息。

在这里插入图片描述
在这里插入图片描述

可以看到,此时两个页面直接已经可以进行一对一的聊天了。

代码已上传到git:https://gitee.com/lianaozhe/springboot-websocket.git


http://www.ppmy.cn/news/55558.html

相关文章

Reid之损失函数理论学习讲解

基于深度学习的Reid主要流程为输入图像-->CNN(提取特征)-->Global average pooling-->特征向量&#xff0c;将用这些特征来衡量图像的相似情况。并用这些特征进行检索&#xff0c;返回分类情况。 在训练网络的时候需要涉及损失函数&#xff0c;因此就引出了表征学习和…

Photoshop如何使用图像调色之实例演示?

文章目录 0.引言1.将一张偏冷调的图像调整成暖调2.将图像调整成不同季节色彩倾向3.变换花朵的颜色4.创建人像轮廓风景5.修饰蓝天白云6.调换花草颜色 0.引言 因科研等多场景需要进行绘图处理&#xff0c;笔者对PS进行了学习&#xff0c;本文通过《Photoshop2021入门教程》及其配…

当影像遇上Python:用MoviePy库轻松搞定视频编辑

I. 简介 当影像遇上Python&#xff1a;用MoviePy库轻松搞定视频编辑 I. 简介II. 安装III. 使用 &#x1f680;&#x1f3ac;1. 创建一个视频剪辑对象2. 剪辑视频3. 剪切视频片段4. 改变视频尺寸和速度5. 合并视频6. 合并多个视频7. 用混合模式合并视频8. 添加音频9. 添加背景音…

C#基础 变量在内存中的存储空间

变量存储空间&#xff08;内存中&#xff09; // 1byte 8bit // 1KB 1024byte // 1MB 1024KB // 1GB 1024MB // 1TB 1024GB // 通过sizeof方法 可以获取变量类型所占的内存空间&#xff08;单位&#xff1a;字节&#xff09; 有…

springboot集成kafka的相关配置及自定义

之前的文章末尾&#xff0c;简单的实现了springboot集成kafka&#xff0c;完成了简单的测试&#xff0c;今天我们来扩展一下相关内容。 首先详解一下配置文件的内容&#xff1a; spring:kafka:# 指定 kafka 地址&#xff0c;我这里部署在的虚拟机&#xff0c;开发环境是Windo…

PCL点云库(4) — console模块

目录 4.1 time时间打印 4.2 print 4.3 parse ◆ find_switch() ◆ find_argument() ◆ parse() ◆ parse_2x_arguments() ◆ parse_3x_arguments() ◆ parse_x_arguments() ◆ parse_multiple_arguments() ◆ parse_multiple_2x_arguments() ◆ parse_multiple…

阿里云服务器通用算力u1性能测评CPU处理器网络PPS

阿里云服务器u1通用算力型Universal实例高性价比&#xff0c;CPU采用Intel(R) Xeon(R) Platinum&#xff0c;主频是2.5 GHz&#xff0c;云服务器U1实例的基准vCPU算力与5代企业级实例持平&#xff0c;最高vCPU算力与6代企业级实例持平&#xff0c;提供2c-32c规格和1:1/2/4/8丰富…

Python小姿势 - Python学习笔记——类与对象

Python学习笔记——类与对象 类与对象是面向对象编程的两个基本概念。类是对象的抽象概念&#xff0c;对象是类的具体表现。 类是对一类事物的抽象&#xff0c;它是描述一类事物的模板&#xff0c;而对象是类的具体表现。对象是类的实例&#xff0c;类是对象的模板。 举个例子&…