1.js部分web
var lockReconnect = false; //避免ws重复链接 var ws = null; // 判断当前浏览器是否支持WebSocket var wsUrl = "ws:"+ip+":8081"; createWebSocket(wsUrl); //链接ws function createWebSocket(url) { try { if ('WebSocket' in window) { ws = new WebSocket(url); } else if ('MozWebSocket' in window) { ws = new MozWebSocket(url); } else { layui.use(['layer'], function () { var layer = layui.layer; layer.alert("您的浏览器不支持websocket协议,建议使用新版谷歌、火狐等浏览器,请勿使用IE10如下浏览器,360浏览器请使用极速模式,不要使用兼容模式!"); }); } initEventHandle(); } catch (e) { reconnect(url); console.log(e); } } function initEventHandle() { ws.onclose = function () { console.log("llws链接关闭!" + new Date().toUTCString()); var start=0; reconnect(wsUrl); }; ws.onerror = function () { console.log("llws链接错误!"); reconnect(wsUrl); }; ws.onopen = function () { ws.send(uid); heartCheck.reset().start(); //心跳检测重置 console.log("llws链接成功!" + new Date().toUTCString()); }; ws.onmessage = function (event) { //若是获取到消息,心跳检测重置 var eventData = event.data; handMsg(eventData); heartCheck.reset().start(); //拿到任何消息都说明当前链接是正常的 }; } // 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket链接,防止链接还没断开就关闭窗口,server端会抛异常。 window.onbeforeunload = function () { ws.close(); } function reconnect(url) { if (lockReconnect) return; lockReconnect = true; setTimeout(function () { //没链接上会一直重连,设置延迟避免请求过多 createWebSocket(url); lockReconnect = false; }, 5000); } //心跳检测 var heartCheck = { timeout: 60000, //1分钟发一次心跳 timeoutObj: null, serverTimeoutObj: null, reset: function () { clearTimeout(this.timeoutObj); clearTimeout(this.serverTimeoutObj); return this; }, start: function () { var self = this; this.timeoutObj = setTimeout(function () { ws.send(uid); self.serverTimeoutObj = setTimeout(function () { ws.close(); },self.timeout) },this.timeout) } } function handMsg(eventData){ //ajax链接后台处理业务... }
2.后台代码ajax
//使用监听器机制实现ServletContextListener接口 public class WebContextListener implements ServletContextListener{ //消亡时执行的方法 @Override public void contextDestroyed(ServletContextEvent arg0) { } //项目启动时初始化执行的方法 @Override public void contextInitialized(ServletContextEvent arg0) { WebSocketImpl.DEBUG = false; int port = 8081; WsServer wsServer = new WsServer(port); wsServer.start(); /*new Thread(new Runnable() { @Override public void run() { while (true) { try { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); String msg = simpleDateFormat.format(new Date()); System.out.println(msg); Collection<String> allOnlineUser = WsPool.getAllOnlineUser(); System.out.println(allOnlineUser.size()); if (allOnlineUser.size() > 0) { WsPool.sendMessageToAll(msg); } Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start();*/ } } //链接池 public class WsPool { private static final Map<WebSocket, String> wsUserMap = new HashMap<WebSocket, String>(); //单发 public static WebSocket test(String name){ Set<WebSocket> keySet = wsUserMap.keySet(); for(WebSocket socket : keySet){ String string = wsUserMap.get(socket); if(name.equals(string)){ return socket; } } return null; } //群发 public static List<WebSocket> massTexting(String name){ List<WebSocket> fbList = new ArrayList<WebSocket>(); Set<WebSocket> keySet = wsUserMap.keySet(); for(WebSocket socket : keySet){ String string = wsUserMap.get(socket); if(name.equals(string)){ fbList.add(socket); } } return fbList; } /** * 经过webSocket链接获取用户 * @param conn * @return */ public static String getUserByWs(WebSocket conn) { return wsUserMap.get(conn); } /** * 根据用户获取webSocket对象 * 此处应返回的是一个websocket集合,可是在close方法中将失效的链接移除, * 因此保证返回的是一个 * @param userName * @return */ public static WebSocket getWsByUser(String userName) { Set<WebSocket> webSockets = wsUserMap.keySet(); synchronized (webSockets){ for (WebSocket conn : webSockets) { if (conn.equals(userName)) { return conn; } } } return null; } /** * 获取全部的在线用户 * @return */ public static Collection<String> getAllOnlineUser() { List<String> users = new ArrayList<String>(); Collection<String> values = wsUserMap.values(); for (String value : values) { users.add(value); } return users; } /** * 向链接池中添加链接 * @param userName * @param conn */ public static void addUser(String userName, WebSocket conn) { wsUserMap.put(conn, userName); } /** * 移除池中的特定链接 * @param conn * @return */ public static boolean removeUser(WebSocket conn) { if (wsUserMap.containsKey(conn)) { wsUserMap.remove(conn); return true; }else { return false; } } /** * 向一特定的用户发送消息 * @param msg * @param conn */ public static void sendMessageToUser(String msg, WebSocket conn) { if (null != conn && null != wsUserMap.get(conn)) { conn.send(msg); } } /** * 向所用的用户发送消息 * @param msg */ public static void sendMessageToAll(String msg) { Set<WebSocket> webSockets = wsUserMap.keySet(); synchronized (webSockets) { for (WebSocket conn : webSockets) { String user = wsUserMap.get(conn); if (null != user) { conn.send(msg); } } } } } public class WsServer extends WebSocketServer{ public WsServer(int port) { super(new InetSocketAddress(port)); } public WsServer(InetSocketAddress address) { super(address); } /** * 链接时触发 */ @Override public void onOpen(WebSocket webSocket, ClientHandshake clientHandshake) { //LOGGER.debug("connected~~~~~~"); System.out.println("connected~~~~~~"); } /** * 断开链接时触发的方法 */ @Override public void onClose(WebSocket webSocket, int code, String reason, boolean remote) { //断开链接时,移除链接 userLeave(webSocket); System.out.println(reason); } @Override public void onMessage(WebSocket webSocket, String msg) { System.out.println(msg);//获取用户名 userJoin(webSocket, msg); webSocket.send(msg); } /** * 错误时触发 */ @Override public void onError(WebSocket webSocket, Exception e) { System.out.println("on error"); e.printStackTrace(); } /** * 将链接从池中移除 * @param conn */ private void userLeave(WebSocket conn) { WsPool.removeUser(conn); } /** * 向池中添加链接 * @param conn * @param userName */ private void userJoin(WebSocket conn, String userName) { WsPool.addUser(userName, conn); } } //在service层处理完业务逻辑以后在控制层调用链接池的方法 WebSocket webSocket = WsPool.test(us.getuId()); if(webSocket!=null){ webSocket.send(us.getuId()); }
本人已测可用!浏览器