换了新工作,第一个任务就是和这个有关,以前没接触过,没办法,各种度娘、谷哥,大部分都是只言片语,要么就是特定的配置环境还不贴配置……,踩坑无数, 遂整理成笔记


WebSocket协议

WebSocket是一种在单个TCP连接上进行全双工通讯的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。

WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输

STOMP协议

STOMP是面向文本的消息传送协议。STOMP客户端与支持STOMP协议的消息代理进行通信。STOMP使用不同的命令,如连接,发送,订阅,断开等进行通信。

具体参考:官方介绍

SockJS

SockJS是一个JavaScript库,提供跨浏览器JavaScript的API,创建了一个低延迟、全双工的浏览器和web服务器之间通信通道


以上内容出自维基百科和百度百科

环境配置

  1. SpringBoot2.0全家桶
  2. 特别说明一下,现在很多服务器都支持websocket,我这次写代码用的是SpringBoot内置的tomcat

应用场景

  1. 如果只是单纯的配置一个建立连接发送消息,并不难,具体客户端编写参考这个 菜鸟教程-websocket
  2. 我需要解决的问题是:当客户端和服务器建立连接时,将登录的用户信息从httpSession中取出,这个问题的难点在于,websocket的请求和http请求完全不相关,所以没有办法直接获取HttpSession

实施思路

  1. 服务器端的编码实现,具体有两套方案

    1. 使用继承的方式,这种方式,我在看Spring官方介绍文档时貌似也是这种方式实现的
    2. 使用注解的方式:很蛋疼的是我们的项目使用的是这种方式
  2. 具体思路
    1. 虽然websocket的请求和http请求完全不相关,但是如果基于注解的话,EndPoint支持读取一个配置
    2. 我当时的想法就是在配置中拦截或者获取HttpSession,事实证明思路是正确的,但是当我按照这个思路去百度谷歌发现获取的一律都是null,然后我就崩溃了

具体编码实现

  1. 只贴核心代码,完整项目在本文的底部,我放在了github上

  2. 先上核心的服务器端消息处理类

    /**
    * WebSocket主要的消息类
    * @author 侯叶飞
    */
    //onfigurator = WebsocketConfig.class 该属性就是我上面提到我们可以自己配置的东西
    @ServerEndpoint(value = "/api/websocket", configurator = WebsocketConfig.class)
    @Component
    @Slf4j
    public class WebSocket {
    /*每个浏览器连接都会有一个新的会话对象*/
    private Session session;
    /*用来存储每个会话的session,静态的不会被实例化*/
    private static CopyOnWriteArraySet<WebSocket> webSocketSets = new CopyOnWriteArraySet<>();
    /**
    * 主要用来监听连接建立,config用来获取WebsocketConfig中的配置信息
    * @param session
    * @param config
    */
    @OnOpen
    public void onOpen(Session session, EndpointConfig config) {
    log.info("config:{}", config.getUserProperties().get("name"));
    log.info("session:{}", config.getUserProperties().get("sessionid"));
    this.session = session;
    webSocketSets.add(this);
    log.info("【websocket消息】有新的连接, 总数:{}", webSocketSets.size());
    } @OnClose
    public void onClose() {
    webSocketSets.remove(this);
    log.info("【websocket消息】连接断开, 总数:{}", webSocketSets.size());
    } @OnError
    public void onError(Throwable e, Session session) {
    webSocketSets.remove(this);
    log.info("【websocket消息】连接出错或未关闭socket:" + e.getMessage()); } @OnMessage
    public void onMessage(String message, Session session) {
    for(WebSocket ws:webSocketSets){
    ws.session.getAsyncRemote().sendText("广播:"+message);
    }
    log.info("【websocket消息】收到客户端发来的消息:{}", message);
    }
    }
  3. 下面代码就是核心的配置类

    /**
    * 主要的配置类
    * 本类必须要继承Configurator,因为@ServerEndpoint注解中的config属性只接收这个类型
    * @author 侯叶飞
    *
    */
    @Configuration
    @Slf4j
    public class WebsocketConfig extends ServerEndpointConfig.Configurator { private static final String HttpSession = null;
    /* 修改握手,就是在握手协议建立之前修改其中携带的内容 */
    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
    /*如果没有监听器,那么这里获取到的HttpSession是null*/
    StandardSessionFacade ssf = (StandardSessionFacade) request.getHttpSession();
    if (ssf != null) {
    HttpSession session = (HttpSession) request.getHttpSession();
    sec.getUserProperties().put("sessionid", session);
    log.info("获取到的SessionID:{}",session.getId());
    }
    sec.getUserProperties().put("name", "小强");
    super.modifyHandshake(sec, request, response);
    }
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
    //这个对象说一下,貌似只有服务器是tomcat的时候才需要配置,具体我没有研究
    return new ServerEndpointExporter();
    }
    }
    1. 仅仅有上面的配置获取的肯定是null,至于原因,网上说法不一,我也不确定,解决方案如下
    /**
    * 监听器类:主要任务是用ServletRequest将我们的HttpSession携带过去
    * @author 侯叶飞
    */
    @Component //此注解千万千万不要忘记,它的主要作用就是将这个监听器纳入到Spring容器中进行管理,相当于注册监听吧
    @Slf4j
    public class RequestListener implements ServletRequestListener {
    @Override
    public void requestInitialized(ServletRequestEvent sre) {
    //将所有request请求都携带上httpSession
    HttpSession session = ((HttpServletRequest) sre.getServletRequest()).getSession();
    log.info("将所有request请求都携带上httpSession {}",session.getId());
    }
    public RequestListener() {} @Override
    public void requestDestroyed(ServletRequestEvent arg0) {}
    }
  4. 此外在我谷歌的过程中有博客提到需要添加一个WebListener的注解,结果发现基于springboot的话,如果不加也不影响


GitHub项目地址:Demo


以上代码纯属个人研究,如果有错误的地方,各位留言或者发邮件都可以!

Springboot-WebSocket获取HttpSession问题的更多相关文章

  1. WebSocket获取httpSession空指针异常的解决办法

    小坑:使用requestListner解决不了这个问题! 如何获取HttpSession 在使用webSocket实现p2p或者一对多聊天功能的时候我们经常会有这样的需求:webSocket服务端需要 ...

  2. java使用Websocket获取HttpSession出现的问题与解决

    websocket的写法就不多说了,主要记一记其中出现的问题 1.获取不到httpSession 解决办法:先重写握手方法,将httpsession放入ServerEndpointConfig.get ...

  3. java使用websocket,并且获取HttpSession,源码分析

    转载请在页首注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 一:本文使用范围 此文不仅仅局限于spring boot,普通的sprin ...

  4. WebSocket之获取HttpSession

    WebSocket之获取HttpSession 由于WebSocket与Http协议的不同,故在使用常用的HttpSession方面就存在了一些问题.通过google翻阅到了在onOpen方法下使用H ...

  5. Springboot+Websocket+JWT实现的即时通讯模块

    场景 目前做了一个接口:邀请用户成为某课程的管理员,于是我感觉有能在用户被邀请之后能有个立马通知他本人的机(类似微博.朋友圈被点赞后就有立马能收到通知一样),于是就闲来没事搞了一套. ​ 涉及技术栈 ...

  6. Netty+WebSocket 获取火币交易所数据项目

    Netty+WebSocket 获取火币交易所时时数据项目 先附上项目项目GitHub地址 spring-boot-netty-websocket-huobi 项目简介 本项目使用 SpringBoo ...

  7. webSocket 使用 HttpSession 的数据配置与写法

    1.前言 webSoket 无法获取 HttpSession  ,使用就更谈不上了 !!! 2解决过程 使用   configurator  注入即可 (1) 配置一个类 1 package cn.c ...

  8. SpringBoot+WebSocket

    SpringBoot+WebSocket 只需三个步骤 导入依赖 <dependency> <groupId>org.springframework.boot</grou ...

  9. springboot+websocket+sockjs进行消息推送【基于STOMP协议】

    springboot+websocket+sockjs进行消息推送[基于STOMP协议] WebSocket是在HTML5基础上单个TCP连接上进行全双工通讯的协议,只要浏览器和服务器进行一次握手,就 ...

随机推荐

  1. [NOIP模拟14]题解

    当垃圾已经成为一种常态233333 A.旋转子段 考场上的$n^2$手残少了20分,555  (主要是因为实在打不出来$n^3$的做法所以写不了对拍?ccc为什么考场上没有想起有reverse()这么 ...

  2. 傻瓜教程--------------linix上安装jdk

    大致步骤可分为3步,下面会详细解释 1:Jdk 的下载 2: jdk的解压 3: 环境变量的配置 一:jdk的下载 1官网下载jdk https://www.oracle.com/technetwor ...

  3. 第一次安装hadoop记录

    需求是:安装hadoop连接远程hadoop文件系统.JDK和hadoop需要与集群版本一致 首先去官网下载hadoop http://archive.apache.org/dist/hadoop/c ...

  4. System之nanoTime函数

    原文地址:https://blog.csdn.net/yumolan4325/article/details/79201766 1 System有一个静态的函数nanoTime函数,该函数是返回纳秒的 ...

  5. 在VMware软件下创建CentOs虚拟机

    1.创建新的虚拟机. 打开VMware软件,点击主页内创建新的虚拟机 2.进入新建虚拟机向导 点击典型,点击下一步 3.在下一步中单击稍后安装操作系统 点击下一步 4.选择操作系统类型 因为CentO ...

  6. TIKA环境配置

    本章将指导完成设置Apache Tika在Windows和Linux的配置过程.用户管理是必要的,同时安装了Apache Tika. 系统要求 JDK Java SE 2 JDK 1.6 或以上 内存 ...

  7. 20140506 visio 画布大小 栈实现队列 堆空闲内存地址链表 堆最大可分配的内存 可用内存链表

    1.调整visio的画布大小 按住Ctrl鼠标移动到画布边缘即可 2.两个栈实现一个队列 一个栈用于入队,一个用于出队 #include<iostream> #include<sta ...

  8. Codeforces Round #527 F - Tree with Maximum Cost /// 树形DP

    题目大意: 给定一棵树 每个点都有点权 每条边的长度都为1 树上一点到另一点的距离为最短路经过的边的长度总和 树上一点到另一点的花费为距离乘另一点的点权 选定一点出发 使得其他点到该点的花费总和是最大 ...

  9. springboot配置swagger-rest文档

    前言 swagger是一个很好的restful形式的api文档,可以通过比较小的侵入来提供很好的restful的文档.因为swagger是依赖服务生成的,所以其实是依赖服务的,这也算是它的一个小缺点吧 ...

  10. jetson更换源

    参考链接:https://blog.csdn.net/qq_36396941/article/details/88903094 Nano的镜像默认是国外的源,速度很慢,国内的源有的上不去,有的包无法安 ...