SpringBoot集成WebSocket长连接实际应用详解

前言:

一、WebSocket之初出茅驴

官方定义:WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。是真正的双向平等对话,属于服务器推送技术的一种。

太官方啦,还是博主过来翻译一下吧 :WebSocket技术只需要service和client建立一次连接,就能实现服务器和客户端双方相互频繁的发送请求和通信!(简单加粗暴的翻译有木有,哈哈!)

WebSocket经典的使用场景:网站在线聊天系统、弹幕系统…

臣附议:webSocket技术无法做到向下兼容,不兼容低版本的IE,因此依赖于浏览器版本,这也正是webSocket非常显著的缺陷。

二、WebSocket的出现到底为我们解决了什么实际问题?

在传统的b/s架构中,要实现服务器向client进行实时消息推送功能,市场上常用的解决方案大致分为三类:

定时轮询 客户端以一定的时间间隔向服务端发出请求
长轮询 如果服务器没有可以立即返回给客户端的数据,则不会立刻返回一个空结果
流技术 客户端隐藏的窗口向服务端发出一个长轮询的请求

长轮询机制:

综合这几种方案,您会发现这些目前我们所使用的所谓的实时技术并不是真正的实时技术,它们只是在用 Ajax 方式来模拟实时的效果,定时轮询需要实时获取取服务端信息的应用时, client需要频繁轮询server,为了拿到最新信息, client一直这样循环下去server如果一直没有新的消息, client的大多请求都是属于无效请求, 导致会带来很多无谓的网络传输,所以这是一种非常低效的实时方案。长轮询对服务器造成的压力非常大,并且如果服务端的数据变更非常频繁的话,这种方式无异于定时轮询。所以为了解决传统http请求的实际问题,WebSocket技术应运而生!下面博主给张图让大家生动的理解传统HTTP和WebSocket的差异化:

三、博主使用WebSocket的场景

博主最进在公司调用第三方影像采集系统,由于影像状态是异步返回给业务系统的,导致当业务系统收到第三方回调后,对于前台用户体验来说是无感知的,因此前台必须刷新页面才能获取到影像最新状态。这时候由service主动向client实时发送影像采集状态的通知是最好不过的方案!在上述提到的常用解决方案,像轮询这种比较low的实现,博主作为技术宅,肯定是不会作为技术选型的,哈哈…

四、不多bb,上代码!

本项目是基于SpringBoot环境开发

1、导入websocket坐标

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

2、封装WebSocketUtil工具类,用于提供对session链接、断开连接、推送消息的简单控制。

 public class WebsocketUtil {
  /**
   * 记录当前在线的Session
   */
  private static final Map<String, Session> ONLINE_SESSION = new ConcurrentHashMap<> ();

  /**
   * 添加session
   * @param userId
   * @param session
   */
  public static void addSession(String userId, Session session){
    // 此处只允许一个用户的session链接。一个用户的多个连接,我们视为无效。
    ONLINE_SESSION.putIfAbsent ( userId, session );
  }

  /**
   * 关闭session
   * @param userId
   */
  public static void removeSession(String userId){
    ONLINE_SESSION.remove ( userId );
  }

  /**
   * 给单个用户推送消息
   * @param session
   * @param message
   */
  public static void sendMessage(Session session, String message){
    if(session == null){
      return;
    }

    // 同步
    RemoteEndpoint.Async async = session.getAsyncRemote ();
    async.sendText ( message );
  }

  /**
   * 向所有在线人发送消息
   * @param message
   */
  public static void sendMessageForAll(String message) {
    //jdk8 新方法
    ONLINE_SESSION.forEach((sessionId, session) -> sendMessage(session, message));
  }
}

3、 WebSocketController

如上,已经创建好了简单的session管理和消息管理,接下来要使用注解的方式,使用SpringBoot的websocket包提供的方法,实现OnOpen、OnClose、OnMessage三个方法,再实现一个OnError方法来应对异常。代码段如下:

/**
 * websocket接口处理类
 */
@Component
@ServerEndpoint ( value = "/chat/{userid}" )
public class WebsocketController {

  /**
   * 连接事件,加入注解
   * @param userId
   * @param session
   */
  @OnOpen
  public void onOpen( @PathParam ( value = "userid" ) String userId, Session session ) {
    String message ="[" + userId + "]加入聊天室!!";

    // 添加到session的映射关系中
    WebsocketUtil.addSession ( userId, session );
    // 广播通知,某用户上线了
    WebsocketUtil.sendMessageForAll ( message );
  }

  /**
   * 连接事件,加入注解
   * 用户断开链接
   * @param userId
   * @param session
   */
  @OnClose
  public void onClose(@PathParam ( value = "userId" ) String userId, Session session ) {
    String message ="[" + userId + "]退出了聊天室...";

    // 删除映射关系
    WebsocketUtil.removeSession ( userId );
    // 广播通知,用户下线了
    WebsocketUtil.sendMessageForAll ( message );
  }

  /**
   * 当接收到用户上传的消息
   * @param userId
   * @param session
   */
  @OnMessage
  public void onMessage(@PathParam ( value = "userId" ) String userId, Session session ,String message) {
    String msg ="[" + userId + "]:"+message;

    // 直接广播
    WebsocketUtil.sendMessageForAll ( msg );
  }

  /**
   * 处理用户活连接异常
   * @param session
   * @param throwable
   */
  @OnError
  public void onError(Session session, Throwable throwable) {
    try {
      session.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
    throwable.printStackTrace();
  }
}

4、添加 ServerEndpointExporter 启动Bean

public class DemoApplication {

  public static void main(String[] args) {
    SpringApplication.run(DemoApplication.class, args);
  }

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

那些年踩过的坑:
注意:在websocketEndpoint中,使用@Autowired一些列注解注入Bean时候,一直无法注入,报空指针。原因在于spring管理的都是单例(singleton),和 websocket (多对象)相冲突。
解决办法:通过上下文获取bean实例:从Spring上下文获取bean实例的方法

到此这篇关于SpringBoot集成WebSocket长连接实际应用详解的文章就介绍到这了,更多相关SpringBoot WebSocket长连接内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

时间: 2020-06-09

详解在Spring Boot框架下使用WebSocket实现消息推送

spring Boot的学习持续进行中.前面两篇博客我们介绍了如何使用Spring Boot容器搭建Web项目以及怎样为我们的Project添加HTTPS的支持,在这两篇文章的基础上,我们今天来看看如何在Spring Boot中使用WebSocket. 什么是WebSocket WebSocket为浏览器和服务器之间提供了双工异步通信功能,也就是说我们可以利用浏览器给服务器发送消息,服务器也可以给浏览器发送消息,目前主流浏览器的主流版本对WebSocket的支持都算是比较好的,但是在实际开发中使

关于Spring Boot WebSocket整合以及nginx配置详解

前言 本文主要给大家介绍了关于Spring Boot WebSocket整合及nginx配置的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 一:Spring Boot WebSocket整合 创建一个maven项目,加入如下依赖 <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId>

详解spring boot Websocket使用笔记

本文只作为个人笔记,大部分代码是引用其他人的文章的. 在springboot项目中使用websocket做推送,虽然挺简单的,但初学也踩过几个坑,特此记录. 使用websocket有两种方式:1是使用sockjs,2是使用h5的标准.使用Html5标准自然更方便简单,所以记录的是配合h5的使用方法. 1.pom 核心是@ServerEndpoint这个注解.这个注解是Javaee标准里的注解,tomcat7以上已经对其进行了实现,如果是用传统方法使用tomcat发布项目,只要在pom文件中引入j

SpringBoot+Websocket实现一个简单的网页聊天功能代码

最近做了一个SpringBoot的项目,被SpringBoot那简介的配置所迷住.刚好项目中,用到了websocket.于是,我就想着,做一个SpringBoot+websocket简单的网页聊天Demo. 效果展示: 当然,项目很简单,没什么代码,一眼就能明白 导入websocket的包. 通过使用SpringBoot导入包的时候,我们可以发现,很多包都是以 spring-boot-starter 开头的,对于我这种强迫症 ,简直是福音 <dependency> <groupId>

SpringBoot集成WebSocket实现前后端消息互传的方法

什么是WebSocket? WebSocket 协议是基于 TCP 的一种新的网络协议.它实现了浏览器与服务器全双工 (full-duplex) 通信-允许服务器主动发送信息给客户端. 为什么需要WebSocket? 大家都知道以前客户端想知道服务端的处理进度,要不停地使用 Ajax 进行轮询,让浏览器隔个几秒就向服务器发一次请求,这对服务器压力较大.另外一种轮询就是采用 long poll 的方式,这就跟打电话差不多,没收到消息就一直不挂电话,也就是说,客户端发起连接后,如果没消息,就一直不返

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

之前实现WebSocket基于STOMP的,觉得SpringBoot封装的太高,不怎么灵活,现在实现一个纯H5的,也大概了解webSocket在内部是怎么传输的. 1.环境搭建 因为在上一篇基于STOMP协议实现的WebSocket里已经有大概介绍过Web的基本情况了,所以在这篇就不多说了,我们直接进入正题吧,在SpringBoot中,我们还是需要导入WebSocket的包. 在pox.xml加上对springBoot对WebSocket的支持: <!-- webSocket --> <

SpringBoot webSocket实现发送广播、点对点消息和Android接收

1.SpringBoot webSocket SpringBoot 使用的websocket 协议,不是标准的websocket协议,使用的是名称叫做STOMP的协议. 1.1 STOMP协议说明 STOMP,Streaming Text Orientated Message Protocol,是流文本定向消息协议,是一种为MOM(Message Oriented Middleware,面向消息的中间件)设计的简单文本协议. 它提供了一个可互操作的连接格式,允许STOMP客户端与任意STOMP消

springboot websocket简单入门示例

之前做的需求都是客户端请求服务器响应,新需求是服务器主动推送信息到客户端.百度之后有流.长轮询.websoket等方式进行.但是目前更加推崇且合理的显然是websocket. 从springboot官网翻译了一些资料,再加上百度简单实现了springboot使用websocekt与客户端的双工通信. 1.首先搭建一个简单的springboot环境 <!-- Inherit defaults from Spring Boot --> <parent> <groupId>o

jQuery简单入门示例之用户校验demo示例

本文实例讲述了jQuery简单入门示例之用户校验.分享给大家供大家参考,具体如下: jQuery在小编的世界中,也就是JavaScript和查询(Query),即是辅助JavaScript开发的库,百度百科对JQuery的介绍比较详细,小伙伴可以东东自己可耐的小爪子,上网进行搜索,说不定,有意外惊喜哦,今天这篇文章,小编简单的介绍一下JQuery的一些基本知识,然后小编在集合实例,讲解一下在具体的应用过程中,我们的JQuery又是如何在她的舞台熠熠生辉...... 通过JQuery的学习,我们可

Java Spring开发环境搭建及简单入门示例教程

本文实例讲述了Java Spring开发环境搭建及简单入门示例.分享给大家供大家参考,具体如下: 前言 虽然之前用过Spring,但是今天试着去搭建依然遇到了困难,而且上网找教程,很多写的是在web里使用Spring MVC的示例,官方文档里的getting start一开始就讲原理去了(可能打开的方法不对).没办法,好不容易实验成功了,记下来免得自己以后麻烦. 添加依赖包 进入spring官网,切换到projects下点击 spring framework.官网上写的是以maven依赖的形式写

Sanic框架安装与简单入门示例

本文实例讲述了Sanic框架安装与简单用法.分享给大家供大家参考,具体如下: Sanic是一个类似Flask的Python 3.5+ Web服务器,它的写入速度非常快.除了Flask之外,Sanic还支持异步请求处理程序.这意味着你可以使用Python 3.5中新的闪亮的异步/等待语法,使你的代码非阻塞和快速. 前言:Sanic最低支持Python 3.5,如果需要学习Sanic,请先下载版本不低于3.5的Python包 安装Sanic pip3 install sanic 注意:Sanic暂时

利用百度echarts实现图表功能简单入门示例【附源码下载】

本文实例讲述了利用百度echarts实现图表功能.分享给大家供大家参考,具体如下: 百度有一款开源的图表控件,号称是大数据时代最好的图表控件.刚好目前的项目需要用图表展示给客户看数据,所以就选择这个三方的控件.对这种控件一般来说使用起来应该没有太大的难度,基本就是按照它的规则组装json数据,关键是配置上面, 如果刚开始入门,不太懂,可能真要花点时间来搞的.我整理了一个最基本的入门例子,里面有详细的注释,按这种方式去加载相关 js 就没有问题了: <!DOCTYPE html> <hea

SpringBoot如何添加WebSocket的方法示例

一.WebSocket介绍 网站上的即时通讯是很常见的,比如网页的QQ,聊天系统等.按照以往的技术能力通常是采用轮询.Comet技术解决. HTTP协议是非持久化的,单向的网络协议,在建立连接后只允许浏览器向服务器发出请求后,服务器才能返回相应的数据.当需要即时通讯时,通过轮询在特定的时间间隔(如1秒),由浏览器向服务器发送Request请求,然后将最新的数据返回给浏览器.这样的方法最明显的缺点就是需要不断的发送请求,而且通常HTTP request的Header是非常长的,为了传输一个很小的数

史上最简单的MyBatis动态SQL入门示例代码

假如有如下的关于书籍基本信息的表: DROP DATABASE IF EXISTS `books`; CREATE DATABASE `books`; USE books; DROP TABLE IF EXISTS `book`; CREATE TABLE `book` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(128) DEFAULT NULL, `author` varchar(64) DEFAULT NULL, `pres

SpringBoot+WebSocket搭建简单的多人聊天系统

前言 今天闲来无事,就来了解一下WebSocket协议.来简单了解一下吧. WebSocket是什么 首先了解一下WebSocket是什么?WebSocket是一种在单个TCP连接上进行全双工通信的协议.这是一种比较官方的说法,简单点来说就是,在一次TCP连接中,通信的双方可以相互通信.比如A和B在打电话,A说话的时候,B也可以说话来进行信息的交互,这就叫做全双工通信.对应的是单工通信,和半双工通信,单工通信就是只能由A向B通信,比如电脑和打印机.半双工通信是可以AB可以互相通信,但是同一时间只

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

上一篇文章讲了Netty的理论基础,这一篇讲一下Netty在项目中的应用场景之一:消息推送功能,可以满足给所有用户推送,也可以满足给指定某一个用户推送消息,创建的是SpringBoot项目,后台服务端使用Netty技术,前端页面使用WebSocket技术. 大概实现思路: 前端使用webSocket与服务端创建连接的时候,将用户ID传给服务端 服务端将用户ID与channel关联起来存储,同时将channel放入到channel组中 如果需要给所有用户发送消息,直接执行channel组的writ