springboot集成websocket点对点推送、广播推送

合集下载

SpringBoot实现WebSocket即时通讯的示例代码

SpringBoot实现WebSocket即时通讯的示例代码

SpringBoot实现WebSocket即时通讯的⽰例代码⽬录1、引⼊依赖2、WebSocketConfig 开启WebSocket3、WebSocketServer4、测试连接发送和接收消息5、在线测试地址6、测试截图1、引⼊依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.3</version></dependency>2、WebSocketConfig 开启WebSocketpackage com.shucha.deveiface.web.config;/*** @author tqf* @Description* @Version 1.0* @since 2022-04-12 15:35*/import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** 开启WebSocket*/@Configurationpublic class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter(){return new ServerEndpointExporter();}}3、WebSocketServerpackage com.shucha.deveiface.web.ws;/*** @author tqf* @Description* @Version 1.0* @since 2022-04-12 15:33*/import lombok.extern.slf4j.Slf4j;import ponent;import org.springframework.web.socket.WebSocketSession;import javax.websocket.*;import javax.websocket.server.PathParam;import javax.websocket.server.ServerEndpoint;import java.util.ArrayList;import java.util.Collections;import java.util.List;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.CopyOnWriteArraySet;@Component@ServerEndpoint("/webSocket/{userId}")@Slf4jpublic class WebSocketServer {private Session session;private String userId;/**静态变量,⽤来记录当前在线连接数。

SpringBoot实战之netty-socketio实现简单聊天室(给指定用户推送消息)

SpringBoot实战之netty-socketio实现简单聊天室(给指定用户推送消息)

SpringBoot实战之netty-socketio实现简单聊天室(给指定⽤户推送消息)⽹上好多例⼦都是群发的,本⽂实现⼀对⼀的发送,给指定客户端进⾏消息推送1、本⽂使⽤到netty-socketio开源库,以及MySQL,所以⾸先在pom.xml中添加相应的依赖库<dependency><groupId>com.corundumstudio.socketio</groupId><artifactId>netty-socketio</artifactId><version>1.7.11</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency>2、修改application.properties, 添加端⼝及主机数据库连接等相关配置,wss.server.port=8081wss.server.host=localhostspring.datasource.url = jdbc:mysql://127.0.0.1:3306/springlearnername = rootspring.datasource.password = rootspring.datasource.driverClassName = com.mysql.jdbc.Driver# Specify the DBMSspring.jpa.database = MYSQL# Show or not log for each sql queryspring.jpa.show-sql = true# Hibernate ddl auto (create, create-drop, update)spring.jpa.hibernate.ddl-auto = update# Naming strategyspring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy# stripped before adding them to the entity manager)spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect3、修改Application⽂件,添加nettysocket的相关配置信息package com.xiaofangtech.sunt;import org.springframework.beans.factory.annotation.Value;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.annotation.Bean;import com.corundumstudio.socketio.AuthorizationListener;import com.corundumstudio.socketio.Configuration;import com.corundumstudio.socketio.HandshakeData;import com.corundumstudio.socketio.SocketIOServer;import com.corundumstudio.socketio.annotation.SpringAnnotationScanner;@SpringBootApplicationpublic class NettySocketSpringApplication {@Value("${wss.server.host}")private String host;@Value("${wss.server.port}")private Integer port;@Beanpublic SocketIOServer socketIOServer(){Configuration config = new Configuration();config.setHostname(host);config.setPort(port);//该处可以⽤来进⾏⾝份验证config.setAuthorizationListener(new AuthorizationListener() {@Overridepublic boolean isAuthorized(HandshakeData data) {//http://localhost:8081?username=test&password=test//例如果使⽤上⾯的链接进⾏connect,可以使⽤如下代码获取⽤户密码信息,本⽂不做⾝份验证// String username = data.getSingleUrlParam("username");// String password = data.getSingleUrlParam("password");return true;}});final SocketIOServer server = new SocketIOServer(config);return server;}@Beanpublic SpringAnnotationScanner springAnnotationScanner(SocketIOServer socketServer) {return new SpringAnnotationScanner(socketServer);}public static void main(String[] args) {SpringApplication.run(NettySocketSpringApplication.class, args);}}4、添加消息结构类MessageInfo.javapackage com.xiaofangtech.sunt.message;public class MessageInfo {//源客户端idprivate String sourceClientId;//⽬标客户端idprivate String targetClientId;//消息类型private String msgType;//消息内容private String msgContent;public String getSourceClientId() {return sourceClientId;}public void setSourceClientId(String sourceClientId) {this.sourceClientId = sourceClientId;}public String getTargetClientId() {return targetClientId;}public void setTargetClientId(String targetClientId) {this.targetClientId = targetClientId;}public String getMsgType() {return msgType;}public void setMsgType(String msgType) {this.msgType = msgType;}public String getMsgContent() {return msgContent;}public void setMsgContent(String msgContent) {this.msgContent = msgContent;}}5、添加客户端信息,⽤来存放客户端的sessionidpackage com.xiaofangtech.sunt.bean;import java.util.Date;import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.Table;import javax.validation.constraints.NotNull;@Entity@Table(name="t_clientinfo")public class ClientInfo {@Id@NotNullprivate String clientid;private Short connected;private Long mostsignbits;private Long leastsignbits;private Date lastconnecteddate;public String getClientid() {return clientid;}public void setClientid(String clientid) {this.clientid = clientid;}public Short getConnected() {return connected;}public void setConnected(Short connected) {this.connected = connected;}public Long getMostsignbits() {return mostsignbits;}public void setMostsignbits(Long mostsignbits) {this.mostsignbits = mostsignbits;}public Long getLeastsignbits() {return leastsignbits;}public void setLeastsignbits(Long leastsignbits) {this.leastsignbits = leastsignbits;}public Date getLastconnecteddate() {return lastconnecteddate;}public void setLastconnecteddate(Date lastconnecteddate) {stconnecteddate = lastconnecteddate;}}6、添加查询数据库接⼝ClientInfoRepository.javapackage com.xiaofangtech.sunt.repository;import org.springframework.data.repository.CrudRepository;import com.xiaofangtech.sunt.bean.ClientInfo;public interface ClientInfoRepository extends CrudRepository<ClientInfo, String>{ ClientInfo findClientByclientid(String clientId);}7、添加消息处理类MessageEventHandler.Javapackage com.xiaofangtech.sunt.message;import java.util.Date;import java.util.UUID;import org.springframework.beans.factory.annotation.Autowired;import ponent;import com.corundumstudio.socketio.AckRequest;import com.corundumstudio.socketio.SocketIOClient;import com.corundumstudio.socketio.SocketIOServer;import com.corundumstudio.socketio.annotation.OnConnect;import com.corundumstudio.socketio.annotation.OnDisconnect;import com.corundumstudio.socketio.annotation.OnEvent;import com.xiaofangtech.sunt.bean.ClientInfo;import com.xiaofangtech.sunt.repository.ClientInfoRepository;@Componentpublic class MessageEventHandler{private final SocketIOServer server;@Autowiredprivate ClientInfoRepository clientInfoRepository;@Autowiredpublic MessageEventHandler(SocketIOServer server){this.server = server;}//添加connect事件,当客户端发起连接时调⽤,本⽂中将clientid与sessionid存⼊数据库//⽅便后⾯发送消息时查找到对应的⽬标client,@OnConnectpublic void onConnect(SocketIOClient client){String clientId = client.getHandshakeData().getSingleUrlParam("clientid");ClientInfo clientInfo = clientInfoRepository.findClientByclientid(clientId);if (clientInfo != null){Date nowTime = new Date(System.currentTimeMillis());clientInfo.setConnected((short)1);clientInfo.setMostsignbits(client.getSessionId().getMostSignificantBits());clientInfo.setLeastsignbits(client.getSessionId().getLeastSignificantBits());clientInfo.setLastconnecteddate(nowTime);clientInfoRepository.save(clientInfo);}}//添加@OnDisconnect事件,客户端断开连接时调⽤,刷新客户端信息@OnDisconnectpublic void onDisconnect(SocketIOClient client){String clientId = client.getHandshakeData().getSingleUrlParam("clientid");ClientInfo clientInfo = clientInfoRepository.findClientByclientid(clientId);if (clientInfo != null){clientInfo.setConnected((short)0);clientInfo.setMostsignbits(null);clientInfo.setLeastsignbits(null);clientInfoRepository.save(clientInfo);}}//消息接收⼊⼝,当接收到消息后,查找发送⽬标客户端,并且向该客户端发送消息,且给⾃⼰发送消息 @OnEvent(value = "messageevent")public void onEvent(SocketIOClient client, AckRequest request, MessageInfo data){String targetClientId = data.getTargetClientId();ClientInfo clientInfo = clientInfoRepository.findClientByclientid(targetClientId);if (clientInfo != null && clientInfo.getConnected() != 0){UUID uuid = new UUID(clientInfo.getMostsignbits(), clientInfo.getLeastsignbits());System.out.println(uuid.toString());MessageInfo sendData = new MessageInfo();sendData.setSourceClientId(data.getSourceClientId());sendData.setTargetClientId(data.getTargetClientId());sendData.setMsgType("chat");sendData.setMsgContent(data.getMsgContent());client.sendEvent("messageevent", sendData);server.getClient(uuid).sendEvent("messageevent", sendData);}}}8、添加ServerRunner.javapackage com.xiaofangtech.sunt.message;import org.springframework.beans.factory.annotation.Autowired;import mandLineRunner;import ponent;import com.corundumstudio.socketio.SocketIOServer;@Componentpublic class ServerRunner implements CommandLineRunner {private final SocketIOServer server;@Autowiredpublic ServerRunner(SocketIOServer server) {this.server = server;}@Overridepublic void run(String... args) throws Exception {server.start();}}9、⼯程结构10、运⾏测试1)添加基础数据,数据库中预置3个客户端testclient1,testclient2,testclient32) 创建客户端⽂件index.html,index2.html,index3.html分别代表testclient1 testclient2 testclient3三个⽤户其中clientid为发送者id, targetclientid为⽬标⽅id,本⽂简单的将发送⽅和接收⽅写死在html⽂件中使⽤以下代码进⾏连接io.connect('http://localhost:8081?clientid='+clientid);index.html ⽂件内容如下<!DOCTYPE html><html><head><meta charset="utf-8" /><title>Demo Chat</title><link href="bootstrap.css" rel="external nofollow" rel="stylesheet"><style>body {padding:20px;}#console {height: 400px;overflow: auto;}.username-msg {color:orange;}.connect-msg {color:green;}.disconnect-msg {color:red;}.send-msg {color:#888}</style><script src="js/socket.io/socket.io.js"></script><script src="js/moment.min.js"></script><script src="/jquery-1.10.1.min.js"></script><script>var clientid = 'testclient1';var targetClientId= 'testclient2';var socket = io.connect('http://localhost:8081?clientid='+clientid);socket.on('connect', function() {output('<span class="connect-msg">Client has connected to the server!</span>');});socket.on('messageevent', function(data) {output('<span class="username-msg">' + data.sourceClientId + ':</span> ' + data.msgContent);});socket.on('disconnect', function() {output('<span class="disconnect-msg">The client has disconnected!</span>');});function sendDisconnect() {socket.disconnect();}function sendMessage() {var message = $('#msg').val();$('#msg').val('');var jsonObject = {sourceClientId: clientid,targetClientId: targetClientId,msgType: 'chat',msgContent: message};socket.emit('messageevent', jsonObject);}function output(message) {var currentTime = "<span class='time'>" + moment().format('HH:mm:ss.SSS') + "</span>";var element = $("<div>" + currentTime + " " + message + "</div>");$('#console').prepend(element);}$(document).keydown(function(e){if(e.keyCode == 13) {$('#send').click();}});</script></head><body><h1>Netty-socketio Demo Chat</h1><br/><div id="console" class="well"></div><form class="well form-inline" onsubmit="return false;"><input id="msg" class="input-xlarge" type="text" placeholder="Type something..."/><button type="button" onClick="sendMessage()" class="btn" id="send">Send</button><button type="button" onClick="sendDisconnect()" class="btn">Disconnect</button></form></body></html>3、本例测试时testclient1 发送消息给 testclient2testclient2 发送消息给 testclient1testclient3发送消息给testclient1运⾏结果如下以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。

springbootwebsocket简单入门示例

springbootwebsocket简单入门示例

springbootwebsocket简单⼊门⽰例之前做的需求都是客户端请求服务器响应,新需求是服务器主动推送信息到客户端.百度之后有流、长轮询、websoket等⽅式进⾏.但是⽬前更加推崇且合理的显然是websocket.从springboot官⽹翻译了⼀些资料,再加上百度简单实现了springboot使⽤websocekt与客户端的双⼯通信.1.⾸先搭建⼀个简单的springboot环境<!-- Inherit defaults from Spring Boot --><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.4.RELEASE</version></parent><!-- Add typical dependencies for a web application --><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies>2.引⼊springboot整合websocket依赖<!-- https:///artifact/org.springframework.boot/spring-boot-starter-websocket --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId><version>2.0.4.RELEASE</version></dependency>3.创建启动springboot的核⼼类package com;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class GlobalConfig {public static void main(String[] args) {SpringApplication.run(GlobalConfig.class, args);}}4.创建websocket服务器正如,需要实现WebSocketHandler或者继承TextWebSocketHandler/BinaryWebSocketHandler当中的任意⼀个.package com.xiaoer.handler;import com.alibaba.fastjson.JSONObject;import org.springframework.web.socket.TextMessage;import org.springframework.web.socket.WebSocketSession;import org.springframework.web.socket.handler.TextWebSocketHandler;import java.util.HashMap;import java.util.Map;/*** 相当于controller的处理器*/public class MyHandler extends TextWebSocketHandler {@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {String payload = message.getPayload();Map<String, String> map = JSONObject.parseObject(payload, HashMap.class);System.out.println("=====接受到的数据"+map);session.sendMessage(new TextMessage("服务器返回收到的信息," + payload));}}5.注册处理器package com.xiaoer.config;import com.xiaoer.handler.MyHandler;import org.springframework.context.annotation.Configuration;import org.springframework.web.socket.WebSocketHandler;import org.springframework.web.socket.config.annotation.EnableWebSocket;import org.springframework.web.socket.config.annotation.WebSocketConfigurer;import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;@Configuration@EnableWebSocketpublic class WebSocketConfig implements WebSocketConfigurer {@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(myHandler(), "myHandler/{ID}");}public WebSocketHandler myHandler() {return new MyHandler();}}6.运⾏访问出现如上图是因为不能直接通过http协议访问,需要通过html5的ws://协议进⾏访问.7.创建Html5 客户端<!DOCTYPE html><html><head><meta charset="utf-8" /><title></title></head><body><input id="text" type="text" /><button onclick="send()">Send</button><button onclick="closeWebSocket()">Close</button><div id="message"></div><script src="https:///jquery-3.1.1.min.js"></script><script>var userID="888";var websocket=null;$(function(){connectWebSocket();})//建⽴WebSocket连接function connectWebSocket(){console.log("开始...");//建⽴webSocket连接websocket = new WebSocket("ws://127.0.0.1:8080/myHandler/ID="+userID);//打开webSokcet连接时,回调该函数websocket.onopen = function () {console.log("onpen");}//关闭webSocket连接时,回调该函数websocket.onclose = function () {//关闭连接console.log("onclose");}//接收信息websocket.onmessage = function (msg) {console.log(msg.data);}}//发送消息function send(){var postValue={};postValue.id=userID;postValue.message=$("#text").val();websocket.send(JSON.stringify(postValue));}//关闭连接function closeWebSocket(){if(websocket != null) {websocket.close();}}</script></body></html>8.运⾏利⽤客户端运⾏之后仍然会出现上图中的⼀连接就中断了websocket连接.这是因为spring默认不接受跨域访问:As of Spring Framework 4.1.5, the default behavior for WebSocket and SockJS is to accept only same origin requests.需要在WebSocketConfig中设置setAllowedOrigins.package com.xiaoer.config;import com.xiaoer.handler.MyHandler;import org.springframework.context.annotation.Configuration;import org.springframework.web.socket.WebSocketHandler;import org.springframework.web.socket.config.annotation.EnableWebSocket;import org.springframework.web.socket.config.annotation.WebSocketConfigurer;import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;@Configuration@EnableWebSocketpublic class WebSocketConfig implements WebSocketConfigurer {@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(myHandler(), "myHandler/{ID}").setAllowedOrigins("*");}public WebSocketHandler myHandler() {return new MyHandler();}}如下图,并未输出中断,说明连接成功.9.服务器和客户端的相互通信服务器端收到消息客户端收到服务器主动推送消息以上就是⼀个最基础的springboot简单应⽤.还可以通过拦截器、重写WebSocketConfigurer中的⽅法进⾏更为复杂的属性操作.具体可以参考以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。

关于SpringBootWebSocket整合以及nginx配置详解

关于SpringBootWebSocket整合以及nginx配置详解

关于SpringBootWebSocket整合以及nginx配置详解前⾔本⽂主要给⼤家介绍了关于Spring Boot WebSocket整合及nginx配置的相关内容,分享出来供⼤家参考学习,下⾯话不多说了,来⼀起看看详细的介绍吧。

⼀:Spring Boot WebSocket整合创建⼀个maven项⽬,加⼊如下依赖<dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>1.4.0.RELEASE</version><scope>import</scope><type>pom</type></dependency></dependencies></dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency></dependencies>代码如下:package com.wh.web;import org.springframework.web.socket.TextMessage;import org.springframework.web.socket.WebSocketSession;import org.springframework.web.socket.handler.TextWebSocketHandler;public class CountWebSocketHandler extends TextWebSocketHandler {private static long count = 0;protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {session.sendMessage(new TextMessage("你是第" + (++count) + "位访客"));}}package com.wh.web;import org.springframework.context.annotation.Configuration;import org.springframework.web.socket.config.annotation.WebSocketConfigurer;import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;@Configurationpublic class WebsocketConfiguration implements WebSocketConfigurer {public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(new CountWebSocketHandler(), "/web/count");}}package com.wh.web;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.web.socket.config.annotation.EnableWebSocket;@EnableWebSocket@SpringBootApplicationpublic class ServerApp {public static void main(String[] args) {SpringApplication.run(ServerApp.class, args);}}application.properties 内容如下:server.port=9080spring.resources.static-locations=classpath:/webapp/html/src/main/resources/webapp/html/index.html 内容如下:<!DOCTYPE html><html><head><meta charset="UTF-8" /><title>web socket</title></head><body><h1>web socket</h1><script type="text/javascript">var url = 'ws://'+window.location.hostname+':9080/web/count';var ws = new WebSocket(url);ws.onopen = function(event){ws.send('hello');};ws.onmessage = function(event) {alert(event.data);};ws.onerror = function(event) {alert(event);}</script></body></html>⼆:nginx配置nginx 通过在客户端和后端服务器之间建⽴起⼀条隧道来⽀持WebSocket。

websocket实现消息推送

websocket实现消息推送

websocket实现消息推送闲来⽆事,写⼀篇关于websocket推送消息的⽂章,概念我们就不多讲了,直接上⼲货吧我们要做的就是:使⽤websocket来推送消息,但是如果说接收消息的那个⽤户没有连接上websocket,那么他就会接收不到我们的消息,这时候我们需要将消息存到数据库,等⽤户上线时⾃⼰查询数据库⾥⾯⾃⼰的消息,假如⽤户在线,我们就会将消息直接推送给他并且也保存在数据库,这时我们的前端未读消息数量应该+1,这个我们可以使⽤⼀个定时任务,⽐如隔5s我就像全部⽤户都推送消息,让前端触发消息回调的⽅法,我们可以在那个⽅法⾥⾯做⼿脚,就是去查询⼀遍我们的数据库中当前⽤户的未读消息,来达到消息数量的增减。

1.引⼊websocket依赖和⼀些其他依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.16</version><scope>compile</scope></dependency><!--thymeleaf--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency>2.编写websocket配置类@Componentpublic class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}}3.编写websocket连接类@Component@ServerEndpoint("/webSocket/{userId}")@Slf4jpublic class WebSocket {private String userId;private Session session;private static Map<String, Session> sessionPool = new HashMap<String, Session>();private static CopyOnWriteArraySet<WebSocket> webSocketSet = new CopyOnWriteArraySet<>();@OnOpenpublic void onOpen(Session session,@PathParam(value = "userId") String userId) {this.session = session;erId = userId;webSocketSet.add(this);sessionPool.put(userId, session);("【websocket消息】有新的连接, 总数:{}", webSocketSet.size());}@OnClosepublic void onClose() {webSocketSet.remove(this);sessionPool.remove(erId);("【websocket消息】连接断开, 总数:{}", webSocketSet.size());}@OnMessagepublic void onMessage(String message) {("【websocket消息】收到客户端发来的消息:{}", message);}/*** 服务端推送消息(单点发送)** @param userId* @param message*/public void pushMessage(String userId, String message) {Session session = sessionPool.get(userId);if (session != null && session.isOpen()) {try {("【websocket消息】单点消息:" + message);session.getAsyncRemote().sendText(message);} catch (Exception e) {e.printStackTrace();}}}/*** 服务器端推送消息(群发)*/public void pushMessage(String message) {try {webSocketSet.forEach(ws -> ws.session.getAsyncRemote().sendText(message));} catch (Exception e) {e.printStackTrace();}}}4.编写两个控制器@RequestMapping("/demo")@RestControllerpublic class DemoContrlller {@AutowiredWebSocket webSocket;private Integer num = 1;/*** 单点发送* @param userId* @param message*/@RequestMapping("/sendMessage")public void sendMessage(String userId, String message) {webSocket.pushMessage(userId, message);}/*** 群发* @param message*/@RequestMapping("/send")public void send(String message) {webSocket.pushMessage(message);}/*** 模拟消息增加* @return*/@RequestMapping("/add")public Integer num() {num++;return num;}/*** 模拟消息减少* @return*/@RequestMapping("/reduce")public Integer jian() {num--;return num;}}// ⽤于访问到对应的视图@Controller@RequestMapping("/test")public class TestController {@RequestMapping("/index")public String index() {return "index";}}前端代码<!DOCTYPE html><html lang="en" xmlns:th=""><head><meta charset="UTF-8"><title>Title</title><!-- 最新版本的 Bootstrap 核⼼ CSS ⽂件 --><link rel="stylesheet" href="https:///bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous"><!-- 可选的 Bootstrap 主题⽂件(⼀般不⽤引⼊) --><link rel="stylesheet" href="https:///bootstrap/3.4.1/css/bootstrap-theme.min.css" integrity="sha384-6pzBo3FDv/PJ8r2KRkGHifhEocL+1X2rVCTTkUfGk7/0pbek5mMa1upzvWbrUbOZ" crossorigin="anonymous"> <!-- 最新的 Bootstrap 核⼼ JavaScript ⽂件 --><script src="https:///bootstrap/3.4.1/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script></head><body><div class="btn btn-default"><span class="glyphicon glyphicon-envelope" aria-hidden="true"></span><span class="badge badge-danger" style="background-color:#FF0000;color:#FFFFFF " id ="ms"></span></div><button id="add" onclick="add()">添加</button><button id="reduce" onclick="reduce()">减少</button><div id="message"></div><script src="https:///jquery/1.12.4/jquery.min.js"></script><script src="https:///bootstrap/3.3.5/js/bootstrap.min.js"></script><script>var websocket = null;if ('WebSocket' in window) {websocket = new WebSocket('ws://192.168.1.189:8001/webSocket/1');} else {alert('该浏览器不⽀持websocket!');}websocket.onopen = function (event) {console.log('建⽴连接');}websocket.onclose = function (event) {console.log('连接关闭');}websocket.onmessage = function (event) {// 收到消息console.log('收到消息:' + event.data)setMessageInnerHTML(event.data);f();}websocket.onerror = function () {alert('websocket通信发⽣错误!');}window.onbeforeunload = function () {websocket.close();}function setMessageInnerHTML(innerHTML) {document.getElementById('message').innerHTML = innerHTML + '<br/>';}function f() {$.ajax({type: 'post',dataType: 'text',url: '/demo/num',data: {},cache: false,async: true,success: function (data) {var data = eval('(' + data + ')');console.log('数量:' + data)if(data>0){document.getElementById('ms').innerHTML = data + '<br/>'; }}});}function add() {$.ajax({type: 'post',dataType: 'text',url: '/demo/add',data: {},cache: false,async: true,success: function (data) {if(data>0){document.getElementById('ms').innerHTML = data + '<br/>'; }}});}function reduce() {$.ajax({type: 'post',dataType: 'text',url: '/demo/reduce',data: {},cache: false,async: true,success: function (data) {if(data>0){document.getElementById('ms').innerHTML = data + '<br/>'; }else{document.getElementById('ms').innerHTML ='';}}});}</script></body></html>效果我们也可以通过postman来测试推送消息,看数量是否增加效果有问题,欢迎评论留⾔。

SpringBoot+Netty+WebSocket实现消息发送的示例代码

SpringBoot+Netty+WebSocket实现消息发送的示例代码

SpringBoot+Netty+WebSocket实现消息发送的⽰例代码⼀.导⼊Netty依赖<dependency><groupId>ty</groupId><artifactId>netty-all</artifactId><version>4.1.25.Final</version></dependency>⼆.搭建websocket服务器@Componentpublic class WebSocketServer {/*** 主线程池*/private EventLoopGroup bossGroup;/*** ⼯作线程池*/private EventLoopGroup workerGroup;/*** 服务器*/private ServerBootstrap server;/*** 回调*/private ChannelFuture future;public void start() {future = server.bind(9001);System.out.println("netty server - 启动成功");}public WebSocketServer() {bossGroup = new NioEventLoopGroup();workerGroup = new NioEventLoopGroup();server = new ServerBootstrap();server.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new WebsocketInitializer());}}三.初始化Websocketpublic class WebsocketInitializer extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();// ------------------// ⽤于⽀持Http协议// ------------------// websocket基于http协议,需要有http的编解码器pipeline.addLast(new HttpServerCodec());// 对写⼤数据流的⽀持pipeline.addLast(new ChunkedWriteHandler());// 添加对HTTP请求和响应的聚合器:只要使⽤Netty进⾏Http编程都需要使⽤//设置单次请求的⽂件的⼤⼩pipeline.addLast(new HttpObjectAggregator(1024 * 64));//webSocket 服务器处理的协议,⽤于指定给客户端连接访问的路由 :/wspipeline.addLast(new WebSocketServerProtocolHandler("/ws"));// 添加Netty空闲超时检查的⽀持// 1. 读空闲超时(超过⼀定的时间会发送对应的事件消息)// 2. 写空闲超时// 3. 读写空闲超时pipeline.addLast(new IdleStateHandler(4, 8, 12));pipeline.addLast(new HearBeatHandler());// 添加⾃定义的handlerpipeline.addLast(new ChatHandler());}}四.创建Netty监听器@Componentpublic class NettyListener implements ApplicationListener<ContextRefreshedEvent> {@Resourceprivate WebSocketServer websocketServer;@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {if(event.getApplicationContext().getParent() == null) {try {websocketServer.start();} catch (Exception e) {e.printStackTrace();}}}}五.建⽴消息通道public class UserChannelMap {/*** ⽤户保存⽤户id与通道的Map对象*/// private static Map<String, Channel> userChannelMap;/* static {userChannelMap = new HashMap<String, Channel>();}*//*** 定义⼀个channel组,管理所有的channel* GlobalEventExecutor.INSTANCE 是全局的事件执⾏器,是⼀个单例*/private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); /*** 存放⽤户与Chanel的对应信息,⽤于给指定⽤户发送消息*/private static ConcurrentHashMap<String,Channel> userChannelMap = new ConcurrentHashMap<>();private UserChannelMap(){}/*** 添加⽤户id与channel的关联* @param userNum* @param channel*/public static void put(String userNum, Channel channel) {userChannelMap.put(userNum, channel);}/*** 根据⽤户id移除⽤户id与channel的关联* @param userNum*/public static void remove(String userNum) {userChannelMap.remove(userNum);}/*** 根据通道id移除⽤户与channel的关联* @param channelId 通道的id*/return;}for (String s : userChannelMap.keySet()) {Channel channel = userChannelMap.get(s);if(channelId.equals(channel.id().asLongText())) {System.out.println("客户端连接断开,取消⽤户" + s + "与通道" + channelId + "的关联"); userChannelMap.remove(s);UserService userService = SpringUtil.getBean(UserService.class);userService.logout(s);break;}}}/*** 打印所有的⽤户与通道的关联数据*/public static void print() {for (String s : userChannelMap.keySet()) {System.out.println("⽤户id:" + s + " 通道:" + userChannelMap.get(s).id());}}/*** 根据好友id获取对应的通道* @param receiverNum 接收⼈编号* @return Netty通道*/public static Channel get(String receiverNum) {return userChannelMap.get(receiverNum);}/*** 获取channel组* @return*/public static ChannelGroup getChannelGroup() {return channelGroup;}/*** 获取⽤户channel map* @return*/public static ConcurrentHashMap<String,Channel> getUserChannelMap(){return userChannelMap;}}六.⾃定义消息类型public class Message {/*** 消息类型*/private Integer type;/*** 聊天消息*/private String message;/*** 扩展消息字段*/private Object ext;public Integer getType() {return type;}public void setType(Integer type) {this.type = type;}public MarketChatRecord getChatRecord() {return marketChatRecord;public void setChatRecord(MarketChatRecord chatRecord) {this.marketChatRecord = chatRecord;}public Object getExt() {return ext;}public void setExt(Object ext) {this.ext = ext;}@Overridepublic String toString() {return "Message{" +"type=" + type +", marketChatRecord=" + marketChatRecord +", ext=" + ext +'}';}}七.创建处理消息的handlerpublic class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);/*** ⽤来保存所有的客户端连接*/private static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);/***当Channel中有新的事件消息会⾃动调⽤*/@Overrideprotected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception { // 当接收到数据后会⾃动调⽤// 获取客户端发送过来的⽂本消息Gson gson = new Gson();("服务器收到消息:{}",msg.text());System.out.println("接收到消息数据为:" + msg.text());Message message = gson.fromJson(msg.text(), Message.class);//根据业务要求进⾏消息处理switch (message.getType()) {// 处理客户端连接的消息case 0:// 建⽴⽤户与通道的关联// 处理客户端发送好友消息break;case 1:// 处理客户端的签收消息break;case 2:// 将消息记录设置为已读break;case 3:// 接收⼼跳消息break;default:break;}}// 当有新的客户端连接服务器之后,会⾃动调⽤这个⽅法@Overridepublic void handlerAdded(ChannelHandlerContext ctx) throws Exception {("handlerAdded 被调⽤"+ctx.channel().id().asLongText());// 添加到channelGroup 通道组UserChannelMap.getChannelGroup().add(ctx.channel());// clients.add(ctx.channel());@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {("{异常:}"+cause.getMessage());// 删除通道UserChannelMap.getChannelGroup().remove(ctx.channel());UserChannelMap.removeByChannelId(ctx.channel().id().asLongText());ctx.channel().close();}@Overridepublic void handlerRemoved(ChannelHandlerContext ctx) throws Exception {("handlerRemoved 被调⽤"+ctx.channel().id().asLongText());//删除通道UserChannelMap.getChannelGroup().remove(ctx.channel());UserChannelMap.removeByChannelId(ctx.channel().id().asLongText());UserChannelMap.print();}}⼋.处理⼼跳public class HearBeatHandler extends ChannelInboundHandlerAdapter {@Overridepublic void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {if(evt instanceof IdleStateEvent) {IdleStateEvent idleStateEvent = (IdleStateEvent)evt;if(idleStateEvent.state() == IdleState.READER_IDLE) {System.out.println("读空闲事件触发...");}else if(idleStateEvent.state() == IdleState.WRITER_IDLE) {System.out.println("写空闲事件触发...");}else if(idleStateEvent.state() == IdleState.ALL_IDLE) {System.out.println("---------------");System.out.println("读写空闲事件触发");System.out.println("关闭通道资源");ctx.channel().close();}}}}搭建完成后调⽤测试到此这篇关于SpringBoot+Netty+WebSocket实现消息发送的⽰例代码的⽂章就介绍到这了,更多相关SpringBoot Netty WebSocket消息发送内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!。

websocket-基于springboot的简单实现

websocket-基于springboot的简单实现1.新建⼀个springboot⼯程,添加⼀个maven依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>⽂件⽬录结构如下:2. 创建websocket服务端类MoneyServer.java/*** @author Page* @date 2019-07-02 10:00* @description websocket 服务*/@Component@Slf4j@ServerEndpoint(value = "/money/{userId}", decoders = {MessageDecoder.class,}, encoders = {MessageEncoder.class,}, configurator = MoneyRepayConfig.class)public class MoneyServer {private static final Map<String, Session> SESSION_MAP = new HashMap<>();@OnOpenpublic void connect(Session session, @PathParam("userId") String userId) {// 将session按照房间名来存储,将各个房间的⽤户隔离SESSION_MAP.put(userId, session);("websocket成功连接!");}@OnMessagepublic void repay(RepayReq req, Session session) {SESSION_MAP.put(req.getUserId(), session);("{}正在还钱:{} 元", req.getName(), req.getMoneyNum());}public void send(RepayResultRes res) throws IOException, EncodeException {if (SESSION_MAP.get(res.getUserId()) == null) {("没有找到连接,消息⽆法推送");return;}SESSION_MAP.get(res.getUserId()).getBasicRemote().sendObject(res);("{}成功还钱:{} 元,userId:{},还钱结果:{}", res.getName(),res.getMoneyNum(), res.getUserId(), res.isRepayResult()?"还成功" :"失败了");}}这⾥我还添加了⼀个⾃定义的解码器和⼀个编码器,⽤于解析java对象和前端传来的字符串,以及⼀个⾃定义的websocket配置类.不过在这个配置类⾥边⽬前什么都没有做.MessageDecoder.javapublic class MessageDecoder implements Decoder.Text<RepayReq> {@Overridepublic RepayReq decode(String s) {("primal string" + s);RepayReq repayReq = null;try {repayReq = JSONObject.parseObject(s, RepayReq.class);} catch (Exception ex) {log.error(ex.getMessage());}return repayReq;}@Overridepublic boolean willDecode(String s) {return (s != null);}@Overridepublic void init(EndpointConfig endpointConfig) {// do nothing.}@Overridepublic void destroy() {// do nothing.}}MessageEncoder.java@Slf4jpublic class MessageEncoder implements Encoder.Text<RepayResultRes> { @Overridepublic String encode(RepayResultRes object) {String s = null;try {s = JSONObject.toJSONString(object);("primal: " + object.toString());} catch (Exception ex) {log.error(ex.getMessage());}return s;}@Overridepublic void init(EndpointConfig endpointConfig) {// do nothing.}@Overridepublic void destroy() {// do nothing.}}MoneyRepayConfig.java*/@Slf4jpublic class MoneyRepayConfig extends ServerEndpointConfig.Configurator{@Overridepublic boolean checkOrigin(String originHeaderValue) {("1=========originHeaderValue====={}", originHeaderValue);return true;}@Overridepublic <T> T getEndpointInstance(Class<T> clazz) throws InstantiationException {("2========{}========={}==",clazz, super.getEndpointInstance(clazz));return super.getEndpointInstance(clazz);}@Overridepublic String getNegotiatedSubprotocol(List<String> supported, List<String> requested) {("3========{}====={}======{}", supported, requested, super.getNegotiatedSubprotocol(supported, requested));return super.getNegotiatedSubprotocol(supported, requested);}@Overridepublic List<Extension> getNegotiatedExtensions(List<Extension> installed, List<Extension> requested) {("4======{}====={}======{}", installed, requested, super.getNegotiatedExtensions(installed, requested));return super.getNegotiatedExtensions(installed, requested);}@Overridepublic void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {("5======{}======{}======{}", sec, request, response);super.modifyHandshake(sec, request, response);}}ServerEndpointConfig ⾥有⼏个可以重写的⽅法,通过这些⽅法可以获取websocket的信息以及对连接的⼀些信息进⾏修改等.3. 创建WebSocketConfig通过这个配置类对websocket服务进⾏发布@Configuration@ServletComponentScanpublic class WebSocketConfig extends WsSci {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}}4.创建controller这⾥我还创建了⼀个控制器类,⽤于模拟服务器的响应,发送消息通知客户端.RepaySuccessController.java*/@Controller@RequestMapping("/money")public class RepaySuccessController {@ResourceMoneyServer moneyServer;@PostMapping("/repaySuccess")public void repaySuccess(RepayResultRes req) throws IOException, EncodeException { moneyServer.send(req);}}⼯程代码已经放在我的github仓库,有需要的可以下载。

websocket服务器推送

websocket服务器推送1.1 服务器推送WebSocket作为⼀种通信协议,属于的⼀种,IE10+⽀持。

,有短轮询、长轮询、WebSocket、Server-sent Events(SSE)等,他们:#短轮询长轮询Websocket sse 通讯⽅式http http基于TCP长连接通讯http 触发⽅式轮询轮询事件事件优点兼容性好容错性强,实现简单⽐短轮询节约资源全双⼯通讯协议,性能开销⼩、安全性⾼,有⼀定可扩展性实现简便,开发成本低缺点安全性差,占较多的内存资源与请求数安全性差,占较多的内存资源与请求数传输数据需要进⾏⼆次解析,增加开发成本及难度只适⽤⾼级浏览器适⽤范围b/s服务b/s服务⽹络游戏、银⾏交互和⽀付服务端到客户端单向推送短轮询最简单,在⼀些简单的场景也会经常使⽤,就是隔⼀段时间就发起⼀个ajax请求。

那么长轮询是什么呢?长轮询(Long Polling)是在Ajax轮询基础上做的⼀些改进,在没有更新的时候不再返回空响应,⽽且把连接保持到有更新的时候,客户端向服务器发送Ajax请求,服务器接到请求后hold住连接,直到有新消息才返回响应信息并关闭连接,客户端处理完响应信息后再向服务器发送新的请求。

它是⼀个解决⽅案,但不是最佳的技术⽅案。

如果说短轮询是客户端不断打电话问服务端有没有消息,服务端回复后⽴刻挂断,等待下次再打;长轮询是客户端⼀直打电话,服务端接到电话不挂断,有消息的时候再回复客户端并挂断。

SSE(Server-Sent Events)与长轮询机制类似,区别是每个连接不只发送⼀个消息。

客户端发送⼀个请求,服务端保持这个连接直到有新消息发送回客户端,仍然保持着连接,这样连接就可以⽀持消息的再次发送,由服务器单向发送给客户端。

然⽽IE直到11都不⽀持,不多说了....1.2 WebSocket的特点为什么已经有了轮询还要WebSocket呢,是因为短轮询和长轮询有个缺陷:通信只能由客户端发起。

springboot集成websocketrabbitmq

Sprin‎‎g boot 中使用we‎‎b sock‎‎e t 和rabb‎‎itmq 1.首先我们得‎创建一个s‎‎p ring‎‎b oot的‎项目,目录结构如‎下2.配置依赖3.结构如下图‎4.编写con‎‎t roll‎e rpacka‎‎g e com.contr‎‎o ller‎‎;impor‎‎t org.sprin‎‎g fram‎‎e work‎‎.beans‎‎.facto‎‎r y.annot‎‎a t ion‎‎.Autow‎‎ired;impor‎‎t org.sprin‎‎g fram‎‎e work‎‎.web.bind.annot‎‎a tion‎‎.Reque‎‎s tMap‎‎p ing;impor‎‎t org.sprin‎‎g fram‎‎e work‎‎.web.bind.annot‎‎a tion‎‎.RestC‎‎o ntro‎‎ller;impor‎‎t com.servi‎‎c e.Direc‎‎t Mess‎‎a geSe‎‎r vice‎‎;@RestC‎‎o ntro‎‎ller@Reque‎‎s tMap‎‎p ing("/produ‎‎c t Mes‎‎s age")publi‎‎c class‎‎W ebSo‎‎c ketC‎‎o ntro‎‎ller {@Autow‎‎iredpriva‎‎t e Direc‎‎t Mess‎‎a geSe‎‎r vice‎‎ direc‎‎t Mess‎‎a geSe‎‎r vice‎‎;@Reque‎‎s tMap‎‎p ing("/getMs‎‎g")publi‎‎c void produ‎‎c tMsg‎‎() throw‎‎s Excep‎‎t ion{direc‎‎t Mess‎‎a geSe‎‎r vice‎‎.getMs‎‎g();}}5.编写ser‎‎v icepacka‎‎g e com.servi‎‎c e;impor‎‎t org.sprin‎‎g fram‎‎e work‎‎.beans‎‎.facto‎‎r y.annot‎‎a t ion‎‎.Autow‎‎ired;impor‎‎t org.sprin‎‎g fram‎‎e work‎‎.stere‎‎o type‎‎.Compo‎‎n ent;impor‎‎t com.dao.Direc‎‎t Mess‎‎a geDa‎‎o;@Compo‎‎n entpubli‎‎c class‎‎ Direc‎‎t Mess‎‎a geSe‎‎r vice‎‎ {@Autow‎‎iredpriva‎‎t e Direc‎‎t Mess‎‎a geDa‎‎o direc‎‎t Mess‎‎a geDa‎‎o;publi‎‎c void getMs‎‎g() throw‎‎s Excep‎‎t ion{Direc‎‎t Mess‎‎a geDa‎‎o.Produ‎‎c t Mes‎‎s age("dbb", "xiaox‎‎i");}}6.编写dao‎‎packa‎‎g e com.dao;impor‎‎t java.io.IOExc‎‎e ptio‎‎n;impor‎‎t java.util.Rando‎‎m;impor‎‎t java.util.UUID;impor‎‎t java.util.concu‎‎r rent‎‎.Timeo‎‎u tExc‎‎e ptio‎‎n;impor‎‎t org.sprin‎‎g fram‎‎e work‎‎.stere‎‎o type‎‎.Compo‎‎n ent;impor‎‎t com.rabbi‎‎t mq.clien‎‎t.Chann‎‎e l;impor‎‎t com.rabbi‎‎t mq.clien‎‎t.Conne‎‎c tion‎‎;impor‎‎t com.rabbi‎‎t mq.clien‎‎t.Conne‎‎c tion‎‎F acto‎‎r y;@Compo‎‎n entpubli‎‎c class‎‎ Direc‎‎t Mess‎‎a geDa‎‎o{priva‎‎t e stati‎‎c final‎ Strin‎‎g EXCHA‎‎N GE_N‎‎A ME = "ex_lo‎‎g s_di‎r ect";/* publi‎‎c stati‎‎c void main(Strin‎‎g[] argv) throw‎‎s java.io.IOExc‎‎e ptio‎‎n, Excep‎‎t ion{Conne‎‎c tion‎‎F acto‎‎r y facto‎‎r y = new Conne‎‎c tion‎‎F a cto‎‎r y();facto‎‎r y.setHo‎‎s t("local‎h ost");Conne‎‎c tion‎‎ conne‎‎c tion‎‎ = facto‎‎r y.newCo‎‎n nect‎‎ion();Chann‎‎e l chann‎‎e l = conne‎‎c tion‎‎.creat‎‎e Chan‎‎n el();chann‎‎e l.excha‎‎n geDe‎‎c lare‎‎(EXCHA‎‎N G E_N‎‎A M E, "direc‎‎t");for (int i = 0; i < 6; i++){Strin‎‎g sever‎‎ity = "dbb";Strin‎‎g messa‎‎g e = sever‎‎ity + "_log :" + UUID.rando‎‎m UUID‎‎().toStr‎‎ing();chann‎‎e l.basic‎‎P ubli‎s h(EXCHA‎‎N GE_N‎‎A ME, sever‎‎ity, null, messa‎‎g e.getBy‎‎t es());Syste‎‎m.out.print‎‎ln(" [x] produ‎‎c t '" + messa‎‎g e + "'");}chann‎‎e l.close‎‎();conne‎‎c tion‎‎.close‎‎();} */publi‎‎c stati‎c void Produ‎‎c t Mes‎‎s a ge(Strin‎‎g userI‎‎D, Strin‎‎g msg) throw‎‎s Excep‎‎t ion{ Conne‎‎c t ion‎‎F acto‎‎r y facto‎‎r y = new Conne‎‎c tion‎‎F a cto‎‎r y();facto‎‎r y.setHo‎‎s t("local‎h ost");Conne‎‎c tion‎‎ conne‎‎c tion‎‎ = facto‎‎r y.newCo‎‎n nect‎‎ion();Chann‎‎e l chann‎‎e l = conne‎‎c tion‎‎.creat‎‎e Chan‎‎n el();chann‎‎e l.excha‎‎n geDe‎‎c lare‎‎(EXCHA‎‎N G E_N‎‎A M E, "direc‎‎t");Strin‎‎g sever‎‎ity = "dbb";Strin‎‎g messa‎‎g e = sever‎‎ity + "_log :" + UUID.rando‎‎m UUID‎‎().toStr‎‎ing();chann‎‎e l.basic‎‎P ubli‎s h(EXCHA‎‎N GE_N‎‎A ME, sever‎‎ity, null, messa‎‎g e.getBy‎‎t es());Syste‎‎m.out.print‎‎ln(" [x] produ‎‎c t '" + messa‎‎g e + "'");chann‎‎e l.close‎‎();conne‎‎c tion‎‎.close‎‎();}}7.编写MyW‎‎e bSoc‎‎k e tpacka‎‎g e com.webso‎‎c ket;impor‎‎t java.io.IOExc‎‎e ptio‎‎n;impor‎‎t java.util.concu‎‎r rent‎‎.CopyO‎‎n Writ‎‎e Arra‎‎y Set;impor‎‎t javax‎‎.webso‎‎c ket.Endpo‎‎intCo‎‎n fig;impor‎‎t javax‎‎.webso‎‎c ket.OnClo‎‎s e;impor‎‎t javax‎‎.webso‎‎c ket.OnErr‎‎o r;impor‎‎t javax‎‎.webso‎‎c ket.OnMes‎‎s age;impor‎‎t javax‎‎.webso‎‎c ket.OnOpe‎‎n;impor‎‎t javax‎‎.webso‎‎c ket.Sessi‎‎o n;impor‎‎t javax‎‎.webso‎‎c ket.serve‎‎r.PathP‎‎a ram;impor‎‎t javax‎‎.webso‎‎c ket.serve‎‎r.Serve‎‎r Endp‎‎o int;//该注解用来‎指定一个U‎‎R I,客户端可以‎通过这个U‎‎R I来连接‎到W ebS‎‎o cket‎‎。

SpringBoot实现STOMP协议的WebSocket的方法步骤

SpringBoot实现STOMP协议的WebSocket的⽅法步骤1.概述我们之前讨论过Java Generics的基础知识。

在本⽂中,我们将了解Java中的通⽤构造函数。

泛型构造函数是⾄少需要有⼀个泛型类型参数的构造函数。

我们将看到泛型构造函数并不都是在泛型类中出现的,⽽且并⾮所有泛型类中的构造函数都必须是泛型。

2.⾮泛型类⾸先,先写⼀个简单的类:Entry,它不是泛型类:public class Entry {private String data;private int rank;}在这个类中,我们将添加两个构造函数:⼀个带有两个参数的基本构造函数和⼀个通⽤构造函数。

2.1 基本构造器Entry第⼀个构造函数:带有两个参数的简单构造函数:public Entry(String data, int rank) {this.data = data;this.rank = rank;}现在,让我们使⽤这个基本构造函数来创建⼀个Entry对象@Testpublic void givenNonGenericConstructor_whenCreateNonGenericEntry_thenOK() {Entry entry = new Entry("sample", 1);assertEquals("sample", entry.getData());assertEquals(1, entry.getRank());}2.2 泛型构造器接下来,第⼆个构造器是泛型构造器:public <E extends Rankable & Serializable> Entry(E element) {this.data = element.toString();this.rank = element.getRank();}虽然Entry类不是通⽤的,但它有⼀个参数为E的泛型构造函数。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
privateString message;
privateT data;
}
三、因为要实现点对点的推送,所以需要创建一个监听器来获取到websocket的session,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
importorg.springframework.beans.factory.annotation.Autowired;
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
importlombok.extern.slf4j.Slf4j;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.messaging.Message;
importorg.springframework.messaging.MessageChannel;
//STOMP监听类
@Bean
publicSTOMPConnectEventListener applicationStartListener(){
returnnewSTOMPConnectEventListener();
}
@Override
publicvoidregisterStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
publicclassSTOMPConnectEventListenerimplementsApplicationListener<SessionConnectEvent> {
@Autowired
privateRedisHelper redisHelper;
@Override
publicvoidonApplicationEvent(SessionConnectEvent event) {
importorg.springframework.messaging.simp.config.ChannelRegistration;
importorg.springframework.messaging.simp.config.MessageBrokerRegistry;
importorg.springframework.messaging.simp.stomp.StompCommand;
String sessionId = sha.getSessionId();
redisHelper.redisTemplate.opsForValue().set("websocket:"+userid,sessionId);
}
}
四、最重要的配置类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
二、推送到前端的消息实体类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
importlombok.AllArgsConstructor;
importlombok.Builder;
importlombok.Data;
importlombok.NoArgsConstructor;
importjava.io.Serializable;
StompHeaderAccessor sha = StompHeaderAccessor.wrap(event.getMessage());
//login get from browser
if(sha.getNativeHeader("userid")==null){
return;
}
String userid = sha.getNativeHeader("userid").get(0);
importorg.springframework.web.socket.config.annotation.*;
@Configuration
@EnableWebSocketMessageBroker
@Slf4j
publicclassWebSocketConfigextendsAbstractWebSocketMessageBrokerConfigurer {
importorg.springframework.messaging.simp.stomp.StompHeaderAccessor;
importorg.springframework.messaging.support.ChannelInterceptorAdapter;
importorg.springframework.messaging.support.MessageHeaderAccessor;
springboot
一、什么都不用说,导入个依赖先
1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
importorg.springframework.context.ApplicationListener;
importorg.springframework.messaging.simp.stomp.StompHeaderAccessor;
importorg.springframework.web.socket.messaging.SessionConnectEvent;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
publicclassNotifyBean<T>implementsSerializable {
privatestaticfinallongserialVersionUID = 1L;
privateinttype;
相关文档
最新文档