Springboot中使用websocket发送信息给指定用户和群发

2023-11-05

 

websocket是一种长连接协议,相较于传统的http短连接,websocket不仅可以由客户端向服务器发送消息,可以主动向客户端发起信息,经常用于及时聊天,游戏和服务器向客户端推送信息。

主要优点:

1. 节约带宽。 不停地轮询服务端数据这种方式,使用的是http协议,head信息很大,有效数据占比低, 而使用WebSocket方式,头信息很小,有效数据占比高。
2. 无浪费。 轮询方式有可能轮询10次,才碰到服务端数据更新,那么前9次都白轮询了,因为没有拿到变化的数据。 而WebSocket是由服务器主动回发,来的都是新数据。

3. 实时性,考虑到服务器压力,使用轮询方式不可能很短的时间间隔,否则服务器压力太多,所以轮询时间间隔都比较长,好几秒,设置十几秒。 而WebSocket是由服务器主动推送过来,实时性是最高。

接下来我们看看怎么在springboot中使用websocket和html页面交互:

首先新建springboot项目,导入需要的websocket和springboot依赖,pom.xml配置如下:
 

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
 
	<groupId>com.lk</groupId>
	<artifactId>websocketdemo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>
 
	<name>websocketdemo</name>
	<description>Demo project for Spring Boot</description>
 
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
 
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>
 
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-websocket</artifactId>
		</dependency>
 
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>
 
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
 
 
</project>

application.properties中配置tomcat端口,我配置的是80:

server.port=80

然后就可以开始配置websocket了,首先创建WebSocket配置文件:WebSocketConfig.class

@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
 
}

再创建WebSocket服务器类:WebSocketServer.class,具体代码说明注释都写得很清楚了:

 

package com.cyjz.impl;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;

@Component
//访问服务端的url地址
@ServerEndpoint(value = "/websocket/{id}")
public class WebSocketServer {
    private static int onlineCount = 0;
    private static ConcurrentHashMap<String, WebSocketServer> webSocketSet = new ConcurrentHashMap<>();

    //与某个客户端的连接会话,需要通过它来给客户端发送数据
    private Session session;
    private static Logger log = LogManager.getLogger(WebSocketServer.class);
    private String id = "";
    /**
     * 连接建立成功调用的方法*/
    @OnOpen
    public void onOpen(@PathParam(value = "id") String id, Session session) {
        this.session = session;
        this.id = id;//接收到发送消息的人员编号
        webSocketSet.put(id, this);     //加入set中
        addOnlineCount();           //在线数加1
        log.info("用户"+id+"加入!当前在线人数为" + getOnlineCount());
        try {
            sendMessage("连接成功");
        } catch (IOException e) {
            log.error("websocket IO异常");
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        webSocketSet.remove(this);  //从set中删除
        subOnlineCount();           //在线数减1
        log.info("有一连接关闭!当前在线人数为" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息*/
    @OnMessage
    public void onMessage(String message, Session session) {
        System.err.println("来自客户端的消息:" + message);
        log.info("来自客户端的消息:" + message);
        //可以自己约定字符串内容,比如 内容|0 表示信息群发,内容|X 表示信息发给id为X的用户
        String sendMessage = message.split("[|]")[0];
        String sendUserId = message.split("[|]")[1];
        try {
            if(sendUserId.equals("0"))
                sendtoAll(sendMessage);
            else
                sendtoUser(sendMessage,sendUserId);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误");
        error.printStackTrace();
    }


    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    /**
     * 发送信息给指定ID用户,如果用户不在线则返回不在线信息给自己
     * @param message
     * @param sendUserId
     * @throws IOException
     */
    public void sendtoUser(String message,String sendUserId) throws IOException {
        if (webSocketSet.get(sendUserId) != null) {
            if(!id.equals(sendUserId))
                webSocketSet.get(sendUserId).sendMessage( "用户" + id + "发来消息:" + " <br/> " + message);
            else
                webSocketSet.get(sendUserId).sendMessage(message);
        } else {
            //如果用户不在线则返回不在线信息给自己
            sendtoUser("当前用户不在线",id);
        }
    }

    /**
     * 发送信息给所有人
     * @param message
     * @throws IOException
     */
    public void sendtoAll(String message) throws IOException {
        for (String key : webSocketSet.keySet()) {
            try {
                webSocketSet.get(key).sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }

    public static ConcurrentHashMap<String, WebSocketServer> getWebSocketSet() {
        return webSocketSet;
    }

    public static void setWebSocketSet(ConcurrentHashMap<String, WebSocketServer> webSocketSet) {
        WebSocketServer.webSocketSet = webSocketSet;
    }
}

这时我们的webSocket后端已经创建好了,接下来写两个前端代码:


<!DOCTYPE HTML>
<html>
<head>
    <title>WebSocket</title>
</head>
 
<body>
Welcome<br/>
<input id="text" type="text" /><button onclick="send()">Send</button>    <button onclick="closeWebSocket()">Close</button>
<div id="message">
</div>
</body>
 
<script type="text/javascript">
    var websocket = null;
 
    //判断当前浏览器是否支持WebSocket
    if('WebSocket' in window){
        websocket = new WebSocket("ws://localhost:80/websocket/2");
    }
    else{
        alert('Not support websocket')
    }
 
    //连接发生错误的回调方法
    websocket.onerror = function(){
        setMessageInnerHTML("error");
    };
 
    //连接成功建立的回调方法
    websocket.onopen = function(event){
        setMessageInnerHTML("open");
    }
 
    //接收到消息的回调方法
    websocket.onmessage = function(event){
        setMessageInnerHTML(event.data);
    }
 
    //连接关闭的回调方法
    websocket.onclose = function(){
        setMessageInnerHTML("close");
    }
 
    //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
    window.onbeforeunload = function(){
        websocket.close();
    }
 
    //将消息显示在网页上
    function setMessageInnerHTML(innerHTML){
        document.getElementById('message').innerHTML += innerHTML + '<br/>';
    }
 
    //关闭连接
    function closeWebSocket(){
        websocket.close();
    }
 
    //发送消息
    function send(){
        var message = document.getElementById('text').value;
        websocket.send(message);
    }
</script>
</html>
<!DOCTYPE HTML>
<html>
<head>
    <title>WebSocket</title>
</head>
 
<body>
Welcome<br/>
<input id="text" type="text" /><button onclick="send()">Send</button>    <button onclick="closeWebSocket()">Close</button>
<div id="message">
</div>
</body>
 
<script type="text/javascript">
    var websocket = null;
 
    //判断当前浏览器是否支持WebSocket
    if('WebSocket' in window){
        websocket = new WebSocket("ws://localhost:80/websocket/1");
    }
    else{
        alert('Not support websocket')
    }
 
    //连接发生错误的回调方法
    websocket.onerror = function(){
        setMessageInnerHTML("error");
    };
 
    //连接成功建立的回调方法
    websocket.onopen = function(event){
        setMessageInnerHTML("open");
    }
 
    //接收到消息的回调方法
    websocket.onmessage = function(event){
        setMessageInnerHTML(event.data);
    }
 
    //连接关闭的回调方法
    websocket.onclose = function(){
        setMessageInnerHTML("close");
    }
 
    //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
    window.onbeforeunload = function(){
        websocket.close();
    }
 
    //将消息显示在网页上
    function setMessageInnerHTML(innerHTML){
        document.getElementById('message').innerHTML += innerHTML + '<br/>';
    }
 
    //关闭连接
    function closeWebSocket(){
        websocket.close();
    }
 
    //发送消息
    function send(){
        var message = document.getElementById('text').value;
        websocket.send(message);
    }
</script>
</html>

两个前端代码都是一样的,不同的地方在于一个访问是new WebSocket("ws://localhost:80/websocket/1");一个是new WebSocket("ws://localhost:80/websocket/2");即访问id传参不同,这时启动springboot后台服务,再打开两个前端html文件:

根据之前在代码中定义的输入格式:“信息内容|接受者Id|”进行输入,当输入id为0时表示群发:

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Springboot中使用websocket发送信息给指定用户和群发 的相关文章

随机推荐

  • Java基础-对象序列化

    对象序列化 作用 以内存为基准 把内存中的对象存储到磁盘文件中去 称为对象序列化 使用到的流是对象字节输出流 ObjectOutputStream package per mjn serializable import java io Se
  • Ubuntu下漏洞的修复流程

    最近需要修复cve漏洞 研究了如何在源码上修复漏洞 在这里记录一下 目录 I 介绍 漏洞和补丁 CVE漏洞 普通漏洞和CVE漏洞的区别 II 获取补丁 III 应用补丁 常见的打补丁工具 打补丁的步骤 patch的用法 I 介绍 首先介绍一
  • 最优检索二叉树

    最优检索二叉树 最优检索二叉树 抛出问题 算法的基本解决思路 空隙 检索数据的平均时间 小结 最优二叉检索树的实现算法分析 关于优化函数的递推方程 复杂性估计 总结 最优检索二叉树 抛出问题 算法的基本解决思路 空隙 所谓的空隙也就是查找的
  • 第十五讲:神州交换机端口安全配置

    知识点 开启端口安全模式 设置端口最大安全数 端口绑定MAC地址 违规处理 锁定安全端口 MAC地址与IP的绑定 端口镜像 实验拓扑如下图所示 PC机 IP地址 掩码 MAC地址 端口 PC1 192 168 1 10 255 255 25
  • 信息隐藏——二值图像的信息隐藏

    二值图像的信息隐藏 实验目的 使用一个特定图像区域中黑像素的个数来编码秘密信息 若某块P1 Bi gt 50 则嵌入一个1 若P0 Bi gt 50 则嵌入一个0 在嵌入过程中 为达到希望的像素关系 需要对一些像素的颜色进行调整 实验内容
  • [论文阅读] (06) 万字详解什么是生成对抗网络GAN?经典论文及案例普及

    娜璋带你读论文 系列主要是督促自己阅读优秀论文及听取学术讲座 并分享给大家 希望您喜欢 由于作者的英文水平和学术能力不高 需要不断提升 所以还请大家批评指正 非常欢迎大家给我留言评论 学术路上期待与您前行 加油 前一篇文章分享了Pvop老师
  • iOS 3DTouch的小细节

    在App启动后 添加3DTouch的快捷入口 代码如下 NSMutableArray arrShortcutItem NSMutableArray UIApplication sharedApplication shortcutItems
  • C语言程序-打印九九乘法表

    一 问题描述 使用C语言实现打印九九乘法表程序 二 程序实现 代码如下 include
  • 悲观锁(Synchronized)和乐观锁(CAS)

    文章目录 悲观锁和乐观锁 Synchronized Synchronized使用 Synchronized底层原理 Java1 6对Synchronized的优化 synchronized的等待唤醒机制 CAS CAS使用 CAS底层原理
  • 若依框架代码生成器的应用

    java后端 先设计数据库中的表 我这里的表名为 food 找到代码生成器 点击导入表 然后选择要导入的表名 这里选择的是自己的表名 点击编辑 这里填 表明和实体类的类名 一般不需要填都是自动生成的 然后作者名 可以填 自己的作者名称 生成
  • cs1.6修改服务器参数设置,[心得] cs的网络参数调整指南

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 其实HL网路新技术的引擎就是把自己的电脑每一个动作和网路紧密的连结在一起 不过世界上有太多不同的网路 所以没以办法做的一庞大的资料库自动一一校正 所以 说这麽多 就是设定成这样cl latenc
  • cmd命令进入某个目录

    每次都记不住命令 终于整理了一下 1 开始 gt 运行 gt cmd 2 进入某个磁盘 直接盘符代号 如d 然后回车 到D盘下 不用CD 命令切换 3 输入dir 可以看到d盘下的各个文件名称 3 进入除根录以外的文件夹 cd 文件夹路径
  • 链表(应用篇)

    1 概述 链表是在程序设计过程中经常使用的数据结构 bcos系统内部的调度和tasklet的实现都是基于链表 所以 对链表的支持是bcos与生俱来的特性 bcos的链表设计参考了Linux内核链表的设计思想 如果用户想使用链表只需要在自己的
  • C++基础六:C++入门知识、黑盒测试(详解)与复杂度

    cin与cout cin与cout是C 中的输入和输出函数 需要添加头文件 include
  • QT常用分层式软件架构

    第一次写博客 只做个分享吧 关于软件架构的常用模型目前找到的最详细的解说基于Qt的软件框架设计 amwha的专栏 CSDN博客 qt软件框架 1 QMainWWindow主界面类 转到线程是在实例化子界面对象时 将对应的数据处理类对象转到新
  • 笔记-TCP/IP IP地址字符串表示最大长度

    笔记 TCP IP IP地址字符串表示最大长度 IPv4 IPv6 IPv4 定义在
  • 经典vue面试题:谈一谈computed计算属性和watch监听属性的区别

    computed计算属性和watch监听的区别 computed属性 首先computed计算属性是用于在HTML模板中表达式更加简洁 易维护 特点 computed具有缓存功能 当与computed变量相关的变量值不发生改变时 一直用的是
  • windows7 64位机上配置MinGW+Codeblocks+ wxWidgets

    在Windows7 64位机子上安装配置MinGW Codeblocks wxWidgets步骤如下 1 下载mingw get inst 20111118 http sourceforge net projects mingw 2 双击m
  • vue预渲染

    vue预渲染 vue是一个单页面应用 spa 只有一个 html 文件 内容只有一个 app根节点 通过加载js脚本来填充页面要渲染的内容 然而这种方式无法被爬虫和百度搜索到 如果想对某些页面进行SEO 搜索引擎优化 优化 可以通过预渲染实
  • Springboot中使用websocket发送信息给指定用户和群发

    websocket是一种长连接协议 相较于传统的http短连接 websocket不仅可以由客户端向服务器发送消息 可以主动向客户端发起信息 经常用于及时聊天 游戏和服务器向客户端推送信息 主要优点 1 节约带宽 不停地轮询服务端数据这种方