1、简介
作为下一代的Web标准,HTML5拥有许多引人注目的新特性,如 Canvas、本地存储、多媒体编程接口、WebSocket等等。这其中有“Web的 TCP”之称的 WebSocket格外吸引开发人员的注意。WebSocket的出现使得浏览器提供对 Socket的支持成为可能,从而在浏览器和服务器之间提供了一个基于TCP连接的双向通道。Web开发人员可以非常方便地使用WebSocket构建实时 web 应用,开发人员的手中从此又多了一柄神兵利器。
Web 应用的信息交互过程通常是客户端通过浏览器发出一个请求,服务器端接收和审核完请求后进行处理并返回结果给客户端,然后客户端浏览器将信息呈现出来,这种机制对于信息变化不是特别频繁的应用尚能相安无事,但是对于那些实时要求比较高的应用来说,比如说在线游戏、在线证券、设备监控、新闻在线播报、RSS订阅推送等等,当客户端浏览器准备呈现这些信息的时候,这些信息在服务器端可能已经过时了。
所以保持客户端和服务器端的信息同步是实时 Web应用的关键要素,对 Web开发人员来说也是一个难题。在 WebSocket规范出来之前,开发人员想实现这些实时的Web应用,不得不采用一些折衷的方案,其中最常用的就是轮询(Polling)和 Comet 技术,而Comet技术实际上是轮询技术的改进,又可细分为两种实现方式,一种是长轮询机制,一种称为流技术。
Html5 WebSocket 设计出来的目的就是要取代轮询和 Comet技术,使客户端浏览器具备像 C/S架构下桌面系统的实时通讯能力。浏览器通过JavaScript向服务器发出建立 WebSocket连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP连接直接交换数据。因为 WebSocket连接本质上就是一个TCP连接,所以在数据传输的稳定性和数据传输量的大小方面,和轮询以及Comet技术比较,具有很大的性能优势。
但是鉴于web socket 对浏览器要求比较高,为了解决这个问题,推出了sockJS,SockJS是一个JavaScript库,提供跨浏览器javascript的API,创建了一个低延迟、全双工的浏览器和web服务器之间通信通道。
2、相关环境要求
Spring4.0.6(要选择4.0+),tomcat7.0.55版本,JDK1.7。
3、具体代码
(以下代码亲测可用!)
(1)web.xml:
代码如下 | 复制代码 |
xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"> true true 30 |
(2) dispatcher-servlet.xml
代码如下 | 复制代码 |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> |
(3)HandshakeInterceptor.java
代码如下 | 复制代码 |
packagezyy.sockjs.config; importjava.util.Map; importorg.springframework.http.server.ServerHttpRequest; importorg.springframework.http.server.ServerHttpResponse; importorg.springframework.stereotype.Component; importorg.springframework.web.socket.WebSocketHandler; importorg.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
@Component publicclassHandshakeInterceptorextendsHttpSessionHandshakeInterceptor { @Override publicbooleanbeforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map System.out.println("Before Handshake"); returnsuper.beforeHandshake(request,response,wsHandler,attributes); }
@Override publicvoidafterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) { System.out.println("After Handshake"); super.afterHandshake(request,response,wsHandler,ex); } } |
(4)InfoSocketEndPoint.Java
代码如下 | 复制代码 |
packagezyy.sockjs.config; importorg.springframework.stereotype.Component; importorg.springframework.web.socket.TextMessage; importorg.springframework.web.socket.WebSocketSession; importorg.springframework.web.socket.handler.TextWebSocketHandler;
@Component publicclassInfoSocketEndPointextendsTextWebSocketHandler { publicInfoSocketEndPoint() { }
@Override protectedvoidhandleTextMessage(WebSocketSession session, TextMessage message)throwsException { super.handleTextMessage(session, message); TextMessage returnMessage =newTextMessage(message.getPayload() +" received at server"); session.sendMessage(returnMessage); } } |
(5)SystemWebSocketHandler.java
代码如下 | 复制代码 |
packagezyy.sockjs.config; importorg.springframework.stereotype.Component; importorg.springframework.web.socket.CloseStatus; importorg.springframework.web.socket.TextMessage; importorg.springframework.web.socket.WebSocketHandler; importorg.springframework.web.socket.WebSocketMessage; importorg.springframework.web.socket.WebSocketSession; /** * * @author dayu */
@Component publicclassSystemWebSocketHandlerimplementsWebSocketHandler { @Override publicvoidafterConnectionEstablished(WebSocketSession session)throwsException { System.out.println("connect to the websocket success......"); session.sendMessage(newTextMessage("Server:connected OK!")); }
@Override publicvoidhandleMessage(WebSocketSession wss, WebSocketMessage> wsm)throwsException { TextMessage returnMessage =newTextMessage(wsm.getPayload() +" received at server"); wss.sendMessage(returnMessage); }
@Override publicvoidhandleTransportError(WebSocketSession wss, Throwable thrwbl)throwsException { if(wss.isOpen()){ wss.close(); } System.out.println("websocket connection closed......"); }
@Override publicvoidafterConnectionClosed(WebSocketSession wss, CloseStatus cs)throwsException { System.out.println("websocket connection closed......"); }
@Override publicbooleansupportsPartialMessages() { returnfalse; } } |
(6)WebSocketConfig.java
代码如下 | 复制代码 |
packagezyy.sockjs.config; importorg.springframework.context.annotation.Bean; importorg.springframework.context.annotation.Configuration; importorg.springframework.web.servlet.config.annotation.EnableWebMvc; importorg.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; importorg.springframework.web.socket.WebSocketHandler; importorg.springframework.web.socket.config.annotation.EnableWebSocket; importorg.springframework.web.socket.config.annotation.WebSocketConfigurer; importorg.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration @EnableWebMvc @EnableWebSocket publicclassWebSocketConfigextendsWebMvcConfigurerAdapterimplements WebSocketConfigurer { publicWebSocketConfig() { }
@Override publicvoidregisterWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(systemWebSocketHandler(),"/websck").addInterceptors(newHandshakeInterceptor()); System.out.println("registed!"); registry.addHandler(systemWebSocketHandler(),"/sockjs/websck/info").addInterceptors(newHandshakeInterceptor()) .withSockJS(); }
@Bean publicWebSocketHandler systemWebSocketHandler() { returnnewSystemWebSocketHandler(); } } |
(7)testSocket.jsp
代码如下 | 复制代码 |
<%@ page language="java"contentType="text/html; charset=ISO-8859-1"pageEncoding="ISO-8859-1"%>
#connect-container { float: left; width: 400px } #connect-container div { padding: 5px; } #console-container { float: left; margin-left: 15px; width: 400px; } #console { border:1px solid #CCCCCC; border-right-color:#33333333; border-bottom-color:#999999; height: 170px; overflow-y: scroll; padding: 5px; width: 100%; } #console p { padding: 0; margin: 0; }
var ws = null; var url = null; var transports = []; function setConnected(connected) { document.getElementById('connect').disabled = connected; document.getElementById('disconnect').disabled = !connected; document.getElementById('echo').disabled = !connected; } function connect() { if (!url) { log('Select whether to use W3C WebSocket or SockJS'); return; } //ws = (url.indexOf('sockjs') != -1) ?new SockJS(url, undefined, {protocols_whitelist: transports}) : new WebSocket(url); if ('WebSocket'in window) { ws= new WebSocket("ws://localhost:8080/SpringSocketJs/websck"); }else { ws = new SockJS("http://localhost:8080/SpringSocketJs/sockjs/websck/info"); } //websocket = new SockJS("http://localhost:8084/SpringWebSocketPush/sockjs/websck"); ws.onopen = function () { setConnected(true); //log('Info: connection opened.'); }; ws.onmessage = function (event) { log('Received:' + event.data); }; ws.onclose = function (event) { setConnected(false); log('Info: connection closed.'); log(event); }; } function disconnect() { if (ws != null) { ws.close(); ws = null; } setConnected(false); } function echo() { if (ws != null) { var message = document.getElementById('message').value; log('Sent:' + message); ws.send(message); } else { alert('connection not established, please connect.'); } } function updateUrl(urlPath) { if (urlPath.indexOf('sockjs') != -1) { url = urlPath; document.getElementById('sockJsTransportSelect').style.visibility ='visible'; } else { if (window.location.protocol =='http:') { url = 'ws://' + window.location.host + urlPath; }else{ url = 'wss://' + window.location.host + urlPath; } document.getElementById('sockJsTransportSelect').style.visibility ='hidden'; } } function updateTransport(transport) { transports = (transport == 'all') ? [] : [transport]; } function log(message) { var console = document.getElementById('console'); var p = document.createElement('p'); p.style.wordWrap = 'break-word'; p.appendChild(document.createTextNode(message)); console.appendChild(p); while (console.childNodes.length > 25) { console.removeChild(console.firstChild); } console.scrollTop = console.scrollHeight; }
rely on Javascript being enabled. Please enable Javascript and reloadthispage!
SockJS transport:
|