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

(图片来源网络,侵删)
- 技术栈选择:解释为什么选择这些技术。
- 项目结构:清晰展示文件组织。
- 核心源码:提供关键部分(服务器端和客户端)的完整、可读的代码。
- 运行步骤:手把手教你如何启动和测试。
技术栈选择
对于一个教学和入门级的即时通讯项目,我们选择以下成熟且易于理解的技术组合:
- 后端:
- 框架: 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的配置文件。

(图片来源网络,侵删)
# 服务器端口 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。

(图片来源网络,侵删)
<!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;
}
运行步骤
-
环境准备:
- 确保你已经安装了 JDK 11 或更高版本。
- 确保你已经安装了 Maven。
-
创建项目:
- 你可以直接复制上面的代码,手动创建文件和目录结构。
- 更推荐的方式: 使用 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
- Group:
- Dependencies:
- 点击 "ADD DEPENDENCIES",搜索并添加 Spring Web, Spring WebSocket, Thymeleaf。
- 点击 "GENERATE" 下载项目 zip 文件,然后解压。
-
添加源码:
- 将上面提供的
ChatWebSocketHandler.java,Message.java,ChatController.java复制到src/main/java/com/example/im/对应的子目录下。 - 将
index.html,chat.js,style.css复制到src/main/resources/对应的目录下。 - 确保
pom.xml和application.properties的内容与上面提供的一致。
- 将上面提供的
-
启动应用:
- 在项目根目录(
instant-messaging-app/)下,打开命令行/终端。 - 运行以下Maven命令来启动Spring Boot应用:
mvn spring-boot:run
- 等待看到类似
Started InstantMessagingAppApplication in X.XXX seconds (JVM running for Y.YYY)的日志,说明启动成功。
- 在项目根目录(
-
测试:
- 打开你的浏览器(推荐使用 Chrome 或 Firefox)。
- 访问
http://localhost:8080,你应该能看到一个聊天室界面。 - 打开两个或更多浏览器窗口或标签页,都访问
http://localhost:8080。 - 在一个窗口的输入框中输入消息,点击 "Send"。
- 你会立刻在所有打开的窗口的聊天区域看到这条消息。
总结与进阶方向
这个项目为你提供了一个功能完整的即时通讯基础框架,你可以基于此进行扩展:
- 用户认证与授权: 目前所有用户都是匿名的 "User",可以集成 Spring Security,实现用户登录,并在
Message模型中记录真实的发送者。 - 持久化存储: 目前消息只存在于内存中,重启后丢失,可以集成 MySQL 或 PostgreSQL 数据库,使用 Spring Data JPA 或 MyBatis 将消息保存到数据库中。
- 点对点聊天: 目前的实现是广播(群聊),你可以修改
ChatWebSocketHandler,增加@ServerEndpoint的路径参数(如/chat/{userId}),实现用户之间的私聊。 - 更丰富的功能: 添加表情包、文件传输、在线用户列表、消息历史记录等功能。
- 前端框架升级: 使用 Vue.js 或 React 重写前端,以获得更丰富的交互体验和组件化开发能力。
希望这个详细的示例能帮助你理解Java Web版即时通讯的核心原理和实现方式!
