前言

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 2018/12/20 09:46*/
@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter(){return new ServerEndpointExporter();}
}

三:编写websocket服务端代码

package com.sailing.websocket.common;import org.springframework.stereotype.Component;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.sailing.websocket.common* @Description: WebSocket服务端代码,包含接收消息,推送消息等接口* @date 2018/12/200948*/
@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* @ https://blog.csdn.net/lenkvin/article/details/79482205*/
@Configuration
public 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.sailing.websocket.common.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 2018/12/20 10:11*/
@RestController
public 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后台会自动修改积分,导致现在积分较高,可以去下面地址免费下载:https://github.com/KingOfMonkey/springboot-mybatis

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

  1. socket接收的消息怎么更新到页面_spring boot 集成 websocket 实现消息主动

    前言 http协议是无状态协议,每次请求都不知道前面发生了什么,而且只可以由浏览器端请求服务器端,而不能由服务器去主动通知浏览器端,是单向的,在很多场景就不适合,比如实时的推送,消息通知或者股票等信息 ...

  2. SpringBoot 集成 WebSocket 实现消息群发推送

    一. 什么是 WebSocket WebSocket 是一种全新的协议.它将 TCP 的 Socket(套接字)应用在了web page上,从而使通信双方建立起一个保持在活动状态的连接通道,并且属于全 ...

  3. spring boot 集成socketIo 做消息推送

    spring boot 集成socketIo 做消息推送 项目需求 代码展示 客户端代码 服务端代码 项目需求 后台管理系统用户小铃铛,消息推送功能并展示有多少条消息或者小红点 代码展示 客户端代码 ...

  4. SpringBoot2.x系列教程(四十五)Spring Boot集成WebSocket实现技术交流群功能

    在上篇文章中,我们了解了WebSocket的基本功能及相关概念.本篇文章中我们以具体的实例来演示,在Spring Boot中整合WebSocket,同时实现一个场景的业务场景功能. 针对在Spring ...

  5. php订阅号发送消息,PHP版微信公共平台消息主动推送,突破订阅号一天只能发送一条信息...

    2013年10月06日最新整理. PHP版微信公共平台消息主动推送,突破订阅号一天只能发送一条信息限制 微信公共平台消息主动推送接口一直是腾讯的私用接口,相信很多朋友都非常想要用到这个功能. 通过学习 ...

  6. 小程序消息主动推送php,微信小程序有几种推送消息的方式

    微信小程序有5种推送消息的方式,分别为:1.小票机订单提醒,实现对商家的消息提醒:2.短信提醒:3.模板消息,各种动态可及时掌握:4.公众号订单提醒:5.消息主动推送,商家主动出击.推销自己的最好手段 ...

  7. Spring Boot 集成 WebSocket通信信息推送!

    一.什么是websocket? WebSocket 协议是基于 TCP 的一种新的网络协议. 它实现了客户端与服务器之间的全双工通信,学过计算机网络都知道,既然是全双工,就说明了服务器可以主动发送信息 ...

  8. java websocket注解_【websocket】spring boot 集成 websocket 的四种方式

    集成 websocket 的四种方案 1. 原生注解 pom.xml org.springframework.boot spring-boot-starter-websocket WebSocketC ...

  9. 基于 SSE 实现服务端消息主动推送解决方案

    一.SSE 服务端消息推送 SSE 是 Server-Sent Events 的简称, 是一种服务器端到客户端(浏览器)的单项消息推送.对应的浏览器端实现 Event Source 接口被制定为HTM ...

最新文章

  1. [BZOJ2216][Poi2011]Lightning Conductor[决策单调性优化]
  2. 去除字符串标点 + 泛型算法使用
  3. NSURLConnection和NSRunLoop
  4. Hadoop权威指南 _03_第I部分Hadoop基础知识_第1章初识Hadoop.
  5. mysql数据库密码错误_MySQL数据库经典错误六 数据库密码忘记的问题
  6. 在5分钟内学习Vuex
  7. 对thinkphp的命名空间的理解
  8. python 输出文件中返回码为200的接口的平均响应时间_Django查看响应时间问题
  9. python绘制k线图(蜡烛图)报错 No module named 'matplotlib.finance
  10. 第二次作业+105032014037
  11. [RL] 配置 gym 与 atari 游戏
  12. 评测 | 千元以下的扫拖一体机器人,到底值不值得买?
  13. Eclipse如何重置窗口
  14. 第一部分 线程APIs(Thread APIs)线程和运行(Threads and Runnables)
  15. MySQL frm、MYD、MYI数据文件恢复
  16. 百度注册登录页面简单实现——仿照
  17. 计算机主板芯片组型号有哪些,如何鉴别主板芯片组型号
  18. spark推测执行 优点 缺点
  19. 戴尔计算机无法安装Win10,教您戴尔无法开机如何重装win10
  20. 软考 - 09 预约挂号管理系统

热门文章

  1. html樱花飘落代码_武大樱花又盛开,用python画一棵樱花树
  2. 仿写携程旅游手机浏览器页面
  3. 高速工业相机应用领域
  4. 自然人代开是什么政策,怎么操作呢?
  5. 转:elasticsearch下载太慢在国内, 我把包放到了云盘上,还有kibana,logstash.有需要自取,持续更新版本
  6. python提取cad坐标_教你一个实用的CAD坐标提取技巧
  7. 计算机应用专业顶岗实习计划,计算机学生顶岗实习计划(网络版)
  8. 【canvas使用】
  9. 循环调用scrapy框架出现的问题:twisted.internet.error.ReactorNotRestartable,解决方法
  10. 兔子繁衍问题—c语言