jfinal整合websocket 伺服器向瀏覽器推送通知
阿新 • • 發佈:2018-12-15
最近,需要公司需要寫一個app下單之後,後臺要接收到提醒的功能,需要伺服器向瀏覽器推送下單提醒通知。查了好多資料,中間也是遇到了一些坑,所以在這裡記錄一下。第一次寫部落格,有不對的地方,希望大牛指正。
一、要做的準備工作:
1.將專案放在tomcat裡面
2.下載一個wepsockt-api的jar包
3.新建一個websocketController
4.新建一個indexConter和一個test頁面(這裡因為涉及到 公司的私密,所以暫時搞了個test頁面)
二、wepsockt-api.jar包下載
三.websocketContrller程式碼
package com.mult.work.websocket; import java.io.IOException; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import com.jfinal.kit.Kv; import com.jfinal.kit.LogKit; import com.jfinal.kit.StrKit; @ServerEndpoint("/websocket.ws/{ids}") public class WebSocketController { public static final WebSocketController me = new WebSocketController(); //用來存放每個客戶端對應的MyWebSocket物件。 private static final Map<String, WebSocketController> WEB_SOCKET_MAP = new ConcurrentHashMap<String, WebSocketController>(); private static final Map<String, Kv> WEB_KV = new ConcurrentHashMap<String, Kv>(); //與某個客戶端的連線會話,需要通過它來給客戶端傳送資料 private Session session; //UUID 生成的IDS private String ids; //name 暱稱 private String name; /** * 連線建立成功呼叫的方法 * @param session 可選的引數。session為與某個客戶端的連線會話,需要通過它來給客戶端傳送資料 */ @OnOpen public void onOpen(@PathParam("ids")String ids,Session session){ this.ids = ids; this.session = session; WEB_SOCKET_MAP.put(ids, this); this.name = getKvByIds(ids).getStr("name"); System.out.println("session=" + session.getId()); } /** * 連線關閉呼叫的方法 */ @OnClose public void onClose(){ WEB_SOCKET_MAP.remove(this.session); System.out.println("有一連線關閉!當前線上人數為" + WEB_SOCKET_MAP.size()); System.out.println("session=" + session.getId()); sendMessage(this.name); } /** * 收到客戶端訊息後呼叫的方法 * @param message 客戶端傳送過來的訊息 * @param session 可選的引數 */ @OnMessage public void onMessage(String message, Session session) { System.out.println("來自客戶端的訊息:" + message); System.out.println("session=" + session.getId()); sendMessage(message); } /** * 發生錯誤時呼叫 * @param session * @param error */ @OnError public void onError(Session session, Throwable error){ error.printStackTrace(); } /** * 指定 傳送訊息 */ public void sendMessage(String ids, String message){ WebSocketController me = WEB_SOCKET_MAP.get(ids); if (me != null) { me.sendMessage(message); } // else{ // this.sendMessage("【系統訊息】" + getNameByIds(ids) + " 不線上"); // } } /** * 向客戶端 傳送訊息 */ protected void sendMessage(String message){ try { this.session.getBasicRemote().sendText(message); } catch (IOException e) { e.printStackTrace(); } //this.session.getAsyncRemote().sendText(message); } public static Kv getKvByIds(String ids){ Kv kv = WEB_KV.get(ids); if (kv == null) { WEB_KV.put(ids, new Kv()); return getKvByIds(ids); } return kv; } public static String getNameByIds(String ids){ return getKvByIds(ids).getStr("name"); } public static String setNameByIds(String ids, String name){ if (StrKit.isBlank(name)) { name = "匿名使用者"; } Kv kv = getKvByIds(ids); if ( ! name.equals(kv.get("name"))) { kv.set("name", name); // 同步成員變數 WebSocketController me = WEB_SOCKET_MAP.get(ids); if (me != null) { me.name = name; } } return name; } }
@ServerEndpoint("/websocket.ws/{ids}")因為這裡沒有在config裡面配置,所以要在路由這裡加上一個.ws的字尾,不然的話會報404的錯
四、indexController檔案程式碼段
package com.mult.work.websocket; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.net.URLEncoder; import com.jfinal.kit.Ret; import com.jfinal.kit.StrKit; import com.mult.common.annotation.Controller; import com.mult.common.controller.WorkController; /** * 總控制器 * @author dufuzhong * */ @Controller(controllerKey = "/websocket/index") public class IndexController extends WorkController { /*** * 設定暱稱 */ public void getwebsocket(){ String host = getPara("host"); String name = getPara("name"); String ids = getPara("ids"); if (StrKit.isBlank(ids)) { ids = StrKit.getRandomUUID(); setCookie("websocket_ids", ids, (3 * 365 * 24 * 60 * 60), true); } name = WebSocketController.setNameByIds(ids, name); setCookie("websocket_name", encode(name), (3 * 365 * 24 * 60 * 60), true); renderJson(Ret.ok("url", "ws://" + host + "/websocket.ws/" + ids)); } private String encode(String name){ if (StrKit.notBlank(name)) { try { return URLEncoder.encode(name, "utf-8"); } catch (UnsupportedEncodingException e) {} } return null; } private String decode(String name){ if (StrKit.notBlank(name)) { try { return URLDecoder.decode(name, "utf-8"); } catch (UnsupportedEncodingException e) {} } return null; } }
五、test頁面程式碼段
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <!-- for HTML5 --> <title>Java後端WebSocket的Tomcat實現</title> </head> <body> Welcome <br /> <input id="text" type="text" /> <button onclick="send()">傳送訊息</button> <hr /> <button onclick="closeWebSocket()">關閉WebSocket連線</button> <hr /> <div id="message"></div> </body> <script type="text/javascript"> var websocket = null; //判斷當前瀏覽器是否支援WebSocket var name = $("#name").val(); var host = window.location.host;//+window.location.pathname; $.getJSON("/websocket/index/getwebsocket", { "name": name, "host": host,"ids":88 }, function(ret){ if(ret.state == "ok") { newWebSocket(ret.url); }else{ alert('抱歉,失敗') } }); function newWebSocket(url){ if ('WebSocket' in window) { websocket = new WebSocket(url); } else { alert('請使用火狐或谷歌瀏覽器') return; } //連線發生錯誤的回撥方法 websocket.onerror = function () { setMessageInnerHTML("離線"); } //連線成功建立的回撥方法 websocket.onopen = function () { setMessageInnerHTML("上線"); } //接收到訊息的回撥方法 websocket.onmessage = function (event) { setMessageInnerHTML(event.data); } //連線關閉的回撥方法 websocket.onclose = function () { setMessageInnerHTML("下線"); } } //監聽視窗關閉事件,當視窗關閉時,主動去關閉websocket連線,防止連線還沒斷開就關閉視窗,server端會拋異常。 window.onbeforeunload = function() { closeWebSocket(); } //將訊息顯示在網頁上 function setMessageInnerHTML(innerHTML) { document.getElementById('message').innerHTML += innerHTML + '<br/>'; } //關閉WebSocket連線 function closeWebSocket() { websocket.close(); } //傳送訊息 function send() { var message = document.getElementById('text').value; websocket.send(message); } </script> </html>
六、總結
1.公司伺服器用的是tomcat和nginx反代理,所以在配置的時候要注意下配置nginx的配置。
2.websocket-api.jar包在伺服器環境中可以不要,但是在開發環境中需要,不然的話會報錯的。