• Springboot整合WebSocket和RabbitMQ实现服务器消息推送


    这里只实现服务器端WebScket到消息中间件RabbitMQ部分,前端代码不会。前端跟中间件交互部分的功能(向中间件发送消息、从中间件读取消息)用接口代替

    实现思路

    前端发起请求与服务器建立连接 ->WebSocket发送消息到RabbitMQ队列中->WebSocket监听Rabbit消息队列中的消息

    项目结构

    image

    配置RabbitMQ

    #配置rabbitmq的基本信息 : ip 端口  账号和密码
    
    spring:
      rabbitmq:
        host: localhost
        port: 5672
        username: guest
        password: guest
        virtual-host: /
    

    写一个RabbitMQ的配置类

    package com.example.demo.config;
    
    import org.springframework.amqp.core.Binding;
    import org.springframework.amqp.core.BindingBuilder;
    import org.springframework.amqp.core.DirectExchange;
    import org.springframework.amqp.core.Queue;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * @author lyd
     * @Description: 配置RabbitMQ,创建一个交换机、一个队列
     * @date 14:46
     */
    @Configuration
    public class AppConfig {
    
    	public static final String ROUTING_KEY = "rabbit.msg";
    	public static final String DIRECT_EXCHANGE = "directexchange";
    	public static final String DIRECT_QUEUE = "directqueue";
    
    	@Bean
    	public Queue directQueue() {
    		return new Queue(DIRECT_QUEUE);
    	}
    
    	@Bean
    	public DirectExchange directExchange() {
    		return new DirectExchange(DIRECT_EXCHANGE);
    	}
    
    	@Bean
    	public Binding binding() {
    		return BindingBuilder.bind(directQueue()).to(directExchange()).with(ROUTING_KEY);
    	}
    
    
    }
    

    再写一个WebSocket启动类,开启WebSocket支持

    package com.example.demo.config;
    
    import org.springframework.amqp.rabbit.core.RabbitTemplate;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.stereotype.Component;
    import org.springframework.web.socket.server.standard.ServerEndpointExporter;
    
    /**
     * @author lyd
     * @Description: 开启WebSocket支持
     * @date 15:43
     */
    @Configuration
    @Component
    public class WebSocketConfig {
    
    	@Bean
    	public ServerEndpointExporter serverEndpointExporter(){
    		return new ServerEndpointExporter();
    	}
    
    }
    
    

    实现WebSocket的核心类,通过@OnOpen@OnClose@OnMessag@OnError四个注解实现四个核心的方法

    package com.example.demo.websocket;
    
    import com.example.demo.direct.DirectSender;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import javax.websocket.*;
    import javax.websocket.server.ServerEndpoint;
    import java.io.IOException;
    import java.util.concurrent.CopyOnWriteArraySet;
    
    @ServerEndpoint(value = "/webSocket")
    @Component
    public class WebSocketServer {
    
    	/**
    	 * 存放每个客户端对应的WebSocket对象
    	 */
    	public static CopyOnWriteArraySet<WebSocketServer> webSockets = new CopyOnWriteArraySet<WebSocketServer>();
    
    
    	@Autowired
    	static DirectSender directSender;
    
    	/**
    	 * 连接建立成功调用的方法
    	 */
    	@OnOpen
    	public void onOpen() throws InterruptedException, IOException {
    		webSockets.add(this);
    		System.out.println("有新用户加入");
    	}
    
    	@OnClose
    	public void onClose() throws IOException {
    		webSockets.remove(this);
    		System.out.println("有用户离开");
    	}
    
    	/**
    	 * 收到客户端消息后调用的方法
    	 */
    	@OnMessage
    	public void onMessage(String msg) throws InterruptedException {
    		System.out.println("从客户端接受的消息: " + msg);
    	}
    
    	@OnError
    	public void onError(Throwable error) {
    		error.printStackTrace();
    	}
    
    
    }
    
    

    定义一个消息发送类,实现一个通过WebSocket向队列发送消息的方法

    package com.example.demo.direct;
    
    import com.example.demo.config.AppConfig;
    import com.example.demo.websocket.WebSocketServer;
    import org.springframework.amqp.rabbit.core.RabbitTemplate;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    /**
     * @author lyd
     * @Description:
     * @date 14:50
     */
    @Component
    public class DirectSender {
    
    	@Autowired
    	RabbitTemplate rabbitTemplate;
    
    	/**
    	 * 向RabbitMQ队列中发送消息,方便后面客户端可以从队列中读取该消息
    	 *
    	 * 也可以用来代替客户端向队列中发送消息,我不会写前端连接rabbitmq的代码,就用这个接口代替了。或者在RabbitMQ的管理面板中手动输入数据
    	 * @param msg
    	 */
    	public void sendDirect(String msg) {
    
    		for (WebSocketServer webSocketServer : WebSocketServer.webSockets) {
    			rabbitTemplate.convertAndSend(AppConfig.DIRECT_EXCHANGE, AppConfig.ROUTING_KEY, msg +" ("+webSocketServer.toString()+")");
    		}
    
    	}
    
    
    }
    

    定义一个消息接收类,实现一个通过WebSocket从队列中读取消息的方法

    package com.example.demo.direct;
    
    import com.example.demo.config.AppConfig;
    import com.example.demo.websocket.WebSocketServer;
    import org.springframework.amqp.rabbit.annotation.RabbitHandler;
    import org.springframework.amqp.rabbit.annotation.RabbitListener;
    import org.springframework.stereotype.Component;
    
    import java.io.IOException;
    
    /**
     * @author lyd
     * @Description: 监听RabbitMQ中队列消息
     * @date 15:16
     */
    @Component
    public class DirectReceive {
    
    
    	/**
    	 * 监听客户端发送到RabbitMQ队列中的消息,并把消息发送给WebSocketServer
    	 * @param msg
    	 * @throws InterruptedException
    	 * @throws IOException
    	 */
    	@RabbitListener(queues = AppConfig.DIRECT_QUEUE)
    	@RabbitHandler
    	public void processToPre(String msg) throws InterruptedException, IOException {
    		Thread.sleep(500);
    		for (WebSocketServer webSocketServer : WebSocketServer.webSockets) {
    			System.out.println("WebSocket从队列中取出客户端("+webSocketServer.toString()+")发送过来的消息:");
    			webSocketServer.onMessage(msg);
    		}
    	}
    
    
    
    }
    

    再写一个发送消息的接口,方便测试用

    package com.example.demo.controller;
    
    import com.example.demo.direct.DirectSender;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.RestController;
    
    
    /**
     * @author lyd
     * @Description:
     * @date 14:49
     */
    @RestController
    public class MessageController {
    
    	@Autowired
    	DirectSender directSender;
    
    	/**
    	 * 接口:
    	 * 调用向队列中发送消息的方法
    	 */
    	@RequestMapping("senderMsg")
    	@ResponseBody
    	public void senderMsg() {
    		directSender.sendDirect("我是向队列中存储的消息");
    	}
    
    
    }
    

    最后写一个html页面,用于前端跟客户端建立连接

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>Insert title here</title>
    </head>
    <body>
    
    </body>
    <script type="text/javascript">
        var websocket = null;
        if ('WebSocket' in window) {
            websocket = new WebSocket('ws://localhost:8080/webSocket');
        } else {
            alert('该浏览器不支持websocket');
        }
    
        websocket.onopen = function (e) {
            console.log('websocket建立连接');
            websocket.send('websocket建立连接');
        }
        websocket.onclose = function (e) {
            console.log('websocket关闭连接');
        }
        websocket.onmessage = function (e) {
            console.log(e, 'websocket收到消息');
            document.getElementById('msgs').innerHTML = document.getElementById('msgs').innerHTML + '<br/>' + e.data;
        }
        websocket.onerror = function (event) {
            console.log('websocket通信发生错误');
    
        }
        window.onbeforeunload = function (event) {
            websocket.close();
        }
    
    </script>
    </html>
    

    测试

    1)启动项目后访问http://localhost:8080/chat.html,客户端跟服务端建立连接

    image

    2) 调用http://localhost:8080/senderMsg,WebSocket向RabbitMQ队列中发送消息,这一步也同时实现了服务端监听队列消息并把消息发给WebSocket

    image

    项目源码

    https://github.com/Wranglery/test-rabbitMQ-websocket

  • 相关阅读:
    Centos系统通过tar.gz包安装MySQL5.7
    性能优化之MySQL优化(慕课)
    高性能可扩展MySQL数据库设计及架构优化 电商项目(慕课)第2章 电商实例数据库结构设计
    高性能可扩展MySQL数据库设计及架构优化 电商项目(慕课)第1章 数据库开发规范的制定
    道路交通实时流量监控预测系统(大讲台)
    Deepgreen DB 是什么(含Deepgreen和Greenplum下载地址)
    Linux常用命令-----------------磁盘挂载命令
    一站式学习Redis 从入门到高可用分布式实践(慕课)第十一章 Redis云平台Cachecloud
    一站式学习Redis 从入门到高可用分布式实践(慕课)第十章 缓存设计与优化
    一站式学习Redis 从入门到高可用分布式实践(慕课)第九章 Redis Cluster利用redis-trib.rb快速搭建集群
  • 原文地址:https://www.cnblogs.com/lyd447113735/p/14951601.html
Copyright © 2020-2023  润新知