实现一个基于 Spring Boot 和 Vue.js 的实时消息推送系统

news2024/12/31 1:32:01

在现代互联网应用中,实时消息推送已经成为一个非常重要的功能。不论是即时通讯、通知系统,还是其他需要实时互动的应用场景,消息的实时性直接影响到用户的体验和应用的效率。在这篇文章中,我将详细介绍如何使用 Spring Boot 和 Vue.js 创建一个实时消息推送系统,并确保每个用户只能接收属于自己的消息。这个系统不仅功能强大,而且实现起来并不复杂。

项目概述

我们的系统主要包括以下几个功能:

  1. 实时消息推送。
  2. 消息的持久化存储(使用 MySQL 和 Redis)。
  3. 用户的历史消息查看。

技术栈

为了实现上述功能,我们需要使用以下技术:

  • 后端:Spring Boot、WebSocket、MySQL、Redis
  • 前端:Vue.js、SockJS、STOMP

关键概念介绍

在正式开始实现之前,了解一些关键概念是非常重要的:

1. WebSocket

WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。它允许服务器和客户端之间实时地交换数据,从而大大提升了数据传输的效率。与传统的 HTTP 不同,WebSocket 是一个持久化的连接,可以在客户端和服务器之间建立一个持续的双向通信通道。这样,无论是服务器向客户端推送消息,还是客户端向服务器发送数据,都能做到实时、低延迟。

2. STOMP

STOMP(Simple Text Oriented Messaging Protocol)是一个简单的、基于文本的消息传递协议。STOMP 协议本身不依赖于任何特定的传输协议,因此可以在多种传输协议上使用,如 TCP、WebSocket 等。STOMP 的引入简化了我们在 WebSocket 上处理消息订阅和发布的工作,它使得消息的管理变得更加直观和简单。

3. SockJS

SockJS 是一个用于 WebSockets 的 JavaScript 库。它提供了一个 WebSocket-like 的接口,并且在 WebSocket 不可用时能够回退到其他传输方式(如 AJAX 长轮询)。SockJS 确保了在各种网络条件和浏览器环境下都能正常工作,为我们的实时消息推送系统提供了坚实的基础。

项目实现步骤

步骤一:后端实现
1. WebSocket 配置

首先,我们需要配置 WebSocket,以便实现消息的实时推送。在 Spring Boot 中,我们可以通过 WebSocketConfig 类来进行配置。这部分代码的核心在于启用 STOMP 消息代理,并注册 WebSocket 端点。

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

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

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic", "/queue");
        config.setApplicationDestinationPrefixes("/app");
        config.setUserDestinationPrefix("/user");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS();
    }
}
2. 消息实体类

为了保存和管理消息,我们需要创建一个实体类 Message。这个实体类将用于存储消息的基本信息,例如发送者、接收者、内容和时间戳。

@Entity
@Table(name = "messages")
public class Message {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String fromUser;
    private String toUser;
    private String topic;
    private String content;

    @Column(name = "timestamp", nullable = false, updatable = false)
    private LocalDateTime timestamp;

    // Getters and setters
}
3. 消息服务

消息服务是实现消息发送和存储的核心部分。我们需要确保每次发送消息时,消息不仅会被推送到接收者,还会被保存到数据库中,以便后续查看历史消息。

@Service
public class MessageService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private SimpMessagingTemplate messagingTemplate;

    @Autowired
    private MessageRepository messageRepository;

    public void sendMessage(String fromUser, String toUser, String topic, String content) {
        // 保存消息到Redis
        redisTemplate.opsForList().leftPush(topic, content);

        // 保存消息到MySQL
        Message message = new Message();
        message.setFromUser(fromUser);
        message.setToUser(toUser);
        message.setTopic(topic);
        message.setContent(content);
        message.setTimestamp(LocalDateTime.now());
        messageRepository.save(message);

        // 推送消息到接收者客户端
        messagingTemplate.convertAndSend("/queue/messages", message);
    }

    // 从Redis获取消息
    public List<Object> getMessagesFromRedis(String topic) {
        return redisTemplate.opsForList().range(topic, 0, -1);
    }

    // 从MySQL获取历史消息
    public List<Message> getMessagesFromDatabase(String topic) {
        return messageRepository.findByTopicOrderByTimestampDesc(topic);
    }
}
4. 消息控制器

消息控制器用于处理客户端的请求,包括发送消息和获取历史消息。

@RestController
@RequestMapping("/messages")
public class MessageController {

    @Autowired
    private MessageService messageService;

    @PostMapping("/send")
    public void sendMessage(@RequestParam String fromUser, @RequestParam String toUser, @RequestParam String topic, @RequestParam String content) {
        messageService.sendMessage(fromUser, toUser, topic, content);
    }

    @GetMapping("/history")
    public List<Message> getHistoryMessages(@RequestParam String topic) {
        return messageService.getMessagesFromDatabase(topic);
    }
}

步骤二:前端实现

前端部分需要实现 WebSocket 的连接和消息的发送与接收。

1. WebSocket 服务

WebSocket 服务用于管理 WebSocket 的连接和消息的发送。

// src/services/websocket-service.js
import SockJS from 'sockjs-client';
import Stomp from 'stompjs';

let stompClient = null;

export function connect(userId, onMessageReceived) {
    const socket = new SockJS('/ws');
    stompClient = Stomp.over(socket);
    stompClient.connect({}, frame => {
        console.log('Connected: ' + frame);
        stompClient.subscribe(`/queue/messages`, message => {
            onMessageReceived(JSON.parse(message.body));
        });
    });
}

export function sendMessage(fromUser, toUser, topic, content) {
    const message = {
        fromUser,
        toUser,
        topic,
        content,
        timestamp: new Date().toISOString()
    };
    stompClient.send('/app/send', {}, JSON.stringify(message));
}
2. API 服务

API 服务用于与后端进行 HTTP 请求。

// src/services/api-service.js
import axios from 'axios';

export function fetchHistoryMessages(topic) {
    return axios.get('/messages/history', { params: { topic } });
}

export function sendMessage(fromUser, toUser, topic, content) {
    return axios.post('/messages/send', null, { params: { fromUser, toUser, topic, content } });
}
3. Vue 组件

Vue 组件用于展示消息并与用户交互。

<template>
    <div>
        <div>
            <h2>历史消息</h2>
            <div v-for="message in historyMessages" :key="message.id">
                <strong>{{ message.timestamp }} ({{ message.fromUser }} -> {{ message.toUser }}):</strong> {{ message.content }}
            </div>
        </div>
        <div>
            <h2>实时消息</h2>
            <div v-for="message in messages" :key="message.timestamp">
                <strong>{{ message.timestamp }} ({{ message.fromUser }} -> {{ message.toUser }}):</strong> {{ message.content }}
            </div>
            <input v-model="newMessage" @keyup.enter="sendMessage">
        </div>
    </div>
</template>

<script>
import { connect, sendMessage } from '@/services/websocket-service';
import { fetchHistoryMessages } from '@/services/api-service';

export default {
    data() {
        return {
            newMessage: '',
            messages: [],
            historyMessages: [],
            fromUser: 'user1', // should be dynamic based on your app logic
            toUser: 'user2',   // should be dynamic based on your app logic
            topic: 'topic1'    // should be dynamic based on your app logic
        };
    },
    created() {
        connect(this.fromUser, message => {
            this.messages.push(message);
        });

        // 获取历史消息
        fetchHistoryMessages(this.topic).then(response => {
            this.historyMessages = response.data;
        });
    },
    methods: {
        sendMessage() {
            sendMessage(this.fromUser, this.toUser, this.topic, this.newMessage).then(() => {
                this.newMessage = '';
            });
        }
    }
};
</script>

结论

通过本文,我们展示了如何使用 Spring Boot 和 Vue.js 实现一个实时消息推送系统。我们详细介绍了 WebSocket、STOMP 和 SockJS 等关键概念,并通过代码示例展示了如何配置和实现消息的实时推送和持久化存储。

这个系统不仅适用于即时通讯应用,还可以用于各种需要实时消息推送的场景,如通知系统、在线客服等。通过结合使用 Redis 和 MySQL,我们既保证了消息的实时性,又能提供可靠的消息存储解决方案,满足用户查看历史消息的需求。

实现一个高效、可靠的实时消息推送系统,可以极大地提升用户体验和应用的互动性。希望本文能对你有所帮助,并启发你在自己的项目中实现类似的功能。

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

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

相关文章

.net 调用海康SDK实现NVR录像视频的下载

📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!📢本文作者:由webmote 原创📢作者格言:新的征程,最近一直被测试拿捏,痛苦的挣扎中… 我们面对的不仅仅是技术还有人心,人心不可测,海水不可量,唯有技术,才是深沉黑夜中的一座闪烁的灯…

简单计算机网络概念

1.浏览器过程 输入url&#xff0c;解析url 1.协议http、https的区别&#xff1b;HTTPS就是在HTTP与TCP之间增加了SSL/TSL安全传输层 2.格式&#xff1a;协议//主机:端口/路径&#xff1b; 3.HTTP版本&#xff1a;1.0和1.1 4.HTTP/1.1&#xff1a;1. 持久连接&#xff1a;为了…

Windows子系统Ubuntu安装MySQL及windows的navicate连接

Windows子系统Ubuntu安装MySQL及局域网连接 MySQL8.0之前 mysql8.0版本

证件照背景替换软件有哪些?证照之星怎么换背景色

在照相馆拍的证件照不满意&#xff0c;自行在家拍摄了证件照&#xff0c;却不会处理复杂的照片背景怎么办呢&#xff1f;其实可以使用专业软件来替换证件照背景。这篇文章就告诉大家证件照背景替换软件有哪些&#xff0c;证件照背景替换怎么弄。 一、证件照背景替换软件有哪些…

4千6历年高考英语试题大全ACCESS\EXCEL数据库

《历年高#考英语试题大全ACCESS数据库》搜集了大量的全#国各#地高#考英语模拟试题&#xff0c;每道题目均有相应的答案和解析&#xff1b;这种数据虽然没有《一站到底》类的数据结构&#xff08;一个选项一个字段&#xff09;那么好&#xff0c;但是通过技术人员还是可以很简单…

基于SSM的图书馆管理系统的设计与实现 (含源码+sql+视频导入教程+文档+PPT)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于SSM的图书馆管理系统7拥有两种角色&#xff1a;管理员和用户 管理员&#xff1a;图书管理、类型管理、借阅管理、续借管理、归还管理、罚金管理、留言管理等 学生用户&#xff1a;借…

前端速通面经八股系列(八)—— React篇(上)

React目录 一、组件基础1. React 事件机制2. React的事件和普通的HTML事件有什么不同&#xff1f;3. React 组件中怎么做事件代理&#xff1f;它的原理是什么&#xff1f;4. React 高阶组件、Render props、hooks 有什么区别&#xff0c;为什么要不断迭代5. 对React-Fiber的理解…

眼科市场格局固化,排名靠后的光正眼科还能逆袭吗?

眼科是A股的热门领域&#xff0c;也是医疗的黄金赛道。或许也正因为如此&#xff0c;这条赛道已经习惯了通过并购&#xff0c;利用资本杠杆跑马圈地。以最大规模的龙头爱尔眼科为首&#xff0c;并购是眼科的常规操作。 然而&#xff0c;真正观察赛道腰部及以下的公司&#xff…

十八、计算机视觉-canny边缘检测

文章目录 前言一、canny检测的流程1.高斯滤波&#xff08;Gaussian Smoothing&#xff09;2.梯度计算&#xff08;Gradient Calculation&#xff09;3.非极大值抑制&#xff08;Non-maximum Suppression&#xff09;4.双阈值检测&#xff08;Double Thresholding&#xff09;5.…

6、Flume安装

按照采集通道规划&#xff0c;需在hadoop102&#xff0c;hadoop104两台节点分别部署一个Flume。可参照以下步骤先在hadoop102安装&#xff0c;然后再进行分发。 1. Flume安装部署 1.1 安装地址 &#xff08;1&#xff09; Flume官网地址&#xff1a;Welcome to Apache Flume…

COCI2016-2017#1 Kralj

目录 COCI2016-2017#1 Kralj题目描述背景输入输出数据范围 题解解法 打赏 COCI2016-2017#1 Kralj 题目描述 背景 精灵王将 n n n个精灵编号为 1 , ⋯ , n 1 , \cdots , n 1,⋯,n&#xff0c;矮人王将 n n n个矮人围成一个圆环&#xff0c;从某个矮人开始顺时针编号为 1 , ⋯…

Mysql高级篇(中)——SQL性能分析

Mysql高级篇&#xff08;中&#xff09;—— SQL性能分析 一、&#xff08;了解&#xff09;MySQL Query Optimizer 的主要功能和原理二、&#xff08;了解&#xff09;MySQL 常见瓶颈三、关键字 EXPLAIN1、是什么2、基本语法3、EXPLAIN 执行信息详解&#xff08;1&#xff09…

Windows--linux共享文件夹

1、如果共享文件夹设置在Windows上面 文件夹设置 个人家里电脑通常不设置用户名密码 linux端mount命令行 mount -t cifs -o usernamewade,vers3.0 //192.168.0.143/openvswitch-2.17.10 /root/windows

计算机专业选题推荐-基于python的岗位兼职招聘平台【python-爬虫-大数据定制】

&#x1f496;&#x1f525;作者主页&#xff1a;毕设木哥 精彩专栏推荐订阅&#xff1a;在 下方专栏&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; 实战项目 文章目录 实战项目 一、基于python的岗位兼职招聘平…

我的第3个AI项目-Advanced RAG with Gemma, Weaviate, and LlamaIndex

目录 一、项目简介概述时间kaggle地址&#xff08;代码和详细注解&#xff09;主要工作和收获技术栈数据集结果 二、bug修复在 Kaggle 使用模型时需要先同意该模型的使用条款使用 GPU 时显存不足把 Weaviate 从V3升级到V4改动一&#xff1a;创建client改动二&#xff1a;判断某…

网络编程day02(字节序、TCP编程)

目录 【1】字节序 1》大小端转换 2》端口转换 3》IP地址转换 主机字节序转换为网络字节序 &#xff08;小端序->大端序&#xff09; 网络字节序转换为主机字节序&#xff08;大端序->小端序&#xff09; 【2】TCP编程 1》流程 2》函数接口 1> socket 2> …

免费的 Mac 应用清理工具Pearcleaner v3.8.6

免费的 Mac 应用清理工具。这是一款免费开源的 Mac 应用清理工具&#xff0c;能够彻底卸载应用并清理残留文件。它采用 SwiftUI 开发&#xff0c;提供了简单易用的界面&#xff0c;支持右键卸载、迷你模式和 Homebrew 清理等功能。 下载链接&#xff1a;https://pan.quark.cn/s…

【Visual Studio 报错】vs 在使用二进制写入文件时弹窗报错:使用简体中文 gb2312 编码加载文件

如以下报错 解决办法 解决方法&#xff1a;文件->高级保存选项->将文件编码形式改为“UTF-8带签名” 若找不到高级保存选项&#xff0c;可以跟着下面路径把该选项调出来 &#xff1a;工具->自定义->命令->菜单栏中改成文件->预览右边点添加命令->类别中…

BRAM IP Native模式使用

简介 BRAM&#xff08;‌Block RAM&#xff09;是‌FPGA&#xff08;Field-Programmable Gate Array&#xff09;中的一种专用RAM资源&#xff0c;固定分布在FPGA内部的特定位置。该内容主要对BRAM&#xff08;Block RAM”的缩写&#xff09;Native模式下IP界面做详细描述和使用…

C语言进阶版第9课—指针(3)

文章目录 1. 字符指针变量2. 数组指针变量3. 二维数组传参的本质4. 函数指针变量5. typedef关键字6. 函数指针数组7. 函数指针数组的应用—转移表 1. 字符指针变量 练习题 2. 数组指针变量 在学习数组指针前&#xff0c;我们先回忆一下什么是指针数组指针数组 → 存放指针的数…