博客地址:https://ainyi.com/67css
有一個月沒有寫博客了,也是由於年前需求多、回家過春節的緣由,如今返回北京的次日,想一想,應該也要分享技術專題的博客了!!html
主題
基於 websocket 網頁端聊天室前端
WebSocket 協議是基於 TCP 的一種新的網絡協議。它實現了瀏覽器與服務器全雙工 (full-duplex) 通訊——容許服務器主動發送信息給客戶端。java
使用 java 開發後臺jquery
須要導入一個jar包:javax.websocket-api-1.0-rc4.jarweb
後臺代碼
package com.krry.socket; import java.io.IOException; import java.util.concurrent.CopyOnWriteArraySet; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; //該註解用來指定一個URI,客戶端能夠經過這個URI來鏈接到WebSocket。相似Servlet的註解mapping。無需在web.xml中配置。 @ServerEndpoint("/websocket") public class MyWebSocket { //靜態變量,用來記錄當前在線鏈接數。應該把它設計成線程安全的。 private static int onlineCount = 0; //concurrent包的線程安全Set,用來存放每一個客戶端對應的MyWebSocket對象。若要實現服務端與單一客戶端通訊的話,可使用Map來存放,其中Key能夠爲用戶標識 private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<MyWebSocket>(); //與某個客戶端的鏈接會話,須要經過它來給客戶端發送數據 private Session session; /** * 鏈接創建成功調用的方法 * @param session 可選的參數。session爲與某個客戶端的鏈接會話,須要經過它來給客戶端發送數據 */ @OnOpen public void onOpen(Session session){ this.session = session; webSocketSet.add(this); //加入set中 addOnlineCount(); //在線數加1 System.out.println("有新鏈接加入!當前在線人數爲" + getOnlineCount()); } /** * 鏈接關閉調用的方法 */ @OnClose public void onClose(){ webSocketSet.remove(this); //從set中刪除 subOnlineCount(); //在線數減1 System.out.println("有一鏈接關閉!當前在線人數爲" + getOnlineCount()); } /** * 收到客戶端消息後調用的方法 * @param message 客戶端發送過來的消息 * @param session 可選的參數 */ @OnMessage public void onMessage(String message, Session session) { System.out.println("來自客戶端的消息:" + message); //羣發消息 for(MyWebSocket item: webSocketSet){ try { item.sendMessage(message); } catch (IOException e) { e.printStackTrace(); continue; } } } /** * 發生錯誤時調用 * @param session * @param error */ @OnError public void onError(Session session, Throwable error){ System.out.println("發生錯誤"); error.printStackTrace(); } /** * 這個方法與上面幾個方法不同。沒有用註解,是根據本身須要添加的方法。 * @param message * @throws IOException */ public void sendMessage(String message) throws IOException{ this.session.getBasicRemote().sendText(message); //this.session.getAsyncRemote().sendText(message); } public static synchronized int getOnlineCount() { return onlineCount; } public static synchronized void addOnlineCount() { MyWebSocket.onlineCount++; } public static synchronized void subOnlineCount() { MyWebSocket.onlineCount--; } }
前端代碼
注意
前端須要實現這幾個方法:api
// 註冊事件 // 監聽打開鏈接 ws.onopen = function(){ openWs(); }; // 監聽消息 ws.onmessage = function(event){ msgWs(event); }; // 監聽關閉鏈接 ws.onclose = function(){ closeWs(); }; // 監聽發送錯誤 ws.onerror = function(){ errorWs(); };
具體代碼
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <!doctype html> <html> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta name="keywords" content=""> <meta name="description" content=""> <title> 基於Java服務器端的消息主動推送技術揭祕 --krry </title> <link rel="stylesheet" href="css/animate.css" /> <link rel="stylesheet" type="text/css" href="css/sg.css" /> <style> *{margin:0;padding:0;} body{background:url("images/5.jpg");background-size:cover;} h1{margin-top:50px;text-align:center;color:#fff;text-shadow:1px 1px 1px #000;font-family:-webkit-body;font-size:24px;} .box{width:700px;margin:20px auto;} .box span{color:#f60;font-size:16px;font-family:"微軟雅黑";} .box .shu{text-indent:1em;height:24px;font-family:"微軟雅黑";border:0;outline:none;font-size:14px;} .box .add{width:300px;margin-right:24px;} .box .user{width:200px;} .box .btn{width:80px;height:34px;color:#fff;background:#6c0;border:0;outline:none;cursor:pointer;margin-top:20px;font-size:16px;font-family:"微軟雅黑";} .box .area{line-height: 29px;height:280px;width:680px;padding:10px;overflow:auto;font-size:16px;font-family:"微軟雅黑";margin:20px 0;outline:none;box-shadow:1px 2px 18px #000} .box .setex{text-indent:1em;height:28px;border:1px solid #6c0;width:618px;outline:none;float:left;font-family:"微軟雅黑";} .box .send{font-size:14px;width:80px;height:30px;color:#fff;background:#6c0;border:0;outline:none;cursor:pointer;font-family:"微軟雅黑";} </style> </head> <body> <h1> 基於Java服務器端的消息主動推送技術揭祕 --krry </h1> <div class="box"> <span> 服務器地址: </span> <input type="text" class="shu add" value="www.ainyi.com/krry_NetChat/websocket" readonly/> <span> 用戶名: </span> <input type="text" class="shu user" value="匿名" /> <input type="button" value="鏈接" class="btn" /> <div class="area" id="boxx"> </div> <div class="c_cen"> <input type="text" class="setex" /> <input type="button" value="發送" class="send"> </div> </div> <script src="js/jquery-1.11.1.min.js"> </script> <script src="js/sg.js"> </script> <script src="js/sgutil.js"> </script> <script> var close = true; var ws; $(function() { $(".c_cen").hide(); //首先判斷瀏覽器是否支持webSocket,支持h5的瀏覽器纔會支持 if (window.WebSocket) { printMsg("您的瀏覽器支持WebSocket,您能夠嘗試鏈接到聊天服務器!", "OK"); } else { printMsg("您的瀏覽器不支持WebSocket,請選擇其餘瀏覽器!", "ERROR"); //設置按鈕不可點擊 $(".btn").attr("disabled", "true"); } }); //打印信息 function printMsg(msg, msgType) { if (msgType == "OK") { msg = "<span style='color:green'>" + msg + "</span>"; } if (msgType == "ERROR") { msg = "<span style='color:red'>" + msg + "</span>"; } $(".area").append(msg + "<br/>"); var boxx = document.getElementById("boxx"); boxx.scrollTop = boxx.scrollHeight; //使滾動條一直在底部 } //打開Socket function openWs() { printMsg("連接已創建", "OK"); ws.send("【" + $(".user").val() + "】已進入聊天室"); $(".c_cen").show(); } //接收消息的時候 function msgWs(e) { printMsg(e.data); } //關閉鏈接 function closeWs() { $(".btn").val("鏈接"); $(".c_cen").hide(); } //產生錯誤 function errorWs() { printMsg("您與服務器鏈接錯誤...", "ERROR"); } //點擊發送按鈕 $(".send").click(function() { var text = $(".setex").val(); if (text == null || text == "") return; $(".setex").val(""); ws.send("【" + $(".user").val() + "】:" + text); }); //點擊鏈接 $(".btn").click(function() { if ($(".add").val() && $(".user").val()) { if (close) { printMsg("正在準備鏈接服務器,請稍等..."); var url = "wss://" + $(".add").val(); if ("WebSocket" in window) { ws = new WebSocket(url); } else if ("MozWebSocket" in window) { ws = new MozWebSocket(url); } //已鏈接 $(".btn").val("斷開"); close = false; //註冊事件 ws.onopen = function() { openWs(); }; ws.onmessage = function(event) { msgWs(event); }; ws.onclose = function() { closeWs(); }; ws.onerror = function() { errorWs(); }; //監聽窗口關閉事件,當窗口關閉時,主動去關閉websocket鏈接,防止鏈接還沒斷開就關閉窗口,server端會拋異常。 window.onbeforeunload = function() { ws.send("【" + $(".user").val() + "】離開了聊天室"); close = true; ws.close(); }; } else { ws.send("【" + $(".user").val() + "】離開了聊天室"); close = true; ws.close(); } } else { $.tmDialog.alert({ open: "left", content: "服務器地址和用戶名不能爲空哦...", title: "提示哦~~~" }); } }); //回車鍵 $(".setex").keypress(function(event) { if (event.keyCode == 13) { $(".send").trigger("click"); } }); </script> </body> </html>
到這裏大功告成瀏覽器
聊天方法
- 打開兩個窗口輸入項目地址進行聊天
- 能夠把連接發給朋友打開,進行聊天
來一波截圖
移動端
在線演示
PC 端:https://www.ainyi.com/krry_NetChat 移動端:https://www.ainyi.com/krry_NetChatPho安全
打完收工~服務器
博客地址:https://ainyi.com/67