详解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技术实际上是轮询技术的改进,又可细分为两种实现方式,一种是长轮询机制,一种称为流技术。
Html5WebSocket设计出来的目的就是要取代轮询和Comet技术,使客户端浏览器具备像C/S架构下桌面系统的实时通讯能力。浏览器通过JavaScript向服务器发出建立WebSocket连接的请求,连接建立以后,客户端和服务器端就可以通过TCP连接直接交换数据。因为WebSocket连接本质上就是一个TCP连接,所以在数据传输的稳定性和数据传输量的大小方面,和轮询以及Comet技术比较,具有很大的性能优势。
但是鉴于websocket对浏览器要求比较高,为了解决这个问题,推出了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-appversion="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/javaeehttp://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/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/contexthttp://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
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(ServerHttpRequestrequest, ServerHttpResponseresponse,WebSocketHandlerwsHandler, Map<String,Object>attributes)throwsException{ System.out.println("BeforeHandshake"); returnsuper.beforeHandshake(request,response,wsHandler,attributes); } @Override publicvoidafterHandshake(ServerHttpRequestrequest, ServerHttpResponseresponse,WebSocketHandlerwsHandler, Exceptionex){ System.out.println("AfterHandshake"); 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(WebSocketSessionsession, TextMessagemessage)throwsException{ super.handleTextMessage(session,message); TextMessagereturnMessage=newTextMessage(message.getPayload() +"receivedatserver"); 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; /** * *@authordayu */ @Component publicclassSystemWebSocketHandlerimplementsWebSocketHandler{ @Override publicvoidafterConnectionEstablished(WebSocketSessionsession)throwsException{ System.out.println("connecttothewebsocketsuccess......"); session.sendMessage(newTextMessage("Server:connectedOK!")); } @Override publicvoidhandleMessage(WebSocketSessionwss,WebSocketMessage<?>wsm)throwsException{ TextMessagereturnMessage=newTextMessage(wsm.getPayload() +"receivedatserver"); wss.sendMessage(returnMessage); } @Override publicvoidhandleTransportError(WebSocketSessionwss,Throwablethrwbl)throwsException{ if(wss.isOpen()){ wss.close(); } System.out.println("websocketconnectionclosed......"); } @Override publicvoidafterConnectionClosed(WebSocketSessionwss,CloseStatuscs)throwsException{ System.out.println("websocketconnectionclosed......"); } @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(WebSocketHandlerRegistryregistry){ registry.addHandler(systemWebSocketHandler(),"/websck").addInterceptors(newHandshakeInterceptor()); System.out.println("registed!"); registry.addHandler(systemWebSocketHandler(),"/sockjs/websck/info").addInterceptors(newHandshakeInterceptor()) .withSockJS(); } @Bean publicWebSocketHandlersystemWebSocketHandler(){ returnnewSystemWebSocketHandler(); } }
(7)testSocket.jsp
<%@pagelanguage="java"contentType="text/html;charset=ISO-8859-1"pageEncoding="ISO-8859-1"%> <!DOCTYPEhtmlPUBLIC"-//W3C//DTDHTML4.01Transitional//EN""http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <metahttp-equiv="Content-Type"content="text/html;charset=ISO-8859-1"> <title>WebSocket/SockJSEchoSample(AdaptedfromTomcat'sechosample)</title> <styletype="text/css"> #connect-container{ float:left; width:400px } #connect-containerdiv{ padding:5px; } #console-container{ float:left; margin-left:15px; width:400px; } #console{ border:1pxsolid#CCCCCC; border-right-color:#33333333; border-bottom-color:#999999; height:170px; overflow-y:scroll; padding:5px; width:100%; } #consolep{ padding:0; margin:0; } </style> <scriptsrc="http://cdn.sockjs.org/sockjs-0.3.min.js"></script> <scripttype="text/javascript"> varws=null; varurl=null; vartransports=[]; functionsetConnected(connected){ document.getElementById('connect').disabled=connected; document.getElementById('disconnect').disabled=!connected; document.getElementById('echo').disabled=!connected; } functionconnect(){ if(!url){ log('SelectwhethertouseW3CWebSocketorSockJS'); return; } //ws=(url.indexOf('sockjs')!=-1)?newSockJS(url,undefined,{protocols_whitelist:transports}):newWebSocket(url); if('WebSocket'inwindow){ ws=newWebSocket("ws://localhost:8080/SpringSocketJs/websck"); }else{ ws=newSockJS("http://localhost:8080/SpringSocketJs/sockjs/websck/info"); } //websocket=newSockJS("http://localhost:8084/SpringWebSocketPush/sockjs/websck"); ws.onopen=function(){ setConnected(true); //log('Info:connectionopened.'); }; ws.onmessage=function(event){ log('Received:'+event.data); }; ws.onclose=function(event){ setConnected(false); log('Info:connectionclosed.'); log(event); }; } functiondisconnect(){ if(ws!=null){ ws.close(); ws=null; } setConnected(false); } functionecho(){ if(ws!=null){ varmessage=document.getElementById('message').value; log('Sent:'+message); ws.send(message); }else{ alert('connectionnotestablished,pleaseconnect.'); } } functionupdateUrl(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'; } } functionupdateTransport(transport){ transports=(transport=='all')?[]:[transport]; } functionlog(message){ varconsole=document.getElementById('console'); varp=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><h2style="color:#ff0000">Seemsyourbrowserdoesn'tsupportJavascript!Websockets relyonJavascriptbeingenabled.Pleaseenable Javascriptandreloadthispage!</h2></noscript> <div> <divid="connect-container"> <inputid="radio1"type="radio"name="group1"onclick="updateUrl('/SpringSocketJs/websocket');"> <labelfor="radio1">W3CWebSocket</label> <br> <inputid="radio2"type="radio"name="group1"onclick="updateUrl('/SpringSocketJs/sockjs/websocket');"> <labelfor="radio2">SockJS</label> <divid="sockJsTransportSelect"style="visibility:hidden;"> SockJStransport: <selectonchange="updateTransport(this.value)"> <optionvalue="all">all</option> <optionvalue="websocket">websocket</option> <optionvalue="xhr-polling">xhr-polling</option> <optionvalue="jsonp-polling">jsonp-polling</option> <optionvalue="xhr-streaming">xhr-streaming</option> <optionvalue="iframe-eventsource">iframe-eventsource</option> <optionvalue="iframe-htmlfile">iframe-htmlfile</option> </select> </div> <div> <buttonid="connect"onclick="connect();">Connect</button> <buttonid="disconnect"disabled="disabled"onclick="disconnect();">Disconnect</button> </div> <div> <textareaid="message"style="width:350px">Hereisamessage!</textarea> </div> <div> <buttonid="echo"onclick="echo();"disabled="disabled">Echomessage</button> </div> </div> <divid="console-container"> <divid="console"></div> </div> </div> </body> </html>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。