Springboot整合Websocket实现ws和wss连接

news2024/9/21 16:44:54

1. 引入pom依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
    <version>2.7.10</version>
</dependency>

2. 新建websocket配置文件

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration
public class WebSocketConfig {

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

3. 新建websocket常量配置

public class WebsocketConst {

    /**
     * 消息类型 heartcheck
     */
    public static final String CMD_CHECK = "heartcheck";
}

4. 编写websocket代码

import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
@Slf4j
@ServerEndpoint("/websocket/{userId}")
public class WebSocketServer {

    /**线程安全Map*/
    private static ConcurrentHashMap<String, Session> sessionPool = new ConcurrentHashMap<>();

    //==========【websocket接受、推送消息等方法 —— 具体服务节点推送ws消息】=====================================================
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "userId") String userId) {
        try {
            sessionPool.put(userId, session);
            log.info("【系统 WebSocket】有新的连接,总数为:" + sessionPool.size());
        } catch (Exception e) {
        }
    }

    @OnClose
    public void onClose(@PathParam("userId") String userId) {
        try {
            sessionPool.remove(userId);
            log.info("【系统 WebSocket】连接断开,总数为:" + sessionPool.size());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * ws推送消息
     *
     * @param userId
     * @param message
     */
    public void pushMessage(String userId, String message) {
        for (Map.Entry<String, Session> item : sessionPool.entrySet()) {
            //userId key值= {用户id + "_"+ 登录token的md5串}
            if (item.getKey().contains(userId)) {
                Session session = item.getValue();
                try {
                    synchronized (session){
                        log.info("【系统 WebSocket】推送单人消息:" + message);
                        session.getBasicRemote().sendText(message);
                    }
                } catch (Exception e) {
                    log.error(e.getMessage(),e);
                }
            }
        }
    }

    /**
     * ws遍历群发消息
     */
    public void pushMessage(String message) {
        try {
            for (Map.Entry<String, Session> item : sessionPool.entrySet()) {
                try {
                    item.getValue().getAsyncRemote().sendText(message);
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }
            log.info("【系统 WebSocket】广播消息:" + message);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * ws接受客户端消息
     */
    @OnMessage
    public void onMessage(String message, @PathParam(value = "userId") String userId) {
        if(!"ping".equals(message) && !WebsocketConst.CMD_CHECK.equals(message)){
            log.info("【系统 WebSocket】收到客户端消息:" + message);
        }else{
            log.debug("【系统 WebSocket】收到客户端消息:" + message);
        }
    }

    /**
     * 配置错误信息处理
     *
     * @param session
     * @param t
     */
    @OnError
    public void onError(Session session, Throwable t) {
        log.warn("【系统 WebSocket】消息出现错误");
        t.printStackTrace();
    }
    //==========【系统 WebSocket接受、推送消息等方法 —— 具体服务节点推送ws消息】=================================================


}

5. ws连接测试

在这里插入图片描述

6. wss连接配置

  1. 生成ssl证书

    openssl req -newkey rsa:2048 -nodes -keyout server.key -x509 -days 3650 -out server.crt
    
  2. nginx配置

    server {
            listen    8443 ssl;
            server_name  localhost;
            ssl_certificate      /etc/nginx/conf.d/certs/server.crt;
            ssl_certificate_key  /etc/nginx/conf.d/certs/server.key;
            ssl_session_cache    shared:SSL:1m;
            ssl_session_timeout  5m;
            ssl_ciphers  HIGH:!aNULL:!MD5;
            ssl_prefer_server_ciphers  on;
            root html;
                  charset 'utf-8';
    
            location / {
                root   /dsp/app/dsp-web/dist/; #你项目在系统中的路径
                try_files $uri $uri/ /index.html;
                index  index.html index.htm;
            }
    
    		# 拦截API
            location ^~ /prod-api {
              proxy_pass http://dsp-gateway:9999/;
              proxy_redirect off;
              rewrite /prod-api/(.*)$ /$1 break;
              proxy_set_header Host $http_host;
              proxy_set_header X-Real-IP $remote_addr;
              proxy_set_header REMOTE-HOST $remote_addr;
              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            }
    
    		# 拦截websocket
            location /websocket/ {
              proxy_pass http://dsp-gateway:9999/;
              proxy_redirect off;
              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection "upgrade";
              proxy_set_header Host $host:$server_port;
              proxy_set_header X-Real-IP $remote_addr;
              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
           }
    
    }
    
    
  3. wss连接测试
    在这里插入图片描述

注意:使用postman测试wss时,可能会报证书验证失败的问题,如下:
在这里插入图片描述

可能是SSL认证拦截了请求,可以在postman的 设置 中将 SSL certificate verification关闭。
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ElementUI Form:Radio 单选框

ElementUI安装与使用指南 Radio 单选框 点击下载learnelementuispringboot项目源码 效果图 el-radio.vue 页面效果图 项目里el-radio.vue代码 <script> export default {name: el_radio,data() {return {radio: 1,radio2: 2,radio3: 3,radio4: 上海,radio5: 上海,ra…

【JAVA】单例模式的线程安全性

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;JAVA ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 正文 我的其他博客 正文 老生常谈的问题了&#xff0c;首先要说的是单例模式的线程安全意味着&#xff1a;某个类的实例在多线程环境 下只会被…

Codeforces Round 922 (Div. 2) (A~B)

A. Brick Wall 读题不谨慎翻车半小时&#xff0c;警惕黑体加粗的单词&#xff0c;真的很重要。 给你n高&#xff0c;m宽的方框&#xff0c;往里面放 1*k 大小的砖头&#xff0c;k自己选&#xff0c;但是>2&#xff0c;塞满方框的情况并且不超出边界&#xff0c;输出最大的…

(M)UNITY三段攻击制作

三段攻击逻辑 基本逻辑&#xff1a; 人物点击攻击按钮进入攻击状态&#xff08;bool isAttack&#xff09; 在攻击状态下&#xff0c; 一旦设置的触发器&#xff08;trigger attack&#xff09;被触发&#xff0c;设置的计数器&#xff08;int combo&#xff09;查看目前攻击…

【计算机网络】网络的网络

网络的网络 客户 customer 接入ISP提供商 provider 全球承载ISP多个ISP的层级结构 第一层ISP &#xff08;tier-1 ISP &#xff09; 位于顶部 区域ISP &#xff08;reginal ISP&#xff09;Level 3通信 &#xff0c;AT&T&#xff0c;Sprint &#xff0c;NTT存在点&#x…

交叉注意力融合时域、频域特征的FFT + CNN-Transformer-CrossAttention轴承故障识别模型

目录 往期精彩内容&#xff1a; 前言 1 快速傅里叶变换FFT原理介绍 第一步&#xff0c;导入部分数据 第二步&#xff0c;故障信号可视化 第三步&#xff0c;故障信号经过FFT可视化 2 轴承故障数据的预处理 2.1 导入数据 2.2 制作数据集和对应标签 3 交叉注意力机制 …

【机器学习300问】21、什么是激活函数?常见激活函数都有哪些?

在我写的上一篇文章中介绍了感知机&#xff08;单个神经元&#xff09;的构成&#xff0c;其中就谈到了神经元会计算传送过来的信号的总和&#xff0c;只有当这个总和超过了某个界限值时&#xff0c;才会输出值。这也称为“神经元被激活”。如果想对神经网络是什么有更多了解的…

人工智能是哪个专业

人工智能是一个以计算机科学为基础&#xff0c;由计算机、心理学、哲学等多学科交叉融合的交叉学科、新兴学科。其研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学&#xff0c;企图了解智能的实质&#xff0c;并生产出一种新的能以人类…

机器学习——绪论总结

目录 一、引入 二、基本术语 三、假设空间与归纳偏 四、模型选择 一、引入 机器学习&#xff1a;通过计算手段&#xff0c;得出具有能够自我修改、完善能力的模型&#xff0c;利用经验改善系统自身性能。算法使用数据得到模型的过程即称为学习&#xff0c;或训练 流程&…

uni-app app引入天地图

话不多说咸鱼来了 <template><view><div class"mapBox" style"width: 100%; height: 100vh;background: #ddc0c0;" id"mapId" ></div></view> </template> <script module"test" lang"r…

vue使用antv-x6 绘制流程图DAG图(二)

代码&#xff1a; <template><div class"graph-wrap" click.stop"hideFn"><Toobar :graph"graph"></Toobar><!-- 小地图 --><div id"minimap" class"mini-map-container"></div>…

Security ❀ TCP异常报文详解

文章目录 1. TCP Out-Of-Order2. TCP Previous Segment Lost3. TCP Retransmission4. TCP Dup Ack XXX#X5. TCP Windows Update6. TCP Previous segment not captured7. 异常案例分析 TCP协议中seq和ack seq的联系&#xff1a; id4的http请求报文由客户端发向服务器&#xff0…

C++ 数论相关题目 台阶-Nim游戏

现在&#xff0c;有一个 n 级台阶的楼梯&#xff0c;每级台阶上都有若干个石子&#xff0c;其中第 i 级台阶上有 ai 个石子(i≥1 )。 两位玩家轮流操作&#xff0c;每次操作可以从任意一级台阶上拿若干个石子放到下一级台阶中&#xff08;不能不拿&#xff09;。 已经拿到地面…

JAVA处理类似饼状图占比和100%问题,采用最大余额法

前言&#xff1a; 在做数据统计报表的时候&#xff0c;有两种方式解决占比总和达不到100%或者超过100%问题。 第一种方式是前端echart图自带的算分框架。 第二种方式是java后端取处理这个问题。 现存问题&#xff1a; 前端通过饼状图的方式去展示各个分类的占比累加和为100%问题…

vue前端页面时间显示问题解决方法

解决方法&#xff0c; <template slot-scope"scope"><span>{{ parseTime(scope.row.boxClosingOnlineTime, {y}-{m}-{d} {h}:{i}:{s}) }}</span> </template> 刷新页面&#xff1a; 此外&#xff0c;使用JsonFormat(pattern "yyyy-M…

Kaggle竞赛系列_SpaceshipTitanic金牌方案分析_数据分析

文章目录 【文章系列】【前言】【比赛简介】【正文】&#xff08;一&#xff09;数据获取&#xff08;二&#xff09;数据分析1. 缺失值2. 重复值3. 属性类型分析4. 类别分析5. 分析目标数值占比 &#xff08;三&#xff09;属性分析1. 对年龄Age分析&#xff08;1&#xff09;…

OpenHarmony—环境准备

JS SDK安装失败处理指导 问题现象 下载JS SDK时&#xff0c;下载失败&#xff0c;提示“Install Js dependencies failed”。解决措施 JS SDK下载失败&#xff0c;一般情况下&#xff0c;主要是由于npm代理配置问题&#xff0c;或未清理npm缓存信息导致&#xff0c;可按照如…

如何更新github上fork的项目(需要一定git基础)

如何更新Fork的项目(需要一定git基础) 前言&#xff1a;本文记录一下自己在github上fork了大佬的开源博客项目https://github.com/tangly1024/NotionNext&#xff0c;如何使用git克隆以及自定义开发和同步合并原项目更新迭代内容的的步骤 如何更新fork的项目(进阶版) 首先你…

MyBatis 源码系列:MyBatis 解析配置文件、二级缓存、SQL

文章目录 解析全局配置文件二级缓存解析解析二级缓存缓存中的调用过程缓存中使用的设计模式 解析SQL 解析全局配置文件 启动流程分析 String resource "mybatis-config.xml"; //将XML配置文件构建为Configuration配置类 reader Resources.getResourceAsReader(re…

华天动力OA ntkodownload.jsp 任意文件读取漏洞复现

0x01 产品简介 华天动力OA是一款将先进的管理思想、 管理模式和软件技术、网络技术相结合,为用户提供了低成本、 高效能的协同办公和管理平台。 0x02 漏洞概述 华天动力OA ntkodownload.jsp接口处存在任意文件读取漏洞,未经身份认证的攻击者可利用此漏洞获取服务器内部敏感…