随着互联网的发展,多人在线聊天室成为了一个热门的应用场景。WebSocket是一种在单个TCP连接上进行全双工通信的方式,它可以实现实时的双向通信,因此在开发多人在线聊天室时常用到。在本文中,我们将介绍如何使用Spring Boot搭建一个基于WebSocket的多人聊天室。

一、环境搭建

在开始之前,需要安装以下环境:

二、创建项目

选择一个空的Spring Boot项目,在pom.xml文件中添加以下依赖:

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

三、编写Java程序

  1. 创建WebSocketConfig类

在项目的src/main/java目录下创建一个名为WebSocketConfig的Java类,并添加@EnableWebSocket注解,表示启用WebSocket。代码如下:

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
 
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(chatRoomHandler(),"/chatRoom").withSockJS();
    }
 
    @Bean
    public ChatRoomHandler chatRoomHandler() {
        return new ChatRoomHandler();
    }
}

registerWebSocketHandlers方法用于注册WebSocket处理程序,这里我们使用ChatRoomHandler作为处理程序,并将它映射到/chatRoom路径上。withSockJS()方法表示启用SockJS支持。

  1. 创建ChatRoomMessage类

在项目的src/main/java目录下创建一个名为ChatRoomMessage的Java类,用于表示聊天室中的消息。代码如下:

public class ChatRoomMessage {
    private String content;
    private String sender;
    private MessageType type;
 
    // 省略getter和setter方法
}

ChatRoomMessage中有三个字段,分别表示消息的内容、发送者和消息类型。MessageType是自定义的枚举类型,表示消息类型。

  1. 创建ChatRoomHandler类

在项目的src/main/java目录下创建一个名为ChatRoomHandler的Java类,用于处理WebSocket连接和消息的发送和接收。代码如下:

@Component
public class ChatRoomHandler extends TextWebSocketHandler {
 
    // 保存WebSocketSession列表
    private static List<WebSocketSession> webSocketSessions = new CopyOnWriteArrayList<>();
 
    // 处理WebSocket连接建立事件
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        webSocketSessions.add(session);
    }
 
    // 处理WebSocket连接关闭事件
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        webSocketSessions.remove(session);
    }
 
    // 处理WebSocket消息接收事件
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        ChatRoomMessage chatRoomMessage = new ObjectMapper().readValue(message.getPayload(), ChatRoomMessage.class);
        chatRoomMessage.setSender(session.getId());
        broadcast(chatRoomMessage);
    }
 
    // 广播消息给所有WebSocketSession
    private void broadcast(ChatRoomMessage chatRoomMessage) throws IOException {
        for (WebSocketSession webSocketSession : webSocketSessions) {
            webSocketSession.sendMessage(new TextMessage(new ObjectMapper().writeValueAsString(chatRoomMessage)));
        }
    }
}

ChatRoomHandler继承自TextWebSocketHandler,处理文本格式的WebSocket消息。在类中定义了一个静态的webSocketSessions列表,用于保存所有的WebSocketSession。在WebSocket连接建立时,将新的WebSocketSession加入webSocketSessions列表中,在WebSocket连接关闭时,将WebSocketSession从webSocketSessions列表中移除。在WebSocket消息接收时,将消息转换为ChatRoomMessage对象,并设置发送者为WebSocketSession的ID,并调用broadcast方法将消息广播给所有的WebSocketSession。

  1. 创建ChatRoomController类

在项目的src/main/java目录下创建一个名为ChatRoomController的Java类,用于处理聊天室页面的渲染和消息的发送。代码如下:

@Controller
public class ChatRoomController {
 
    @GetMapping("/chatRoom")
    public String chatRoom() {
        return "chatRoom";
    }
 
    @MessageMapping("/sendMessage")
    @SendTo("/topic/chatRoom")
    public ChatRoomMessage sendMessage(ChatRoomMessage chatRoomMessage) {
        return chatRoomMessage;
    }
}

ChatRoomController定义了一个映射到/chatRoom路径上的GET请求,返回聊天室的页面。同时,它还定义了一个映射到/sendMessage路径上的WebSocket消息,使用@SendTo注解将消息发送到/topic/chatRoom路径上。

  1. 创建Thymeleaf模板

在项目的src/main/resources/templates目录下创建一个名为chatRoom.html的Thymeleaf模板,用于渲染聊天室页面。

<!DOCTYPE html>
<html>
<head>
    <title>Spring Boot WebSocket Chat Room</title>
    <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
 
<div id="app">
    <h1>Spring Boot WebSocket Chat Room</h1>
 
    <div>
        <label>Username:</label>
        <input type="text" v-model="username"/>
        <button v-on:click="login()">Login</button>
    </div>
 
    <div v-if="loggedIn">
        <hr/>
        <div v-for="message in messages">
            <span v-html="message.sender + ': '"></span>
            <span v-html="message.content"></span>
        </div>
        <hr/>
        <div>
            <input type="text" v-model="message"/>
            <button v-on:click="sendMessage()">Send</button>
        </div>
    </div>
</div>
 
<script>
    var app = new Vue({
        el: '#app',
        data: {
            username: '',
            messages: [],
            message: '',
            loggedIn: false,
            stompClient: null
        },
        methods: {
            login: function () {
                var _this = this;
                var socket = new SockJS('/chatRoom');
                this.stompClient = Stomp.over(socket);
                this.stompClient.connect({}, function (frame) {
                    console.log('Connected:', frame);
                    _this.stompClient.subscribe('/topic/chatRoom', function (payload) {
                        var message = JSON.parse(payload.body);
                        _this.messages.push(message);
                    });
                });
                this.loggedIn = true;
            },
            sendMessage: function () {
                var chatRoomMessage = {
                    content: this.message,
                    sender: this.username,
                    type: 'CHAT'
                };
                this.stompClient.send('/app/sendMessage', {}, JSON.stringify(chatRoomMessage));
                this.message = '';
            }
        }
    });
</script>
 
</body>
</html>

Thymeleaf模板中包含了一个Vue组件,用于渲染聊天室页面。同时,它还包含了Stomp.js和SockJS的引用,用于建立WebSocket连接和发送和接收消息。

四、运行程序

在IDE中运行程序,访问http://localhost:8080/chatRoom,进入聊天室页面。输入用户名并点击“Login”按钮,即可进入聊天室。在输入框中输入消息并点击“Send”按钮,即可发送消息。

五、总结

本文介绍了如何使用Spring Boot搭建一个基于WebSocket的多人聊天室。通过WebSocket的双向通信特性,可以实现实时交流,为多人在线聊天室应用提供了很大的便利。