我可以为你提供一个非常详细、分步、可直接运行的Java Web版即时通讯项目示例,这个示例将包含:

java网页版即时通讯源码
(图片来源网络,侵删)
  1. 技术栈选择:解释为什么选择这些技术。
  2. 项目结构:清晰展示文件组织。
  3. 核心源码:提供关键部分(服务器端和客户端)的完整、可读的代码。
  4. 运行步骤:手把手教你如何启动和测试。

技术栈选择

对于一个教学和入门级的即时通讯项目,我们选择以下成熟且易于理解的技术组合:

  • 后端:
    • 框架: Spring Boot - 极大地简化了Java Web应用的配置和开发。
    • Web容器: Tomcat (内嵌在Spring Boot中)。
    • 通信协议: WebSocket - 这是实现服务端与客户端全双工(双向)实时通信的最佳技术,比传统的轮询效率高得多。
    • JSON处理: Jackson (Spring Boot默认集成) - 用于客户端和服务器端之间数据的序列化和反序列化。
  • 前端:
    • 核心: 原生 JavaScript - 不依赖任何前端框架(如Vue, React),让你能更专注于WebSocket通信的核心逻辑。
    • UI: Bootstrap - 提供一个简洁、美观的聊天界面。
  • 数据库:
    • H2 Database - 一个轻量级的内存数据库,非常适合演示和快速原型开发,数据在应用重启后会丢失,但足以演示功能。

项目结构

我们将创建一个标准的Maven项目,结构如下:

instant-messaging-app/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/
│   │   │       └── example/
│   │   │           └── im/
│   │   │               ├── controller/
│   │   │               │   └── ChatController.java      // 处理HTTP请求,返回聊天页面
│   │   │               ├── model/
│   │   │               │   └── Message.java             // 消息实体类
│   │   │               ├── repository/
│   │   │               │   └── MessageRepository.java    // 模拟消息存储
│   │   │               └── websocket/
│   │   │                   └── ChatWebSocketHandler.java // WebSocket核心处理器
│   │   ├── resources/
│   │   │   ├── static/
│   │   │   │   ├── css/
│   │   │   │   │   └── style.css                       // 自定义样式
│   │   │   │   └── js/
│   │   │   │       └── chat.js                          // 前端JavaScript逻辑
│   │   │   ├── templates/
│   │   │   │   └── index.html                          // 聊天页面
│   │   │   └── application.properties                  // Spring Boot配置文件
│   │   └── ...
│   └── test/
├── pom.xml                                              // Maven依赖管理文件

核心源码

1 后端源码

pom.xml

这是项目的依赖文件,定义了我们需要的所有库。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.5</version> <!-- 使用一个稳定的Spring Boot版本 -->
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>instant-messaging-app</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>instant-messaging-app</name>
    <description>Instant Messaging App for Web</description>
    <properties>
        <java.version>11</java.version>
    </properties>
    <dependencies>
        <!-- Spring Boot WebSocket支持 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <!-- Spring Boot Thymeleaf模板引擎 (用于渲染HTML) -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!-- Spring Boot Test (用于单元测试) -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

src/main/resources/application.properties

Spring Boot的配置文件。

java网页版即时通讯源码
(图片来源网络,侵删)
# 服务器端口
server.port=8080
# 禁用Thymeleaf缓存,方便开发时实时修改页面
spring.thymeleaf.cache=false

src/main/java/com/example/im/model/Message.java

消息的数据模型。

package com.example.im.model;
import java.util.Date;
public class Message {
    private String from;     // 发送者
    private String text;     // 消息内容
    private Date timestamp; // 时间戳
    public Message() {
        this.timestamp = new Date();
    }
    public Message(String from, String text) {
        this();
        this.from = from;
        this.text = text;
    }
    // Getters and Setters
    public String getFrom() { return from; }
    public void setFrom(String from) { this.from = from; }
    public String getText() { return text; }
    public void setText(String text) { this.text = text; }
    public Date getTimestamp() { return timestamp; }
    public void setTimestamp(Date timestamp) { this.timestamp = timestamp; }
}

src/main/java/com/example/im/websocket/ChatWebSocketHandler.java

这是后端的核心!它处理所有的WebSocket连接、消息接收和发送。

package com.example.im.websocket;
import com.example.im.model.Message;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArrayList; // 线程安全的List
@Component
public class ChatWebSocketHandler extends TextWebSocketHandler {
    // 存储所有连接的WebSocket会话
    private static final CopyOnWriteArrayList<WebSocketSession> sessions = new CopyOnWriteArrayList<>();
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        // 当有新的用户连接时,将其加入会话列表
        sessions.add(session);
        System.out.println("New connection established: " + session.getId());
    }
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        // 收到客户端发来的消息
        String payload = message.getPayload();
        System.out.println("Received message from " + session.getId() + ": " + payload);
        try {
            // 将JSON字符串反序列化为Message对象
            ObjectMapper mapper = new ObjectMapper();
            Message msg = mapper.readValue(payload, Message.class);
            // 将消息广播给所有连接的客户端
            broadcast(msg);
        } catch (Exception e) {
            System.err.println("Error processing message: " + e.getMessage());
        }
    }
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        // 当用户断开连接时,将其从会话列表中移除
        sessions.remove(session);
        System.out.println("Connection closed: " + session.getId());
    }
    /**
     * 广播消息给所有在线用户
     * @param message 要广播的消息对象
     */
    private void broadcast(Message message) {
        // 将Message对象序列化为JSON字符串
        ObjectMapper mapper = new ObjectMapper();
        String jsonMessage;
        try {
            jsonMessage = mapper.writeValueAsString(message);
        } catch (Exception e) {
            System.err.println("Error serializing message: " + e.getMessage());
            return;
        }
        // 遍历所有会话,并发送消息
        for (WebSocketSession session : sessions) {
            try {
                if (session.isOpen()) {
                    session.sendMessage(new TextMessage(jsonMessage));
                }
            } catch (IOException e) {
                System.err.println("Error sending message to session " + session.getId() + ": " + e.getMessage());
                // 如果发送失败,可能连接已断开,可以将其移除
                sessions.remove(session);
            }
        }
    }
}

src/main/java/com/example/im/controller/ChatController.java

一个简单的控制器,用于访问聊天页面。

package com.example.im.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class ChatController {
    @GetMapping("/")
    public String chat() {
        return "index"; // 返回 templates/index.html
    }
}

2 前端源码

src/main/resources/templates/index.html

聊天室的UI界面,使用了Bootstrap和Thymeleaf。

java网页版即时通讯源码
(图片来源网络,侵删)
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">Java WebSocket Chat</title>
    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" th:href="@{/css/style.css}">
</head>
<body>
<div class="container mt-5">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header bg-primary text-white">
                    <h4 class="mb-0">Java WebSocket Chat Room</h4>
                </div>
                <div class="card-body p-0">
                    <!-- 聊天消息显示区域 -->
                    <div id="messageArea" class="chat-messages p-3" style="height: 400px; overflow-y: auto;">
                        <!-- 消息将在这里动态显示 -->
                    </div>
                </div>
                <div class="card-footer p-3">
                    <form id="messageForm">
                        <div class="input-group">
                            <input type="text" id="messageInput" class="form-control" placeholder="Type a message..." autocomplete="off">
                            <button class="btn btn-primary" type="submit">Send</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
<!-- Bootstrap JS and Popper.js -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<!-- 自定义JS -->
<script th:src="@{/js/chat.js}"></script>
</body>
</html>

src/main/resources/static/js/chat.js

这是前端的核心!它负责建立WebSocket连接、发送消息和接收消息。

document.addEventListener('DOMContentLoaded', function () {
    // 1. 获取DOM元素
    const messageForm = document.getElementById('messageForm');
    const messageInput = document.getElementById('messageInput');
    const messageArea = document.getElementById('messageArea');
    // 2. 创建WebSocket连接
    // 注意:ws:// 是WebSocket协议,http://是HTTP协议
    // window.location.host 可以获取当前服务器的地址和端口 ( localhost:8080)
    const socket = new WebSocket('ws://' + window.location.host + '/chat');
    // 3. WebSocket事件处理
    // 连接成功时触发
    socket.onopen = function (event) {
        console.log('WebSocket connection established.');
        addSystemMessage('You have connected to the chat room.');
    };
    // 收到消息时触发
    socket.onmessage = function (event) {
        console.log('Message received from server:', event.data);
        const message = JSON.parse(event.data);
        displayMessage(message);
    };
    // 连接关闭时触发
    socket.onclose = function (event) {
        if (event.wasClean) {
            console.log(`Connection closed cleanly, code=${event.code} reason=${event.reason}`);
        } else {
            console.error('Connection died unexpectedly.');
        }
        addSystemMessage('You have been disconnected from the chat room.');
    };
    // 发生错误时触发
    socket.onerror = function (error) {
        console.error('WebSocket Error:', error);
        addSystemMessage('An error occurred with the WebSocket connection.');
    };
    // 4. 表单提交处理
    messageForm.addEventListener('submit', function (event) {
        event.preventDefault(); // 阻止表单默认的提交行为(页面刷新)
        const messageText = messageInput.value.trim();
        if (messageText) {
            // 创建要发送的消息对象
            const message = {
                from: 'User', // 在实际应用中,这里应该是登录用户的用户名
                text: messageText,
                timestamp: new Date().toISOString()
            };
            // 将消息对象转换为JSON字符串并发送
            socket.send(JSON.stringify(message));
            // 清空输入框
            messageInput.value = '';
            messageInput.focus();
        }
    });
    // 5. 辅助函数
    // 在聊天区域显示消息
    function displayMessage(message) {
        const messageElement = document.createElement('div');
        messageElement.classList.add('mb-2');
        const fromElement = document.createElement('strong');
        fromElement.textContent = message.from + ': ';
        const textElement = document.createElement('span');
        textElement.textContent = message.text;
        messageElement.appendChild(fromElement);
        messageElement.appendChild(textElement);
        messageArea.appendChild(messageElement);
        messageArea.scrollTop = messageArea.scrollHeight; // 自动滚动到底部
    }
    // 显示系统消息(非用户消息)
    function addSystemMessage(text) {
        const messageElement = document.createElement('div');
        messageElement.classList.add('mb-2', 'text-muted', 'text-center');
        messageElement.textContent = text;
        messageArea.appendChild(messageElement);
        messageArea.scrollTop = messageArea.scrollHeight;
    }
});

src/main/resources/static/css/style.css (可选)

一些简单的样式美化。

.chat-messages {
    background-color: #f8f9fa;
    border: 1px solid #dee2e6;
    border-radius: 0.25rem;
}

运行步骤

  1. 环境准备:

    • 确保你已经安装了 JDK 11 或更高版本。
    • 确保你已经安装了 Maven
  2. 创建项目:

    • 你可以直接复制上面的代码,手动创建文件和目录结构。
    • 更推荐的方式: 使用 Spring Initializr (https://start.spring.io/) 来生成项目骨架。
      • Project: Maven Project
      • Language: Java
      • Spring Boot: 选择一个稳定版本 (如2.7.x)
      • Project Metadata:
        • Group: com.example
        • Artifact: instant-messaging-app
        • Name: instant-messaging-app
        • Packaging: Jar
        • Java: 11
      • Dependencies:
        • 点击 "ADD DEPENDENCIES",搜索并添加 Spring Web, Spring WebSocket, Thymeleaf
      • 点击 "GENERATE" 下载项目 zip 文件,然后解压。
  3. 添加源码:

    • 将上面提供的 ChatWebSocketHandler.java, Message.java, ChatController.java 复制到 src/main/java/com/example/im/ 对应的子目录下。
    • index.html, chat.js, style.css 复制到 src/main/resources/ 对应的目录下。
    • 确保 pom.xmlapplication.properties 的内容与上面提供的一致。
  4. 启动应用:

    • 在项目根目录(instant-messaging-app/)下,打开命令行/终端。
    • 运行以下Maven命令来启动Spring Boot应用:
      mvn spring-boot:run
    • 等待看到类似 Started InstantMessagingAppApplication in X.XXX seconds (JVM running for Y.YYY) 的日志,说明启动成功。
  5. 测试:

    • 打开你的浏览器(推荐使用 Chrome 或 Firefox)。
    • 访问 http://localhost:8080,你应该能看到一个聊天室界面。
    • 打开两个或更多浏览器窗口或标签页,都访问 http://localhost:8080
    • 在一个窗口的输入框中输入消息,点击 "Send"。
    • 你会立刻在所有打开的窗口的聊天区域看到这条消息。

总结与进阶方向

这个项目为你提供了一个功能完整的即时通讯基础框架,你可以基于此进行扩展:

  • 用户认证与授权: 目前所有用户都是匿名的 "User",可以集成 Spring Security,实现用户登录,并在 Message 模型中记录真实的发送者。
  • 持久化存储: 目前消息只存在于内存中,重启后丢失,可以集成 MySQLPostgreSQL 数据库,使用 Spring Data JPAMyBatis 将消息保存到数据库中。
  • 点对点聊天: 目前的实现是广播(群聊),你可以修改 ChatWebSocketHandler,增加 @ServerEndpoint 的路径参数(如 /chat/{userId}),实现用户之间的私聊。
  • 更丰富的功能: 添加表情包、文件传输、在线用户列表、消息历史记录等功能。
  • 前端框架升级: 使用 Vue.jsReact 重写前端,以获得更丰富的交互体验和组件化开发能力。

希望这个详细的示例能帮助你理解Java Web版即时通讯的核心原理和实现方式!