700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > spring boot 集成 websocket 实现消息主动推送

spring boot 集成 websocket 实现消息主动推送

时间:2021-11-01 06:42:36

相关推荐

spring boot 集成 websocket 实现消息主动推送

前言

http协议是无状态协议,每次请求都不知道前面发生了什么,而且只可以由浏览器端请求服务器端,而不能由服务器去主动通知浏览器端,是单向的,在很多场景就不适合,比如实时的推送,消息通知或者股票等信息的推送;在没有 websocket 之前,要解决这种问题,只能依靠ajax轮询或者长轮询,这两种方式极大的消耗资源;而websocket,只需要借助http协议进行握手,然后保持着一个websocket连接,直到客户端主动断开;相对另外的两种方式,websocket只进行一次连接,当有数据的时候再推送给浏览器,减少带宽的浪费和cpu的使用。

WebSocket是html5新增加的一种通信协议,目前流行的浏览器都支持这个协议,例如Chrome,Safari,Firefox,Opera,IE等等,对该协议支持最早的应该是chrome,从chrome12就已经开始支持,随着协议草案的不断变化,各个浏览器对协议的实现也在不停的更新。该协议还是草案,没有成为标准,不过成为标准应该只是时间问题了,从WebSocket草案的提出到现在已经有十几个版本了,目前对该协议支持最完善的浏览器应该是chrome,毕竟WebSocket协议草案也是Google发布的,下面我们教程我们使用springboot 集成 websocket 实现消息的一对一以及全部通知功能。

本文使用spring boot 2.1.1+ jdk1.8 + idea。

一:引入依赖

如何创建springboot项目本文不再赘述,首先在创建好的项目pom.xml中引入如下依赖:

<!--引入websocket依赖 -->

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-websocket</artifactId>

</dependency>

<!--引入thymeleaf模板引擎依赖-->

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-thymeleaf</artifactId>

</dependency>

二:创建websocket配置类

ServerEndpointExporter会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint。要注意,如果使用独立的servlet容器,而不是直接使用springboot的内置容器,就不要注入ServerEndpointExporter,因为它将由容器自己提供和管理。

package com.sailing.websocket.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** @author baibing* @project: springboot-socket* @package: com.sailing.websocket.config* @Description: socket配置类,往 spring 容器中注入ServerEndpointExporter实例* @date /12/20 09:46*/@Configurationpublic class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter(){return new ServerEndpointExporter();}}

三:编写websocket服务端代码

package com.mon;import org.ponent;import javax.websocket.*;import javax.websocket.server.PathParam;import javax.websocket.server.ServerEndpoint;import java.io.IOException;import java.util.HashMap;import java.util.Map;import java.util.concurrent.atomic.AtomicInteger;/*** @author baibing* @project: springboot-socket* @package: com.mon* @Description: WebSocket服务端代码,包含接收消息,推送消息等接口* @date /12/48*/@Component@ServerEndpoint(value = "/socket/{name}")public class WebSocketServer {//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。private static AtomicInteger online = new AtomicInteger();//concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象。private static Map<String,Session> sessionPools = new HashMap<>();/*** 发送消息方法* @param session 客户端与socket建立的会话* @param message 消息* @throws IOException*/public void sendMessage(Session session, String message) throws IOException{if(session != null){session.getBasicRemote().sendText(message);}}/*** 连接建立成功调用* @param session 客户端与socket建立的会话* @param userName 客户端的userName*/@OnOpenpublic void onOpen(Session session, @PathParam(value = "name") String userName){sessionPools.put(userName, session);addOnlineCount();System.out.println(userName + "加入webSocket!当前人数为" + online);try {sendMessage(session, "欢迎" + userName + "加入连接!");} catch (IOException e) {e.printStackTrace();}}/*** 关闭连接时调用* @param userName 关闭连接的客户端的姓名*/@OnClosepublic void onClose(@PathParam(value = "name") String userName){sessionPools.remove(userName);subOnlineCount();System.out.println(userName + "断开webSocket连接!当前人数为" + online);}/*** 收到客户端消息时触发(群发)* @param message* @throws IOException*/@OnMessagepublic void onMessage(String message) throws IOException{for (Session session: sessionPools.values()) {try {sendMessage(session, message);} catch(Exception e){e.printStackTrace();continue;}}}/*** 发生错误时候* @param session* @param throwable*/@OnErrorpublic void onError(Session session, Throwable throwable){System.out.println("发生错误");throwable.printStackTrace();}/*** 给指定用户发送消息* @param userName 用户名* @param message 消息* @throws IOException*/public void sendInfo(String userName, String message){Session session = sessionPools.get(userName);try {sendMessage(session, message);}catch (Exception e){e.printStackTrace();}}public static void addOnlineCount(){online.incrementAndGet();}public static void subOnlineCount() {online.decrementAndGet();}}

四:增加测试页面路由配置类

如果为每一个页面写一个action太麻烦,spring boot 提供了页面路由的统一配置,在 spring boot 2.0 以前的版本中我们只需要继承WebMvcConfigurerAdapter ,并重写它的addViewControllers 方法即可,但是2.0版本后WebMvcConfigurerAdapter已经被废弃,使用 WebMvcConfigurer 接口代替(其实WebMvcConfigurerAdapter也是实现了WebMvcConfigurer),所以我们只需要实现它即可:

package com.sailing.websocket.config;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;/*** 在SpringBoot2.0及Spring 5.0 WebMvcConfigurerAdapter已被废弃,目前找到解决方案就有* 1 直接实现WebMvcConfigurer (官方推荐)* 2 直接继承WebMvcConfigurationSupport* @ /lenkvin/article/details/79482205*/@Configurationpublic class WebMvcConfig implements WebMvcConfigurer {/*** 为各个页面提供路径映射* @param registry*/@Overridepublic void addViewControllers(ViewControllerRegistry registry) {registry.addViewController("/client").setViewName("client");registry.addViewController("/index").setViewName("index");}}

五:创建测试页面

在 resources下面创建 templates 文件夹,编写两个测试页面index.htmlclient.html和上面配置类中的viewName相对应,两个页面内容一模一样,只是在连接websocket部分模拟的用户名不一样,一个叫 lucy 一个叫 lily :

<!DOCTYPE HTML><html><head><title>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;//判断当前浏览器是否支持WebSocketif('WebSocket' in window){websocket = new WebSocket("ws://localhost:8080/socket/lucy");}else{alert('Not support websocket')}//连接发生错误的回调方法websocket.onerror = function(){setMessageInnerHTML("error");};//连接成功建立的回调方法websocket.onopen = function(event){setMessageInnerHTML("open");}//接收到消息的回调方法websocket.onmessage = function(event){setMessageInnerHTML(event.data);}//连接关闭的回调方法websocket.onclose = function(){setMessageInnerHTML("close");}//监听窗口关闭事件,当窗口关闭时,主动去关闭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>

<!DOCTYPE HTML><html><head><title>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;//判断当前浏览器是否支持WebSocketif('WebSocket' in window){websocket = new WebSocket("ws://localhost:8080/socket/lily");}else{alert('Not support websocket')}//连接发生错误的回调方法websocket.onerror = function(){setMessageInnerHTML("error");};//连接成功建立的回调方法websocket.onopen = function(event){setMessageInnerHTML("open");}//接收到消息的回调方法websocket.onmessage = function(event){setMessageInnerHTML(event.data);}//连接关闭的回调方法websocket.onclose = function(){setMessageInnerHTML("close");}//监听窗口关闭事件,当窗口关闭时,主动去关闭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>

六:测试webscoket controller

package com.sailing.websocket.controller;import com.mon.WebSocketServer;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;import java.io.IOException;/*** @author baibing* @project: springboot-socket* @package: com.sailing.websocket.controller* @Description: websocket测试controller* @date /12/20 10:11*/@RestControllerpublic class SocketController {@Resourceprivate WebSocketServer webSocketServer;/*** 给指定用户推送消息* @param userName 用户名* @param message 消息* @throws IOException*/@RequestMapping(value = "/socket", method = RequestMethod.GET)public void testSocket1(@RequestParam String userName, @RequestParam String message){webSocketServer.sendInfo(userName, message);}/*** 给所有用户推送消息* @param message 消息* @throws IOException*/@RequestMapping(value = "/socket/all", method = RequestMethod.GET)public void testSocket2(@RequestParam String message){try {webSocketServer.onMessage(message);} catch (IOException e) {e.printStackTrace();}}}

七:测试

访问http://localhost:8080/index和http://localhost:8080/client分别打开两个页面并连接到websocket,http://localhost:8080/socket?userName=lily&message=helloworld给lily发送消息,http://localhost:8080/socket/all?message=LOL给全部在线用户发送消息:

到这里,spring boot 集成 websocket 就结束了,不足之处希望各位指正~~~

项目下载:springboot集成websocket实现消息的主动推送

因csdn后台会自动修改积分,导致现在积分较高,可以去下面地址免费下载:/KingOfMonkey/springboot-mybatis

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。