大批量數據導入時,須要即時顯示對文件的處理進度。考慮ajax輪詢太浪費資源,使用websocket實現。html
項目使用Spring MVC(3.1),與websocket結合要求版本4.0以上。因此沒有使用Spring提供的websocket。java
1.依賴Tomcat 7 或者 J2EE 7web
maven導入:ajax
<!-- webscoket start --> <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-websocket-api</artifactId> <version>7.0.47</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>7.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.java-websocket</groupId> <artifactId>Java-WebSocket</artifactId> <version>1.3.0</version> </dependency> <!-- webscoket end -->
2.服務端apache
工具類,存儲惟一key和鏈接api
import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import javax.websocket.Session; public class WebsocketSessionUtils { public static Map<String, Session> clients = new ConcurrentHashMap<>(); public static void put(String batchKey, Session session) { clients.put(batchKey, session); } public static Session get(String batchKey) { return clients.get(batchKey); } public static void remove(String batchKey) { clients.remove(batchKey); } public static boolean hasConnection(String batchKey) { return clients.containsKey(batchKey); } }
websocket處理類,不要添加業務邏輯tomcat
import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @ServerEndpoint("/websocket.ws/{batchKey}") public class WebsocketEndPoint { private static Log log = LogFactory.getLog(WebsocketEndPoint.class); @OnOpen public void onOpen(@PathParam("batchKey") String batchKey, Session session) { log.info("Websocket Start Connecting:" + batchKey); WebsocketSessionUtils.put(batchKey, session); } @OnMessage public String onMessage(@PathParam("batchKey") String batchKey, String message) { return "Got your message (" + message + ").Thanks !"; } @OnError public void onError(@PathParam("batchKey") String batchKey, Throwable throwable, Session session) { log.info("Websocket Connection Exception:" + batchKey); log.info(throwable.getMessage(), throwable); WebsocketSessionUtils.remove(batchKey); } @OnClose public void onClose(@PathParam("batchKey") String batchKey, Session session) { log.info("Websocket Close Connection:" + batchKey); WebsocketSessionUtils.remove(batchKey); } }
3.客戶端websocket
使用js閉包封裝websocket,導入websocket.jsjava-web
var myWebSocket = (function() { var mySocket = {}; mySocket.tryTime = 0; mySocket.webSocketUrl = null; mySocket.batchKey = null; mySocket.webSocket = null; mySocket.initSocket = function() { if (!window.WebSocket) { // alert("Your browsers don't support websocket."); return false; } mySocket.webSocket = new WebSocket(mySocket.webSocketUrl + mySocket.batchKey); mySocket.webSocket.onmessage = function(msg) { console.log(msg); }; mySocket.webSocket.onerror = function(event) { console.log(event); }; mySocket.webSocket.onopen = function(event) { console.log(event); }; mySocket.webSocket.onclose = function() { if (mySocket.tryTime < 10) { setTimeout(function() { webSocket = null; mySocket.tryTime++; mySocket.initSocket(); }, 500); } else { mySocket.tryTime = 0; } }; }; mySocket.closeSocket = function() { if (mySocket.webSocket) { mySocket.webSocket.close(); } }; return mySocket; })();
在ajax執行時啓動websocket,使用timestamp做爲惟一key。session
var commissionWebsocketUrl = "ws://${remote_websocket}/commission/websocket.ws/";
var timestamp=new Date().getTime(); $.ajax({ type : "POST", url : trialUrl+"?batchKey="+timestamp, data : $("#batchUploadForm").serialize(), dataType : "html", beforeSend: function(xhr) { var countDiv = $('#loading #countDiv'); if(countDiv.length==0){ countDiv =$("<div id='countDiv'></span>"); $('#loading').append(countDiv); } $('#loading').show(); myWebSocket.webSocketUrl = commissionWebsocketUrl; myWebSocket.batchKey = timestamp; myWebSocket.initSocket(); myWebSocket.webSocket.onmessage = function(msg) { countDiv.html("mTusker is processing date,Please wait... "+msg.data); }; }, complete: function(){ $('#loading').hide(); myWebSocket.closeSocket(); }, success : function(data) { $("#trialInfoPopup").html(data); mydialog = $("#trialInfoPopup").dialog({ position: ['center',100] ,width : 1400,height: 600, modal : true, title : "Batch Upload Trial" }); } });
java項目做爲客戶端
import java.io.IOException; import javax.websocket.ClientEndpoint; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; @ClientEndpoint public class WebsocketClient { @OnOpen public void onOpen(Session session) { System.out.println("Connected to endpoint:" + session.getBasicRemote()); try { session.getBasicRemote().sendText("Hello"); } catch (IOException ex) { } } @OnMessage public void onMessage(String message) { System.out.println(message); } @OnError public void onError(Throwable t) { t.printStackTrace(); } }
import java.io.IOException; import java.net.URI; import javax.websocket.ContainerProvider; import javax.websocket.DeploymentException; import javax.websocket.Session; import javax.websocket.WebSocketContainer; public class WebsocketApp { private static String webUrl = "localhost"; public static void send(String batchKey, String message) { WebSocketContainer container = ContainerProvider.getWebSocketContainer(); String uri = "ws://"+webUrl+"/websocket.ws/" + batchKey; System.out.println("Connecting to" + uri); try { Session session = WebsocketSessionUtils.get(batchKey); if (session == null) { session = container.connectToServer(WebsocketClient.class, URI.create(uri)); WebsocketSessionUtils.put(batchKey, session); } session.getBasicRemote().sendText(message); } catch (DeploymentException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public static String getWebUrl() { return webUrl; } public static void setWebUrl(String webUrl) { WebsocketApp.webUrl = webUrl; } }
把導入文件處理部分,當作java項目客戶端,處理過程當中調用websocket
int num = 0; for(Map<String,String> rowInfo : rows){ WebsocketApp.send(batchKey, num++ + "/" + rows.size()); ...... }
由此實如今處理文件過程當中即時發送處理進度。
注: 當使用https時須要改成
var commissionWebsocketUrl = "wss://${remote_websocket}/commission/websocket.ws/";