详解WebSocket+spring示例demo(已使用sockJs库)
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:
<?xmlversionxmlversion="1.0"encoding="utf-8"?> <web-app version="3.1" 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"> <description>用来测试websocket基础上推送的功能</description> <distributable/> <filter> <filter-name>encodingfilter</filter-name> <filter-class>org.springframework.web.filter.characterencodingfilter</filter-class> <async-supported>true</async-supported> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> <init-param> <param-name>forceencoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingfilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <listener> <listener-class>org.springframework.web.context.contextloaderlistener</listener-class> </listener> <!-- spring 刷新introspector防止内存泄露 --> <listener> <listener-class>org.springframework.web.util.introspectorcleanuplistener</listener-class> </listener> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.dispatcherservlet</servlet-class> <init-param> <param-name>contextconfiglocation</param-name> <param-value>classpath:dispatcher-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> <async-supported>true</async-supported> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <session-config> <session-timeout> 30 </session-timeout> </session-config> <welcome-file-list> <welcome-file>testsocket.jsp</welcome-file> </welcome-file-list> </web-app>
(2) dispatcher-servlet.xml
<?xmlversionxmlversion="1.0"encoding="utf-8"?> <beans:beansxmlnsbeans:beansxmlns="http://www.springframework.org/schema/mvc" 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"> <annotation-driven/> <!-- 自动扫描的包名 --> <context:component-scanbase-packagecontext:component-scanbase-package="zyy.sockjs.config"></context:component-scan> </beans:beans>
(3)handshakeinterceptor.java
package zyy.sockjs.config; import java.util.map; import org.springframework.http.server.serverhttprequest; import org.springframework.http.server.serverhttpresponse; import org.springframework.stereotype.component; import org.springframework.web.socket.websockethandler; import org.springframework.web.socket.server.support.httpsessionhandshakeinterceptor; @component public class handshakeinterceptor extends httpsessionhandshakeinterceptor { @override public boolean beforehandshake(serverhttprequest request, serverhttpresponse response, websockethandler wshandler, map<string, object> attributes) throws exception { system.out.println("before handshake"); return super.beforehandshake(request,response,wshandler,attributes); } @override public void afterhandshake(serverhttprequest request, serverhttpresponse response, websockethandler wshandler, exception ex) { system.out.println("after handshake"); super.afterhandshake(request,response,wshandler,ex); } }
(4)infosocketendpoint.java
package zyy.sockjs.config; import org.springframework.stereotype.component; import org.springframework.web.socket.textmessage; import org.springframework.web.socket.websocketsession; import org.springframework.web.socket.handler.textwebsockethandler; @component public class infosocketendpoint extends textwebsockethandler { public infosocketendpoint() { } @override protected void handletextmessage(websocketsession session, textmessage message) throws exception { super.handletextmessage(session, message); textmessage returnmessage = new textmessage(message.getpayload() + " received at server"); session.sendmessage(returnmessage); } }
(5)systemwebsockethandler.java
package zyy.sockjs.config; import org.springframework.stereotype.component; import org.springframework.web.socket.closestatus; import org.springframework.web.socket.textmessage; import org.springframework.web.socket.websockethandler; import org.springframework.web.socket.websocketmessage; import org.springframework.web.socket.websocketsession; /** * * @author dayu */ @component public class systemwebsockethandler implements websockethandler { @override public void afterconnectionestablished(websocketsession session) throws exception { system.out.println("connect to the websocket success......"); session.sendmessage(new textmessage("server:connected ok!")); } @override public void handlemessage(websocketsession wss, websocketmessage<?> wsm) throws exception { textmessage returnmessage = new textmessage(wsm.getpayload() + " received at server"); wss.sendmessage(returnmessage); } @override public void handletransporterror(websocketsession wss, throwable thrwbl) throws exception { if(wss.isopen()){ wss.close(); } system.out.println("websocket connection closed......"); } @override public void afterconnectionclosed(websocketsession wss, closestatus cs) throws exception { system.out.println("websocket connection closed......"); } @override public boolean supportspartialmessages() { return false; } }
(6)websocketconfig.java
package zyy.sockjs.config; import org.springframework.context.annotation.bean; import org.springframework.context.annotation.configuration; import org.springframework.web.servlet.config.annotation.enablewebmvc; import org.springframework.web.servlet.config.annotation.webmvcconfigureradapter; import org.springframework.web.socket.websockethandler; import org.springframework.web.socket.config.annotation.enablewebsocket; import org.springframework.web.socket.config.annotation.websocketconfigurer; import org.springframework.web.socket.config.annotation.websockethandlerregistry; @configuration @enablewebmvc @enablewebsocket public class websocketconfig extends webmvcconfigureradapter implements websocketconfigurer { public websocketconfig() { } @override public void registerwebsockethandlers(websockethandlerregistry registry) { registry.addhandler(systemwebsockethandler(), "/websck").addinterceptors(new handshakeinterceptor()); system.out.println("registed!"); registry.addhandler(systemwebsockethandler(), "/sockjs/websck/info").addinterceptors(new handshakeinterceptor()) .withsockjs(); } @bean public websockethandler systemwebsockethandler() { return new systemwebsockethandler(); } }
(7)testsocket.jsp
<%@ page language="java"contenttype="text/html; charset=iso-8859-1" pageencoding="iso-8859-1"%> <!doctype htmlpublic"-//w3c//dtd html 4.01 transitional//en""http://www.w3.org/tr/html4/loose.dtd"> <html> <head> <meta http-equiv="content-type"content="text/html; charset=iso-8859-1"> <title>websocket/sockjs echo sample (adapted from tomcat's echo sample)</title> <style type="text/css"> #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; } </style> <script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script> <script type="text/javascript"> 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; } </script> </head> <body> <noscript><h2 style="color:#ff0000">seems your browser doesn't supportjavascript!websockets rely on javascript being enabled. please enable javascript and reload this page!</h2></noscript> <div> <div id="connect-container"> <input id="radio1"type="radio"name="group1"onclick="updateurl('/springsocketjs/websocket');"> <label for="radio1">w3c websocket</label> <br> <input id="radio2"type="radio"name="group1"onclick="updateurl('/springsocketjs/sockjs/websocket');"> <label for="radio2">sockjs</label> <div id="sockjstransportselect" style="visibility:hidden;"> sockjs transport: <select onchange="updatetransport(this.value)"> <option value="all">all</option> <option value="websocket">websocket</option> <option value="xhr-polling">xhr-polling</option> <option value="jsonp-polling">jsonp-polling</option> <option value="xhr-streaming">xhr-streaming</option> <option value="iframe-eventsource">iframe-eventsource</option> <option value="iframe-htmlfile">iframe-htmlfile</option> </select> </div> <div> <button id="connect"onclick="connect();">connect</button> <button id="disconnect"disabled="disabled"onclick="disconnect();">disconnect</button> </div> <div> <textarea id="message"style="width:350px">here is a message!</textarea> </div> <div> <button id="echo"onclick="echo();"disabled="disabled">echo message</button> </div> </div> <div id="console-container"> <div id="console"></div> </div> </div> </body> </html>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: Java棋类游戏实践之中国象棋
下一篇: .net开发中几个重要的认识误区小结