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和编译后的class文件整体压缩包大小为23.31MB。已有218人下载学习适合用于课程设计、毕业设计或技术栈整合练习。项目完整实现了用户注册登录、好友管理、消息收发、会话状态保持等功能代码结构清晰涵盖Servlet处理、WebSocket通信、MySQL数据持久化、AJAX异步交互及基础安全防护如用户名校验、SQL注入防范可直接部署运行并作为二次开发模板。1. 为什么一个“基于Javaweb的网络聊天室.zip”能卡住90%刚学完Servlet的新手不是它太难而是它太“全”——表面看只是个带登录注册的网页聊天框背后却横跨了HTTP短连接的天然缺陷、Session状态管理的边界、数据库事务一致性、前端长连接的兼容性、以及Tomcat线程模型对并发的真实压力。我见过太多人在UserLoginServlet里写完request.getSession().setAttribute(user, user)就以为登录成功了结果一开两个浏览器窗口消息发着发着就串号也见过有人把WebSocketTest当成普通Servlet配在web.xml里启动报ClassNotFoundException还翻遍百度找不到原因。这个压缩包不是玩具项目它是用最朴素的JSPServletMySQL堆出来的Javaweb能力压力测试仪你能跑通说明你真懂请求生命周期你调通消息实时推送才算摸到Web通信的底层脉搏你让10个用户同时上线不丢消息、不卡顿、不报500才敢说“会做Javaweb项目”。适合刚啃完《Head First Servlet JSP》、正卡在“学了但不会串起来”的人也适合想用最小成本验证自己工程能力的求职者——别急着抄源码先搞清每个.java文件在Tomcat里到底活了几秒、被谁调用、状态存在哪。2. 从解压到可运行三步搭起能登录、注册、发消息的最小闭环这个.zip包不是IDEA直接打开就能跑的“智能项目”它本质是传统Maven结构缺失、依赖全靠手动拷jar包、配置散落在多个XML里的老派Web应用。新手常在这里翻车解压后双击index.jsp看到空白页或者在IDEA里右键Run As → Run on Server却提示“No servlet container configured”。别慌我们按Tomcat原生部署逻辑走绕过所有IDE自动配置陷阱。2.1 解压后目录结构必须满足的硬性约定打开压缩包你会看到类似这样的结构chat-room/ ├── src/ # Java源码注意不是标准maven src/main/java │ ├── servlet/ # 所有Servlet类 │ │ ├── UserLoginServlet.java │ │ ├── UserRegisterServlet.java │ │ └── WebSocketTest.java ← 关键这是WebSocket端点不是普通Servlet │ └── bean/ # 用户实体类 ├── WebContent/ # 等价于标准WebApp根目录不是WebRoot也不是src/main/webapp │ ├── WEB-INF/ │ │ ├── web.xml # 核心配置必须含servlet-mapping和websocket配置 │ │ └── lib/ # 所有jar包servlet-api.jar、mysql-connector-java.jar、javax.websocket-api.jar │ ├── index.jsp │ ├── login.jsp │ ├── chat.jsp │ └── ... └── db/ # SQL建表脚本通常叫chat_db.sql提示如果解压后看到src/main/java或pom.xml说明你拿到的是别人二次改造过的Maven版和原始标题不符。请退回下载源认准纯src/WebContent/结构。2.2 数据库初始化MySQL 8.0必须改的三个坑原始SQL脚本如db/chat_db.sql大概率是为MySQL 5.x写的直接source进8.0会报错。重点改这三处-- 原始脚本常见写法在MySQL 8.0会失败 CREATE TABLE users ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL ); -- ✅ 必须改成指定存储引擎显式字符集 CREATE TABLE users ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_0900_ai_ci; -- 原始密码字段可能用MD5但MySQL 8.0默认禁用old_passwords -- ✅ 创建用户时强制用caching_sha2_password插件推荐或切回mysql_native_password ALTER USER your_userlocalhost IDENTIFIED WITH caching_sha2_password BY your_pass;执行完建表插入一条测试数据INSERT INTO users (username, password) VALUES (test, e10adc3949ba59abbe56e057f20f883e); -- MD5(123456)2.3 Tomcat 9部署绕过IDEA自动配置的纯净启动法不要用IDEA的“Add Framework Support”或“Create Artifact”直接物理部署将整个chat-room/WebContent/目录重命名为chat-room去掉WebContent层然后复制到$TOMCAT_HOME/webapps/下确保$TOMCAT_HOME/lib/里有javax.websocket-api.jarTomcat 9自带Tomcat 8需手动放启动Tomcat$TOMCAT_HOME/bin/startup.shLinux/Mac或startup.batWindows访问http://localhost:8080/chat-room/index.jsp参数说明chat-room是Context Path由文件夹名决定index.jsp是欢迎文件在web.xml中声明welcome-file-listwelcome-fileindex.jsp/welcome-file/welcome-file-list。若访问404请检查webapps/chat-room/目录下是否存在WEB-INF/web.xml且路径无拼写错误。3. 登录注册流程拆解为什么UserLoginServlet总跳转失败UserLoginServlet和UserRegisterServlet看着简单但它们暴露了Javaweb最经典的请求-响应-重定向-转发认知盲区。很多人写完response.sendRedirect(chat.jsp)发现跳转后session丢失、用户名为空其实是没吃透sendRedirect和RequestDispatcher.forward的本质区别。3.1 UserLoginServlet一次登录背后的三次状态流转核心逻辑链// UserLoginServlet.java 伪代码 protected void doPost(HttpServletRequest request, HttpServletResponse response) { String username request.getParameter(username); String password request.getParameter(password); // 1️⃣ 查询数据库这里省略DAO但必须用PreparedStatement防SQL注入 User user userDao.findByUsername(username); // 2️⃣ 验证密码原始项目多用明文或MD5生产环境必须BCrypt if (user ! null user.getPassword().equals(md5(password))) { // 3️⃣ 关键将用户存入Session不是request不是application HttpSession session request.getSession(true); // true表示不存在则创建 session.setAttribute(currentUser, user); // 键名必须和JSP里EL表达式一致 // 4️⃣ 重定向到聊天页注意redirect会发起新请求原request对象销毁 response.sendRedirect(request.getContextPath() /chat.jsp); } else { request.setAttribute(error, 用户名或密码错误); request.getRequestDispatcher(/login.jsp).forward(request, response); } }逻辑说明sendRedirect触发浏览器发起全新HTTP GET请求所以原request里的setAttribute失效但session是服务端全局状态只要Session ID通常存cookie没丢chat.jsp里就能通过session.getAttribute(currentUser)取到用户。而forward是在服务端内部跳转request对象复用所以能传error信息给login.jsp。3.2 UserRegisterServlet事务与重复注册的双重校验原始代码常只查一次数据库就插入高并发下必然出现重复用户名。必须加事务和唯一索引// UserRegisterServlet.java 关键片段 protected void doPost(HttpServletRequest request, HttpServletResponse response) { String username request.getParameter(username); String password request.getParameter(password); Connection conn null; PreparedStatement ps null; try { conn dataSource.getConnection(); // 假设已配好JNDI或Druid数据源 conn.setAutoCommit(false); // 开启事务 // 先查重SELECT FOR UPDATE锁住该行防止并发插入 ps conn.prepareStatement(SELECT id FROM users WHERE username ? FOR UPDATE); ps.setString(1, username); ResultSet rs ps.executeQuery(); if (rs.next()) { request.setAttribute(error, 用户名已存在); request.getRequestDispatcher(/register.jsp).forward(request, response); return; } // 再插入MySQL唯一索引会兜底 ps conn.prepareStatement(INSERT INTO users (username, password) VALUES (?, ?)); ps.setString(1, username); ps.setString(2, md5(password)); ps.executeUpdate(); conn.commit(); // 提交事务 response.sendRedirect(request.getContextPath() /login.jsp?registeredtrue); } catch (SQLException e) { if (conn ! null) try { conn.rollback(); } catch (SQLException ignored) {} e.printStackTrace(); request.setAttribute(error, 注册失败请重试); request.getRequestDispatcher(/register.jsp).forward(request, response); } }参数说明FOR UPDATE是InnoDB行锁比单纯SELECTINSERT更可靠dataSource.getConnection()要求web.xml中已配置JNDI资源见下一章md5(password)仅作教学演示实际必须用BCrypt.hashpw(password, BCrypt.gensalt())。4. WebSocketTest为什么你的聊天消息总延迟3秒以上WebSocketTest.java是整个项目的灵魂也是最容易被当普通Servlet误配的模块。它不是HTTP协议不走web.xml里的servlet-mapping而是通过ServerEndpoint注解由Tomcat的WebSocket容器自动扫描加载。如果你在web.xml里给它配了servlet标签启动时就会报java.lang.IllegalArgumentException: Not a WebSocket endpoint。4.1 WebSocket端点正确注册方式Tomcat 8.5WebSocketTest.java必须满足三个条件类上加ServerEndpoint(/ws/chat)注解路径即WebSocket连接URL实现OnOpen、OnMessage、OnClose、OnError四个生命周期方法用静态ConcurrentHashMap存在线用户Session不能用HttpSession// WebSocketTest.java 完整关键片段 ServerEndpoint(/ws/chat) public class WebSocketTest { // ✅ 用ConcurrentHashMap存所有WebSocket Session非HttpSession private static final MapString, Session onlineUsers new ConcurrentHashMap(); OnOpen public void onOpen(Session session, EndpointConfig config) { // 从HTTP Session获取登录用户关键WebSocket本身无Session HttpSession httpSession (HttpSession) session.getUserProperties().get(httpSession); if (httpSession null || httpSession.getAttribute(currentUser) null) { session.close(); // 未登录拒绝连接 return; } User user (User) httpSession.getAttribute(currentUser); onlineUsers.put(user.getUsername(), session); } OnMessage public void onMessage(String message, Session session) { // 解析JSON消息原始项目多用简单字符串拼接此处升级为标准JSON try { JSONObject json new JSONObject(message); String from json.getString(from); String to json.getString(to); // 私聊目标 String content json.getString(content); // 广播给所有人或精准推送给to for (Session s : onlineUsers.values()) { if (s.isOpen()) { s.getBasicRemote().sendText( new JSONObject() .put(from, from) .put(content, content) .put(time, System.currentTimeMillis()) .toString() ); } } } catch (Exception e) { e.printStackTrace(); } } OnClose public void onClose(Session session) { // 从Map中移除断开连接的用户 onlineUsers.values().removeIf(s - s.getId().equals(session.getId())); } }逻辑说明session.getUserProperties().get(httpSession)是Tomcat特有机制需在HTTP请求阶段手动注入——这要求login.jsp提交登录后UserLoginServlet在重定向前把HttpSession对象塞进WebSocket握手请求的属性里见下节。ConcurrentHashMap保证线程安全避免HashMap在多线程put时死循环。4.2 前端JavaScript连接WebSocket的必填参数chat.jsp里不能直接写new WebSocket(ws://localhost:8080/ws/chat)因为路径必须带Context Path/chat-room/ws/chat必须携带Cookie含JSESSIONID才能关联HTTP Session需监听onopen后才允许发消息否则send()报错!-- chat.jsp 中的WebSocket初始化 -- script let ws; const contextPath % request.getContextPath() %; // 动态获取上下文路径 function connectWebSocket() { const wsUrl ws:// window.location.host contextPath /ws/chat; ws new WebSocket(wsUrl); ws.onopen function(event) { console.log(WebSocket连接成功); // ✅ 连接成功后前端才可发送消息 document.getElementById(sendBtn).disabled false; }; ws.onmessage function(event) { const data JSON.parse(event.data); const msgDiv document.createElement(div); msgDiv.innerHTML strong[${data.from}]/strong: ${data.content}; document.getElementById(chatBox).appendChild(msgDiv); document.getElementById(chatBox).scrollTop document.getElementById(chatBox).scrollHeight; }; ws.onerror function(event) { console.error(WebSocket错误:, event); alert(连接异常请刷新页面重试); }; } // 页面加载完成时连接 window.onload function() { connectWebSocket(); }; /script参数说明window.location.host确保跨域时URL正确request.getContextPath()动态适配部署路径避免硬编码/chat-roomonopen回调是唯一安全的发消息时机过早调用ws.send()会触发InvalidStateError。5. 避坑指南五个让新手调试到凌晨三点的真实问题这些不是理论假设而是我在带训时收集的血泪经验——每个都导致至少3人连续2小时卡死在同一个地方。5.1 现象登录后chat.jsp显示nullsession.getAttribute(currentUser)始终为空原因UserLoginServlet用了response.sendRedirect()但chat.jsp试图从request取用户request.getAttribute(currentUser)而重定向后request已销毁。解决chat.jsp必须用session.getAttribute(currentUser)且确认UserLoginServlet中session.setAttribute()的键名与JSP中完全一致大小写敏感。5.2 现象WebSocket连接报404浏览器控制台显示WebSocket connection to ws://... failed原因web.xml里错误配置了servlet映射或WebSocketTest.java未放在src/下被编译Tomcat扫描不到class文件。解决删除web.xml中所有关于WebSocketTest的servlet配置确认WebSocketTest.class存在于webapps/chat-room/WEB-INF/classes/下路径要和包名一致如com/chat/WebSocketTest.class。5.3 现象MySQL插入中文变???日志显示Incorrect string value: \xE4\xBD\xA0\xE5\xA5\xBD原因MySQL服务器、数据库、表、连接URL四层字符集不统一常见于只改了表字符集但没改连接URL。解决在web.xml的JDBC URL末尾强制指定jdbc:mysql://localhost:3306/chat_db?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/Shanghai5.4 现象UserRegisterServlet插入重复用户名不报错数据库却出现两条相同记录原因没在MySQL表上建UNIQUE索引仅靠Java层判断高并发时两次查询都返回null然后双双插入。解决执行SQL建唯一索引ALTER TABLE users ADD UNIQUE INDEX idx_username (username);并捕获SQLIntegrityConstraintViolationException做友好提示。5.5 现象Tomcat启动后控制台疯狂刷SEVERE: Error starting static Resources项目无法访问原因WebContent/下存在隐藏文件如.DS_Store、Thumbs.db或WEB-INF/lib/里混入了tomcat-*开头的jar包与Tomcat内置冲突。解决彻底删除WebContent/下所有以.开头的文件检查WEB-INF/lib/只保留mysql-connector-java-x.x.x.jar、javax.websocket-api.jar、servlet-api.jarTomcat 9无需servlet-api.jar删掉。6. 进阶验证用curl和jconsole亲手测出你的聊天室真实并发能力跑通不等于健壮。真正的验收不是“能发消息”而是在100个并发连接下消息不丢失、不乱序、平均延迟200ms。下面这两个命令能让你甩开所有“Hello World”教程进入真实工程验证层。6.1 用curl模拟10个用户批量登录生成有效Session ID别再手动点登录按钮。用curl脚本批量获取Session为压测铺路#!/bin/bash # login_test.sh for i in {1..10}; do usernameuser$i password123456 # 第一步GET登录页获取初始JSESSIONID cookie$(curl -s -I http://localhost:8080/chat-room/login.jsp | grep Set-Cookie | head -n1 | sed s/Set-Cookie: \(.*\);.*/\1/) # 第二步POST登录携带cookie并提取新session response$(curl -s -X POST \ -H Cookie: $cookie \ -d username$username \ -d password$password \ http://localhost:8080/chat-room/UserLoginServlet \ -w \n%{http_code} -o /dev/null) if [ $response 302 ]; then echo ✅ 用户$usernam登录成功 else echo ❌ 用户$usernam登录失败HTTP状态码: $response fi done技巧说明-w \n%{http_code}让curl输出HTTP状态码302表示重定向成功即登录成功grep Set-Cookie提取cookie是关键因为Tomcat每次重定向会生成新JSESSIONID必须捕获它才能用于后续WebSocket连接。6.2 用jconsole实时监控Tomcat线程与内存定位卡顿根源当多人聊天开始卡顿时打开$JAVA_HOME/bin/jconsole连接本地Tomcat进程监控项正常阈值危险信号应对动作Threadspeak 200peak 300 且持续不降检查WebSocketTest.onMessage是否有阻塞IO如同步DB写Heap Memoryused 70%used 90% 且Full GC频繁增加JVM参数-Xms512m -Xmx1024mLoaded Classessteady ~1500持续上涨类泄漏检查onlineUsersMap是否及时清理断开连接实操细节在WebSocketTest.onClose()里加日志System.out.println(用户断开: session.getId());对照jconsole的Thread列表看是否有大量WebSocket线程处于WAITING状态——那说明onClose没被触发onlineUsers没清理最终OOM。6.3 终极验证WebSocket消息时序一致性测试表用以下JSON格式发10条消息验证后端是否严格按接收顺序广播[ {from:user1,to:all,content:msg1,seq:1}, {from:user2,to:all,content:msg2,seq:2}, {from:user1,to:all,content:msg3,seq:3} ]在WebSocketTest.onMessage()里打印接收时间戳System.out.println(收到[ json.getInt(seq) ] System.currentTimeMillis());合格标准10条消息的seq字段在服务端打印顺序必须严格递增且任意两条间隔50ms排除网络抖动。如果出现seq:5先于seq:4打印说明你的ConcurrentHashMap遍历或sendText()调用存在非线程安全操作——立刻检查onlineUsers.values()迭代过程是否加锁。我带过的学员里能跑通登录注册的占70%能调通WebSocket的剩40%但最后用jconsole把线程数压到200以下、消息延迟稳定在150ms内的不到15%。这项目的价值不在代码量而在于它逼你直面Tomcat线程池、JVM内存模型、MySQL锁机制、浏览器Event Loop这四座大山。每次你修复一个NullPointerException其实是在和Java的类加载器握手每次你解决WebSocket断连都是在和TCP的TIME_WAIT状态谈判。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

日语动词活用全攻略:分类、音便与六大变形规则一次讲透

日语动词活用全攻略:分类、音便与六大变形规则一次讲透

日语动词活用是很多人卡住的第一道大坎。说实话,我当年自学的时候也被て形音便折磨得不轻——单词明明都认识,一放到句子里就不知道该怎么变,问老师,老师只说“这是固定搭配,记住就行”,可一背又是几十条规…

2026/9/23 23:09:33 阅读更多 →
Flutter与鸿蒙开发环境搭建指南

Flutter与鸿蒙开发环境搭建指南

1. 环境搭建前的认知准备鸿蒙操作系统作为新一代智能终端操作系统,其分布式能力和全场景特性为开发者带来了全新机遇。而Flutter作为跨平台开发框架,其高效的渲染引擎和丰富的组件库使其成为移动开发的热门选择。将两者结合,可以充分发挥Flut…

2026/9/23 23:09:33 阅读更多 →
有源负载放大电路:增益、偏置与稳定性的工程全解

有源负载放大电路:增益、偏置与稳定性的工程全解

简介:本资源是一篇面向电子类竞赛选手与高校电类专业学生的深度技术解析文章,聚焦集成运放电路中关键的有源负载放大电路设计原理与工程化计算方法。内容系统覆盖恒流源电路的恒流值与内阻计算、镜像恒流源建模、多级/差分放大结构的动态指标&#xff08…

2026/9/23 23:09:33 阅读更多 →

最新新闻

G6 事件系统完全指南:从 Graph/Canvas/Element 事件监听到底层分发机制

G6 事件系统完全指南:从 Graph/Canvas/Element 事件监听到底层分发机制

数据可视化前端图表库 【免费下载链接】G6 ♾ A Graph Visualization Framework in JavaScript. 项目地址: https://gitcode.com/gh_mirrors/g6/G6 点击查看 免费下载 G6(antv/g6)的事件系统是在底层图形渲染引擎 G 为主线,结合仓…

2026/9/24 0:36:46 阅读更多 →
Terminal.Gui TreeView 深度解析:构建可交互的层次结构树控件

Terminal.Gui TreeView 深度解析:构建可交互的层次结构树控件

UI组件跨平台桌面应用 【免费下载链接】Terminal.Gui Cross Platform Terminal UI toolkit for .NET 项目地址: https://gitcode.com/gh_mirrors/te/Terminal.Gui 点击查看 免费下载 Terminal.Gui 是面向 .NET 的跨平台终端 UI 工具包,其内置的 TreeVie…

2026/9/24 0:36:46 阅读更多 →
跳频频率合成器设计:DDS+PLL混合架构实战指南

跳频频率合成器设计:DDS+PLL混合架构实战指南

简介:本资源是一篇聚焦跳频通信系统核心组件——跳频频率合成器的深度技术论文,面向通信工程、电子信息系统设计领域的高校师生、射频工程师及军事通信研发人员,重点解决高速跳频中DDS输出频率受限与PLL锁定时间过长的技术矛盾。文中提出并详…

2026/9/24 0:36:46 阅读更多 →
Salt 执行模块 systemd_service 完全指南:基于 systemd 的服务管理实战

Salt 执行模块 systemd_service 完全指南:基于 systemd 的服务管理实战

运维配置管理后端 【免费下载链接】salt Software to automate the management and configuration of infrastructure and applications at scale. 项目地址: https://gitcode.com/gh_mirrors/sa/salt 点击查看 免费下载 本文是 Salt 官方参考文档 doc/ref/modules…

2026/9/24 0:36:46 阅读更多 →
PyBullet机械臂抓取闭环:从深度学习检测到仿真控制

PyBullet机械臂抓取闭环:从深度学习检测到仿真控制

简介:本资源是一套基于深度学习的平面抓取检测与机械臂控制完整仿真实现方案,面向机器人学、计算机视觉及AI控制方向的学习者与开发者,解决真实场景中抓取位姿估计与仿真闭环控制的关键问题。压缩包共1031个文件,含149个URDF模型&…

2026/9/24 0:36:46 阅读更多 →
RISC-V中断子系统深入解析:CLINT与PLIC的分工协作

RISC-V中断子系统深入解析:CLINT与PLIC的分工协作

自己写嵌入式固件这些年,经手过ARM Cortex-M的NVIC,也调过RISC-V的完整中断链路。说实话,刚接触RISC-V中断子系统的时候,最直观的感受就是“怎么这么绕”,又是CLINT又是PLIC,还要配合一堆CSR寄存器。但真正…

2026/9/24 0:35:46 阅读更多 →

日新闻

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为…

2026/9/24 0:00:19 阅读更多 →
单细胞注释实战:基于Scanpy的标记基因与参考映射流程解析

单细胞注释实战:基于Scanpy的标记基因与参考映射流程解析

简介:一份基于单细胞RNA测序数据的细胞类型注释算法研究Python毕业设计源码,针对计算机相关专业正在做毕设或需要项目实战的学习者,可用于课程设计与期末大作业。项目代码完整、经导师指导评审通过,可直接运行,覆盖数据…

2026/9/24 0:00:19 阅读更多 →
C#源生成器实战:用增量生成器替代反射,告别AOT崩溃

C#源生成器实战:用增量生成器替代反射,告别AOT崩溃

第一次在项目里被反射卡住,是在一个老旧的WinForms模块里:几十个类依赖PropertyChanged通知,运行时反射读属性、发通知,每次启动慢半拍不说,一上.NET Native/AOT裁剪模式几乎全面崩盘。后来我把这段逻辑全部改成C#源生…

2026/9/24 0:00:19 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/23 4:55:02 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/23 4:49:06 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/23 9:53:41 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/23 9:53:40 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/23 9:53:40 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/23 9:53:40 阅读更多 →