Springboot整合Websocket实现ws和wss连接

1. 引入pom依赖

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
    <version>2.7.10</version>
</dependency>

2. 新建websocket配置文件

java 复制代码
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常量配置

java 复制代码
public class WebsocketConst {

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

4. 编写websocket代码

java 复制代码
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证书

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

    conf 复制代码
    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关闭。

相关推荐
h***04771 天前
SpringBoot集成Flink-CDC,实现对数据库数据的监听
数据库·spring boot·flink
o***74171 天前
Springboot中SLF4J详解
java·spring boot·后端
孤独斗士1 天前
maven的pom文件总结
java·开发语言
雨中散步撒哈拉1 天前
18、做中学 | 初升高 | 考场一 | 面向过程-家庭收支记账软件
开发语言·后端·golang
CoderYanger1 天前
递归、搜索与回溯-记忆化搜索:38.最长递增子序列
java·算法·leetcode·1024程序员节
面试鸭1 天前
科大讯飞,你好大方。。。
java·计算机·职场和发展·求职招聘
韩立学长1 天前
【开题答辩实录分享】以《智慧物业管理系统的设计与实现》为例进行答辩实录分享
java·后端·mysql
10km1 天前
java:json-path支持fastjson作为JSON解析提供者的技术实现
java·json·fastjson·json-path
小张程序人生1 天前
深入理解SpringSecurity从入门到实战
java
d***95621 天前
springboot接入deepseek深度求索 java
java·spring boot·后端