WebSocket是HTML5提出的一个用于通信的协议规范,该协议通过一个握手机制,在客户端和服务端之间建立一个类似于TCP的连接,从而方便客户端和服务端之间的通信。

WebSocket协议本质上是一个基于TCP的协议,是先通过HTTP/HTTPS协议发起一条特殊的HTTP请求进行握手后创建一个用于交换数据的TCP连接,此后服务端与客户端通过此TCP连接进行实时通信。客户端和服务端只需要要做一个握手的动作,在建立连接之后,服务端和客户端之间就可以通过此TCP连接进行实时通信。

websocket是建立在物理层上的连接,相比于基于网络层的长连接可以节约资源,相比于AJAX轮训可以降低服务器压力。

spring在4.0后将websocket集成进去,要使用spring的websocket的话,spring的版本要在4.0及以上。

spring使用websocket需要的jar(pom.xml)

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>4.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>4.0.6.RELEASE</version>
</dependency>

web.xml中对websocket的配置

  <servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/springMVC/spring-webSocket.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

springMVC中对websocket的xml配置

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/websocket
http://www.springframework.org/schema/websocket/spring-websocket-4.0.xsd"> <!-- websocket处理类 -->
<bean id="msgHandler" class="com.test.websocket.MyWebSocketHandler" />
<!-- 握手接口/拦截器 ,看项目需求是否需要-->
<bean id="handshakeInterceptor" class="com.test.websocket.MyHandshakeInterceptor" />
<websocket:handlers>
<websocket:mapping path="/websocket" handler="msgHandler" />
<websocket:handshake-interceptors>
<ref bean="handshakeInterceptor" />
</websocket:handshake-interceptors>
</websocket:handlers>
<!-- 注册 sockJS,sockJs是spring对不能使用websocket协议的客户端提供一种模拟 -->
<websocket:handlers>
<websocket:mapping path="/sockjs/websocket" handler="msgHandler" />
<websocket:handshake-interceptors>
<ref bean="handshakeInterceptor" />
</websocket:handshake-interceptors>
<websocket:sockjs />
</websocket:handlers>
</beans>

springMVC中对websocket的注解配置

@Configuration
@EnableWebSocket
public class WebSocketServerConfig implements WebSocketConfigurer { @Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
// 添加拦截地址以及相应的websocket消息处理器
WebSocketHandlerRegistration registration = registry.addHandler(new MyWebSocketHandler(), "/websocket","sockjs/websocket");
SockJsServiceRegistration sockJS = registration.withSockJS();
// 添加拦截器
registration.addInterceptors(new MyHandshakeInterceptor());
} }

握手拦截器,继承HttpSessionHandshakeInterceptor类,做一些连接握手或者握手后的一些处理

public class MyHandshakeInterceptor extends HttpSessionHandshakeInterceptor {

    // 握手前
@Override
public boolean beforeHandshake(ServerHttpRequest request,
ServerHttpResponse response, WebSocketHandler wsHandler,
Map<String, Object> attributes) throws Exception { System.out
.println("++++++++++++++++ HandshakeInterceptor: beforeHandshake ++++++++++++++"
+ attributes); return super.beforeHandshake(request, response, wsHandler, attributes);
} // 握手后
@Override
public void afterHandshake(ServerHttpRequest request,
ServerHttpResponse response, WebSocketHandler wsHandler,
Exception ex) { System.out
.println("++++++++++++++++ HandshakeInterceptor: afterHandshake ++++++++++++++"); super.afterHandshake(request, response, wsHandler, ex);
}
}

创建MyWebSocketHandler类继承WebSocketHandler类(Spring提供的有AbstractWebSocketHandler类、TextWebSocketHandler类、BinaryWebSocketHandler类,看自己需要进行继承),该类主要是用来处理消息的接收和发送

public class MyWebSocketHandler implements WebSocketHandler {

    private Logger logger = LoggerFactory.getLogger(MsgWebSocketHandler.class);

    //保存用户链接
private static ConcurrentHashMap<String, WebSocketSession> users = new ConcurrentHashMap<String, WebSocketSession>();
// 连接 就绪时
@Override
public void afterConnectionEstablished(WebSocketSession session)
throws Exception {
users.put(session.getId(), session);
} // 处理信息
@Override
public void handleMessage(WebSocketSession session,
WebSocketMessage<?> message) throws Exception {
System.err.println(session + "---->" + message + ":"+ message.getPayload().toString());
} // 处理传输时异常
@Override
public void handleTransportError(WebSocketSession session,
Throwable exception) throws Exception { } // 关闭 连接时
@Override
public void afterConnectionClosed(WebSocketSession session,
CloseStatus closeStatus) {
logger.debug("用户: " + session.getRemoteAddress() + " is leaving, because:" + closeStatus); } //是否支持分包
@Override
public boolean supportsPartialMessages() {
return false;
}
}

要进行发送消息的操作,自己可以写方法,利用保存的已经完成连接的WebSocketSession,通过调用sendMessage(WebScoketMessage<?> message)方法进行消息的发送,参数message是发送的消息内容,Spring提供的类型有TextMessage、BinaryMessage、PingMessage、PongMessage。

前端客户端JS

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>websocket</title>
</head>
<style type="text/css">
#div {
color: red;
}
</style>
<body>
<h1>WEBSOCKET----TEST</h1>
<div id="div"> </div>
</script>
<script type="text/javascript">
var div = document.getElementById('div');
var socket = new WebSocket('ws://127.0.0.1:8088/websocket'); socket.onopen = function(event){
console.log(event);
socket.send('websocket client connect test');
} socket.onclose = function(event){
console.log(event);
} socket.onerror = function(event){
console.log(event);
} socket.onmessage = function(event){
console.log(event)
div.innerHTML += (' @_@ ' + event.data + ' ~_~ ');
}
</script>
</body>
</html>

其实在后台也可以进行websocket客户端的创建

@Test
public void connectTest(){
WsWebSocketContainer wsWebSocketContainer = new WsWebSocketContainer();
wsWebSocketContainer.setDefaultMaxSessionIdleTimeout(300);
StandardWebSocketClient client = new StandardWebSocketClient(wsWebSocketContainer);
WebSocketHandler webSocketHandler = new MyWebSocketHandler();
String uriTemplate = "ws://127.0.0.1:8088/websocket?account=11111";
Object uriVars = null;
ListenableFuture<WebSocketSession> future = client.doHandshake(webSocketHandler, uriTemplate, uriVars);
try {
WebSocketSession session = future.get();
session.sendMessage(new TextMessage("hello world"));
} catch (InterruptedException | ExecutionException | IOException e) {
e.printStackTrace();
} } @Test
public void connectTest2(){
StandardWebSocketClient client = new StandardWebSocketClient();
WebSocketHandler webSocketHandler = new MyWebSocketHandler();
String uriTemplate = "ws://127.0.0.1:8088/websocket";
UriComponentsBuilder fromUriString = UriComponentsBuilder.fromUriString(uriTemplate);
fromUriString.queryParam("account","111111");
/*
* 作用同上,都是将请求参数填入到URI中
* MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
* params.add("account","111111");
* fromUriString.queryParams(params);
* */
URI uri = fromUriString.buildAndExpand().encode().toUri();
WebSocketHttpHeaders headers = null;
ListenableFuture<WebSocketSession> doHandshake = client.doHandshake(webSocketHandler, headers , uri);
try {
WebSocketSession session = doHandshake.get();
session.sendMessage(new TextMessage("hello world"));
} catch (InterruptedException | ExecutionException | IOException e) {
e.printStackTrace();
} }

这是我利用Junit进行的测试,实验证明是可以完成websocket的连接。

注意:websocket在进行连接的时候是可以类似get请求一样,将参数拼接到url中。还可以自己将参数封装进URI中,利用另一个方法进行连接的握手操作。

spring对websocket的集成和使用的更多相关文章

  1. tomcat 7下spring 4.x mvc集成websocket以及sockjs完全参考指南

    之所以sockjs会存在,说得不好听点,就是因为微软是个流氓,现在使用windows 7的系统仍然有近半,而windows 7默认自带的是ie 8,有些会自动更新到ie 9,但是大部分非IT用户其实都 ...

  2. tomcat 7下spring 4.x mvc集成websocket以及sockjs完全参考指南(含nginx/https支持)

    之所以sockjs会存在,说得不好听点,就是因为微软是个流氓,现在使用windows 7的系统仍然有近半,而windows 7默认自带的是ie 8,有些会自动更新到ie 9,但是大部分非IT用户其实都 ...

  3. Spring Chapter4 WebSocket 胡乱翻译 (二)

    书接上文,Spring Chapter4 WebSocket 胡乱翻译 (一) 4.4.4. 消息流 一旦暴露了STOMP端点,Spring应用程序就成为连接客户端的STOMP代理. 本节介绍服务器端 ...

  4. Spring Chapter4 WebSocket 胡乱翻译 (一)

    4. WebSocket 包含了Servlet stack,原生WebSocket交互,通过SockJS模拟,并且通过STOMP在WebSocket之上订阅.发布消息. 4.1 简介 不扯了,看到这个 ...

  5. Spring+SpringMvc+Mybatis框架集成搭建教程

    一.背景 最近有很多同学由于没有过SSM(Spring+SpringMvc+Mybatis , 以下简称SSM)框架的搭建的经历,所以在自己搭建SSM框架集成的时候,出现了这样或者那样的问题,很是苦恼 ...

  6. NoSql存储日志数据之Spring+Logback+Hbase深度集成

    NoSql存储日志数据之Spring+Logback+Hbase深度集成 关键词:nosql, spring logback, logback hbase appender 技术框架:spring-d ...

  7. 菜鸟学习Spring——60s学会Spring与Hibernate的集成

    一.概述. Spring与Hibernate的集成在企业应用中是很常用的做法通过Spring和Hibernate的结合能提高我们代码的灵活性和开发效率,下面我就一步一步的给大家讲述Spring如何和H ...

  8. 玩转spring boot——websocket

    前言 QQ这类即时通讯工具多数是以桌面应用的方式存在.在没有websocket出现之前,如果开发一个网页版的即时通讯应用,则需要定时刷新页面或定时调用ajax请求,这无疑会加大服务器的负载和增加了客户 ...

  9. spring boot / cloud (三) 集成springfox-swagger2构建在线API文档

    spring boot / cloud (三) 集成springfox-swagger2构建在线API文档 前言 不能同步更新API文档会有什么问题? 理想情况下,为所开发的服务编写接口文档,能提高与 ...

随机推荐

  1. AJ学IOS(54)多线程网络之NSOperation重要知识

    AJ分享,必须精品 一:队列的类型与队列添加任务 1: 主队列 [NSOperationQueue mainQueue] 添加到”主队列”中的操作,都会放到主线程中执行. 2:非主队列 [[NSOpe ...

  2. 分屏神器PoweToys

    win+~调用设置分屏界面,shift+软件拖到分屏位置

  3. 最后の冲刺 for Alpha release 12/15/2015

    好开心啊,又吃成长快乐了~ 据说release前一天,团队的工作效率会达到顶峰.亲证无效!!! release当天才是团队智力效力能力的巅峰好不好?!因为,今天,plan B:福昕pdf reader ...

  4. 一文回顾Reids五大对象(数据类型)

    Redis 是一个高性能的分布式内存型数据库,在国内外各大互联网公司中都有着广泛的使用,即使是一些非互联网公司中也有着非常重要的适用场景,所以对 Redis 的掌握也成为后端工程师必备的基础技能,在面 ...

  5. D. Ehab the Xorcist

    题意: 略: 感觉被演了一波,这是CFdiv2吗? 算是这个构造题吧. 1 首先我们可以将u进行二进制拆分来考虑.加入u>v那么小与v的那些数在怎么拼接也无法使异或值为u. 比如二进制U=1 0 ...

  6. 玩转控件:Fucking ERP之流程图

    前言 首先,跟守护在作者公众号和私信作者催更的朋友们道个歉.疫情的原因,公司从年初到现在一直处于996+的高压模式,导致公众号更新频率较低.而且作者每更新一篇原创公众号,既要对自己沉淀知识负责,也要对 ...

  7. C++养成好的代码习惯

    [C++小技巧] -------------------------------------------------------------#ifdef _DEBUG    imwrite(" ...

  8. css: scroll-table

    .scroll-table { table tbody { display: block; max-height: 120px; overflow-y: scroll; } table thead,t ...

  9. 用pytorch做手写数字识别,识别l率达97.8%

    pytorch做手写数字识别 效果如下: 工程目录如下 第一步  数据获取 下载MNIST库,这个库在网上,执行下面代码自动下载到当前data文件夹下 from torchvision.dataset ...

  10. pytorch-API实现线性回归

    示例: import torch import torch.nn as nn from torch import optim class MyModel(nn.Module): def __init_ ...