WebSocket是为解决客户端与服务端实时通信而产生的技术。其本质是先通过HTTP/HTTPS协议进行握手后创建一个用于交换数据的TCP连接,此后服务端与客户端通过此TCP连接进行实时通信。
以前我们实现推送技术,用的都是轮询,在特点的时间间隔有浏览器自动发出请求,将服务器的消息主动的拉回来,在这种情况下,我们需要不断的向服务器 发送请求,然而HTTP request 的header是非常长的,里面包含的数据可能只是一个很小的值,这样会占用很多的带宽和服务器资源。会占用大量的带宽和服务器资源。
WebSocket 最伟大之处在于服务器和客户端可以在给定的时间范围内的任意时刻,相互推送信息。在建立连接之后,服务器可以主动传送数据给客户端。此外,服务器与客户端之间交换的标头信息很小。
WebSocket并不限于以Ajax(或XHR)方式通信,因为Ajax技术需要客户端发起请求,而WebSocket服务器和客户端可以彼此相互推送信息。
如何使用?
注意:spring4.0以后加入了对websocket技术的支持,base项目的spring版本为3.1.4,升到4.0.2后加入spring自带的websocket包。
1、maven pom.xml加入websocket所依赖的jar包
<!-- websocket --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.3.1</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.3.3</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-websocket</artifactId> <version>4.0.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-messaging</artifactId> <version>4.0.1.RELEASE</version> </dependency>
2、在servlet-context中添加
http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket.xsd
handleTextMessage
消息处理方法,接收会话中前端发送给后台的message,再通过sendMessage发送到前端
afterConnectionEstablished 连接建立后处理方法
afterConnectionClosed 连接关闭后处理方法
package cn.com.bmsoft.base.websocket; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.TimerTask; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.TextWebSocketHandler; import cn.com.bmsoft.base.service.face.management.IGasService; import cn.com.bmsoft.base.service.face.management.IHomeMonitorService; import cn.com.bmsoft.base.service.face.management.IInfraredService; @RequestMapping("websocket") public class WebsocketEndPoint extends TextWebSocketHandler { @Autowired IHomeMonitorService homeMonitorService; @Autowired IGasService gasService; @Autowired IInfraredService infraredService; @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { super.handleTextMessage(session, message); String phonemessage = message.getPayload(); session.sendMessage(message); } @Override public void afterConnectionEstablished(final WebSocketSession session) throws Exception { ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(1); System.out.println("Connection Establied!"); newScheduledThreadPool.scheduleWithFixedDelay(new TimerTask() { public void run() { try { Map<String, Object> queryParams = new HashMap<String, Object>(); queryParams.put("gStatus","1"); queryParams.put("iStatus","1"); //查询未通知异常条数 int gwarns = gasService.count(queryParams); int iwarns = infraredService.count(queryParams); if((gwarns+iwarns)!=0){ session.sendMessage(new TextMessage((gwarns+iwarns)+"")); }else{ session.sendMessage(new TextMessage(0+"")); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }, 0, 5000, TimeUnit.MILLISECONDS); } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { System.out.println("Connection Closed!"); } }
4、创建握手协议
package cn.com.bmsoft.base.websocket; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor; import java.util.Map; public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor { @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception { return super.beforeHandshake(request, response, wsHandler, attributes); } @Override public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) { super.afterHandshake(request, response, wsHandler, ex); } }5、servletcontext配置处理类和握手协议
<!-- spring-websocket配置start--> <bean id="websocket" class="cn.com.bmsoft.base.websocket.WebsocketEndPoint" /> <websocket:handlers> <websocket:mapping path="/websocket" handler="websocket" /> <websocket:handshake-interceptors> <bean class="cn.com.bmsoft.base.websocket.HandshakeInterceptor" /> </websocket:handshake-interceptors> </websocket:handlers> <!-- spring-websocket配置end-->
6、客户端页面
<!DOCTYPE html> <html> <head> <title>websocket example</title> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=8,9,10" /> <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: #999999; 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" src="${requestContext.contextPath}/resources/scripts/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() { alert("url:"+url); if (!url) { alert('Select whether to use W3C WebSocket or SockJS'); return; } ws = new WebSocket(url); //申请一个WebSocket对象 ws.onopen = function () { setConnected(true); log('Info: connection opened.'); }; ws.onmessage = function (event) { //var msgJson=eval("("+event.data+")"); 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); var msg = '"frdId":"'+28+'",' + '"content":"' + message + '"'; ws.send(msg); // ws.send(message); } else { alert('connection not established, please connect.'); } } function updateUrl(urlPath) { if (window.location.protocol == 'http:') { url = 'ws://' + window.location.host + urlPath; } else { url = 'wss://' + window.location.host + urlPath; } } 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> <script type="text/javascript" src="${requestContext.contextPath}/resources/scripts/jquery-${jqueryVersion}.min.js"></script> <script type="text/javascript"> $(function(){ //移除顶端遮罩 if (top.hideMask) top.hideMask(); }); </script> <body> <div> <div id="connect-container"> <input id="radio1" type="radio" name="group1" onclick="updateUrl('/base/websocket');"> <label for="radio1">W3C WebSocket</label> <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>
sockjs-0.3.min.js链接:http://pan.baidu.com/s/1c2uLpDY 密码:5zxh