1. SpringBoot网络聊天系统设计与实现
最近在整理技术笔记时,翻到一个去年做的SpringBoot网络聊天系统项目。这个系统虽然不算复杂,但完整实现了用户注册、好友管理、实时聊天等核心功能,还整合了WebSocket协议实现消息推送。今天就把这个项目的技术实现细节和踩过的坑完整分享出来,源码已经放在文末(提取码44665),需要的朋友可以直接拿去参考。
这个系统特别适合刚学完SpringBoot基础想找项目练手的同学,也适合需要快速搭建内部通讯工具的中小团队。用SpringBoot做聊天系统有个明显优势 - 你不需要像传统JavaEE项目那样配置一大堆XML,基本上一个main类加几个注解就能跑起来。下面我会从技术选型、核心实现到部署上线,把每个环节的要点都讲清楚。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构解析
2.1 整体技术栈
先看下项目的主要技术组件:
- 后端框架:SpringBoot 2.7.x(选择这个版本是因为它长期支持)
- 前端模板:Thymeleaf + Bootstrap(避免前后端分离的复杂度)
- 实时通信:WebSocket + STOMP协议
- 数据库:MySQL 8.0 + MyBatis-Plus
- 安全控制:Spring Security
- 辅助工具:Lombok、Hutool
这里有个选型细节:为什么用STOMP而不是原生WebSocket?因为STOMP在WebSocket之上提供了消息格式规范,相当于HTTP之于TCP的关系。实际开发中处理订阅、广播这些场景会方便很多。
2.2 系统模块划分
项目按功能划分成这几个核心模块:
- 用户管理模块(注册/登录/个人信息)
- 好友关系模块(添加/删除/查询)
- 消息通信模块(单聊/群聊/历史记录)
- 系统通知模块(上线提醒等)
每个模块都遵循标准的MVC结构:
code复制com
└── chat
├── config # 配置类
├── controller # 控制器
├── entity # 实体类
├── mapper # MyBatis接口
├── service # 业务逻辑
└── util # 工具包
3. 核心功能实现
3.1 WebSocket配置
实时通信是聊天系统的核心,SpringBoot中配置WebSocket主要分三步:
首先在pom.xml添加依赖:
xml复制<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
然后创建WebSocket配置类:
java复制@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws-chat")
.setAllowedOrigins("*")
.withSockJS(); // 支持SockJS回退
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic", "/queue"); // 消息代理前缀
registry.setApplicationDestinationPrefixes("/app"); // 应用前缀
}
}
最后在Controller处理消息:
java复制@Controller
public class ChatController {
@MessageMapping("/chat.send")
@SendTo("/topic/public")
public ChatMessage sendMessage(@Payload ChatMessage message) {
return message;
}
}
踩坑提醒:生产环境一定要配置心跳检测!我们遇到过连接假死导致消息堆积的问题,后来通过下面配置解决:
java复制registry.setHeartbeatValue(new long[]{10000, 10000}); // 10秒心跳
3.2 用户上下线通知
实现用户上下线广播的关键是继承ApplicationListener:
java复制@Component
public class PresenceEventListener
implements ApplicationListener<SessionConnectEvent> {
@Autowired
private SimpMessagingTemplate messagingTemplate;
@Override
public void onApplicationEvent(SessionConnectEvent event) {
String username = event.getUser().getName();
messagingTemplate.convertAndSend("/topic/presence",
new ChatMessage("系统", username + "上线了"));
}
}
对应的前端订阅代码:
javascript复制function connect() {
var socket = new SockJS('/ws-chat');
stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
stompClient.subscribe('/topic/presence', function(message) {
showSystemMessage(JSON.parse(message.body));
});
});
}
3.3 消息存储设计
消息表的核心字段设计:
sql复制CREATE TABLE `chat_message` (
`id` bigint NOT NULL AUTO_INCREMENT,
`sender_id` bigint NOT NULL COMMENT '发送者ID',
`receiver_id` bigint NOT NULL COMMENT '接收者ID/群ID',
`content` text NOT NULL COMMENT '消息内容',
`content_type` tinyint DEFAULT 0 COMMENT '0文本 1图片 2文件',
`is_read` tinyint DEFAULT 0 COMMENT '是否已读',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_sender_receiver` (`sender_id`,`receiver_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
这里有几个优化点:
- 使用utf8mb4字符集支持emoji
- 联合索引加速消息查询
- 内容类型字段为未来扩展预留空间
4. 关键问题解决方案
4.1 消息可靠性保证
网络聊天最怕消息丢失,我们通过三级保障解决:
- 客户端消息确认机制
- 服务端消息持久化
- 定时任务补偿发送
核心补偿逻辑示例:
java复制@Scheduled(fixedDelay = 300000) // 5分钟检查一次
public void checkUnsentMessages() {
List<ChatMessage> unsent = messageMapper.selectUnsent();
unsent.forEach(msg -> {
messagingTemplate.convertAndSendToUser(
msg.getReceiverId().toString(),
"/queue/private",
msg
);
msg.setStatus(1);
messageMapper.updateById(msg);
});
}
4.2 大文件传输处理
直接通过WebSocket传大文件性能很差,我们的解决方案:
- 前端先上传文件到OSS
- 后端只传文件URL
- 接收方根据URL下载
关键代码片段:
java复制@PostMapping("/upload")
public Result uploadFile(@RequestParam("file") MultipartFile file) {
String fileName = UUID.randomUUID() +
file.getOriginalFilename().substring(
file.getOriginalFilename().lastIndexOf("."));
// 上传到阿里云OSS
ossClient.putObject(bucketName, fileName, file.getInputStream());
return Result.success(ossEndpoint + "/" + fileName);
}
5. 部署与优化
5.1 多环境配置
使用Spring Profiles管理不同环境配置:
yaml复制# application-dev.yml
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/chat_dev
# application-prod.yml
server:
port: 80
spring:
datasource:
url: jdbc:mysql://prod-db:3306/chat_prod
启动时指定profile:
bash复制java -jar chat-system.jar --spring.profiles.active=prod
5.2 Docker部署
生产环境推荐用Docker部署,这是我们的Dockerfile:
dockerfile复制FROM openjdk:8-jdk-alpine
VOLUME /tmp
COPY target/chat-system.jar app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
构建和运行命令:
bash复制docker build -t chat-system .
docker run -d -p 8080:8080 -e "SPRING_PROFILES_ACTIVE=prod" chat-system
6. 源码结构与使用说明
项目完整结构:
code复制chat-system
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── chat
│ │ │ ├── config # 配置类
│ │ │ ├── controller # 控制器
│ │ │ ├── entity # 实体类
│ │ │ ├── mapper # MyBatis接口
│ │ │ ├── service # 业务逻辑
│ │ │ └── util # 工具包
│ │ └── resources
│ │ ├── static # 静态资源
│ │ ├── templates # 页面模板
│ │ └── application.yml # 主配置
│ └── test # 测试代码
├── pom.xml # Maven配置
└── sql # 数据库脚本
启动步骤:
- 创建MySQL数据库并执行sql/init.sql
- 修改application.yml中的数据库配置
- 运行Application主类
- 访问http://localhost:8080
7. 常见问题排查
7.1 WebSocket连接失败
可能原因及解决方案:
- 跨域问题 - 检查@CrossOrigin配置
- SockJS版本不匹配 - 确保前后端版本一致
- 代理服务器未配置 - Nginx需要添加:
nginx复制location /ws-chat { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }
7.2 消息延迟高
优化建议:
- 检查心跳配置是否合理
- 考虑使用Redis作为消息代理
- 监控网络延迟:
java复制@Scheduled(fixedRate = 60000) public void monitorLatency() { long latency = System.currentTimeMillis() - lastMessageTime; if(latency > 5000) { log.warn("高延迟警告:{}ms", latency); } }
这个项目从技术实现上来说不算复杂,但涉及到了SpringBoot的多个核心功能点。我在开发过程中最大的体会是:WebSocket虽然强大,但在生产环境一定要做好断线重连和消息可靠性的保障。源码已经打包好,提取码44665,大家在使用过程中遇到任何问题都可以随时交流。
