资讯详情

Tomcat8+Java7+ExtJS WebSocket聊天室源码拆解

📅 2026/10/23 16:18:25 | 华诺云谱 👁 阅读
Tomcat8+Java7+ExtJS WebSocket聊天室源码拆解
简介这份源码包围绕 Tomcat8、Java7 与 ExtJS 搭建 WebSocket 实时聊天室面向具备 Java Web 基础、希望理解全双工通信与富客户端集成的开发者和课程学习者可用于学习服务端端点生命周期、消息广播及前后端联调。包内共 1753 个文件压缩后约 7.01MB以 gif、scss、png 等界面与样式素材为主辅以 js、css 前端脚本以及 java、class、jar、xml 等服务端与工程配置较完整地还原了一个 Eclipse 风格 Web 项目结构。已有 263 人学习适合作为实时通信入门到进阶的对照案例。读者可从中梳理 ServerEndpoint 的 onOpen、onMessage、onClose 处理流程观察 ExtJS 组件如何承载输入框、按钮与聊天窗口并结合连接管理、消息存储广播、SSL/TLS 加密与并发优化等内容形成从编码、测试到 Tomcat 部署运维的排错思路。1. 先看连接路径Tomcat8 Java7 ExtJS 的聊天室源码包到底能干什么标题里写的是 webscoket实际落地按 WebSocket 协议来。这套基于 Tomcat8 Java7 ExtJS 的 WebSocket 聊天室源码包干的事情很直接浏览器用 ExtJS 搭聊天窗口Tomcat8 通过 JSR-356 端点接住连接消息在内存里按房间广播不依赖数据库和额外中间件。它适合想补 WebSocket 握手、会话管理、前端消息刷新这几块实战经验的人也适合拿一份能跑的源码做内部值班沟通页的底座。拆这类源码包我第一眼不看界面先看连接路径和 Session 容器因为聊天室出问题八成不在按钮上。2. 架构与目录ExtJS 界面、WebSocket 端点和 Tomcat8 容器怎么串起来这套聊天室的骨架不复杂但几个关键点必须一次摆正ExtJS 只负责界面和消息展示浏览器原生 WebSocket 负责连接Tomcat8 里的 JSR-356 端点负责接连接、收消息、按房间广播。服务端没有数据库在线状态和房间成员都放在ConcurrentHashMap里所以重启 Tomcat 会掉线历史消息也不会自己留。Java7 的限制也要提前记住不能写 lambda不能写 Stream集合遍历和异步任务都得用 Java7 的写法否则编译期就会翻车。2.1 一条消息的链路从 ExtJS 按钮到 OnMessage用户在 ExtJS 文本框里敲完消息点发送前端调用WebSocket.send(text)。浏览器先把 HTTP 请求升级成 WebSocket 握手Tomcat8 根据ServerEndpoint(/chat/{room}/{user})匹配到端点把路径里的房间名和用户名注入PathParam然后回调onOpen。onOpen里把当前Session塞进房间成员表后面每条消息走onMessage服务端把文本包装成 JSON再遍历同一房间的Session逐个sendText。前端onmessage收到 JSON 后解码往 ExtJS Store 里加一条记录Grid 自然刷新。这条链路里有两个容易被忽略的点。第一WebSocket 握手仍然是 HTTP所以 context path、端点路径、WAR 包名必须完全对齐少一层就会 404。第二服务端广播时不能假设每个Session都还活着移动端切后台、浏览器关标签页都会留下半开连接广播前要判断isOpen()发送失败要顺手剔除。把这两个点守住聊天室的基本盘就稳了。2.2 目录结构与 WAR 骨架源码包里的静态资源和 Java 类放哪传统 Tomcat Web 工程一般按下面这种结构组织如果拿到的是 Maven 版把WebContent换成src/main/webapp就行Java 源码路径对应src/main/java。关键不是构建工具而是别把websocket-api.jar打进 WARTomcat8 运行时自己带实现重复打包很容易出类加载冲突。chat-room/ ├─ src/ │ └─ chat/ │ ├─ endpoint/ │ │ └─ ChatEndpoint.java │ └─ codec/ │ └─ MessageCodec.java ├─ WebContent/ │ ├─ index.jsp │ ├─ app.js │ ├─ extjs/ │ │ ├─ ext-all.js │ │ └─ resources/ │ └─ WEB-INF/ │ ├─ web.xml │ ├─ classes/ │ └─ lib/ └─ build/ChatEndpoint是 WebSocket 入口MessageCodec负责把消息拼成 JSON 并做转义index.jsp负责挂 context path 和加载 ExtJSapp.js放前端视图与连接封装。WEB-INF/classes放编译后的.classWEB-INF/lib只放业务确实需要的 jar。web.xml要注意metadata-complete不要设成true否则 Tomcat8 可能不扫描ServerEndpoint注解表现就是握手一直 404。文件作用常见改动点ChatEndpoint.java接连接、收消息、按房间广播加鉴权、加消息落库、改房间规则MessageCodec.java拼 JSON、转义特殊字符加消息类型、加私聊字段index.jsp输出 context path、加载 ExtJS改静态资源路径、加登录参数app.jsExtJS 视图、WebSocket 封装改 UI、加重连、改消息渲染web.xmlWeb 应用描述检查注解扫描、欢迎页、编码过滤器2.3 消息协议用 JSON 字段把系统消息和聊天消息分开服务端发给前端的消息建议统一成一种结构前端只认type分流。聊天消息用chat进入/离开房间用sysonline带当前在线人数ts带服务端时间戳。这样 ExtJS 的 Store 不用为系统消息另建一套模型后面要加私聊、撤回、图片消息也有地方扩。{ type: chat, room: ops, from: dev01, content: 今晚谁值守, online: 3, ts: 1730000000000 }参数说明type决定前端渲染样式room方便前端做多房间切换from是发送人content是正文online是在线人数ts是服务端毫秒时间。客户端发给服务端可以保持纯文本服务端再包 JSON这样 Java7 端不用为了解析一个字段引入完整 JSON 框架如果要做私聊约定用户名 内容的前缀在onMessage里拆一次即可。注意content必须转义双引号、反斜杠、换行和控制字符否则前端Ext.JSON.decode会直接解不出来。3. 核心代码拆解Java7 端点广播、JSON 编解码与 ExtJS Store 刷新核心代码分三块看服务端端点管连接和广播编解码类管消息格式前端封装管连接状态和界面刷新。三块之间的契约就是上一节的 JSON 字段任何一块改字段另外两块都要同步。Java7 下写这些代码不复杂关键是别用 Java8 语法别在广播循环里做耗时操作。3.1 ChatEndpointSession 容器、房间映射和广播方法ROOMS用“房间名 - 用户名 - Session”的两层ConcurrentHashMap这样同一房间广播时只遍历本房间成员不需要全量扫。onOpen里用putIfAbsent初始化房间避免两个连接同时进房时把对方覆盖掉。同一个用户名重复进房时旧 Session 要主动关掉否则会出现两个标签页抢同一个身份。广播方法对每个Session加同步锁再sendText因为getBasicRemote()不是线程安全的两个线程同时往一个连接写会抛异常。package chat.endpoint; import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.logging.Level; import java.util.logging.Logger; ServerEndpoint(/chat/{room}/{user}) public class ChatEndpoint { private static final Logger LOG Logger.getLogger(ChatEndpoint.class.getName()); // 房间 - 用户 - 会话只存在内存里重启即清空 private static final ConcurrentMapString, ConcurrentMapString, Session ROOMS new ConcurrentHashMapString, ConcurrentMapString, Session(); private String room; private String user; OnOpen public void onOpen(Session session, PathParam(room) String room, PathParam(user) String user) throws IOException { this.room room; this.user user; session.getUserProperties().put(room, room); session.getUserProperties().put(user, user); session.setMaxIdleTimeout(30 * 60 * 1000L); ConcurrentMapString, Session members ROOMS.get(room); if (members null) { ConcurrentMapString, Session created new ConcurrentHashMapString, Session(); members ROOMS.putIfAbsent(room, created); if (members null) { members created; } } // 同一用户重复进房时关掉旧连接避免一个身份两个会话 Session old members.put(user, session); if (old ! null old ! session) { try { old.close(); } catch (IOException ignored) { } } broadcast(room, MessageCodec.system(room, user 进入房间, members.size())); } OnMessage public void onMessage(String payload, Session session) { if (payload null) { return; } String text payload.trim(); if (text.length() 0) { return; } // 单条消息限长防止一个连接把广播通道打满 if (text.length() 2000) { p a hrefhttps://download.csdn.net/download/weixin_38669628/11523994 stylecolor:#ec7500;font-size:14px; 本文还有配套的精品资源点击获取 /a img altmenu-r.4af5f7ec.gif srchttps://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif stylewidth:16px;margin-left:4px;vertical-align:text-bottom;cursor:text; /p
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑