简介:这份软件工程实习记录文档面向本科软件工程专业学生,尤其适合正在撰写实习周记、实习报告或毕业实习材料、需要真实过程素材参考的读者,可用于对照修改与补全个人记录。压缩包内共1个doc文件,约40KB,篇幅集中,便于直接查阅和摘录。文档按周记录实习过程:从入司动员、分组开发,到实现文件查找与排序、用HTML/CSS/JavaScript完成教师信息展示与添加,再到Node.js结合Express与MySQL实现单页数据增删改查,并涉及Redhat Linux环境、ARM开发板及网络服务器配置。记录中还穿插软件开发可行性分析、需求分析、概要设计、详细设计、编码与验收六阶段流程,以及项目经理职责和开发岗位分工等知识点。目前已有2924人学习,适合用来补充技术细节、梳理岗位认知并改写为符合学校要求的实习记录。
1. 从「写代码」到「交付」:一张软件工程实习全景图
很多人对软件工程实习的想象是坐下就敲代码、一天交一个功能。翻完一份完整的软件工程实习记录会发现节奏完全不是这样:五周时间里,纯敲键盘写业务逻辑的比例低得惊人,剩下的全花在读需求、搭环境、导数据、联调、排错和演示上。这份毕业实习记录的价值也在这里——它把「软件开发流程六步」「前后端与数据库怎么串起来」「服务器怎么部署」这三条线按时间摊开,让你看到每一步真实的卡点长什么样。它适合两类人:正在写实习记录、需要一份可对照的时序与知识点骨架的人;以及复习软件工程、想把课上背的六步流程和技术栈对应到具体动作上的人。整份材料的技术重心其实只有四块:流程与角色、桌面端与前端、数据链路、环境与部署。
2. 开发流程六步:可行性分析到验收,每一步到底交什么
几乎每个人都能背出可行性分析、需求分析、概要设计、详细设计、编码、项目验收这六步,但被追问「概要设计和详细设计的边界在哪」「哪一步该出文档、哪一步该出可运行的东西」就卡住了。实习记录里那条最容易被忽略的判断是:编码只占整个开发过程约百分之十五的时间,剩下八成多分布在需求澄清、设计表达、环境准备和验收沟通上。把这个比例记住,六步流程就不再是背下来的名词,而是一条时间分配曲线。
2.1 六个阶段的产出物与跳步的代价
流程之所以是六步而不是三步,是因为每一步都在降低后一步的不确定性。把它拆成「核心问题 + 典型产出 + 跳过的后果」三列,复习时一眼就能对上号:
| 阶段 | 核心问题 | 典型产出 | 跳过的后果 |
|---|---|---|---|
| 可行性分析 | 这件事值不值得做、技术上做不做得成 | 可行性结论、技术选型初判 | 做到一半发现依赖不成立,返工 |
| 需求分析 | 用户到底要什么、边界在哪 | 需求清单、功能点列表 | 功能做出来没人用,验收扯皮 |
| 概要设计 | 系统分几块、模块之间怎么调用 | 架构图、模块划分、接口约定 | 各写各的,联调时接口对不上 |
| 详细设计 | 每个模块内部怎么实现 | 类图、表结构、字段定义 | 数据库建错,后期改表牵一发动全身 |
| 编码 | 把设计翻译成可运行程序 | 可运行代码、单元自测 | 只有代码没有依据,出问题无法回溯 |
| 项目验收 | 做出来的东西是否满足当初的需求 | 演示、验收记录、部署包 | 交付即结束,问题全留在上线后 |
这张表最值得盯的是「概要设计」和「详细设计」的分界:前者回答「系统由哪些部分组成、部分之间怎么说话」,后者回答「每一个部分内部用什么结构、数据怎么存」。实习记录里图书信息录入功能的建模,落在概要设计与详细设计之间——把用户需求画成可讨论的模型,让客户能直观看到功能长什么样,再往下才落到表结构和字段。
2.2 编码只占 15%:时间被谁吃掉了
从五周的记录往回倒推,时间消耗大致是这样的:环境搭建与依赖安装、数据准备与清洗、前后端联调、错误定位、功能演示与修改,这五项加起来远超写业务代码本身。这不是效率低,而是软件工程的常态。真正决定项目能不能按时交付的,往往不是算法写得多漂亮,而是环境能不能一次跑通、数据能不能正确落库、出错时能不能从日志里一眼看出原因。
举个记录里的真实片段:把一个写好的项目部署到服务器上,配置完端口和地址后访问首页失败。直觉会去翻代码,实际原因是配置的端口已经被别的进程占用,换一个端口立刻正常。这类问题在流程里根本没有位置,却实实在在吃掉半天时间。复习时如果把六步流程理解成「写代码的六个前置步骤」,就会低估中间那些不产出代码的环节;理解成「风险逐层收敛的六个关卡」,才对得上那条 15% 的经验值。
2.3 岗位地图:开发员、架构师、项目经理各自盯什么
实习记录里提到的一批 IT 岗位,其实是流程六步在不同角色身上的投影。软件开发员盯编码与自测,项目经理盯计划、组织、协调、控制这条线,架构师盯概要设计和技术选型,技术总监盯多条产品线的技术方向,售前售后则站在需求与验收两端。把它们和流程对齐,比孤立背岗位名称有用得多:
- 项目经理对「需求分析」和「项目验收」两端负主要责任,中间所有延期都汇到他这里;
- 架构师对「概要设计」负主要责任,决定模块怎么切、技术栈怎么选;
- 软件开发员对「详细设计」和「编码」负主要责任,是唯一大量产出代码的岗位;
- 售前在需求分析之前介入,售后在验收之后介入,两头都不写代码但直接影响客户满意度。
复习到这里可以记住一个判断:一个岗位在六步流程里覆盖的段数越多,越偏管理与决策;覆盖段数越少但越深,越偏技术执行。实习阶段被安排「扮演项目经理角色、共同探讨系统要实现哪些功能」,本质是让你提前体验需求分析这一步的决策压力,而不是真让你管人。
2.4 先建模再写码:模型是需求的简化实现
记录里有一句判断很关键:模型是用户需求的简化实现,通过建模可以让客户更直观地了解软件功能的具体实现形式,对开发人员有现实指导意义。这句话解释了为什么很多项目在需求确认后不直接开工,而是先做一个能点、能看的模型。
以图书信息录入功能为例,建模阶段要确定的是「录入哪些字段、字段之间有没有约束、录入后在哪里看到结果」,而不是「用哪个控件、走哪个接口」。前者的改动成本是一次讨论,后者的改动成本是一次重构。很多团队翻车的地方在于把两者混在一起:模型还没确认就开始写代码,等客户说「这个字段我不需要」时,代码已经写进三层结构里了。
建模还有一个隐性收益:它是团队内部对齐术语的场合。编号、姓名、课程名这类字段,在需求文档里可能叫法各不相同,画进模型之后必须统一成一个名字,后面建表、写接口、做页面才有共同的锚点。
3. 桌面端与前端:Swing 文件查找排序与 HTML/CSS/JS 页面
实习前两周的技术内容横跨桌面和网页两端,表面上是两个不相干的任务,实际练的是同一件事:把「用户输入 → 处理 → 结果回显」这条链路走通。桌面端用 Swing 做文件查找与排序,网页端用 HTML、CSS、JavaScript 做教师信息的表格展示与添加。这条链路看着简单,但两个端各埋了一个典型坑:桌面端把路径写死,网页端把数据重复渲染。
3.1 视图与主程序分包:view 和 main 的职责边界
桌面程序被拆成两个包:一个放视图,一个放主程序。视图包里做的是新建面板、添加组件和按钮、设置组件功能与相对位置;主程序包里按运行逻辑写入口和调度。这种分法在小项目里显得啰嗦,但它对应的是软件工程里最基本的一条原则——界面负责呈现和收集输入,逻辑负责处理,两者之间靠方法调用而不是互相引用。
复习时可以这样检验自己是否真的理解分包:如果把视图层整个换掉(比如从 Swing 换成网页),主程序里的业务逻辑要不要改?答案是尽量不改。一旦发现换个界面就要动业务代码,说明职责没分干净。实习记录里第二天写视图、第三天写主程序,顺序上就是先定界面长什么样,再定点击之后发生什么。
3.2 固定路径写死:查找功能的第一个真实缺陷
查找功能的需求是:在输入框输入文件名或商品名,支持模糊查找,把结果回显到页面。第一版做完能跑,但只能从固定的地址查找。这个问题在演示时几乎必然被发现,因为演示者一定会问「能不能查别的目录」。修改方式是把目录从常量抽成参数,代码结构大致如下:
// 修改前:目录写死在方法里,换个位置就要改代码 // File root = new File("D:/data/"); // 修改后:目录作为参数传入,界面上的选择结果直接透传 public List<File> searchByName(File root, String keyword) { List<File> result = new ArrayList<>(); if (root == null || !root.exists()) { return result; // 目录不存在直接返回空,避免空指针 } File[] files = root.listFiles(); if (files == null) { return result; // 无权限访问时 listFiles 返回 null,必须判空 } for (File f : files) { if (f.isDirectory()) { result.addAll(searchByName(f, keyword)); // 递归子目录 } else if (f.getName().contains(keyword)) { result.add(f); // 模糊匹配用 contains,等价于 SQL 的 like %keyword% } } return result; }这段代码有三个值得记住的参数与判断:root从写死变成外部传入,是「可配置」和「可测试」的分水岭;listFiles()在目录无访问权限时返回null而不是空数组,不判空会直接抛空指针;模糊匹配用contains就够,不需要正则,因为需求只要求包含关系。递归遍历在目录层级深时有栈溢出风险,实际项目里应改成队列做广度遍历,但实习阶段用递归把逻辑讲清楚更重要。
提示:把「写死」当成一个检查项。凡是代码里出现绝对路径、固定 IP、固定端口、固定账号,都标记出来,它们在本地跑得通,换台机器就翻车。
3.3 冒泡排序按文件名排序:能跑,但别当最终方案
排序功能的需求是把磁盘中现存的文件按文件名排序。记录里用的算法是冒泡排序,比较依据是文件名。作为教学示例它没问题,作为工程实现要补三个认知:
第一,文件名是字符串,字符串比较要用compareTo而不是减号,比较结果的正负号才代表大小关系。第二,String.compareTo按字符编码逐位比较,中文文件名的排序结果既不是拼音序也不是笔画序,只是一个稳定的字典序;如果产品要求按拼音排,必须额外引入排序键。第三,冒泡排序的时间复杂度是 O(n²),文件数量上千之后切换目录就能感觉到卡顿,实际应换成带比较器的排序。
// 按文件名排序,冒泡实现,仅用于理解比较逻辑 public void sortByFileName(List<File> files) { for (int i = 0; i < files.size() - 1; i++) { boolean swapped = false; // 标记本轮是否发生交换 for (int j = 0; j < files.size() - 1 - i; j++) { // 字符串比较必须用 compareTo,> 0 表示前者应排在后 if (files.get(j).getName().compareTo(files.get(j + 1).getName()) > 0) { File tmp = files.get(j); files.set(j, files.get(j + 1)); files.set(j + 1, tmp); swapped = true; } } if (!swapped) { break; // 本轮无交换说明已有序,提前退出 } } }swapped标记是冒泡排序里最容易被省略又最该保留的一行,它让最好情况(本来就有序)降到 O(n)。files.size() - 1 - i里的- i是因为每轮结束后末尾的 i 个元素已经就位,不需要再比。理解这两处,比背下整个算法更有用。
3.4 三件套分工与「重复渲染」这个坑
网页端的分工很清晰:HTML 负责结构和布局,CSS 负责外观,JavaScript 负责动态效果。教师信息展示的做法是先把数据放在数组里,再用表格渲染到页面。这一步只是静态数据,真实项目里数据来自数据库,读取后再回显,这个「静态数组先跑通、再换成数据库」的路径是合理的,因为它把「渲染逻辑对不对」和「数据来源通不通」两个问题拆开了。
添加功能暴露的坑更典型:新建三个输入框分别读取编号、姓名、课程名,点击添加按钮后把信息显示到页面,结果每次添加都会把之前的记录重复渲染一遍,页面越点越长。原因在于渲染函数是「追加」而不是「重建」——每次添加都往容器里再插一遍全量数据。修法是在添加前先清空容器再整体重绘,或者只增量插入新增的那一条。
// 反例:每次添加都追加全量数据,页面出现重复行 // list.forEach(item => table.appendChild(renderRow(item))); // 正例:先清空再整体重绘,保证页面与数据源一致 function renderTable(list) { const tbody = document.querySelector('#teacherTable tbody'); tbody.innerHTML = ''; // 关键一步:清空旧节点 list.forEach(item => { const tr = document.createElement('tr'); tr.innerHTML = `<td>${item.id}</td><td>${item.name}</td><td>${item.course}</td>`; tbody.appendChild(tr); }); }「数据变了就整体重绘」这个思路在数据量小的时候完全够用,它保证页面永远是数据源的一次投影,不会出现新旧混杂。数据量大时再考虑增量更新和虚拟列表,但那是优化,不是第一版要解决的问题。
4. 从静态到动态:Node.js + Express + MySQL 的数据链路
第二周后半段的任务是把网页从「数组里的假数据」推到「数据库里的真数据」,整条链路是:浏览器发起请求 → Node.js 服务接收 → Express 路由分发 → 查询 MySQL → 结果转 JSON → 回显到页面。这条链路是后端入门最标准的骨架,也是复习时最该在纸上默画一遍的部分,因为它的每一段都有一个对应的排错入口。
4.1 项目初始化:npm init 之后得到了什么
在空目录里执行npm init,得到的是一个package.json,它记录项目名、版本、入口文件和依赖列表。很多人把它当成一个可跳过的步骤,实际上它是后面所有依赖管理的根:装了 Express、装了 MySQL 驱动,都会写进这里;换台机器只要npm install就能还原环境。目录约定上,入口文件放服务启动逻辑,静态页面放公开目录,路由和数据访问各自成文件,这样后面加功能不用在一个文件里翻。
4.2 请求响应层:get 和 post 各管什么
Express 的核心就两件事:定义路由、处理请求与响应。get 用于获取数据,参数挂在 URL 上,服务端用req.query取;post 用于提交数据,参数在请求体里,服务端用req.body取,且必须先挂解析中间件,否则取到的是 undefined。这条差异是新手最常见的翻车点:用 post 提交表单却忘了挂解析器,打印出来永远是空对象。
const express = require('express'); const app = express(); app.use(express.json()); // 解析 application/json 请求体 app.use(express.urlencoded({ extended: true })); // 解析表单提交 // get:查询参数走 URL,用 req.query 取 app.get('/api/books', async (req, res) => { const keyword = req.query.keyword || ''; // 缺省为空串,等价于查全部 const rows = await queryBooks(keyword); res.json({ code: 0, data: rows }); // 统一返回结构,前端好处理 }); // post:提交数据走请求体,用 req.body 取 app.post('/api/books', async (req, res) => { const { name, author } = req.body; if (!name) { return res.status(400).json({ code: 1, msg: '书名不能为空' }); // 参数校验前置 } await insertBook(name, author); res.json({ code: 0 }); }); app.listen(3000, () => console.log('server on 3000')); // 端口被占用会直接报错express.json()和express.urlencoded()两行中间件决定了req.body有没有值;res.json()会自动设置内容类型并序列化,不要手动拼字符串;app.listen的端口如果被别的进程占用,启动阶段就会抛错,这是好事——比运行到一半才失败容易定位。
4.3 数据落库:Excel 导入、JSON 转换与驱动选择
数据从 Excel 进数据库,中间要过三关:第一关是建库建表,字段类型要和 Excel 列的实际内容对得上,编号用整型、名称用变长字符串;第二关是导入,把 Excel 另存为可解析的格式再批量插入,逐条手输只适合几十行以内的演示数据;第三关是读出来给前端,Node 查 MySQL 拿到的是结果集对象,需要转成 JSON 才能被页面消费。
驱动层要装的是 MySQL 的 Node 辅助包,连接时把主机、端口、用户名、密码、库名和字符集一起配上。字符集这一项最容易漏,漏了之后单机测试一切正常,一遇到中文就出问题。
4.4 增删改查的本质:按钮 → JS 函数 → SQL
记录里有一句总结很到位:对数据库的增删改查,实际上是通过页面按钮的点击激活不同的 JavaScript 函数,由函数去执行脚本,从而执行不同的 SQL 语句。把这句话展开成一条可复现的路径:
- 页面上为每个操作绑定按钮,按钮的点击事件指向一个函数;
- 函数里用
fetch或表单提交把参数发到对应路由,新增和修改走 post,删除和查询走 get 或 post; - 路由里拼 SQL,查询用
SELECT、新增用INSERT、修改用UPDATE、删除用DELETE; - 执行完把影响行数或结果集返回,前端据此刷新表格。
这里最该警惕的是 SQL 拼接。用字符串拼where name = '+ 输入值 +',遇到带引号的内容就会报错,更严重的是留下注入风险。参数化查询用占位符把值和语句分开,是唯一正确的写法:
// 错误:直接拼接用户输入,引号和注入都挡不住 // const sql = `select * from book where name like '%${keyword}%'`; // 正确:占位符 + 参数数组,驱动负责转义 const sql = 'select id, name, author from book where name like ?'; const rows = await pool.query(sql, [`%${keyword}%`]); // 模糊匹配由通配符承担?的个数必须和参数数组长度一致,多一个少一个都会报错;通配符%要放在参数里而不是 SQL 里,否则占位符会失效。
4.5 中文乱码的三处源头:页面、连接、库表
中文信息录不进数据库,是这条链路上出现频率最高的问题。原因只有一个:链路上某一段的字符集和其他段不一致。页面用一套编码提交,连接用另一套编码传输,库表用第三套编码存储,中间任何一段对不上,中文就变成问号或乱码。记录里的处理是把数据库和页面的编码统一,问题解决;更稳的做法是全链路统一成支持四字节的字符集,从建库、建表、连接串到页面声明保持一致。
排查顺序建议固定成三步:先看页面声明和提交编码,再看连接配置里的字符集参数,最后看库和表的默认字符集。三步都对齐还乱码,再去看是不是导入数据时源文件的编码不对。这个顺序能覆盖绝大多数情况,也能避免「只改页面编码就以为修好了」的误判。
5. 易错点:环境配置与部署排错的五条血泪经验
第三周到第五周的内容从写代码转向了搭环境和部署,这部分在实习记录里占的篇幅不大,但对复习的人来说信息密度最高,因为它记的全是「按教程做完却跑不起来」的场景。要理解这些坑,先得有一张环境地图,知道每一层各自管什么。
5.1 环境地图:Linux、IIS、Tomcat 与三层框架各管一段
Linux 那一层管的是操作系统和编译工具链,任务是能在命令行下编写、编译、运行一个最小程序,并了解交叉编译的流程。服务器那一层分三类角色:文件服务器把大容量磁盘空间提供给网上客户机使用,接收数据处理和文件存取请求;打印服务器接收来自客户机的打印任务;通信服务器负责网与网之间的通信并提供多种接口。Web 容器那一层是 IIS 和 Tomcat 的天下,IIS 跑在 Windows 上、以站点和虚拟目录为单位组织,Tomcat 跑 Java Web 项目、以 webapps 目录为单位组织。
框架那一层则是 Java Web 的三段式分工:Struts 对应表示层,Spring 对应业务逻辑层,Hibernate 对应持久层。这样切的动机不是学术分类,而是让分工不同的部门在同一套模式下写代码,保证一个人写的程序另一个人能读懂,同时把建表、映射这类重复劳动自动生成,既保证可读性也降低成本。Spring 通过控制反转(也叫依赖注入)把对象的创建和依赖关系交给容器管理,还引入面向切面编程处理事务这类横切逻辑;Hibernate 在 JDBC 之上再封一层,实现对象与关系映射,不用手写 SQL 就能操作数据库。JSP 则是页面层的老技术,在传统页面文件中加入 Java 程序片段和标签实现动态输出,好处是对浏览器端要求低。
5.2 交叉编译的最小闭环与它真正验证了什么
在 Linux 环境下的第一个练习通常是:新建目录,写一个 hello.c 和一个 Makefile,编译后下载到目标开发板上运行。这个练习的价值不在 hello 本身,而在于它一次性验证了四件事:工具链装对了、Makefile 写得对、编译产物能生成、产物能烧到板子上跑起来。任何一环断了,后面的项目都无从谈起。
复习时容易把「跑通了 hello」等同于「掌握了嵌入式开发」,这是误判。它只证明了工具链闭环成立,不证明你会写驱动、会调硬件接口。把它当成环境自检脚本更准确:换一台机器、换一个开发板,这套最小闭环要能重新跑一遍,这才叫环境可控。
5.3 五条易错点逐条对账
第一条:中文乱码只改页面编码就收工。易漏点在于乱码的成因分布在整个链路上,页面只是最显眼的一段。为什么漏:改页面编码最快见效,改完看到部分正常就以为修好了。怎么补:固定按「页面声明 → 连接参数 → 库表默认字符集」三步查,三步全对齐再谈其他。
第二条:看到 500 错误就去改配置文件。记录里那个 Java 网站用 Tomcat 作服务器,浏览器加载时报 500,去服务器日志里找到一句「数据加载失败」,一开始怀疑 Tomcat 配置,改了很多遍都没用,最后发现是驱动包和数据库版本不匹配导致的连接错误。为什么漏:500 是服务端通用错误码,它只说明「服务器处理时抛异常了」,不说明异常在哪,凭猜测改配置等于盲改。怎么补:先去日志里找第一条带异常类名的堆栈,从最内层的 caused by 往外读,配置只在堆栈指向配置时才动。
第三条:部署后访问失败,先怀疑代码。项目挪到 webapps 目录、配好端口和地址、启动服务器、访问首页失败,最后发现是端口已被占用,换端口后正常。为什么漏:部署环节的失败原因大部分在环境而不在代码,但人的注意力天然在刚写完的代码上。怎么补:按「进程是否起来 → 端口是否在监听 → 地址和路径是否对 → 应用是否报错」四步排查,端口占用这一类问题在第二步就能拦住。
第四条:本地 IIS 站点建好却打不开。记录里的处理是:装系统、装 IIS、设置默认网站的主目录地址,浏览器访问失败,最后查到要设置 Internet 来宾账户的权限,并且因为后续要做后台管理还要勾上修改权限;另外只有在磁盘为 NTFS 格式时才能在对应系统版本下看到安全选项卡。为什么漏:教程只写到「设主目录」,权限这一步默认你会,实际新手根本不知道去哪设。怎么补:记住「站点打不开先看两件事——目录权限和默认文档」,权限不够时错误页往往不报权限,只报 401 或 403,看到这两个码直接去查目录授权。
第五条:数据重复渲染当成样式问题。添加信息后页面越点越长,第一反应往往是去看表格样式。为什么漏:现象出现在页面上,人就会往渲染层找。怎么补:先判断是「数据源里有重复」还是「渲染时重复插入」,打印一次数据源长度就能分清;数据源正常就一定是渲染函数在追加而不是重建。
注意:这五条的共同点是「症状出现的位置」和「根因所在的位置」不在一层。排错的第一步永远是先确认症状属于哪一层,再往下挖。
6. 复习清单:把五周内容压成一张对账表
复习这类实习记录,最省力的方式不是重读一遍流水账,而是把它压成一张能自测的对账表,逐行问自己「这一步的产出是什么、失败时先看哪里」。下面这张表可以直接抄下来当复习卡:
| 模块 | 必须能说清的三个点 | 失败时先看哪里 |
|---|---|---|
| 流程六步 | 每步产出物、概要设计与详细设计的分界、编码占比 | 需求是否确认、设计是否有文档 |
| 角色分工 | 项目经理管两端、架构师管概要设计、开发员管编码 | 责任是否落到具体人 |
| 桌面端 | 视图与逻辑分包、路径参数化、字符串比较 | 是否有写死的绝对路径 |
| 前端三件套 | 结构/样式/行为分工、渲染前清空容器 | 数据源长度是否正常 |
| 数据链路 | 路由分发、参数化查询、结果转 JSON | 请求体解析、占位符个数 |
| 字符集 | 页面、连接、库表三段对齐 | 从页面往库表逐段排查 |
| 部署 | 端口监听、目录权限、驱动版本匹配 | 日志第一条异常堆栈 |
配套的查漏补缺方法有三条,都是我自己反复验证过的。一是「默画链路」:拿一张白纸,从浏览器点击按钮开始,一路画到数据库返回,每一段标上可能的失败点,画不出来的地方就是漏洞。二是「反向读日志」:找一段报错堆栈,从最内层往外读,先定位异常类,再看调用链,最后才看自己写的业务代码。三是「环境复现」:把项目在一台干净机器上从零跑一遍,凡是需要「我记得当时装过什么」的步骤,都补进文档,因为这些步骤就是下次换机器时的坑。
我踩得最狠的一次是排查一个页面打不开的问题,盯着自己刚改的前端代码看了两个小时,最后发现是服务压根没起来,端口还被别的进程占着。从那以后我每次遇到「打不开、连不上、没反应」,都强制走一遍「进程 → 端口 → 路径 → 日志」这四步,不再一上来就怀疑自己写的代码。这份记录里五周的时间线、每类问题的排查路径和知识点分布都是现成的,对着改一遍,比从零回忆快得多,需要的话可以拿去直接用。希望帮到你。
本文还有配套的精品资源,点击获取