webscoket实战之利用httpsession定向推送

开发框架

springboot

场景

在利用websocket主动推送信息给客户端的过程中,经常会遇到一个普遍需求,就是推送的消息要定向推送给不同的用户,或者解释的再普通一点,不同的消息推送给不同的session。例如一个用户admin,可以在多台设备登录,此时就有多个session,当一个设备向后台发起一个请求,处理时间较长(未采用客户端进行ajax轮训或者long poll时),采用websocket协议时,要针对不同session的操作定向返回操作结果。

下面来具体看看如何实现上述需求。

实例

springboot对websocket支持很友好,只需要继承webSocketHandler类,重写几个方法就可以了

public class ResultHandler extends TextWebSocketHandler {
private static final Logger logger = LoggerFactory.getLogger(ResultHandler.class); @Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
} @Override
public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception {
} @Override
public void afterConnectionClosed(WebSocketSession webSocketsession, CloseStatus status) throws Exception { }
}

然后写一个简单的配置类

@EnableWebSocket
@Configuration
public class WebSocketConfig implements WebSocketConfigurer{ @Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
webSocketHandlerRegistry.addHandler(resultHandler (), "/getResult").withSockJS();
} @Bean
public ResultHandler resultHandler(){
return new ResultHandler();
} }

这样一个websocket 服务端就写好了

我们希望能够把websocketSession和httpsession对应起来,这样就能根据当前不同的session,定向对websocketSession进行数据返回

如何解决这个问题呢,考虑到websocket是在http的基础上建立起来的(具体websocket建立,自行百度),能不能在websocket握手的时候,把当前的sessionId放入websocketSession的属性中呢?

在查询资料之后,发现spring中有一个拦截器接口,HandshakeInterceptor,可以实现这个接口,来拦截握手过程,向其中添加属性

public class WebSocketHandshakeInterceptor implements HandshakeInterceptor{

    private static final Logger logger = LoggerFactory.getLogger(WebSocketHandshakeInterceptor.class);
@Override
public boolean beforeHandshake(ServerHttpRequest serverHttpRequest,ServerHttpResponse serverHttpResponse,
WebSocketHandler webSocketHandler, Map<String, Object> map) throws Exception {
if(serverHttpRequest instanceof ServletServerHttpRequest){
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) serverHttpRequest;
HttpSession httpSession = servletRequest.getServletRequest().getSession(true);
if(null != httpSession){
map.put(Constants.SESSION_ID,httpSession.getId());
}
}
return true;
} @Override
public void afterHandshake(ServerHttpRequest serverHttpRequest,
ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) { }
}

beforeHandShake方法中的Map参数 就是对应websocketSession里的属性,向里面添加内容后,可以在上面的resultHandler里面利用websocketSession参数将其取出来 String sessionId = (String)webSocketsession.getAttributes().get(Constants.SESSION_ID);

参考下面代码

public class ResultHandler extends TextWebSocketHandler {
private static final Logger logger = LoggerFactory.getLogger(ResultHandler.class); @Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { } @Override
public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception {
if(null != webSocketSession ){
String sessionId = (String)webSocketSession.getAttributes().get(Constants.SESSION_ID);
addConnectionCount();
logger.info("WebSocket connection established, sessionId={} ConnectCount={}", sessionId, getConnectionCount());
}
} @Override
public void afterConnectionClosed(WebSocketSession webSocketsession, CloseStatus status) throws Exception {
if(null != webSocketsession ){
String sessionId = (String)webSocketsession.getAttributes().get(Constants.SESSION_ID);
SocketSessionManager.socketSessionMap.remove(sessionId);
subConnectionCount();
logger.info("WebSocket connection close, Status={}, connectionCount={}", status, getConnectionCount());
}
}
public static synchronized int getConnectionCount (){
return ScriptTaskResultHandler.connectionCount;
} private static synchronized void addConnectionCount(){
ScriptTaskResultHandler.connectionCount++;
} private static synchronized void subConnectionCount(){
ScriptTaskResultHandler.connectionCount--;
} }

还可以自己写一个webSocketSession管理类,当连接建立好之后,保存在这个管理类中,用sessionId当做Key,webSocketSession当做value,当结果处理完成后,根据sessionId找到相应的webSocketSession,进行数据推送。

拦截器加入的方法

@EnableWebSocket
@Configuration
public class WebSocketConfig implements WebSocketConfigurer{ @Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
webSocketHandlerRegistry.addHandler(resultHandler (), "/getResult").
addInterceptors(new WebSocketHandshakeInterceptor()).withSockJS();
} @Bean
public ResultHandler resultHandler(){
return new ResultHandler();
} }

webscoket实战之利用httpsession定向推送的更多相关文章

  1. 移动互联网实战--Apple的APNS桩推送服务的实现(2)

    前记: 相信大家在搞IOS推送服务的开发时, 会直接使用javapns api来简单实现, 调试也直连Apple的APNS服务(产品/测试版)来实现. 很少有人会写个APNS的桩服务, 事实也是如此. ...

  2. 移动互联网实战--Apple的APNS桩推送服务的实现(1)

    前记: 相信大家在搞IOS推送服务的开发时, 会直接使用javapns api来简单实现, 调试也直连Apple的APNS服务(产品/测试版)来实现. 很少有人会写个APNS的桩服务, 事实也是如此. ...

  3. signalr推送消息

    参考:Tutorial: Getting Started with SignalR 2 and MVC 5 环境:vs2013,webapi2,entity framework6.0 实现效果:当用户 ...

  4. 一步步教你用Prometheus搭建实时监控系统系列(二)——详细分析拉取和推送两种不同模式

    前言 本系列着重介绍Prometheus以及如何用它和其周边的生态来搭建一套属于自己的实时监控告警平台. 本系列受众对象为初次接触Prometheus的用户,大神勿喷,偏重于操作和实战,但是重要的概念 ...

  5. IosPush推送通知的实现

    1. Apple推送通知的机制 上图可以分为三个阶段: 第一阶段:应用程序把要发送的消息.目的iPhone的标识打包,发给APNS. 第二阶段:APNS在自身的已注册Push服务的iPhone列表中, ...

  6. 【android极光推送】—从客户端到后台,一文通吃

    sion android:name="android.permission.VIBRATE" /> <uses-permission android:name=&quo ...

  7. iOS-本地推送(本地通知)

    第一步:注册本地通知: // 设置本地通知 + (void)registerLocalNotification:(NSInteger)alertTime { UILocalNotification * ...

  8. Android 高仿微信实时聊天 基于百度云推送

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38799363 ,本文出自:[张鸿洋的博客] 一直在仿微信界面,今天终于有幸利用百 ...

  9. Android融合推送MixPush SDK集成多家推送平台,共享系统级推送,杀死APP也能收到推送

    消息推送是App运营的重要一环,为了优化消息推送成功率,降低电量和流量消耗,系统级的推送服务显得尤为重要.小米和魅族由此推出了自家的推送平台,在MIUI和Flyme上共享系统级推送服务,让APP在被杀 ...

随机推荐

  1. TableView 多余分割线的处理

    方法一,以下两个方法的实现 - (void)viewDidLoad { [super viewDidLoad]; self.tableView.tableFooterView = [[UIView a ...

  2. 服务器数据库搭建流程(CentOs+mysql)

    前言: 服务器上数据库搭建需要知道Linux系统的版本,以前的Ubuntu14.04直接在终端下输入apt-get install (package)便可方便的下载并安装mysql,但是在centOs ...

  3. 用C#来学习唐诗三百首

    Begin 最近把项目做完了,闲来无事,就想做点好玩的事情,刚好前几天下载了[唐诗三百首]和[全唐诗]这两个txt文件,正好用C#来整理一下. [唐诗三百首]文件格式 [全唐诗]文件格式 目标 将每一 ...

  4. android studio 中的 gradle version

    刚开始接触AS,从geithub上download了好多项目,每一个都需要改动,对我这种新手来说,慢慢琢磨吧 问题一: 解决办法: 在build.gradle中,将gradle的版本改正如上图所示即可 ...

  5. ImportError: No module named cv2 解决方法

    ImportError: No module named cv2 解决方法   import cv2时会出现这个问题 解决方法:将openCV安装目录里的python文件夹内的cv2.pyd复制到Py ...

  6. javaList容器中容易忽略的知识点

    在集合类框架中,List是使用比较多的一种 List |---Arraylist 内部维护的是一个数组,查找快增删慢 |---LinkedList 底层是链表,增删快查询慢. |---Vctor线程安 ...

  7. Windows Phone 8.1开发:触控和指针事件2

    原文出自:http://www.bcmeng.com/windows-phone-touch1/ 请在此输入内容(想死啊,写了一个小时,直接没保存不小心删掉了.那就简单说说吧)Pointer事件有以下 ...

  8. iOS开发之状态栏

    从iOS7开始,状态栏默认情况下归控制器管理,比如状态栏的样式.状态栏的是否可见 控制器通过重写以下方法来控制状态栏 设置状态栏的样式,只需重写下列方法即可: - (UIStatusBarStyle) ...

  9. Struts2(二)之封装请求正文、数据类型转换、数据验证

    一.封装请求正文到对象中(重点) 1.1.静态参数封装 在struts.xml文件中,给动作类注入值,使用的是setter方法 1.2.动态参数封装 通过用户表单封装请求正文参数 1.2.1.动作类作 ...

  10. (转)Zabbix Agent-Windows平台配置指导

      原地址:http://blog.itpub.net/26739940/viewspace-1169538/   zabbix是一个CS结构的监控系统,支持ping,snmp等很多的监控,但是大部分 ...