Spring消息之WebSocket
一、WebSocket简介
WebSocket 的定义?WebSocket是HTML5下一种全双工通信协议。在建立连接后,WebSocket服务器端和客户端都能主动的向对方发送和接收数据,就像Socket一样。
WebSocket 的由来?众所周知,HTTP协议有“无连接”、“不可靠”、“尽最大努力”的特点。WebSocket的出现可以看成是HTTP协议为了支持长连接所打的一个大补丁。首先,由 IETF 制定发布了WebSocket 协议。后来,HTML5为了在Web端支持WebSocket协议,由W3C 发布了一整套WebSocket API。其次,WebSocket主要用于Web端,对于非Web部分的意义不大(毕竟直接使用TCP就好了)。因此,在广义上,Websocket 也常常被人称为是HTML5 下的通信协议。
HTTP 和 WebSocket 的区别?
1、HTTP 和 WebSocket 是两种不同的协议,但是HTTP负责了建立WebSocket的连接。
2、HTTP 请求以 http:// 或 https:// 开始,WebSocket 请求一般以ws:// 或 wss:// 开始。
3、所有浏览器都支持 HTTP 协议,WebScoket 可以会遇到不支持的浏览器(可通过SockJS解决)
4、HTTP长连接中,每次数据交换除了真正的数据部分外,服务器和客户端还要大量交换HTTP header,信息交换效率很低。Websocket协议通过第一个request建立了TCP连接之后,之后交换的数据都不需要发送 HTTP header就能交换数据。
可以看看知乎上的这个回答,解释的挺生动的:https://www.zhihu.com/question/20215561
二、使用Spring的低层级WebSocket API
先来看看客户端如何建立起WebSocket 的连接。首先,我们使用 new WebSocket(url) 创建一个WebSocket 的实例对象;然后,使用这个实例对象建立WebSocket的事件处理功能,onopen、onmessage、onclose 和 onerror 事件,分别对应着 打开连接、接收消息、关闭连接 和 异常处理 事件。
/*WebSocket*/
var url = 'ws://localhost:8080/marco2';
var sock = new WebSocket(url); sock.onopen = function (ev) {
console.log("正在建立连接...");
sayMarco();
}; sock.onmessage = function (ev) {
console.log("接收并处理消息:" + ev.data);
if (count == 10) {
sock.close();
}
setTimeout(
function () {
sayMarco();
count++;
}, 2000);
}; sock.onclose = function (ev) {
console.log("连接关闭...");
}; sock.error = function (ev) {
console.log("连接异常");
}; function sayMarco() {
console.log('Sending Marco !');
sock.send("Marco!")
}
WebSocket客户端
接下来看看服务端这边如何建立起WebSocket的服务:
1、pom 依赖
<!--WebSocket-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<!--辅助包-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.8.10</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.10</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.8.10</version>
</dependency>
2、WebSocket 服务
有两种方案可以建立起WebSocket服务,一种是基于Spring 的 spring-websocket,一种是基于 java 的 websocket-api。
- spring-websocket
WebSocketHandler 接口定义了服务端处理WebSocket消息要做的一系列事情。相比直接实现WebSocketHandler,更为简单的方法是扩展AbstractWebSocketHandler,这是WebSocketHandler的一个抽象实现。当然根据处理消息的类型,还可以选择继承TextWebSocketHandler(文本类消息)、BinaryWebSocketHandler(二进制消息)等...
public class MarcoHandler_2 extends AbstractWebSocketHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(MarcoHandler_2.class);
@Override
public void afterConnectionEstablished(WebSocketSession session) {
LOGGER.info("WebSocket 连接建立......");
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
LOGGER.info("接收到消息:" + message.getPayload());
Thread.sleep(2000);
//发送文本消息
session.sendMessage(new TextMessage("Polo!"));
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus){
LOGGER.info("WebSocket 连接关闭......");
}
}
- websocket-api
websocket-api 提供了一种基于注解、更为简单明了的方式处理WebSocket消息。美中不足的是它需要依赖 javax.websocket-api.jar。
① pom依赖
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
<scope>provided</scope>
</dependency>
② WebSocket服务
/**
* Created by XiuYin.Cui on 2018/5/2.
*
* 基于注解方式的WebSocket 控制器
*/ @ServerEndpoint("/ws")
public class WsController { private static final Logger LOGGER = LoggerFactory.getLogger(WsController.class); @OnOpen
public void onOpen(){
LOGGER.info("连接建立");
} @OnClose
public void onClose(){
LOGGER.info("连接关闭");
} @OnMessage
public void onMessage(String message, Session session){
try {
LOGGER.info("接收到消息:" + message);
Thread.sleep(2000);
session.getBasicRemote().sendText("polo"); //发送消息
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
} @OnError
public void onError(Session session, Throwable throwable){
throw new IllegalArgumentException(throwable);
} }
3、建立映射
现在,已经有了消息处理器类,我们必须要对其进行配置,这样Spring才能将消息转发给它。在Spring的Java配置中,这需要在一个配置类上使用@EnableWebSocket,并实现WebSocketConfigurer接口。
像所有HTTP请求一样,我们需要将WebSocket服务暴露成一个供客户端访问的url 地址。依旧有两种方式,配置类方式 和 XML方式:
3.1、配置类方式
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer { /**
*
* @param registry 该对象可以调用addHandler()来注册信息处理器。
*/
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(marcoHandler_2(),"/marco2")
.addInterceptors(webSocketHandshakeInterceptor()) //声明拦截器
.setAllowedOrigins("*"); //声明允许访问的主机列表
} @Bean
public MarcoHandler_2 marcoHandler_2(){
return new MarcoHandler_2();
} @Bean
public WebSocketHandshakeInterceptor webSocketHandshakeInterceptor(){
return new WebSocketHandshakeInterceptor();
}
}
3.2、xml 方式
<websocket:handlers>
<websocket:mapping handler="marcoHandler_1" path="/marco1"/>
</websocket:handlers>
三、使用SockJS支持WebSocket
既然已经有了WebSocket API 为什么还要有SockJS呢?
1、WebSocket 是一个较新的协议规范,在Web浏览器和应用服务器上可能没有得到一致的支持。
2、防火墙代理通常会限制所有除HTTP以外的流量。它们可能不支持或者还没有配置允许进行WebSocket 通信。
SockJS 又是什么呢?
SockJS是WebSocket技术的一种模拟,在表面上,它尽可能对应WebSocket API,但是在底层它非常智能。SockJS会优先选用WebSocket,但是如果WebSocket不可用的话,它将会从如下的方案中挑选最优的可行方案:
- XHR流。
- XDR流。
- iFrame事件源。
- iFrame HTML文件。
- XHR轮询。
- XDR轮询。
- iFrame XHR轮询。
- JSONP轮询。
接下来让我们看看SockJS 的使用和WebSocket 有什么差异?
- 客户端
1、SockJS客户端库
要在客户端使用SockJS,需要确保加载了SockJS客户端库。
<script type="text/javascript" src="http://cdn.bootcss.com/sockjs-client/1.1.1/sockjs.js"></script>
2、修改URL,构建SockJS实例
SockJS所处理的URL是“http://”或“https://”模式,而不是“ws://”和“wss://”。
var url = 'http://localhost:8080/marcoSockJS';
var sock = new SockJS(url);
- 服务端
服务端这边只要在建立映射的时候加上SockJS的支持即可:
1、配置类方式
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer { /**
*
* @param registry 该对象可以调用addHandler()来注册信息处理器。
*/
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
//声明启用SockJS连接,如果前端还用 new WebSocket(url); 会报:Error during WebSocket handshake: Unexpected response code: 200
registry.addHandler(marcoHandler_2(), "/marcoSockJS")
.setAllowedOrigins("*") ////声明允许访问的主机列表
.withSockJS();
} @Bean
public MarcoHandler_2 marcoHandler_2(){
return new MarcoHandler_2();
} }
2、XML方式
<websocket:handlers>
<websocket:mapping handler="marcoHandler_1" path="/marco1"/>
<websocket:sockjs/> <!--声明启用SockJS功能-->
</websocket:handlers>
效果展示:

演示源码下载链接:https://github.com/JMCuixy/SpringWebSocket/tree/developer
Spring消息之WebSocket的更多相关文章
- spring boot 集成 websocket 实现消息主动推送
spring boot 集成 websocket 实现消息主动 前言 http协议是无状态协议,每次请求都不知道前面发生了什么,而且只可以由浏览器端请求服务器端,而不能由服务器去主动通知浏览器端,是单 ...
- spring boot下WebSocket消息推送
WebSocket协议 WebSocket是一种在单个TCP连接上进行全双工通讯的协议.WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范.WebSo ...
- Spring Boot 集成 WebSocket 实现服务端推送消息到客户端
假设有这样一个场景:服务端的资源经常在更新,客户端需要尽量及时地了解到这些更新发生后展示给用户,如果是 HTTP 1.1,通常会开启 ajax 请求询问服务端是否有更新,通过定时器反复轮询服务端响应的 ...
- Spring Boot之WebSocket
一.项目说明 1.项目地址:https://github.com/hqzmss/test01-springboot-websocket.git 2.IDE:IntelliJ IDEA 2018.1.1 ...
- Spring容器整合WebSocket
原链接:http://blog.csdn.net/canot/article/details/52575054 WebSocker是一个保持web客户端与服务器长链接的技术.这样在两者通信过程中如果服 ...
- 【websocket】spring boot 集成 websocket 的四种方式
集成 websocket 的四种方案 1. 原生注解 pom.xml <dependency> <groupId>org.springframework.boot</gr ...
- 【Java Web开发学习】Spring MVC整合WebSocket通信
Spring MVC整合WebSocket通信 目录 ========================================================================= ...
- Spring框架之websocket源码完全解析
Spring框架之websocket源码完全解析 Spring框架从4.0版开始支持WebSocket,先简单介绍WebSocket协议(详细介绍参见"WebSocket协议中文版" ...
- spring boot下WebSocket消息推送(转)
原文地址:https://www.cnblogs.com/betterboyz/p/8669879.html WebSocket协议 WebSocket是一种在单个TCP连接上进行全双工通讯的协议.W ...
随机推荐
- Cocos2D iOS之旅:如何写一个敲地鼠游戏(十一):完善游戏逻辑
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...
- [mysql]一次主从数据不一致的问题解决过程
之前一篇: 主从更换ip之后重新建立同步 情况时这样的 昨天晚上主动2个机器都迁移了,然后今天才把主动重新连接上,但是从库的偏移量是从今天当前时刻开始的,也就是说虽然现在主动看似正常,其实是少了昨天的 ...
- 听说你又一次放弃了Dagger2,来听老夫说道说道
关于Dagger2是啥,用法网上已经有很多了.不过听说你已经很多次Dagger2从入门到放弃了,来来,让我这个老中医给你治一治.老夫手法纯熟,不会让你有任何痛苦的,放心读下去吧. 本文同步自 博主的私 ...
- iOS开发中 常用枚举和常用的一些运算符(易错总结)
1.色值的随机值: #define kColorValue arc4random_uniform(256)/255.0 // arc4random_uniform(256)/255.0; 求出0.0~ ...
- 类装载器DexClassLoader (android内核剖析)
在java环境中,有个概念叫做"类装载器",其作用是动态装载Class文件.标准的java SDK中有一个ClassLoader类,借助它可以装载 想要的Class文件,每个Cla ...
- FFmpeg深入分析(一)
最近在做一个关于监控的项目,要在iphone 客户端实现播放监控的实时视频以及录像视频.使用到了FFmpeg,看到这篇文章,写的非常不错.转自:http://blog.chinaunix.net/ui ...
- Android开发技巧——TextView加载HTML的图片及代码显示问题
前几天在做一个Gradle用户指南的应用程序,使用的是TextView来加载HTML内容(至于为什么不用WebView,我也没有认真使用并比较过,也许以后会换吧),其中遇见了一些纠结的问题,所幸主要的 ...
- Java 反射之JDK动态代理
Proxy提供用于创建动态代理类和代理对象的静态方法,它也是所有动态代理类的父类.如果我们在程序中为一个或多个接口动态地生成实现类,就可以使用Proxy来创建动态代理类:如果需要为一个或多个接口动态的 ...
- 《java入门第一季》之Arrays类前传(排序问题)
一:冒泡排序 /* * 数组排序之冒泡排序: * 相邻元素两两比较,大的往后放,第一次完毕,最大值出现在了最大索引处 * * 引申: * 利用冒泡排序法,可以获取一个数组的最大值(先冒泡排序,取最后一 ...
- 理解WebKit和Chromium: 网页渲染的基本过程
转载请注明原文地址:http://blog.csdn.net/milado_nju ## 概述 前面介绍了一些渲染引擎的功能,包括网络,资源加载,DOM树,RenderObject树等等,但是,给人以 ...