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

 更新时间:2020年06月11日 09:59:54   作者:有追求的程序狗  
这篇文章主要介绍了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长连接内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring源码解析之推断构造方法

    Spring源码解析之推断构造方法

    今天给大家带来的是关于Java的相关知识,文章围绕着Spring推断构造方法展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-06-06
  • Rabbitmq消息推送功能实现示例

    Rabbitmq消息推送功能实现示例

    rabbitMQ为异步消息处理提出了一个很好的解决方案,它是一个非常好用的消息中间件。主要解决当生产者大量产生数据时,消费者无法快速消费的问题。这个时候需要一个中间层,保存这个数据,rabbitMQ是一个很好的解决方案
    2022-12-12
  • Java通过正则表达式获取字符串中数字的方法示例

    Java通过正则表达式获取字符串中数字的方法示例

    最近工作中遇到了一个需求,需要利用java获取字符串中的数字,尝试几种方法后发现利用正则表达式实现最为方法,下面这篇文章就主要介绍了Java通过正则表达式获取字符串中数字的方法,文中给出了详细的示例代码,需要的朋友可以参考下。
    2017-03-03
  • Java Mybatis框架由浅入深全解析下篇

    Java Mybatis框架由浅入深全解析下篇

    MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码,本文将作为最终篇为大家介绍MyBatis的使用
    2022-07-07
  • java实现写入并保存txt文件的代码详解

    java实现写入并保存txt文件的代码详解

    在本篇文章里小编给大家整理了关于java实现写入并保存txt文件的代码实例内容,需要的朋友们可以参考学习下。
    2020-02-02
  • Spring Data JPA映射自定义实体类操作

    Spring Data JPA映射自定义实体类操作

    这篇文章主要介绍了Spring Data JPA映射自定义实体类操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • Java 线程池详解

    Java 线程池详解

    本文给大家总结了java中的线程池的相关问题,非常的详细也很实用,有需要的小伙伴可以参考下。
    2016-03-03
  • Java后端长时间无操作自动退出的实现方式

    Java后端长时间无操作自动退出的实现方式

    这篇文章主要介绍了Java后端长时间无操作自动退出的实现方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • 23种设计模式(7) java代理模式

    23种设计模式(7) java代理模式

    这篇文章主要为大家详细介绍了23种设计模式之java代理模式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-11-11
  • Java 实战项目锤炼之仿天猫网上商城的实现流程

    Java 实战项目锤炼之仿天猫网上商城的实现流程

    读万卷书不如行万里路,只学书上的理论是远远不够的,只有在实战中才能获得能力的提升,本篇文章手把手带你用java+jsp+servlet+mysql+ajax实现一个仿天猫网上商城项目,大家可以在过程中查缺补漏,提升水平
    2021-11-11

最新评论