Springboot + Vue + WebSocket + Notification实现消息推送功能

实现功能

基于Springboot与Vue架构,首先使用Websocket实现频道订阅,在实现点对点与群发功能后,在前端调用windows自带的消息通知,实现推送功能。

开发环境

  • Springboot 2.6.7
  • vue 2.6.11
  • socket-client 1.0.0

准备工作

在 Vue.js 项目中安装sockjs-client和stompjs。

java 复制代码
npm install sockjs-client stompjs

在后端项目中添加依赖。

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

WebSocket

为完成单播或者广播的频道的订阅功能,需要在前端和后端完成WebSocket的基本配置。

前端配置

需在vue项目中新建websocket.js文件,主要完成:

1.获取userid

2.定义WebSocketService,完成connect、subscribe、unsubscribe、sendMessage、disconnect等主要函数。

代码如下所示。

javascript 复制代码
websocket.js
import SockJS from 'sockjs-client';
import Stomp from 'stompjs';

const userid = JSON.parse(sessionStorage.getItem('CurUser')).id

class WebSocketService {
    constructor() {
        this.stompClient = null;
        this.subscriptions = new Map(); // 存储订阅的频道
    }

    // 连接 WebSocket
    connect() {
        const socket = new SockJS("/api/broadcast"); // 后端地址
        this.stompClient = Stomp.over(socket);
        this.stompClient.connect({}, () => {
            console.log('do connect method');
            console.log('stompClient', this.stompClient)
            this.subscribe('/user/' + userid.toString() + '/alone/getResponse', (response) => {
                if (this.onGlobalNotification) {
                    console.log("message print", response)
                    // this.onGlobalNotification(JSON.parse(message.body));
                    this.onGlobalNotification(response.body);
                }
            });
        });
    }

    // 订阅频道
    subscribe(destination, callback) {
        const subscription = this.stompClient.subscribe(destination, callback);
        this.subscriptions.set(destination, subscription);
    }

    // 取消订阅
    unsubscribe(destination) {
        const subscription = this.subscriptions.get(destination);
        if (subscription) {
            subscription.unsubscribe();
            this.subscriptions.delete(destination);
        }
    }

    // 发送消息到后端
    sendMessage(destination, message) {
        console.log("sendMessage method , message is ", message.content)
        this.stompClient.send(destination, {}, message.content);
    }

    // 断开连接
    disconnect() {
        if (this.stompClient) {
            this.stompClient.disconnect();
            console.log('WebSocket 断开连接!');
        }
    }
}

export default new WebSocketService();

后端配置

在后端同样需要完成频道的订阅,新建文件WebSocketConfig.java,代码如下所示。

java 复制代码
package com.wms.common;

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

import javax.annotation.Resource;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Resource
    public AppConfig appConfig;

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker(
                "/user", "/topic1", "/topic2", "/mass"
        );
        // 点对点使用的订阅前缀(客户端订阅路径上会体现出来),不设置的话,默认也是 /user/
        // 注意,这里必须和上面设置的Broker:/user 一致(两个都可以自定义,但必须一致)。否则连接不上
        registry.setUserDestinationPrefix("/user/");
        // 指服务端接收地址的前缀,意思就是说客户端给服务端发消息的地址的前缀
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        // 注册一个STOMP的endpoint端点,并指定使用SockJS协议
        // 前端使用这个地址连接后端 WebSocket接口
        registry.addEndpoint("/broadcast", "/point")
                // 允许所有源跨域。还可以指定ip配置:http://ip:*
                // 低版本的SpringBoot(2.1.5.RELEASE 就不行)不行
                .setAllowedOriginPatterns(appConfig.getFrontHttpUrl()) // 此处填写前端页面地址
                .withSockJS();
    }
}

Vue

在用户登录之后,首先初始化WebSocket 连接,然后定义全局通知的回调,在回调函数onGlobalNotification中实现调用windows自带的通知功能Notification。

javascript 复制代码
// 初始化 WebSocket 连接
WebSocketService.connect();
// 定义全局通知的回调
WebSocketService.onGlobalNotification = (message) => {
    this.sendNotification('xxx',message)
    // this.$bus.$emit("postTrigger")
};
javascript 复制代码
    // 发送通知的方法
    sendNotification (title, body) {
      // console.log("sendNotification", Notification.permission)
      // 检查浏览器是否支持 Notification API
      if ('Notification' in window) {
        // 如果通知权限已经授予
        if (Notification.permission === "granted") {
          new Notification(title, {
            body: body,
            icon: logoIcon,
            requireInteraction: true
          });
        } else if (Notification.permission !== "denied") {
          // 请求用户授权
          Notification.requestPermission().then(permission => {
            if (permission === "granted") {
              new Notification(title, {
                body: body,
                icon: logoIcon,
                requireInteraction: true
              });
            }
          });
        }
      } else {
        console.log("浏览器不支持通知功能。");
      }
    },

在需要发送消息的地方使用函数sendMessage,在MethodApi处填写后端对应接口。

javascript 复制代码
WebSocketService.sendMessage(
    '/MethodApi', 
        {content: "message you want send"});

Springboot

在后端需要在controller文件中实现对应的MethodApi接口函数, 确定消息传递的目标用户与对应的消息,调用messagingTemplate中的函数convertAndSendToUser,完成在频道/user/userid/alone/getResponse的消息通知。

java 复制代码
controller.java
@Autowired
private SimpMessagingTemplate messagingTemplate;

// p2p notification
@MessageMapping("/MethodApi")
public void p2pNotify(String content){
	System.out.println(content);
	// 可在此处通过接受到的消息确定目标用户 userid(int) 与 对应的消息 message(string)
	System.out.println("=====发送通知=====");
	messagingTemplate.convertAndSendToUser(userid.toString(),"/alone/getResponse",message);
}

效果图

此时就可以在本地进行测试了,效果如下:

服务器部署

因为windows系统通知需要浏览器给予网页权限,所以需要vue启用https协议,配置如下:

javascript 复制代码
module.exports = {
    devServer: {
        port:8001,
        https:true,
        proxy: {
            '/api': {
                target: "http://localhost:8091/", // 代理目标的基础路径
                secure: true,  // 如果是https接口,需要配置这个参数
                changeOrigin: true, // 支持跨域
                pathRewrite: {
                    '^/api': '',
                }
            }
        }
    },
}
相关推荐
難釋懷42 分钟前
Vue解决开发环境 Ajax 跨域问题
前端·vue.js·ajax
KK溜了溜了1 小时前
JAVA-springboot log日志
java·spring boot·logback
挑战者6668881 小时前
vue入门环境搭建及demo运行
前端·javascript·vue.js
我命由我123452 小时前
Spring Boot 项目集成 Redis 问题:RedisTemplate 多余空格问题
java·开发语言·spring boot·redis·后端·java-ee·intellij-idea
面朝大海,春不暖,花不开2 小时前
Spring Boot消息系统开发指南
java·spring boot·后端
hshpy2 小时前
setting up Activiti BPMN Workflow Engine with Spring Boot
数据库·spring boot·后端
jay神2 小时前
基于Springboot的宠物领养系统
java·spring boot·后端·宠物·软件设计与开发
不知几秋3 小时前
Spring Boot
java·前端·spring boot
程序猿ZhangSir3 小时前
Vue3 项目的基本架构解读
前端·javascript·vue.js
亲亲小宝宝鸭4 小时前
写了两个小需求,终于搞清楚了表格合并
前端·vue.js