跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Java大前端java

Java 后端通过 WebSocket 向前端推送消息

基于 Spring Boot 使用 WebSocket 实现后端向前端推送消息的方案。内容包括 WebSocket 配置类、ServerEndpoint 会话管理、Controller 接口定义以及前端 HTML 测试页面。实现了指定客户端推送和全量广播推送功能,涵盖了连接建立、消息收发、异常处理及定时任务推送。

SparkGeek发布于 2026/4/5更新于 2026/10/8103 浏览
Java 后端通过 WebSocket 向前端推送消息

1、WebSocketConfig 配置类

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

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

2、WebSocket 消息发送接收

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Component
@ServerEndpoint(value = "/web/{id}")
public class WebSocketProcess {
    /**
     * 持有每个 webSocket 对象,以 key-value 存储到线程安全 ConcurrentHashMap
     */
    private static ConcurrentHashMap<Long, WebSocketProcess> concurrentHashMap = new ConcurrentHashMap<>(16);

    /**
     * 会话对象
     */
    private Session session;

    /**
     * 客户端创建连接时触发
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("id") long id) {
        //每新建立一个连接,就把当前客户 id 为 key,this 为 value 存储到 map 中
        this.session = session;
        concurrentHashMap.put(id, this);
        log.info("Open a websocket. id={}", id);
    }

    /**
     * 客户端连接关闭时触发
     */
    @OnClose
    public void onClose(Session session, @PathParam("id") long id) {
        //客户端连接关闭时,移除 map 中存储的键值对
        concurrentHashMap.remove(id);
        log.info("close a websocket, concurrentHashMap remove sessionId= {}", id);
    }

    /**
     * 接收到客户端消息时触发
     */
    @OnMessage
    public void onMessage(String message, @PathParam("id") String id) {
        log.info("receive a message from client id={},msg={}", id, message);
    }

    /**
     * 连接发生异常时候触发
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("Error while websocket.", error);
    }

    /**
     * 发送消息到指定客户端
     *
     * @param id
     * @param message
     */
    public void sendMessage(long id, String message) throws Exception {
        //根据 id,从 map 中获取存储的 webSocket 对象
        WebSocketProcess webSocketProcess = concurrentHashMap.get(id);
        if (!ObjectUtils.isEmpty(webSocketProcess)) {
            //当客户端是 Open 状态时,才能发送消息
            if (webSocketProcess.session.isOpen()) {
                webSocketProcess.session.getBasicRemote().sendText(message);
            } else {
                log.error("websocket session={} is closed ", id);
            }
        } else {
            log.error("websocket session={} is not exit ", id);
        }
    }

    /**
     * 发送消息到所有客户端
     */
    public void sendAllMessage(String msg) throws Exception {
        log.info("online client count={}", concurrentHashMap.size());
        Set<Map.Entry<Long, WebSocketProcess>> entries = concurrentHashMap.entrySet();
        for (Map.Entry<Long, WebSocketProcess> entry : entries) {
            Long cid = entry.getKey();
            WebSocketProcess webSocketProcess = entry.getValue();
            boolean sessionOpen = webSocketProcess.session.isOpen();
            if (sessionOpen) {
                webSocketProcess.session.getBasicRemote().sendText(msg);
            } else {
                log.info("cid={} is closed,ignore send text", cid);
            }
        }
    }
}

3、消息推送 Controller

import com.xyl.web.controller.common.WebSocketProcess;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/testws")
public class WebSocketController {
    /**
     * 注入 WebSocketProcess
     */
    @Autowired
    private WebSocketProcess webSocketProcess;

    /**
     * 向指定客户端发消息
     *
     * @param id
     */
    @PostMapping(value = "sendMsgToClientById")
    public void sendMsgToClientById(@RequestParam long id, @RequestParam String text) {
        try {
            webSocketProcess.sendMessage(id, text);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 发消息到所有客户端
     *
     * @param text
     */
    @PostMapping(value = "sendMsgToAllClient")
    public void sendMsgToAllClient(@RequestParam String text) {
        try {
            webSocketProcess.sendAllMessage(text);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 定时向客户端推送消息
     * @throws Exception
     */
    @Scheduled(cron = "0/5 * * * * ?")
    private void configureTasks() throws Exception {
        webSocketProcess.sendAllMessage("向前端推送消息内容");
    }
}

4、测试 HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>websocket 测试</title>
<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
</head>
<body>
<div id="content"></div>
</body>
<script type="text/javascript">
$(function(){
    var ws;
    //检测浏览器是否支持 webSocket
    if("WebSocket"in window){
        $("#content").html("您的浏览器支持 webSocket!");
        //模拟产生 clientID
        let clientID = Math.ceil(Math.random()*100);
        //创建 WebSocket 对象,注意请求路径!!!!
        ws = new WebSocket("ws://127.0.0.1:9095/web/"+clientID);
        //与服务端建立连接时触发
        ws.onopen=function(){
            $("#content").append("<p>与服务端建立连接建立成功!您的客户端 ID="+clientID+"</p>");
            //模拟发送数据到服务器
            ws.send("你好服务端!我是客户端 "+clientID);
        }
        //接收到服务端消息时触发
        ws.onmessage=function(evt){
            let received_msg = evt.data;
            $("#content").append("<p>接收到服务端消息:"+received_msg+"</p>");
        };
        //服务端关闭连接时触发
        ws.onclose=function(){
            console.error("连接已经关闭.....");
        };
    }else{
        $("#content").html("您的浏览器不支持 webSocket!");
    }
})
</script>
</html>

目录

  1. 1、WebSocketConfig 配置类
  2. 2、WebSocket 消息发送接收
  3. 3、消息推送 Controller
  4. 4、测试 HTML

更多推荐文章

查看全部
  • Java 泛型详解:语法、擦除与通配符
  • Continue插件实现本地部署一个“cursor”或“github copilot”
  • LLM 入门:大语言模型发展、架构与应用详解
  • KaiwuDB+CodeArts 智能体,让ai快速构建一个智能家居本地化数据处理系统
  • 前端国际化最佳实践指南
  • 微信小程序全局配置 window 属性详解及常见误区
  • AI 辅助编程工具对比:Copilot、Cursor、Claude Code 与 Codex 解析
  • AI 编程范式:从 Vibe Coding 到 Spec Coding
  • Python 爬取京东商品评论:API 接口与反爬策略解析
  • 2023 网络安全零基础学习路线与进阶指南
  • Linux 开发工具:GDB 调试器使用指南
  • Java Web 蛋糕商城系统设计与实现
  • Agent Native 取代 Copilot:智能体重塑公司架构与组织
  • FPGA 中 XDMA 多通道传输架构:实战解析与工程优化
  • 解决 npm 安装 OpenClaw 时的 Git 报错问题
  • FPGA 原理与典型应用场景解析
  • 利用云端 AI 模型快速生成个人响应式网页
  • Agent Native 取代 Copilot:定义下一代 AI 系统架构
  • 企业实战中的 WebSocket 应用场景
  • 免费模型深度评测:四大开源模型场景化对比与选型指南

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online