记录工作

需要的依赖

<!--fastjson坐标-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.79</version>
</dependency>
<!--RabbitMQ-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!--WebSocket-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.46</version>
</dependency>
<!--JSON-->
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
rabbitmq:
host: 127.0.0.0.1 #(自己的服务地址)
port: 5672
username: admin #rabbitmq的用户名
password: admin #密码
virtual-host: /
# 开启消息发送确认
publisher-confirm-type: correlated
publisher-returns: true
listener:
simple:
acknowledge-mode: manual

rabbitmq创建队列以及路由配置类,这里用的是路由的方式

package com.example.demotest.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; /**
* @title
* @description RabbitMQ 配置类
* @author admin issuser
* @updateTime 2022/11/10 15:44
* @throws
*/
@Slf4j
@Configuration
public class RabbitConfig { //websocket 消息队列
public static final String msg_queue = "msg_queue"; //消息交换机
public static final String msg_exchang = "msg_exchang"; //消息路由键
public static final String msg_routing_key = "msg_routing_key"; /**
* 消息队列
* @return
*/
@Bean
public Queue msgQueue(){
return new Queue(msg_queue);
} @Bean
public Queue newQueue(){
return new Queue("new_queue");
} @Bean
public DirectExchange directExchange(){
return new DirectExchange(msg_exchang);
} @Bean
public DirectExchange directExchange1(){
return new DirectExchange("new_exchang");
} /**
* 消息队列绑定消息交换机
* @return
*/
@Bean
public Binding msgBinding(){
return BindingBuilder.bind(msgQueue()).to(directExchange()).with(msg_routing_key);
} @Bean
public Binding meBinding(){
return BindingBuilder.bind(newQueue()).to(directExchange1()).with("me_key");
} @Bean
public RabbitTemplate createRabbitTemplate(ConnectionFactory connectionFactory){
RabbitTemplate rabbitTemplate = new RabbitTemplate();
rabbitTemplate.setConnectionFactory(connectionFactory);
//设置开启Mandatory,才能触发回调函数,无论消息推送结果怎么样都强制调用回调函数
rabbitTemplate.setMandatory(true); rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> log.info("发送订阅消息确认,确认情况:{}, 原因:{}", ack, cause)); rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> log.info("发送到订阅消息: {} , 回应码: {}, 回应信息: {}, 交换机: {}, 路由键: {}", message, replyCode, replyText, exchange, routingKey)); return rabbitTemplate;
}
}

发送消息的配置类,我这里稍微改造了一下直接变成了接口,如果不需要只需要删除接口有关的注解就可以了,返回类型其实是void

package com.example.demotest.controller;

import com.alibaba.fastjson.JSONObject;
import com.example.demotest.config.RabbitConfig;
import com.example.demotest.entity.ConfigurationTable;
import com.example.demotest.util.Redis;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource;
import java.util.UUID; /**
* @title
* @description 消息提供者
* @author admin issuser
* @updateTime 2022/11/10 15:44
* @throws
*/
@Slf4j
@Component
@RestController
@Api(tags = "发消息")
public class RabbitProduct { @Resource
private RabbitTemplate rabbitTemplate; /**
* 构造方法注入rabbitTemplate
*/
@Autowired
public RabbitProduct(RabbitTemplate rabbitTemplate){
this.rabbitTemplate = rabbitTemplate;
} @Resource
private Redis redis; //发送消息 推送到websocket 参数自定义 转为String发送消息
@GetMapping("/mm")
@ApiOperation(value = "发消息")
public String sendMSG(String msg,ConfigurationTable configurationTable){
CorrelationData correlationId = new CorrelationData(UUID.randomUUID().toString());
redis.selDateKey(1,"ConfigurationType",configurationTable.getConfigurationType(),500);
//把消息对象放入路由对应的队列当中去
rabbitTemplate.convertAndSend(configurationTable.getRoute(),configurationTable.getBindingKey(), JSONObject.toJSON(msg).toString(), correlationId);
return "操作成功!";
} public String sendMsg(String msg,ConfigurationTable configurationTable){
CorrelationData correlationId = new CorrelationData(UUID.randomUUID().toString()); //把消息对象放入路由对应的队列当中去
rabbitTemplate.convertAndSend(configurationTable.getRoute(),configurationTable.getBindingKey(), JSONObject.toJSON(msg).toString(), correlationId);
return "操作成功!";
} }

接下来就是接收消息了,我这里使用的是手动ACK的方式,想要简单一点的话,用注解直接监听,把rabbitConfig中的手动ack删了就好

package com.example.demotest.listener;

import com.example.demotest.config.WebSocketServerEndpoint;
import com.example.demotest.util.Redis;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.IOException; /**
* Description :
* Copyright : Copyright (c) 2022
* Company : 中移(成都)产业研究院 Co. Ltd.
*
* @author daisuhang
* @version 1.0.0
* @createTime 2022年11月14日 09:07:00
*/
@Slf4j
@Component
public class RabbitNewConsumer {
@Autowired
private Redis redis; private static RabbitNewConsumer rabbitNewConsumer;
@Resource
private WebSocketServerEndpoint webSocketServerEndpoint; //引入WebSocket /**
* 构造方法注入rabbitTemplate
*/
@PostConstruct
public void init() {
rabbitNewConsumer = this;
rabbitNewConsumer.webSocketServerEndpoint = webSocketServerEndpoint;
} @RabbitListener(bindings = @QueueBinding(
value = @Queue(value = "new_queue",durable = "true"),
exchange = @Exchange(name = "new_exchang",durable = "true",type = "direct"),
key = "me_key"
)) //监听队列
public void msgReceive(String content, Message message, Channel channel) throws IOException {
log.info("----------------接收到消息--new-queue------------------"+content);
//发送给WebSocket 由WebSocket推送给前端
String configurationType = redis.get("ConfigurationType");
if (configurationType.equals("事件上传")){
rabbitNewConsumer.webSocketServerEndpoint.sendMessageOnline(content);
}
// 确认消息已接收
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
}

下面这个是加了休眠时间的延时

package com.example.demotest.listener;

import com.example.demotest.config.RabbitConfig;
import com.example.demotest.config.WebSocketServerEndpoint;
import com.example.demotest.util.Redis;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.IOException; import static com.example.demotest.config.RabbitConfig.*; /**
* @title
* @description 定时消息队列 消费监听回调
* @author admin issuser
* @updateTime 2022/11/10 15:43
* @throws
*/
@Slf4j
@Component
public class RabbitConsumer { private static RabbitConsumer rabbitConsumer;
@Resource
private WebSocketServerEndpoint webSocketServerEndpoint; //引入WebSocket @Autowired
private Redis redis;
/**
* 构造方法注入rabbitTemplate
*/
@PostConstruct
public void init() {
rabbitConsumer = this;
rabbitConsumer.webSocketServerEndpoint = webSocketServerEndpoint;
} @RabbitListener(bindings = @QueueBinding(
value = @Queue(value = msg_queue,durable = "true"),
exchange = @Exchange(name = msg_exchang,durable = "true",type = "direct"),
key = msg_routing_key
)) //监听队列
public void msgReceive(String content, Message message, Channel channel) throws IOException {
log.info("----------------接收到消息-msg_queue-------------------"+content);
//发送给WebSocket 由WebSocket推送给前端
String configurationType = redis.get("ConfigurationType");
if (configurationType.equals("属性上传")){
rabbitConsumer.webSocketServerEndpoint.sendMessageOnline(content);
// 确认消息已接收
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
channel.basicReject(message.getMessageProperties().getDeliveryTag(),true);
} }

接下来就是socket的一些配置

package com.example.demotest.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter; /**
* WebSocket配置类
*/
@Configuration
public class WebSocketConfig { @Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
} }

连接前端的配置,以及一些方法封装

package com.example.demotest.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import javax.annotation.PostConstruct;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap; /**
* WebSocket 服务配置类
* 定义 userId 为当前连接(在线) WebSocket 的用户
*/
@Slf4j
@Component
@ServerEndpoint(value = "/ws/{userId}")
public class WebSocketServerEndpoint { private Session session; //建立连接的会话
private String userId; //当前连接用户id 路径参数 /**
* 存放存活的Session集合(map保存)
*/
private static ConcurrentHashMap<String , WebSocketServerEndpoint> livingSession = new ConcurrentHashMap<>(); /**
* 建立连接的回调
* session 建立连接的会话
* userId 当前连接用户id 路径参数
*/
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId){
this.session = session;
this.userId = userId;
livingSession.put(userId, this); log.debug("----[ WebSocket ]---- 用户id为 : {} 的用户进入WebSocket连接 ! 当前在线人数为 : {} 人 !--------",userId,livingSession.size());
} /**
* 关闭连接的回调
* 移除用户在线状态
*/
@OnClose
public void onClose(){
livingSession.remove(userId);
log.debug("----[ WebSocket ]---- 用户id为 : {} 的用户退出WebSocket连接 ! 当前在线人数为 : {} 人 !--------",userId,livingSession.size());
} @OnMessage
public void onMessage(String message, Session session, @PathParam("userId") String userId) {
log.debug("--------收到用户id为 : {} 的用户发送的消息 ! 消息内容为 : ------------------",userId,message);
//sendMessageToAll(userId + " : " + message);
} @OnError
public void onError(Session session, Throwable error) {
log.error("----------------WebSocket发生错误----------------");
log.error(error.getStackTrace() + "");
} /**
* 根据userId发送给用户
* @param userId
* @param message
*/
public void sendMessageById(String userId, String message) {
livingSession.forEach((sessionId, session) -> {
//发给指定的接收用户
if (userId.equals(session.userId)) {
sendMessageBySession(session.session, message);
}
});
} /**
* 根据Session发送消息给用户
* @param session
* @param message
*/
public void sendMessageBySession(Session session, String message) {
try {
session.getBasicRemote().sendText(message);
} catch (IOException e) {
log.error("----[ WebSocket ]------给用户发送消息失败---------");
e.printStackTrace();
}
} public void sendMessageBySessionObject(Session session, Object message) {
try {
session.getBasicRemote().sendObject(message);
} catch (IOException | EncodeException e) {
log.error("----[ WebSocket ]------给用户发送消息失败---------");
e.printStackTrace();
}
} /**
* 给在线用户发送消息
* @param message
*/
public void sendMessageOnline(String message) {
livingSession.forEach((sessionId, session) -> {
if(session.session.isOpen()){
sendMessageBySession(session.session, message);
}
});
} /**
* 给在线用户发送消息
* @param message
*/
public void sendMessageOnlineObject(Object message) {
livingSession.forEach((sessionId, session) -> {
if(session.session.isOpen()){
sendMessageBySessionObject(session.session, message);
}
});
} }

最后就是前端页面了

<!DOCTYPE HTML>
<html>
<head>
<title>My WebSocket</title>
</head>
<body>
Welcome<br/>
<input id="text" type="text" /><button onclick="send()">Send</button> <button onclick="closeWebSocket()">Close</button>
<div id="message">
</div>
</body>
<script type="text/javascript">
var websocket = null;
//判断当前浏览器是否支持WebSocket
if('WebSocket' in window){
websocket = new WebSocket("ws://localhost:8001/ws/{123}");
}
else{
alert('当前浏览器 Not support websocket')
} //连接发生错误的回调方法
websocket.onerror = function(){
setMessageInnerHTML("error");
}; //连接成功建立的回调方法
websocket.onopen = function(event){
setMessageInnerHTML("WebSocket连接成功");
} //接收到消息的回调方法
websocket.onmessage = function(event){
setMessageInnerHTML(event.data);
} //连接关闭的回调方法
websocket.onclose = function(){
setMessageInnerHTML("WebSocket连接关闭");
} //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function(){
websocket.close();
} //将消息显示在网页上
function setMessageInnerHTML(innerHTML){
document.getElementById('message').innerHTML += innerHTML + '<br/>';
} //关闭连接
function closeWebSocket(){
websocket.close();
} //发送消息
function send(){
var message = document.getElementById('text').value;
websocket.send(message);
}
</script>
</html>

到此本文就结束了

java springboot+rabbitmq+websocket 订阅展示的更多相关文章

  1. Java使用RabbitMQ之订阅分发(Topic)

    使用RabbitMQ进行消息发布和订阅,生产者将消息发送给转发器(exchange),转发器根据路由键匹配已绑定的消息队列并转发消息,主题模式支持路由键的通配. 生产者代码: package org. ...

  2. Java Springboot webSocket简单实现,调接口推送消息到客户端socket

    Java Springboot webSocket简单实现,调接口推送消息到客户端socket 后台一般作为webSocket服务器,前台作为client.真实场景可能是后台程序在运行时(满足一定条件 ...

  3. springboot+rabbitmq整合示例程

    关于什么是rabbitmq,请看另一篇文: http://www.cnblogs.com/boshen-hzb/p/6840064.html 一.新建maven工程:springboot-rabbit ...

  4. 【Other】最近在研究的, Java/Springboot/RPC/JPA等

    我的Springboot框架,欢迎关注: https://github.com/junneyang/common-web-starter Dubbo-大波-服务化框架 dubbo_百度搜索 Dubbo ...

  5. SpringBoot 整合 WebSocket

    SpringBoot 整合 WebSocket(topic广播) 1.什么是WebSocket WebSocket为游览器和服务器提供了双工异步通信的功能,即游览器可以向服务器发送消息,服务器也可以向 ...

  6. SpringAOP+RabbitMQ+WebSocket实战

    背景 最近公司的客户要求,分配给员工的任务除了有微信通知外,还希望PC端的网页也能实时收到通知.管理员分配任务是在我们的系统A,而员工接受任务是在系统B.两个系统都是现在已投入使用的系统. 技术选型 ...

  7. java~springboot~目录索引

    回到占占推荐博客索引 最近写了不过关于java,spring,微服务的相关文章,今天把它整理一下,方便大家学习与参考. java~springboot~目录索引 Java~关于开发工具和包包 Java ...

  8. SpringBoot集成WebSocket【基于纯H5】进行点对点[一对一]和广播[一对多]实时推送

    代码全部复制,仅供自己学习用 1.环境搭建 因为在上一篇基于STOMP协议实现的WebSocket里已经有大概介绍过Web的基本情况了,所以在这篇就不多说了,我们直接进入正题吧,在SpringBoot ...

  9. SpringBoot基于websocket的网页聊天

    一.入门简介正常聊天程序需要使用消息组件ActiveMQ或者Kafka等,这里是一个Websocket入门程序. 有人有疑问这个技术有什么作用,为什么要有它?其实我们虽然有http协议,但是它有一个缺 ...

  10. springboot rabbitmq 死信队列应用场景和完整demo

    何为死信队列? 死信队列实际上就是,当我们的业务队列处理失败(比如抛异常并且达到了retry的上限),就会将消息重新投递到另一个Exchange(Dead Letter Exchanges),该Exc ...

随机推荐

  1. CSS 奇思妙想之酷炫倒影

    在 CSS 中,倒影是一种比较常见的效果.今天,我们就将尝试,使用 CSS 完成各类不同的倒影效果,话不多说,直接进入主题. 实现倒影的两种方式 首先,快速过一下在 CSS 中,实现倒影的 2 种方式 ...

  2. 通过Docker启动Solace,并在Spring Boot通过JMS整合Solace

    1 简介 Solace是一个强大的实时性的事件驱动消息队列.本文将介绍如何在Spring中使用,虽然代码使用的是Spring Boot,但并没有使用相关starter,跟Spring的整合一样,可通用 ...

  3. appium如何连接多台设备

    我们在做app自动化的时候,若要考虑兼容性问题,需要跑几台设备,要是一台一台的跑比较耗 时,因此需要考虑使用多线程来同时操作多台设备. 1.我们拿两台设备来模拟操作下,使用:adb devices查看 ...

  4. 重写Object类的equals方法-Objects类的equals方法

    重写Object类的equals方法 Object类的equals方法默认比较的是两个对象的地址值,没有意义所以我们学要重写equals方法,比较两个对象的属性值(name,age) 对象的属性值一样 ...

  5. 创建型模式 - 原型模式Prototype

    孩子生来没娘的NT审核机制,又开始说我涉及到广告了,我涉及到什么广告了?我接着发. 学习而来,代码是自己敲的.也有些自己的理解在里边,有问题希望大家指出. 所属:创建型模式  原型模式 一般会和 工场 ...

  6. 将Grafana嵌入自己的应用

    什么是Grafana Grafana是一款强大的可视化工具,无论数据存储在哪里,都可以查询.可视化.警报和理解您的数据.使用Grafana,您可以通过美丽.灵活的仪表板创建.探索和共享所有数据. 场景 ...

  7. Altium Designer v23.0.1.38图文详解

    Altium Designer (AD)  最新安装河蟹教程 ,ltium designer  显著地提高了用户体验和效率,利用时尚界面使设计流程流线化,同时实现了前所未有的性能优化.使用64位体系结 ...

  8. 怎么在GridView中限制显示字数

    三种方法可以实现,前两种是C#代码实现(原理一样),第三种是CSS实现. 1.cs代码中:GridView的RowDataBound中对想做处理的项做Remove()字符串截取. 2.aspx页面中: ...

  9. cv::Mat::step详解

    1.简介 step的几个类别区分: step:矩阵第一行元素的字节数 step[0]:矩阵第一行元素的字节数 step[1]:矩阵中一个元素的字节数 step1(0):矩阵中一行有几个通道数 step ...

  10. CSS_语法格式

    * 格式: 选择器{ 属性名1:属性值1: 属性名2:属性值2: ... } *选择器:筛选具有相似特征的元素 *注意: *没一对属性需要使用":"隔开,对最后一对属性可以不加&q ...