构建即时通讯应用:Spring boot高效集成WebSocket、Stomp协议完成前后端持续通信

news2024/11/24 14:32:49

1. 引入依赖

在你的Spring Boot项目的pom.xml中添加以下依赖:

<dependencies>

        <!-- Spring Boot Starter Thymeleaf -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <!-- Spring Boot Starter WebSocket -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
        </dependency>
    </dependencies>

2. 配置WebSocket

创建一个配置类来设置WebSocket连接端点、STOMP协议和消息传输路径:

@Configuration
@EnableWebSocketMessageBroker
public class WebsocketMessageBrokerConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws") // WebSocket握手端口
                .setAllowedOriginPatterns("*") // 设置跨域
                .withSockJS(); // 开启SockJS回退机制
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.setApplicationDestinationPrefixes("/app") // 发送到服务端目的地前缀
                .enableSimpleBroker("/topic");// 开启简单消息代理,指定消息订阅前缀
    }

}


3. 创建消息处理器

创建一个控制器来处理客户端发送的消息,并将消息广播给订阅了相关主题的客户端:

/**
 * 功能描述:
 *
 * @author Songxianyang
 * @date 2024-08-05 17:24
 */
@Controller
@Slf4j
@RequiredArgsConstructor
public class StompController {

    private final SimpMessagingTemplate messagingTemplate;

    @GetMapping("stomp")
    public ModelAndView stomp() {
        return new ModelAndView("stomp");
    }


    /**
     * 数据通过前端发送到后端,处理完数据后在响应给前端的订阅者“/topic/public”
     * @param chatMessage
     * @return
     */

    // 这个注解的作用是映射客户端发送到服务器的消息路径
    @MessageMapping("/chat.sendMessage")
    @SendTo("/topic/public")
    public ChatMessage sendMessage(ChatMessage chatMessage) {
        return chatMessage;
    }

    @MessageMapping("/chat.addUser")
    @SendTo("/topic/public")
    public ChatMessage addUser(ChatMessage chatMessage, SimpMessageHeaderAccessor headerAccessor) {
        // 将用户名存储在WebSocket会话中
        headerAccessor.getSessionAttributes().put("username", chatMessage.getSender());
        return chatMessage;
    }

    /**
     * 服务端主动给客户端发送消息
     * @return
     */
    @GetMapping("s-to-c")
    @SendTo("/topic/public")
    @ResponseBody
    public ChatMessage sToC() {
        ChatMessage chatMessage = new ChatMessage();
        chatMessage.setContent("西瓜视频");
        chatMessage.setSender("Server");
        chatMessage.setType(ChatMessage.MessageType.CHAT);
        // 发送消息
        messagingTemplate.convertAndSend("/topic/public", chatMessage);
        return chatMessage;
    }




    @GetMapping("/html/greeting")
    public ModelAndView turnToGreetingPage() {
        return new ModelAndView("greeting");
    }

    @MessageMapping("/greeting")
    public String sayGreeting(String name) {
        log.info("Message received: {}", name);
        return "Hello, " + name;
    }


}

4. 创建消息模型

创建一个简单的Java类来表示聊天消息:

/**
 * 聊天消息对象
 */
@Data
public class ChatMessage {
    /**
     * 消息的类型
     */
    private MessageType type;
    /**
     * 消息的内容
     */
    private String content;
    /**
     * 发送者
     */
    private String sender;

    public enum MessageType {
        //普通聊天消息
        CHAT,
        // 加入聊天
        JOIN,
        // 离开聊天
        LEAVE
    }
}

5. 创建前端代码(stomp.html)

在前端(例如使用HTML和JavaScript)中集成WebSocket和STOMP。以下是一个简单的示例:

<!DOCTYPE html>
<html>
<head>
    <title>WebSocket-Chat-stomp</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.6.1/sockjs.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
    <script>
        var stompClient = null;
        // 接收消息
        function connect() {
            var socket = new SockJS('/ws');
            stompClient = Stomp.over(socket);
            stompClient.connect({}, function (frame) {
                console.log('Connected: ' + frame);
                // 客户端订阅服务端消息
                stompClient.subscribe('/topic/public', function (message) {
                    showMessage(JSON.parse(message.body));
                });
            });
        }
        // 发送消息
        function sendMessage() {
            var messageContent = document.getElementById("message").value;
            // 往客户端发送消息
            stompClient.send("/app/chat.sendMessage", {}, JSON.stringify({
                sender: "User",
                content: messageContent,
                type: 'CHAT'
            }));
        }
        // 展示消息
        function showMessage(message) {
            var response = document.getElementById("response");
            var p = document.createElement("p");
            p.appendChild(document.createTextNode(message.sender + ": " + message.content));
            response.appendChild(p);
        }

        // 用户加入
        function addUser() {
            var userName = document.getElementById('username').value;
            if (userName && stompClient) {
                var chatMessage = {
                    sender: userName,
                    content: userName + "已加入聊天!请注意财产安全",
                    type: 'JOIN'
                };
                stompClient.send("/app/chat.addUser", {}, JSON.stringify(chatMessage));
            }
        }

    </script>
</head>
<body onload="connect()">
<div>

    <input type="text" id="username" placeholder="Enter your name" />
    <button onclick="addUser()">用户加入</button>

    <input type="text" id="message" />
    <button onclick="sendMessage()">发送信息</button>
</div>
<div id="response"></div>
</body>
</html>

7. yml配置

server:
  port: 9999
#  servlet:
#    context-path: /demo
spring:
  freemarker:
    request-context-attribute: request
    suffix: .html
    content-type: text/html
    enabled: true
    cache: false
    charset: UTF-8
    allow-request-override: false
    expose-request-attributes: true
    expose-session-attributes: true
    expose-spring-macro-helpers: true

8. 运行应用程序

启动Spring Boot应用程序,并打开你的HTML页面,你应该能够通过WebSocket连接发送和接收消息了。

链接说明
http://localhost:9999/stomp第一个客户端
http://localhost:9999/stomp第二个客户端
http://localhost:9999/s-to-c服务端主动给客户端发送消息
1.前端

在这里插入图片描述

2.用户加入

在这里插入图片描述

3.聊天消息

在这里插入图片描述

4.服务端主动给客户端发送消息

在这里插入图片描述

在这里插入图片描述

总结

通过以上步骤,你可以在Spring Boot项目中集成WebSocket和STOMP协议,实现实时的双向通信功能。这是一个基本的示例,你可以根据需要进行扩展和自定义,例如添加更多的消息处理逻辑、安全认证等。

源码

持续更新 (集群、优化这个应用)

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

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

相关文章

黑龙江日报报道第5届中国计算机应用技术大赛,赛氪提供赛事支持

2024年7月17日&#xff0c;黑龙江日报、极光新闻对在哈尔滨市举办的第5届中国计算机应用技术大赛全国总决赛进行了深入报道。此次大赛由中国计算机学会主办&#xff0c;中国计算机学会计算机应用专业委员会与赛氪网共同承办&#xff0c;吸引了来自全国各地的顶尖技术团队和选手…

振德医疗选择泛微千里聆RPA,助力电商、人事业务流程自动化

振德医疗用品股份有限公司成立于1994年&#xff0c;中国A股上市公司&#xff0c;是医用敷料和感控防护产品主要的供应商之一。 &#xff08;图片素材来自振德医疗官网&#xff09; 振德医疗的业务在线上线下齐发力。目前拥有5个国内生产基地&#xff0c;3个海外工厂&#xff0…

算法分析报告:商江小智文本生成算法

1. 算法全周期分析 算法安全与监测 信息内容安全&#xff1a;算法通过预处理和特征提取确保输入数据的安全&#xff0c;避免敏感信息泄露。信息源安全&#xff1a;算法依赖于训练数据集&#xff0c;需确保数据来源的合法性和隐私保护。信息安全监测&#xff1a;算法应实时监控…

(回溯) LeetCode 17. 电话号码的组合

原题链接 一. 题目描述 17. 电话号码的字母组合 已解答 中等 相关标签 相关企业 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对…

Linux 下 ETCD 安装、配置与命令使用总结

​ 大家好&#xff0c;我是程序员小羊&#xff01; 前言&#xff1a; Linux 下 ETCD 安装、配置与命令使用总结 ETCD 是一个分布式键值存储系统&#xff0c;广泛用于服务发现、分布式锁、配置管理等场景&#xff0c;特别是在 Kubernetes 集群中发挥着至关重要的作用。ETCD 的高…

LoRA实现大模型LLM微调研究

LoRA&#xff0c;即低秩适应&#xff08;Low-Rank Adaptation&#xff09;&#xff0c;作为一种创新的微调方法&#xff0c;为大模型的优化与定制提供了一条高效、节省资源的新途径。 在快速发展的AI时代背景下&#xff0c;大型语言模型因其卓越的性能和广泛的应用前景&#xf…

(限时免费)震惊!流落人间的haproxy宝典被找到了!一切玄妙尽在此处!

目录 haproxy七层代理详解一、负载均衡1.1 什么是负载均衡1.2 为什么使用负载均衡1.3 负载均衡类型1.3.1 硬件负载1.3.2 四层负载1.3.3 七层负载1.3.4 四层与七层的区别 二、haproxy介绍2.1 haproxy简介2.2 haproxy特性 三、haproxy详细部署3.1 实验所用的环境3.2 软件安装3.3 …

【每日一题】【数学推导】【分类讨论】小红的数组重排 牛客周赛 Round 55 C题 C++

牛客周赛 Round 55 C题 小红的数组重排 题目背景 牛客周赛 Round 55 题目描述 样例 #1 样例输入 #1 4 7 2 5 1样例输出 #1 YES 1 5 2 7样例 #1 样例输入 #1 6 1 1 4 5 1 4样例输出 #1 NO做题思路 a 1 ∗ a 2 < a 2 ∗ a 3 < . . . < a n − 1 ∗ a n a_1*a_…

【Kettle】kettle连接MySQL数据库连接不上解决方案汇总

前言 近期项目上经常用到ETL&#xff08;数据抽取转换加载&#xff09;&#xff0c;就想到了之前用过的kettle工具&#xff0c;下班回家想着再玩玩这个工具吧&#xff0c;结果在连接MySQL时&#xff0c;遇到了各种问题&#xff0c;就顺手整理记录一下。所以今天晚上的主题是&a…

SuccBI+低代码文档中心 — 可视化分析(仪表板)(上)

有关仪表板的设计器&#xff1a; 查询设置 由于仪表板的设计器是所见即所得的&#xff0c;可以将当前制作的内容和数据的查询结果实时展示在界面中&#xff0c;当引入到仪表板的模型数据量较大时&#xff0c;为了提高设计器界面的查询性能&#xff0c;提供了以下两种方法&…

PythonStudio 控件使用常用方式(二十一)TTrayIcon

PythonStudio是一个极强的开发Python的IDE工具&#xff0c;官网地址是&#xff1a;https://glsite.com/ &#xff0c;在官网可以下载最新版的PythonStudio&#xff0c;同时&#xff0c;在使用PythonStudio时&#xff0c;它也能及时为用户升到最新版本。它使用的是Delphi的控件&…

SSL发送邮件:如何确保邮件传输过程安全?

SSL发送邮件的安全性评估&#xff1f;SSL发送邮件的条件有哪些&#xff1f; 使用SSL发送邮件是一种有效的措施&#xff0c;能够确保邮件在传输过程中的安全性。AokSend将探讨SSL发送邮件的关键技术及其重要性&#xff0c;帮助您更好地理解如何确保邮件传输过程的安全。 SSL发…

米思奇安装——Mac版本

米思奇安装——Mac版本 1.下载 访问米思奇官网https://mixly.org/bnu-maker/mixl2.0rc 打开官网后在首页点击导航栏的软件平台&#xff0c;选择Mixly离线版 点击Mixly2.0RC4发布下载。 进入百度网盘分享的文件&#xff0c;选择Mac一键更新版本&#xff0c;等待下载完成。 …

机器学习——第十一章 特征选择与稀疏学习

11.1 子集搜索与评价 对一个学习任务来说&#xff0c;给定属性集&#xff0c;其中有些属性可能很关键、很有用&#xff0c;另一些属性则可能没什么用.我们将属性称为"特征" (feature) &#xff0c;对当前学习任务有用的属性称为"相关特征" (relevant featu…

【Pyspark-驯化】一文搞懂Pyspark中表连接的使用技巧

【Pyspark-驯化】一文搞懂Pyspark中表连接的使用技巧 本次修炼方法请往下查看 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我工作、学习、实践 IT领域、真诚分享 踩坑集合&#xff0c;智慧小天地&#xff01; &#x1f387; 相关内容文档获取 微信公众号 &…

ios创建控制器的3种方法实现页面跳转

ios遵守mvc设计模式&#xff0c;下面介绍创建控制器viewcontroller的几种方法&#xff0c;来实现页面的跳转 1.纯代码创建 // // AppDelegate.m // study2024 // // Created by zhifei zhu on 2024/8/7. //#import "AppDelegate.h" #import "MyViewContro…

代理模式-

代理模式通常找到代理方来管理用户的权限访问。如下图&#xff1a; #include<string> #include<iostream> using namespace std; class Video { public:virtual void Free() 0;virtual void VIP() 0;virtual void Ticket() 0; }; class FixbugVideo:public V…

机械学习—零基础学习日志(项目实践01)

llM项目分类与原理解析 Prompt项目 直接产出一些具体的文本与信息&#xff0c;使用markdown的格式。 对prompt进行较好的格式输出&#xff0c;固定格式。 ChatPaper 快速获取论文内容&#xff0c;然后了解对应的信息&#xff0c;判断是否有必要阅读这一篇论文 ChatBI&…

Adobe Dimension DN v4.0.2 解锁版下载及安装教程 (三维3D建模工具)

前言 Adobe Dimension&#xff08;简称DN&#xff09;是一款3D设计软件&#xff0c;三维合成和渲染工具&#xff0c;2D平面的二维转为3D立体的三维合成工具&#xff0c;用于3Dmax\C4D\MAYA等三维软件生成的效果图&#xff0c;在3D场景中排列对象、图形和光照。3D应用程序使用的…

python循环语句之while循环和for循环

文章目录 1. while 循环1.1 介绍1.1.1 生活中的循环1.1.2 程序中的循环 1.2 总结 2. while循环应用&#xff1a;1~100求和2.1 需求2.2 分析 3. while嵌套循环以及运用3.1 while嵌套循环语句的语法格式3.2 while嵌套循环使用3.2.1 要求3.2.2 参考代码 4. for循环4.1 for循环基本…