ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

JavaWeb聊天室实战:Servlet+WebSocket+MySQL完整部署指南

2026/10/5 15:34:44 拓冰建站 浏览量
JavaWeb聊天室实战:Servlet+WebSocket+MySQL完整部署指南 简介这是一份面向Java Web初学者与全栈开发入门者的网络聊天室实战项目资源聚焦Web实时通信场景帮助学习者系统掌握前后端协同开发全流程。资源包含284个文件主体为42个jar包含Spring MVC、数据库驱动等依赖、14个js脚本含jQuery交互逻辑、10个css样式文件、5个xml配置文件及2个jsp页面辅以94个gif和93个png素材用于界面展示整体压缩包23.31MB结构清晰便于按模块理解MVC分层设计。已有219人学习下载内容覆盖HTML/CSS前端布局、jQuery事件处理、Servlet/ Spring MVC后端控制、MySQL数据存储、WebSocket或AJAX异步通信、Session用户状态管理及基础安全防护实践。从User.class实体类到UserLoginServlet.class、WebSocketTest.class等核心类再到ConnectionUtils.class等工具组件完整呈现了用户注册登录、好友管理、消息收发等关键功能实现逻辑是练手Web全栈开发的典型范例。1. 这不是“Hello World”式Demo一个能跑通登录、加好友、实时收发消息的JavaWeb聊天室真·可部署到Tomcat 8.5环境你试过在IDEA里右键Run on Server结果页面空白、控制台报ClassNotFoundException: javax.websocket.server.ServerEndpoint或者好不容易配好WebSocket一发消息就断连后台日志只打一行INFO: Initializing Spring root WebApplicationContext然后静音别急——这个名为基于Javaweb的网络聊天室.zip的资源包不是教学PPT里的伪代码也不是删减版骨架工程。它是一套完整闭环的、带真实数据库交互、用户状态管理、好友关系链和双向WebSocket通信的可运行系统。核心类名UserLoginServlet.class,WebSocketTest.class,AddFriend.class,QueryFriend.class已全部编译就绪无需重写DAO层前端用jQuery封装了sendMsg()和appendMsg()后端用ConnectionUtils.class统一管理MySQL连接池连最让人头疼的CheckUsername.class都做了AJAX异步校验逻辑。适合刚学完Servlet生命周期、想摆脱“静态页面假数据”阶段的中级JavaWeb学习者也适合需要快速验证WebSocket会话隔离机制的运维/测试人员。它不依赖Spring Boot自动装配但兼容Spring MVC 4.x不强制要求Maven但所有.class文件路径严格遵循WEB-INF/classes/标准结构——这意味着你解压后扔进Tomcatwebapps/目录改两行数据库配置就能看到登录页。2. 从.class反推源码结构还原项目骨架与关键依赖链2.1 解压即见真相目录结构与类职责映射表拿到基于Javaweb的网络聊天室.zip后先别急着丢进IDEA。用任意解压工具打开你会看到典型的JavaWeb WAR包结构chatroom/ ├── WEB-INF/ │ ├── web.xml ← Servlet注册中心必须存在 │ ├── classes/ ← 所有编译好的.class文件所在 │ │ ├── UserDaoImpl.class │ │ ├── WebSocketTest.class │ │ ├── UserLoginServlet.class │ │ ├── ConnectionUtils.class │ │ ├── User.class │ │ ├── AddFriend.class │ │ ├── FindUserFriend.class │ │ ├── UserRegisterServlet.class │ │ ├── QueryFriend.class │ │ └── CheckUsername.class │ └── lib/ ← 依赖JAR包存放处注意此包未提供需自行补全 ├── index.jsp ← 首页入口含登录表单 ├── chat.jsp ← 主聊天界面含消息区域输入框 ├── register.jsp ← 注册页 └── css/js/images/ ← 静态资源提示lib/目录为空——这是本资源最大“埋点”。所有依赖如mysql-connector-java-5.1.47.jar、javax.websocket-api-1.1.jar、spring-webmvc-4.3.29.RELEASE.jar必须手动下载并放入WEB-INF/lib/否则ClassNotFoundException和NoClassDefFoundError将贯穿全程。别信网上某些教程说“Tomcat自带WebSocket API”Tomcat 8.5才原生支持JSR-356且需显式引入API JAR。2.2 关键类功能逆向解析为什么WebSocketTest.class是心跳中枢WebSocketTest.class不是测试类而是真正的WebSocket端点实现类。反编译可用JD-GUI或IDEA内置反编译器后可见其继承自javax.websocket.Endpoint并标注ServerEndpoint(/ws/chat)。它内部维护了一个static MapString, Session存储在线用户Session关键逻辑如下// WebSocketTest.class 反编译核心片段Java语法还原 OnOpen public void onOpen(Session session, EndpointConfig config) { String username session.getUserProperties().get(username).toString(); onlineUsers.put(username, session); // 用户上线存入Map broadcast(username 加入聊天室, username); // 广播欢迎消息 } OnMessage public void onMessage(String message, Session session) { String sender (String) session.getUserProperties().get(username); String target parseTarget(message); // 解析JSON消息中的target字段 Session targetSession onlineUsers.get(target); if (targetSession ! null targetSession.isOpen()) { targetSession.getBasicRemote().sendText(message); // 点对点转发 } else { session.getBasicRemote().sendText({\error\:\用户不在线\}); } }参数说明session.getUserProperties().get(username)的值来自UserLoginServlet中session.getBasicRemote().getUserProperties().put(username, username)的注入。这意味着用户登录成功后必须在HTTP Session中写入username并在WebSocket握手时透传——这是实现“登录态绑定WebSocket”的关键跳线也是后续所有消息路由的基础。2.3 数据库设计隐含逻辑从UserDaoImpl.class反推表结构UserDaoImpl.class中SQL语句虽被编译隐藏但通过方法签名可反推表结构。例如其findUserByUsername(String username)方法必然查询user表而addFriend(int userId, int friendId)则指向friendship关系表。结合AddFriend.class和QueryFriend.class行为可确认三张核心表表名字段说明userid INT PK,username VARCHAR(20) UK,password VARCHAR(64),email VARCHAR(50)用户主表密码应为BCrypt加密UserRegisterServlet.class中调用BCryptPasswordEncoderfriendshipid INT PK,user_id INT FK,friend_id INT FK,status TINYINT DEFAULT 1好友关系表status1表示已确认0为待验证messageid BIGINT PK,sender_id INT FK,receiver_id INT FK,content TEXT,create_time DATETIME消息表注意本项目未启用持久化存储仅内存广播但表结构已预留注意ConnectionUtils.class中getConnection()方法使用DriverManager.getConnection(jdbc:mysql://localhost:3306/chatdb?useSSLfalseserverTimezoneUTC, root, 123456)——这意味着你必须提前创建chatdb库并执行建表SQL资源包未附SQL脚本需按上表手写。3. IDEA运行配置四步法绕开90%新手卡点的Tomcat部署实操3.1 创建空Dynamic Web Project拒绝“Import as Maven”陷阱很多初学者直接右键Import → Existing Maven Projects结果IDEA自动创建pom.xml并覆盖原有web.xml结构导致UserLoginServlet注册失效。正确做法是File → New → Project → Java Enterprise → Web Application取消勾选Create web.xml因为资源包里已有完整web.xml重复生成会冲突设置Target runtime为已配置的Tomcat 8.5非9.x因javax.websocket-api-1.1.jar与Tomcat 9的tomcat-websocket.jar存在版本冲突Finish后清空新建项目的src/和WebContent/目录再将zip解压后的chatroom/内容整体复制粘贴到项目根目录确保WEB-INF/与index.jsp同级血泪经验复制后若IDEA提示“Directory is not marked as source root”右键WEB-INF/classes/→Mark Directory as → Sources Root——否则User.class等无法被Servlet识别。3.2 Tomcat启动前必改的三处配置1web.xml中Servlet映射修正原始web.xml中servlet-mapping可能绑定/login但UserLoginServlet.class实际处理的是/user/login。检查并修正servlet servlet-nameUserLoginServlet/servlet-name servlet-classUserLoginServlet/servlet-class /servlet servlet-mapping servlet-nameUserLoginServlet/servlet-name url-pattern/user/login/url-pattern !-- 必须与login.jsp中form action一致 -- /servlet-mapping2ConnectionUtils.class数据库连接参数打开WEB-INF/classes/ConnectionUtils.class反编译源码或直接用文本编辑器搜索jdbc:mysql修改为你的本地MySQL配置private static final String URL jdbc:mysql://127.0.0.1:3306/chatdb?useSSLfalseserverTimezoneAsia/Shanghai; private static final String USER your_db_user; private static final String PASSWORD your_db_password;3Tomcatconf/context.xml追加WebSocket支持在Context标签内加入!-- conf/context.xml -- Resources cachingAllowedtrue cacheMaxSize100000 / JarScanner scanClassPathfalse /原因Tomcat默认扫描所有JAR包而javax.websocket-api-1.1.jar与Tomcat内置WebSocket实现冲突禁用扫描可避免IllegalStateException: The websocket engine has already been initialized。3.3 依赖JAR包精准清单只下这5个多一个都翻车JAR包名称版本下载地址Maven Repository作用是否必需mysql-connector-java5.1.47https://repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.47/MySQL驱动✅javax.websocket-api1.1https://repo1.maven.org/maven2/javax/websocket/javax.websocket-api/1.1/WebSocket JSR-356规范API✅spring-webmvc4.3.29.RELEASEhttps://repo1.maven.org/maven2/org/springframework/spring-webmvc/4.3.29.RELEASE/提供Controller等注解虽本项目未用注解但UserRegisterServlet依赖其ModelAndView✅jstl1.2https://repo1.maven.org/maven2/javax/servlet/jstl/1.2/支持JSP中c:if等标签✅commons-dbcp1.4https://repo1.maven.org/maven2/commons-dbcp/commons-dbcp/1.4/ConnectionUtils.class中BasicDataSource来源✅避坑不要下载spring-boot-starter-websocket这是Spring Boot生态与本项目的Servlet容器原生WebSocket不兼容。4. 避坑WebSocket连接失败、消息不达、好友列表为空的5个真实翻车现场4.1 现象浏览器F12 Network标签页显示ws://localhost:8080/chatroom/ws/chat404原因WebSocketTest.class未被Tomcat加载根本原因是web.xml中缺少listener配置或ServerEndpoint注解未生效Tomcat未开启WebSocket支持。解决确认web.xml顶部声明为web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd version3.1必须是3.1在web.xml中添加listener listener-classorg.springframework.web.context.ContextLoaderListener/listener-class /listener4.2 现象登录成功后WebSocketTest.onOpen()未触发控制台无加入聊天室日志原因UserLoginServlet中未将username写入WebSocket Session属性。反编译发现其doPost()方法末尾缺少HttpSession httpSession request.getSession(); httpSession.setAttribute(username, username); // ✅ 此行必须存在 // 但还缺一步将HTTP Session传递给WebSocket解决在index.jsp登录表单提交后JavaScript需携带username参数建立WebSocket连接var ws new WebSocket(ws://localhost:8080/chatroom/ws/chat?username username);并在WebSocketTest.class的OnOpen方法中解析OnOpen public void onOpen(Session session, EndpointConfig config) { String username session.getRequestParameterMap().get(username).get(0); session.getUserProperties().put(username, username); // ✅ 补上这行 }4.3 现象发送消息后对方收不到但自己能看到回显正常原因onMessage()中broadcast()方法误用session.getBasicRemote().sendText()向自己发送而非遍历onlineUsers。解决检查WebSocketTest.class中broadcast()实现必须是public static void broadcast(String msg, String excludeUser) { for (Map.EntryString, Session entry : onlineUsers.entrySet()) { if (!entry.getKey().equals(excludeUser) entry.getValue().isOpen()) { try { entry.getValue().getBasicRemote().sendText(msg); } catch (IOException e) { /* log */ } } } }4.4 现象QueryFriend.class返回空列表数据库明明有好友数据原因FindUserFriend.class中SQL查询使用了错误的JOIN条件反编译可见String sql SELECT u.* FROM user u JOIN friendship f ON u.id f.user_id WHERE f.friend_id ?;解决应改为查询“当前用户的好友”即f.user_id ?当前用户ID而非f.friend_id ?String sql SELECT u.* FROM user u JOIN friendship f ON u.id f.friend_id WHERE f.user_id ?;4.5 现象CheckUsername.classAJAX校验始终返回{valid:false}原因web.xml中servlet-mapping未配置CheckUsernameServlet或index.jsp中AJAX URL写成/checkUsername而非/user/checkUsername。解决web.xml中补充servlet servlet-nameCheckUsernameServlet/servlet-name servlet-classCheckUsername/servlet-class /servlet servlet-mapping servlet-nameCheckUsernameServlet/servlet-name url-pattern/user/checkUsername/url-pattern /servlet-mappingindex.jsp中AJAX请求URL改为$.get(/chatroom/user/checkUsername?username username, function(data) { ... });5. 进阶技巧用Chrome DevTools抓包日志染色3分钟定位WebSocket消息丢失根源5.1 WebSocket帧级调试看清消息到底发没发出去当怀疑消息未送达时别急着重启Tomcat。打开Chrome DevTools →Network→WSWebSocket标签页点击左侧连接项右侧切换到Frames子标签。这里能看到原始WebSocket帧Text类型帧显示JSON格式消息如{sender:alice,receiver:bob,content:hi}Close类型帧若出现1001Going Away或1006Abnormal Closure说明连接异常中断关键动作在Frames页右键某条消息 →Copy as cURL (bash)可复现发送逻辑技巧在WebSocketTest.class的OnMessage方法开头插入日志System.out.println([WS-RECV] message | From: session.getUserProperties().get(username));这样控制台输出与Frames面板一一对应能立刻判断是前端没发、还是后端没收。5.2 日志染色区分HTTP请求与WebSocket事件Tomcat默认日志混在一起难以追踪用户行为链。在logging.properties中为不同组件设置独立日志级别# conf/logging.properties handlers java.util.logging.ConsoleHandler .level INFO java.util.logging.ConsoleHandler.level ALL # 单独高亮WebSocket事件 com.example.chatroom.WebSocketTest.level FINE # 单独高亮Servlet处理 UserLoginServlet.level FINE # 单独高亮DAO操作 UserDaoImpl.level FINE重启Tomcat后控制台会出现带颜色标记的日志IDEA中不同level用不同颜色FINE [UserLoginServlet] 用户alice登录成功 FINE [WebSocketTest] WS-OPEN: alice FINE [UserDaoImpl] 查询好友列表userId10015.3 模拟并发压力用curl批量创建10个WebSocket连接验证onlineUsersMap线程安全性本项目未加锁高并发下可能出错# 终端执行模拟10个用户同时上线 for i in {1..10}; do curl -i -N http://localhost:8080/chatroom/ws/chat?usernameuser$i done观察Tomcat日志是否出现ConcurrentModificationException。若出现需在WebSocketTest.class中将onlineUsers改为private static final ConcurrentHashMapString, Session onlineUsers new ConcurrentHashMap();5.4 数据库连接池泄漏检测用ConnectionUtils.class埋点ConnectionUtils.class中closeConnection()方法若未被调用会导致连接耗尽。在closeConnection()开头加日志System.out.println([DB-CLOSE] Connection closed at new Date());然后在UserDaoImpl.class所有finally块中确认调用finally { ConnectionUtils.closeConnection(conn, stmt, rs); // ✅ 必须存在 }若长时间运行后日志中[DB-CLOSE]远少于[DB-OPEN]说明存在连接未关闭漏洞。从那以后我每次部署JavaWeb项目都强制走一遍“解压→补JAR→改DB配置→开WS Frames→发一条测试消息”五步验证流——哪怕只是临时演示也绝不跳过。因为线上问题90%源于本地没跑通的细节而细节藏在.class反编译的每一行session.getUserProperties().put()里。希望帮到你。本文还有配套的精品资源点击获取