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. angular : direative : autoResize textarea auto resize

    今天为大家推出自己的auto resize 指令功能. 目的:解决textarea在给height的问题. 参考源码:http://monospaced.github.io/angular-elast ...

  2. Ubuntu 小白安装血泪史

    介绍: 新入手的Ubuntu:版本 命令行模式下 出现 ♦♦♦♦ 图形界面无法获取最高权限:gurb.cfg 无法再图形界面下修改 安装类型: 1.安装Ubuntu,与Window 7共存 2.清除整 ...

  3. HTML中鼠标移动过去变换

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  4. MSCRM 通过Ajax调用WCF服务

    Call WCF Service from Dynamics CRM using AJAX A couple of days back, I had one of my ex-colleagues c ...

  5. 【openstack N版】——块存储服务cinder

    一.块存储服务介绍 1.1块存储服务通常包含以下组件 cinder-api: 接受API请求,并将其路由到"cinder-volume"执行. cinder-volume: 与块存 ...

  6. Linux i2c子系统(一) _动手写一个i2c设备驱动

    i2c总线是一种十分常见的板级总线,本文以linux3.14.0为参考, 讨论Linux中的i2c驱动模型并利用这个模型写一个mpu6050的驱动, 最后在应用层将mpu6050中的原始数据读取出来 ...

  7. input解决浏览器记住密码问题

    <input type="password" name="" id="">可以这样写 <input type=" ...

  8. 3212: Pku3468 A Simple Problem with Integers

    3212: Pku3468 A Simple Problem with Integers Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 1053  So ...

  9. Web 页面测试总结—控件类

    web端页面测试,最常见的是基本控件的测试,只有了解常见的控件和其测试方法,才能掌握测试要点,避免漏测情况发生.根据日常工作总结,将控件和常见逻辑集合在一起,总结了几个控件类测试查场景如下. 导航条 ...

  10. Java 8并发工具包漫游指南

    Java 8并发工具包简介 Java 8并发工具包由3个包组成,分别是java.util.concurrent.java.util.concurrent.atomic和java.util.concur ...