webscoket实战之利用httpsession定向推送
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定向推送的更多相关文章
- 移动互联网实战--Apple的APNS桩推送服务的实现(2)
前记: 相信大家在搞IOS推送服务的开发时, 会直接使用javapns api来简单实现, 调试也直连Apple的APNS服务(产品/测试版)来实现. 很少有人会写个APNS的桩服务, 事实也是如此. ...
- 移动互联网实战--Apple的APNS桩推送服务的实现(1)
前记: 相信大家在搞IOS推送服务的开发时, 会直接使用javapns api来简单实现, 调试也直连Apple的APNS服务(产品/测试版)来实现. 很少有人会写个APNS的桩服务, 事实也是如此. ...
- signalr推送消息
参考:Tutorial: Getting Started with SignalR 2 and MVC 5 环境:vs2013,webapi2,entity framework6.0 实现效果:当用户 ...
- 一步步教你用Prometheus搭建实时监控系统系列(二)——详细分析拉取和推送两种不同模式
前言 本系列着重介绍Prometheus以及如何用它和其周边的生态来搭建一套属于自己的实时监控告警平台. 本系列受众对象为初次接触Prometheus的用户,大神勿喷,偏重于操作和实战,但是重要的概念 ...
- IosPush推送通知的实现
1. Apple推送通知的机制 上图可以分为三个阶段: 第一阶段:应用程序把要发送的消息.目的iPhone的标识打包,发给APNS. 第二阶段:APNS在自身的已注册Push服务的iPhone列表中, ...
- 【android极光推送】—从客户端到后台,一文通吃
sion android:name="android.permission.VIBRATE" /> <uses-permission android:name=&quo ...
- iOS-本地推送(本地通知)
第一步:注册本地通知: // 设置本地通知 + (void)registerLocalNotification:(NSInteger)alertTime { UILocalNotification * ...
- Android 高仿微信实时聊天 基于百度云推送
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38799363 ,本文出自:[张鸿洋的博客] 一直在仿微信界面,今天终于有幸利用百 ...
- Android融合推送MixPush SDK集成多家推送平台,共享系统级推送,杀死APP也能收到推送
消息推送是App运营的重要一环,为了优化消息推送成功率,降低电量和流量消耗,系统级的推送服务显得尤为重要.小米和魅族由此推出了自家的推送平台,在MIUI和Flyme上共享系统级推送服务,让APP在被杀 ...
随机推荐
- Struts2之环境配置
在学习struts2之前,首先我们要明白使用struts2的目的是什么?它能给我们带来什么样的好处? 设计目标 Struts设计的第一目标就是使MVC模式应用于web程序设计.在这儿MVC模式的好处就 ...
- FineUIMvc随笔(4)自定义回发参数与自定义回发
声明:FineUIMvc(基础版)是免费软件,本系列文章适用于基础版. 不能忘却的回发 在上一篇文章中,我们对FineUIMvc中的回发进行了详细描述,目的是为了告诉大家: 1. FineUIMvc中 ...
- 很污的机器学习:从xhamster网站找到喜欢的片子
前言 最近迷上了看黄片(大雾).每次总是去搜索想看的片子,什么asian porn anal pussy 什么的我都不知道. 搜索着搜索着我手也累了,而且我喜欢的片子也是有一定的特征的,我不想把所有的 ...
- Archlinux 的U盘自动装载(二)升级到 udisks2
在安装 mysql-gui-tools 过程中,发现需要用到 udisks2.udisks和udisks2可以互相替换也可以共用.最后决定换用 udisks2 安装 先卸载原来的软件,如果有的话. p ...
- 【转】Lucene.NET详细使用与优化详解
1 lucene简介1.1 什么是luceneLucene是一个全文搜索框架,而不是应用产品.因此它并不像www.baidu.com 或者google Desktop那么拿来就能用,它只是提供了一种工 ...
- JavaScript数据结构——队列的实现
前面楼主简单介绍了JavaScript数据结构栈的实现,http://www.cnblogs.com/qq503665965/p/6537894.html,本次将介绍队列的实现. 队列是一种特殊的线性 ...
- poj 2892---Tunnel Warfare(线段树单点更新、区间合并)
题目链接 Description During the War of Resistance Against Japan, tunnel warfare was carried out extensiv ...
- php人员权限管理(RBAC)
在说权限管理前,应该先知道权限管理要有哪些功能: (1).用户只能访问,指定的控制器,指定的方法 (2).用户可以存在于多个用户组里 (3).用户组可以选择,指定的控制器,指定的方法 (4).可以添 ...
- android使用TextView实现跑马灯的效果(1)
android使用TextView实现跑马灯的效果 1.activity_main.xml <?xml version="1.0" encoding="utf-8& ...
- WebService从服务端到客户端的用例
1.首先编写Wsdl(基于契约优先的方式),要注意的是命名空间(若是使用include或import)最好使用一致的,代码如下: <?xml version="1.0" en ...