WebSocket实现简易聊天室
前台页面:
<html> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <title>Web sockets test</title> <style type="text/css"> .container { font-family: "Courier New"; width: 680px; height: 300px; overflow: auto; border: 1px solid black; } .LockOff { display: none; visibility: hidden; } .LockOn { display: block; visibility: visible; position: absolute; z-index: 999; top: 0px; left: 0px; width: 1024%; height: 768%; background-color: #ccc; text-align: center; padding-top: 20%; filter: alpha(opacity=75); opacity: 0.75; } </style> <script src="jquery-min.js" type="text/javascript"></script> <script type="text/javascript"> var ws; var SocketCreated = false; var isUserloggedout = false; function lockOn(str) { var lock = document.getElementById('skm_LockPane'); if (lock) lock.className = 'LockOn'; lock.innerHTML = str; } function lockOff() { var lock = document.getElementById('skm_LockPane'); lock.className = 'LockOff'; } function ToggleConnectionClicked() { if (SocketCreated && (ws.readyState == 0 || ws.readyState == 1)) { lockOn("离开聊天室..."); ws.send("【" + document.getElementById("txtName").value + "】离开了聊天室!"); SocketCreated = false; isUserloggedout = true; ws.close(); } else { lockOn("进入聊天室..."); Log("准备连接到聊天服务器 ..."); try { if ("WebSocket" in window) { ws = new WebSocket("ws://" + document.getElementById("Connection").value); } else if ("MozWebSocket" in window) { ws = new MozWebSocket("ws://" + document.getElementById("Connection").value); } SocketCreated = true; isUserloggedout = false; } catch (ex) { Log(ex, "ERROR"); return; } document.getElementById("ToggleConnection").innerHTML = "断开"; ws.onopen = WSonOpen; ws.onmessage = WSonMessage; ws.onclose = WSonClose; ws.onerror = WSonError; } }; function WSonOpen() { lockOff(); Log("连接已经建立。", "OK"); $("#SendDataContainer").show(); ws.send("【"+document.getElementById("txtName").value+"】进入了聊天室!"); }; function WSonMessage(event) { // console.log(event) // Log(event.data); var data = event.data; var obj = JSON.parse(data); if ("1" == obj.code) { // 客户端信息回显 Log(obj.data); } else if ("0" == obj.code) { // 在线人数更新 $("#logCount").text(obj.data); } }; function WSonClose() { lockOff(); if (isUserloggedout) Log("【" + document.getElementById("txtName").value + "】离开了聊天室!"); document.getElementById("ToggleConnection").innerHTML = "连接"; $("#SendDataContainer").hide(); }; function WSonError() { lockOff(); Log("远程连接中断。", "ERROR"); }; function SendDataClicked() { if (document.getElementById("DataToSend").value.trim() != "") { ws.send(document.getElementById("txtName").value + "说 :\"" + document.getElementById("DataToSend").value + "\""); document.getElementById("DataToSend").value = ""; } }; function Log(Text, MessageType) { if (MessageType == "OK") Text = "<span style='color: green;'>" + Text + "</span>"; if (MessageType == "ERROR") Text = "<span style='color: red;'>" + Text + "</span>"; document.getElementById("LogContainer").innerHTML = document.getElementById("LogContainer").innerHTML + Text + "<br />"; var LogContainer = document.getElementById("LogContainer"); LogContainer.scrollTop = LogContainer.scrollHeight; }; $(document).ready(function () { $("#SendDataContainer").hide(); var WebSocketsExist = true; try { var dummy = new WebSocket("ws://localhost:8080/test"); } catch (ex) { try { webSocket = new MozWebSocket("ws://localhost:8080/test"); } catch (ex) { WebSocketsExist = false; } } if (WebSocketsExist) { Log("您的浏览器支持WebSocket. 您可以尝试连接到聊天服务器!", "OK"); document.getElementById("Connection").value = "localhost:8080/wschat"; } else { Log("您的浏览器不支持WebSocket。请选择其他的浏览器再尝试连接服务器。", "ERROR"); document.getElementById("ToggleConnection").disabled = true; } $("#DataToSend").keypress(function (evt) { if (evt.keyCode == 13) { $("#SendData").click(); evt.preventDefault(); } }) //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。 window.onbeforeunload = function () { ws.close(); } }); </script> </head> <body> <div id="skm_LockPane" class="LockOff"></div> <form id="form1" runat="server"> <h1>Web Socket 聊天室</h1> <br/> <div> 按下连接按钮,会通过WebSocket发起一个到聊天浏览器的连接。 </div> 服务器地址: <input type="text" id="Connection"/> 用户名: <input type="text" id="txtName" value="黄晓安"/> <button id='ToggleConnection' type="button" onclick='ToggleConnectionClicked();'>连接</button> 在线人数:<span id="logCount">0</span> <br/> <br/> <div id='LogContainer' class='container'></div> <br/> <div id='SendDataContainer'> <input type="text" id="DataToSend" size="88"/> <button id='SendData' type="button" onclick='SendDataClicked();'>发送</button> </div> <br/> </form> </body> </html>后台代码:
package com.uptop.websocket; import com.alibaba.fastjson.JSON; import com.uptop.entity.ResultVo; import javax.websocket.*; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.concurrent.CopyOnWriteArraySet; /** * websocket 聊天室 * * @author Administrator * @create 2018-02-05 15:17 */ @ServerEndpoint("/wschat") public class WebSocketChat { //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。 private static int onlineCount = 0; //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识 public static CopyOnWriteArraySet<WebSocketChat> webSocketSet = new CopyOnWriteArraySet<WebSocketChat>(); //与某个客户端的连接会话,需要通过它来给客户端发送数据 private Session session; /** * 连接建立成功调用的方法 * * @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据 */ @OnOpen public void onOpen(Session session) { this.session = session; webSocketSet.add(this); //加入set中 addOnlineCount(); //在线数加1 // 发送在线人数数据 ResultVo resultVo = new ResultVo("0",this.onlineCount,"from server"); sendMsg(JSON.toJSONString(resultVo)); System.out.println("有新连接加入!当前在线人数为" + getOnlineCount()); } /** * 连接关闭调用的方法 */ @OnClose public void onClose() { webSocketSet.remove(this); //从set中删除 subOnlineCount(); //在线数减1 // 发送在线人数数据 ResultVo resultVo = new ResultVo("0",this.onlineCount,"from server"); sendMsg(JSON.toJSONString(resultVo)); System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount()); } /** * 收到客户端消息后调用的方法 * * @param message 客户端发送过来的消息 * @param session 可选的参数 */ @OnMessage public void onMessage(String message, Session session) { System.out.println("来自客户端的消息:" + message); // 封装客户端消息 ResultVo resultVo = new ResultVo("1",message,"from client"); String jsonStr = JSON.toJSONString(resultVo); //群发消息 for (WebSocketChat item : webSocketSet) { try { item.sendMessage(jsonStr); } 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); } public static synchronized int getOnlineCount() { return onlineCount; } public static synchronized void addOnlineCount() { WebSocketChat.onlineCount++; } public static synchronized void subOnlineCount() { WebSocketChat.onlineCount--; } public static void sendMsg(String msg) { for (WebSocketChat item : webSocketSet) { try { item.sendMessage(msg); } catch (IOException e) { e.printStackTrace(); continue; } } } }
效果图:
注:本案例参考ibm文库案例的前台页面,后台使用Java实现。