springboot+websocket即时聊天

本文介绍如何使用Spring Boot实现WebSocket聊天室,包括依赖配置、WebSocket配置、服务端代码、前端页面设计及SocketEntity实体类。通过具体代码示例,详细展示了如何搭建一个多用户聊天室,支持用户在线状态显示及消息广播。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>

2.WebSocket配置


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * WebSocket 配置
 */
@Configuration
@EnableWebSocket
public class WebSocketStompConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter()
    {
        return new ServerEndpointExporter();
    }

}

3.websocket服务

package com.cq.zxgytx.runing.controller.websoket;

import com.cq.zxgytx.runing.entity.SocketEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.HashSet;
import java.util.Set;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Component
@ServerEndpoint("/webSocket/chat/{roomId}/{userId}")
public class WsServer {

    // 使用map来收集session,key为roomId,value为同一个房间的用户集合
    // concurrentMap的key不存在时报错,不是返回null
    private static final Map<String, Set<SocketEntity>> websockets = new ConcurrentHashMap();


    @OnOpen
    public void connect(@PathParam("roomId") String roomId,@PathParam("userId") String userId, Session session) throws Exception {
        // 将session按照房间名来存储,将各个房间的用户隔离
        if (!websockets.containsKey(roomId)) {
            // 创建房间不存在时,创建房间
            Set<SocketEntity> set = new HashSet<>();
            // 添加用户
            SocketEntity socket1=new SocketEntity();
            socket1.setSession(session).setUserId(userId);
            set.add(socket1);
            websockets.put(roomId, set);
            //messageType 1代表上线 2代表下线 3代表在线名单 4代表普通消息
            //先给所有人发送通知,说我上线了
            broadcast(roomId,userId+"上线了");
        } else {
            // 添加用户
            SocketEntity socket=new SocketEntity();
            socket.setSession(session).setUserId(userId);
            // 房间已存在,直接添加用户到相应的房间
            websockets.get(roomId).add(socket);
            broadcast(roomId,userId+"上线了");
        }
        log.info(userId+"加入房间--"+roomId+"! 当前在线人数" + websockets.get(roomId).size());
    }

    /**
     * 关闭聊天房间
     * @param roomId
     * @param userId
     */
    @OnClose
    public void disConnect(@PathParam("roomId") String roomId,@PathParam("userId") String userId) throws Exception {
        removeUser(roomId,userId);
        broadcast(roomId,userId+"下线了");
        log.info(userId+"退出房间--"+roomId+"! 当前在线人数" + websockets.get(roomId).size());
        if(websockets.get(roomId).size()<1){//房间中没有用户了 关闭房间
            websockets.remove(roomId);
            log.info("房间"+roomId+"关闭");
        }
    }

    @OnMessage
    public void receiveMsg(@PathParam("roomId") String roomId,@PathParam("userId") String userId,
                           String msg, Session session) throws Exception {
        // 此处应该有html过滤
        msg = session.getId() +userId+ ":" + msg;
        log.info(msg);
        // 接收到信息后进行广播
        broadcast(roomId, msg);
    }

    // 按照房间名进行广播
    public static void broadcast(String roomId, String msg) throws Exception {
        for (SocketEntity socketEntity : websockets.get(roomId)) {
            socketEntity.getSession().getBasicRemote().sendText(msg);
        }
    }

    /**
     * 删除用户
     * @param userId
     */
    private void removeUser(@PathParam("roomId") String roomId,@PathParam("userId") String userId) {
        Set<SocketEntity> set=websockets.get(roomId);
        SocketEntity entity = getUserEntity(roomId,userId);
        set.remove(entity);
    }

    /**
     * 获取用户
     * @param userId
     * @return
     */
    private static SocketEntity getUserEntity(String roomId,String userId) {
        SocketEntity entity = null;
        if (websockets.size() == 0) {
            return entity;
        }
        for (SocketEntity socketEntity : websockets.get(roomId)) {
            if (socketEntity.getUserId().contentEquals(userId)) {
                entity = socketEntity;
                break;
            }
        }
        return entity;
    }
}

4.SocketEntity

import lombok.Data;
import lombok.experimental.Accessors;

import javax.websocket.Session;
import java.io.Serializable;

/**
 * socket 实体类
 */
@Accessors(chain=true)
@Data
public class SocketEntity implements Serializable {

    private String userId;//用户id
    private Session session;

}

5.前端room.html

<!DOCTYPE html><html lang="en">
<head>
    <meta charset="UTF-8">
    <title>网络聊天室</title>
</head>
<style type="text/css">
    .msg_board {
        width: 322px;
        height: 100px;
        border: solid 1px darkcyan;
        padding: 5px;
        overflow-y: scroll;
    // 文字长度大于div宽度时换行显示
    word-break: break-all;
    }
    /*set srcoll start*/
    ::-webkit-scrollbar
    {
        width: 10px;
        height: 10px;
        background-color: #D6F2FD;
    }
    ::-webkit-scrollbar-track
    {
        -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
        /*border-radius: 5px;*/
        background-color: #D6F2FD;
    }
    ::-webkit-scrollbar-thumb
    {
        height: 20px;
        /*border-radius: 10px;*/
        -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);
        background-color: #89D7F7;
    }
    /*set srcoll end*/
</style>
<body>
<label>房间ID</label>
<input id="input_roomName" size="10" maxlength="10"><br/>
<label>用户ID</label>
<input id="input_userName" size="10" maxlength="10">
<button type="submit" id="join">进入聊天室</button>
<button type="submit" id="out">退出聊天室</button><br>
<div class="msg_board"></div>
<input id="input_msg" size="43" maxlength="40">
<button type="submit" id="send">发送</button>
</body>
<script src="js/jquery-1.9.1.min.js"/>
<script src="js/swiper.min.js"></script>
<script type="text/javascript">
    var webSocket;

   $("#send").click( function send_msg() {
        if (webSocket != null) {
            var input_msg = document.getElementById("input_msg").value.trim();
            if (input_msg == "") {
                return;
            }
            webSocket.send(input_msg);
            // 清除input框里的信息
            document.getElementById("input_msg").value = "";
        } else {
            alert("您已掉线,请重新进入聊天室...");
        }
    });

    $("#out").click(function closeWs() {
        webSocket.close();
    });

    $("#join").click(function initWebSocket() {
        var roomId = document.getElementById("input_roomName").value;
        var userId = document.getElementById("input_userName").value;
        // 房间名不能为空
        if (roomId == null || roomId == "") {
            alert("请输入房间ID");
            return;
        }
        if (userId == null || userId == "") {
            alert("请输入用户ID");
            return;
        }
        if ("WebSocket" in window) {
//            alert("您的浏览器支持 WebSocket!");
            if (webSocket == null) {
                var url = "ws://localhost:8001/webSocket/chat/" + roomId+"/"+userId;
                // 打开一个 web socket
                webSocket = new WebSocket(url);
            } else {
                alert("您已进入聊天室...");
            }

            webSocket.onopen = function () {
                alert("已进入聊天室,畅聊吧...");
            };

            webSocket.onmessage = function (evt) {
                var received_msg = evt.data;
                console.log("数据已接收:" +received_msg);
                var obj = received_msg;
                setMessageInnerHTML(obj);
            };

            webSocket.onclose = function () {
                // 关闭 websocket,清空信息板
                alert("连接已关闭...");
                webSocket = null;
                document.getElementsByClassName("msg_board")[0].innerHTML = "";
            };
        }
        else {
            // 浏览器不支持 WebSocket
            alert("您的浏览器不支持 WebSocket!");
        }
    })
    //将消息显示在网页上
    function setMessageInnerHTML(innerHTML) {
        var msg_board=document.getElementsByClassName("msg_board")[0];
        msg_board.innerHTML += innerHTML + '<br/>';
        // 让滚动块往下移动
        msg_board.scrollTop = msg_board.scrollTop + 40;
    }
</script>
</html>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值