websocket简易聊天室

    科技2026-02-17  19

    简易聊天室

    POM配置后端前端页面

    基于websocket 使用Spring Boot 完成简易的聊天室功能。

    POM

    //其他的就略去了 就是平常的springboot依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> </dependency>

    配置

    @Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter ServerEndpointExporter() { return new ServerEndpointExporter(); } }

    后端

    @Component @ServerEndpoint(value = "/websocket/{info}") public class WebSocketServer { //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。 private static AtomicInteger onlineNum = new AtomicInteger(); //concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象。 private static ConcurrentHashMap<String, Session> sessionPools = new ConcurrentHashMap<>(); //发送消息 public void sendMessage(Session session, String message) { try { if(session != null){ synchronized (session) { System.out.println("服务端发送数据:" + message); session.getBasicRemote().sendText(message); } } } catch(Exception e) { System.out.println("发送消息异常:"+e.getMessage()); e.printStackTrace(); } } //给指定用户发送信息 public void sendInfo(String userName, String message){ Session session = sessionPools.get(userName); try { sendMessage(session, message); }catch (Exception e){ e.printStackTrace(); } } @OnOpen public void onOpen(@PathParam("info") String info, Session session) { Map<String,String> obj = decodeInfo(info); if(obj != null) { sessionPools.put(obj.get("name"), session); addOnlineCount(); System.out.println(obj.get("name") + "加入webSocket!当前人数为" + onlineNum); Gson gson = new Gson(); String message = gson.toJson(new MapBean("cmd","openConnect","name",obj.get("name"),"onlineNum",onlineNum)); //向所有客户端发送消息 for( String userName : sessionPools.keySet()) { Session sess = sessionPools.get(userName); sendMessage(sess, message); } } } @OnMessage public void onMessage(String message) { String str = "客户端发送:" + message + ",服务端已收到"; // Gson gson = new Gson(); // Map result = gson.fromJson(message, HashMap.class); //向所有登录的人发送消息 for (Session session: sessionPools.values()) { sendMessage(session, message); } } @OnClose public void onClose(@PathParam("info") String info) { Map<String,String> obj = decodeInfo(info); if(obj != null) { sessionPools.remove(obj.get("name")); subOnlineCount(); System.out.println(obj.get("name") + "断开webSocket连接!当前人数为" + onlineNum); Gson gson = new Gson(); String message = gson.toJson(new MapBean("cmd","closeConnect","name",obj.get("name"),"onlineNum",onlineNum)); //向所有客户端发送消息 for (Session session: sessionPools.values()) { sendMessage(session, message); } } } @OnError public void onError(Throwable error) { error.printStackTrace(); } public static void addOnlineCount(){ onlineNum.incrementAndGet(); } public static void subOnlineCount() { onlineNum.decrementAndGet(); } private Map decodeInfo(String info) { Map infoObj = null; try { String base64Decryption = EncryptionUtils.base64Decryption(info); String decode = URLDecoder.decode(base64Decryption, "UTF-8"); Gson gson = new Gson(); infoObj = gson.fromJson(decode, HashMap.class); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } return infoObj; } }

    前端

    <style> .bodyDiv{ width: 100%; height: 100%; } .contentShow { height: 500px; width: 500px; overflow: scroll } .connectDiv { width: 100%; text-align: center; } .msgDiv { padding: 5px; } .msgSpan { border: 1px Solid #000; padding: 2px; border-radius: 5px; width: 400px; } </style> <script> var ws; var name; /** * 创建连接对象 */ function startConnect(){ if(typeof(WebSocket) != "undefined") { name = document.getElementById("nameText").value; document.getElementById("nameText").readOnly = true; document.getElementById("startBtn").style.display = "none"; document.getElementById("endBtn").style.display = "block"; if(ws){ ws.close(); } var info = { name: name }; var encode = window.btoa(encodeURIComponent(JSON.stringify(info))); ws = new WebSocket('ws://localhost:9090/websocket/' + encode); //打开事件 ws.onopen = function() { console.log("websocket已打开"); //socket.send("这是来自客户端的消息" + location.href + new Date()); }; //获得消息事件 ws.onmessage = function(msg) { var result = JSON.parse(msg.data); if(result.cmd == 'openConnect') { //连接建立 var div = document.createElement('div'); div.className = "connectDiv"; div.innerHTML = result.name + " 进入链接"; document.getElementById("contentDiv").appendChild(div); } else if(result.cmd == 'closeConnect') { var div = document.createElement('div'); div.className = "connectDiv"; div.innerHTML = result.name + " 关闭链接"; document.getElementById("contentDiv").appendChild(div); } else if(result.cmd == 'sendMsg') { var div1 = document.createElement('div'); div1.setAttribute("style", "width: 100%;height: 40px;"); var div = document.createElement('div'); div.className = "msgDiv"; var span1 = document.createElement('span'); var span2 = document.createElement('span'); if(name === result.name) { //自己发的 div.setAttribute("style", "float: right;"); span1.className="msgSpan"; span1.innerHTML = result.content; span2.innerHTML = result.name; } else { div.setAttribute("style", "float: left;"); span1.innerHTML = result.name; span2.className="msgSpan"; span2.innerHTML = result.content; } div.appendChild(span1); div.appendChild(span2); div1.appendChild(div); document.getElementById("contentDiv").appendChild(div1); } }; //关闭事件 ws.onclose = function() { console.log("websocket已关闭"); }; //发生了错误事件 ws.onerror = function() { console.log("websocket发生了错误"); } } } /** * 连接关闭 */ function endConnect(){ if(typeof(WebSocket) != "undefined") { if(ws){ ws.close(); document.getElementById("nameText").readOnly = false; document.getElementById("startBtn").style.display = "block"; document.getElementById("endBtn").style.display = "none"; name = document.getElementById('nameText').value; } } } /** * 发送消息 */ function sendMessage(){ if(typeof(WebSocket) != "undefined") { // console.log("您的浏览器支持WebSocket"); if(name && ws){ var contentText = document.getElementById('contentText').value; var msg = '{"cmd":"sendMsg","name":"'+name+'","content":"'+contentText+'"}'; ws.send(msg); document.getElementById('contentText').value = ""; } } } </script> <body> <div class="bodyDiv"> <table align="center" border="1px" cellpadding="10" cellspacing="0"> <tr> <td colspan="2">姓名: <input type="text" id="nameText" name="name"/> </td> <td> <input type="button" id="startBtn" onclick="startConnect()" value="确定"/> <input type="button" id="endBtn" style="display: none;" onclick="endConnect()" value="注销"/> </td> </tr> <tr> <td colspan="3"> <div id="contentDiv" class="contentShow"> <!-- <div class="connectDiv"><span>张三 进入链接</span></div> <div class="msgDiv"><span>张三&nbsp;&nbsp;<span><span class="msgSpan">你好</span></div> <div class="msgDiv"><span>李四&nbsp;&nbsp;<span><span class="msgSpan">你好</span></div> <div class="msgDiv" style="float: right;"><span class="msgSpan">你好</span><span>&nbsp;&nbsp;李四<span></span></div> --> </div> </td> </tr> <tr> <td colspan="2">内容: <input type="text" id="contentText" name="content"/> </td> <td> <input type="button" onclick="sendMessage()" value="发送"/> </td> </tr> </table> </div> </body>

    页面

    Processed: 0.030, SQL: 9