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在被杀 ...
随机推荐
- PDO(PHP Data Object)数据访问抽象层
1.可以访问其它数据库2.具有事务功能3.带有预处理语句功能(防止SQL注入攻击) 访问数据库 PDO::__construct ( string $dsn [, string $username [ ...
- HttpClient 工具
什么是httpclient HTTP 协议可能是现在 Internet 上使用得最多.最重要的协议了,越来越多的 Java 应用程序需要直接通过 HTTP 协议来访问网络资源.虽然在 JDK 的 ja ...
- 高精度模板 Luogu P1932 A+B & A-B & A*B & A/B Problem
P1932 A+B & A-B & A*B & A/B Problem 题目背景 这个题目很新颖吧!!! 题目描述 求A.B的和差积商余! 输入输出格式 输入格式: 两个数两行 ...
- C#基础——集合及特殊集合
集合 集合的基本信息: Systerm.Collections命名空间包含接口和类,这些接口和类定义各种对象(如列表.队列.位数组.哈希表和字典)的集合. Systerm.Collections.Ge ...
- JavaWeb之DBUtils
一.什么是DBUtils及作用 DBUtils是apache公司写的.DBUtils是java编程中的数据库操作实用工具,小巧简单实用. DBUtils封装了对JDBC的操作,简化了JDBC操作.可以 ...
- HTML 5入门知识(三)
<canvas>标签 在网页中使用canvas元素,像使用其他HTML标签一样简单,然后利用JavaScript脚本调用绘图API,绘制各种图形.canvas拥有多种绘制路径.矩形.圆形. ...
- Java程序员入门:程序员究竟可以干多少年?
很多人都说程序员是青春饭,只能干到30岁. 然而事实真的如此么? 今天我们来探讨一下这个老话题,看看为了技术与编程执着究竟能走多远? 01年龄分布图 先来看一下程序员的年龄分布图: 我们可以看到程序员 ...
- h5标签基础 表单form
表单:收集用户信息 一. 组成: 文本框<input type="text"/> 密码框<input type="password"/> ...
- python学习笔记(一)元组tuple
元组由简单的对象组构成,元组与列表相似,但是元组不能在原处修改.元组位置有序的对象集合,元组通过偏移来访问. 为什么有了列表还要元组?元组的不变性提供了某种完整性,可以确保元组在程序中不被另一个引用修 ...
- webots自学笔记(一)软件界面和简单模型仿真
本人是某非理工类某高校大四狗,由于毕设研究需要使用webots软件,在学习使用webots的过程花费了很多时间.由于这个软件基本没有什么中文资料,所以想把自己所学到的一些东西写下来,如有什么错误的地方 ...