基本案例是網上爬的,改了很多,單純發文字聊天功能完整, 1對1單聊, 離線用戶能接受到另一方的留言,增加了一張數據庫表,如果不用表保存離線數據,也可以選擇單例模式緩存來保存。測試了下還可以哦!直接貼代碼不明白的可以問我。
java服務端:
package websockets; import java.io.IOException; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.time.DateFormatUtils; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.springframework.http.server.ServletServerHttpRequest; import Helper.AAAAYulebaoShareSingleton; import Helper.MySqlHepler2; import Helper.EncryptSafa; import java.io.IOException; import java.util.concurrent.CopyOnWriteArraySet; import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; //auth:liaohang @ServerEndpoint("/javaWebSocket") public class javaWebSocket { //靜態變量,用來記錄當前在線連接數。應該把它設計成線程安全的。 private static int onlineCount = 0; //concurrent包的線程安全Set,用來存放每個客戶端對應的MyWebSocket對象。若要實現服務端與單一客戶端通信的話,可以使用Map來存放,其中Key可以為用戶標識 // private static CopyOnWriteArraySet<javaWebSocket> webSocketSets = new CopyOnWriteArraySet<javaWebSocket>(); private static JSONObject webSocketSets = new JSONObject(); //與某個客戶端的連接會話,需要通過它來給客戶端發送數據 private Session session; private String[] parameterArr; private String shareStr; private String userKey; private String shopKey; private String type; //這里來個請求的httpRequest類 /** * 連接建立成功調用的方法 * @param session 可選的參數。session為與某個客戶端的連接會話,需要通過它來給客戶端發送數據 */ private javaWebSocket chatmemeber; //數據庫操作參數 private MySqlHepler2 helper=new MySqlHepler2(); private JSONArray returnJsonArray; private String[] mysqlParameter=null; private JSONObject shareObject; private String datatime; private int shareInt=0; @OnOpen public void onOpen(Session session){ this.session = session; shareStr= session.getRequestURI().toString(); shareStr=shareStr.replace("/yulebaoServlet/javaWebSocket?", ""); shareStr=shareStr.replace("user=", ""); shareStr=shareStr.replace("shop=", ""); shareStr=shareStr.replace("type=", ""); parameterArr=shareStr.split("&"); type=parameterArr[2]; if(type.equals("user")) { userKey=parameterArr[0]; shopKey=parameterArr[1]; webSocketSets.put(userKey, this); //查詢一次數據庫,看是有人在我離線時給我發了消息 mysqlParameter=new String[]{userKey}; returnJsonArray=helper.executeQueryT("select * from AAAAAAAAAChatSheet where sessionKey=?", mysqlParameter); try { shareInt=returnJsonArray.length(); } catch (Exception e) { shareInt=0; } if(returnJsonArray.length()>0) { shareObject=returnJsonArray.getJSONObject(0); shareStr= shareObject.getString("chatContentArray"); try { this.sendMessage(shareStr); } catch (IOException e) { e.printStackTrace(); } mysqlParameter=new String[]{userKey}; helper.executeUpdate("delete from AAAAAAAAAChatSheet where sessionKey=?", mysqlParameter); } } else { userKey=parameterArr[0]; shopKey=parameterArr[1]; webSocketSets.put(shopKey, this); //查詢一次數據庫,看是有人在我離線時給我發了消息 mysqlParameter=new String[]{shopKey}; returnJsonArray=helper.executeQueryT("select * from AAAAAAAAAChatSheet where sessionKey=?", mysqlParameter); try { shareInt=returnJsonArray.length(); } catch (Exception e) { shareInt=0; } if(returnJsonArray.length()>0) { shareObject=returnJsonArray.getJSONObject(0); shareStr= shareObject.getString("chatContentArray"); try { this.sendMessage(shareStr); } catch (IOException e) { e.printStackTrace(); } //刪除key mysqlParameter=new String[]{shopKey}; helper.executeUpdate("delete from AAAAAAAAAChatSheet where sessionKey=?", mysqlParameter); } } //加入set中 addOnlineCount(); //在線數加1 System.out.println("有新連接加入!當前在線人數為" + getOnlineCount()); } /** * 連接關閉調用的方法 */ @OnClose public void onClose(){ if(type.equals("user")) { if(!webSocketSets.isNull(userKey)) { webSocketSets.remove(userKey); } } else { if(!webSocketSets.isNull(shopKey)) { webSocketSets.remove(shopKey); } } //從set中刪除 subOnlineCount(); //在線數減1 System.out.println("有一連接關閉!當前在線人數為" + getOnlineCount()); } /** * 收到客戶端消息后調用的方法 * @param message 客戶端發送過來的消息 * @param session 可選的參數 */ @OnMessage public void onMessage(String message, Session session) { System.out.println("來自客戶端的消息:" + message); //群發消息 if(type.equals("user")) { if(!webSocketSets.isNull(shopKey)) { chatmemeber=(javaWebSocket)webSocketSets.get(shopKey); try { chatmemeber.sendMessage(message); } catch (IOException e) { e.printStackTrace(); } } else { insertDataBase(shopKey,message); } } else { if(!webSocketSets.isNull(userKey)) { chatmemeber=(javaWebSocket)webSocketSets.get(userKey); try { chatmemeber.sendMessage(message); } catch (IOException e) { e.printStackTrace(); } } else { //接消息以方不在,插入數據庫保存 insertDataBase(userKey,message); } } //1對多發消息 /* for(javaWebSocket item: webSocketSets){ 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() { javaWebSocket.onlineCount++; } public static synchronized void subOnlineCount() { javaWebSocket.onlineCount--; } //當一方用戶下線之后,如果再發消息,需要將接收消息保存到數據庫 public void insertDataBase(String shareKey,String message) { shareObject=new JSONObject(); datatime=DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm"); shareObject.put("datatime", datatime); shareObject.put("message", message); mysqlParameter=new String[]{shareKey}; returnJsonArray=helper.executeQueryT("select * from AAAAAAAAAChatSheet where sessionKey=?", mysqlParameter); try { shareInt=returnJsonArray.length(); } catch(Exception e) { shareInt=0; returnJsonArray=new JSONArray(); } if(shareInt==0) //插入數據 { returnJsonArray.put(shareObject); mysqlParameter=new String[]{shareKey,datatime,returnJsonArray.toString()}; helper.executeUpdate("insert into AAAAAAAAAChatSheet(sessionKey,sessionCreateTimes,chatContentArray)values(?,?,?)", mysqlParameter); } else//更新連端的數據 { returnJsonArray.put(shareObject); mysqlParameter=new String[]{returnJsonArray.toString(),shareKey}; helper.executeUpdate("update AAAAAAAAAChatSheet set chatContentArray=? where sessionKey=?", mysqlParameter); } } }
前端頁面User方:
<%@ page language="java" pageEncoding="UTF-8" %> <!DOCTYPE html> <html> <head> <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 if ('WebSocket' in window) { //第一個創建鏈接的用戶需要兩個key,創建一個webosckt鏈接。為了保證JSONObject單個創建的websocket key唯一 所以參數就用雙方的唯一賬戶或id正反組合+類型' //為什么要傳兩個key?比如這個是user請求的鏈接,他創建websocket時需要查詢一下對方有沒有離線留言,如果有離線留言得訪問一次數據庫讀出來返回,所以shop這個key也必須帶上 var user="liaohang"+"xiaoming"+"user"; var shop="xiaoming"+"liaohang"+"shop"; websocket = new WebSocket("ws://localhost:8080/yulebaoServlet/javaWebSocket?user="+user+"&shop="+shop+"&type=user"); } else { alert('當前瀏覽器 Not support websocket') } //連接發生錯誤的回調方法 websocket.onerror = function () { setMessageInnerHTML("WebSocket連接發生錯誤"); }; //連接成功建立的回調方法 websocket.onopen = function () { setMessageInnerHTML("WebSocket連接成功"); } //接收到消息的回調方法 websocket.onmessage = function (event) { setMessageInnerHTML(event.data); } //連接關閉的回調方法 websocket.onclose = function () { setMessageInnerHTML("WebSocket連接關閉"); } //監聽窗口關閉事件,當窗口關閉時,主動去關閉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>
前端頁面Shop方:
<%@ page language="java" pageEncoding="UTF-8" %> <!DOCTYPE html> <html> <head> <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 if ('WebSocket' in window) { //Id account+對方的account +type 接單者發起請求 var user="liaohang"+"xiaoming"+"user"; var shop="xiaoming"+"liaohang"+"shop"; websocket = new WebSocket("ws://localhost:8080/yulebaoServlet/javaWebSocket?user="+user+"&shop="+shop+"&type=shop"); } else { alert('當前瀏覽器 Not support websocket') } //連接發生錯誤的回調方法 websocket.onerror = function () { setMessageInnerHTML("WebSocket連接發生錯誤"); }; //連接成功建立的回調方法 websocket.onopen = function () { setMessageInnerHTML("WebSocket連接成功"); } //接收到消息的回調方法 websocket.onmessage = function (event) { setMessageInnerHTML(event.data); } //連接關閉的回調方法 websocket.onclose = function () { setMessageInnerHTML("WebSocket連接關閉"); } //監聽窗口關閉事件,當窗口關閉時,主動去關閉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>
前端頁面User方和 Shop方 不同的就是傳參數的類型
https://www.bai6du.com/yulebaoServlet/talkTest.jsp