在github上面找了一個看起來還不錯的網頁版聊天室,基於ssm加websocket實現的,特此分享一下,github地址放在文章末尾,大家可以自行下載跑起來玩玩,項目如何跑起來我寫在readme里面了。接下來簡單的看一下項目和核心代碼的實現。
登錄頁面:
首頁:可以實現單人聊天和群聊,還有機器人自動回復功能,還有一些個人設置,系統設置功,日志統計功能...
接下來看看核心代碼websocket的實現:
首頁jsp關於websocket的代碼:
var wsServer = null; var ws = null; wsServer = "ws://" + location.host+"${pageContext.request.contextPath}" + "/chatServer/${userid}"; ws = new WebSocket(wsServer); //創建WebSocket對象 ws.onopen = function (evt) { layer.msg("已經建立連接", { offset: 0}); }; ws.onmessage = function (evt) { analysisMessage(evt.data); //解析后台傳回的消息,並予以展示 }; ws.onerror = function (evt) { layer.msg("產生異常", { offset: 0}); }; ws.onclose = function (evt) { layer.msg("已經關閉連接," + evt.reason, { offset: 0}); };
websocket server的實現;
package com.ccq.webSocket; import com.ccq.pojo.User; import com.ccq.utils.CommonDate; import net.sf.json.JSONObject; import org.apache.log4j.Logger; import javax.servlet.http.HttpSession; import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * @author ccq * @Description webSocket服務 * @date 2017/12/16 17:31 */ @ServerEndpoint(value="/chatServer/{userid}", configurator = HttpSessionConfigurator.class) public class ChatServer { private static Logger logger = Logger.getLogger(ChatServer.class); private static int onlineCount = 0; // 記錄連接數目 // Map<用戶id,用戶信息> private static Map<String, OnlineUser> onlineUserMap = new ConcurrentHashMap<String, OnlineUser>(); // 在線用戶 /** * 連接成功調用的方法 */ @OnOpen public void onOpen(@PathParam("userid") String userid , Session session, EndpointConfig config){ logger.info("[ChatServer] connection : userid = " + userid + " , sessionId = " + session.getId()); // 增加用戶數量 addOnlineCount(); // 獲取當前用戶的session HttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName()); User user = (User) httpSession.getAttribute("user"); // 獲得當前用戶信息 // 將當前用戶存到在線用戶列表中 OnlineUser onlineUser = new OnlineUser(user.getUserid(),user.getNickname(),session); onlineUserMap.put(user.getUserid(),onlineUser); // 通知所有在線用戶,當前用戶上線 String content = "[" + CommonDate.getTime24() + " : " + user.getNickname() + "加入聊天室,當前在線人數為 " + getOnlineCount() + "位" + "]"; JSONObject msg = new JSONObject(); msg.put("content",content); String message = Message.getMessage(msg.toString(),Message.NOTICE,onlineUserMap.values()); Message.broadcast(message,onlineUserMap.values()); } /** * 連接關閉方法 */ @OnClose public void onClose(@PathParam("userid") String userid,Session session,CloseReason closeReason){ logger.info("[ChatServer] close : userid = " + userid + " , sessionId = " + session.getId() + " , closeCode = " + closeReason.getCloseCode().getCode() + " , closeReason = " +closeReason.getReasonPhrase()); // 減少當前用戶 subOnlienCount(); // 移除的用戶信息 OnlineUser removeUser = onlineUserMap.remove(userid); onlineUserMap.remove(userid); // 通知所有在線用戶,當前用戶下線 String content = "["+ CommonDate.getTime24() + " : " + removeUser.getNickname() + " 離開聊天室,當前在線人數為 " + getOnlineCount() + "位" + "]"; JSONObject msg = new JSONObject(); msg.put("content",content); if(onlineUserMap.size() > 0){ String message = Message.getMessage(msg.toString(), Message.NOTICE, onlineUserMap.values()); Message.broadcast(message,onlineUserMap.values()); }else{ logger.info("content : ["+ CommonDate.getTime24() + " : " + removeUser.getNickname() + " 離開聊天室,當前在線人數為 " + getOnlineCount() + "位" + "]"); } } /** * 接收客戶端的message,判斷是否有接收人而選擇進行廣播還是指定發送 * @param data 客戶端發來的消息 */ @OnMessage public void onMessage(@PathParam("userid") String userid,String data){ logger.info("[ChatServer] onMessage : userid = " + userid + " , data = " + data); JSONObject messageJson = JSONObject.fromObject(data); JSONObject message = messageJson.optJSONObject("message"); String to = message.optString("to"); String from = message.optString("from"); // 將用戶id轉換為名稱 to = this.userIdCastNickName(to); OnlineUser fromUser = onlineUserMap.get(from); String sendMessage = Message.getContent(fromUser,to,message.optString("content"),message.optString("time")); String returnData = Message.getMessage(sendMessage, messageJson.optString("type"),null); if(to == null || to.equals("")){ // 進行廣播 Message.broadcast(returnData.toString(),onlineUserMap.values()); }else{ Message.singleSend(returnData.toString(), onlineUserMap.get(from)); // 發送給自己 String[] useridList = message.optString("to").split(","); for(String id : useridList){ if(!id.equals(from)){ Message.singleSend(returnData.toString(), onlineUserMap.get(id)); // 分別發送給指定的用戶 } } } } /** * 發生錯誤 * @param throwable */ @OnError public void onError(@PathParam("userid") String userid,Session session,Throwable throwable){ logger.info("[ChatServer] close : userid = " + userid + " , sessionId = " + session.getId() +" , throwable = " + throwable.getMessage() ); } public static int getOnlineCount() { return onlineCount; } public synchronized void addOnlineCount(){ onlineCount++; } public synchronized void subOnlienCount(){ onlineCount--; } /** * 將用戶id轉換為名稱 * @param userIds * @return */ private String userIdCastNickName(String userIds){ String niceNames = ""; if(userIds != null && !userIds.equals("")){ String[] useridList = userIds.split(","); String toName = ""; for (String id : useridList){ toName = toName + onlineUserMap.get(id).getNickname() + ","; } niceNames = toName.substring(0,toName.length() - 1); } return niceNames; } }
私聊和群聊的發送代碼:
/** * 廣播消息 * @param message 消息 * @param onlineUsers 在線用戶 */ public static void broadcast(String message,Collection<OnlineUser> onlineUsers){ /***************************在線用戶***************************/ StringBuffer userStr = new StringBuffer(); for(OnlineUser user : onlineUsers){ userStr.append(user.getNickname() + ","); } userStr.deleteCharAt(userStr.length()-1); logger.info("[broadcast] message = " + message + ", onlineUsers = " + userStr.toString()); /***************************在線用戶***************************/ for(OnlineUser user : onlineUsers){ try { user.getSession().getBasicRemote().sendText(message); } catch (IOException e) { e.printStackTrace(); logger.info("消息發送失敗!" + e.getMessage()); continue; } } } /** * 對特定用戶發送消息 * @param message * @param onlineUser */ public static void singleSend(String message, OnlineUser onlineUser){ logger.info("[singleSend] message = " + message + ", toUser = " + onlineUser.getNickname()); try { onlineUser.getSession().getBasicRemote().sendText(message); } catch (IOException e) { e.printStackTrace(); logger.info("消息發送失敗!" + e.getMessage()); } }
記住幾個關鍵api:
OnOpen:建立連接
OnClose:關閉連接
OnMessage:接收消息
發送消息的核心方法是通過某個session的.getBasicRemote().sendText(message)來發送的。
ok,websocket大概就是這樣,你可以親自啊跑一下試試,也十分歡迎大家一起來豐富這個小項目,增加一些有趣的功能,讓大家欣賞,我會第一時間在github上面寫上你的大名,以表感謝。
github鏈接:https://github.com/MrLiu1227/WebChat.git
沒有基礎的同學可以跑一個十分干凈的websocket示例:https://github.com/MrLiu1227/websocket.git