河北省科技政策查询系统博客2
一、PSP 表格:各模块开发的预估时间与实际时间
1.1 PSP2.1 过程阶段 —— 预估时间(实现前)
| PSP2.1 | Personal Software Process Stages | 时间(分钟) |
|Planning 计划| | 90 |
| Estimate | 估计这个任务需要多少时间 | 90 |
| Development 开发 | | 870 |
| Analysis | 需求分析(包括学习新技术) | 90 |
| Design Spec | 生成设计文档 | 60 |
| Design Review | 设计复审(和同事审核设计文档) | 60 |
| Coding Standard | 代码规范(为目前的开发制定合适的规范) | 30 |
| Design | 具体设计(数据库、类图、界面原型) | 120 |
| Coding | 具体编码(Java 后端 + JSP 前端 + uni-app) | 360 |
| Code Review | 代码复审(阅读自查) | 90 |
| Test | 测试(自我测试,修改代码,提交修改) | 60 |
| Reporting 报告 | | 180 |
| Test Report | 测试报告 | 60 |
| Size Measurement | 计算工作量 | 60 |
| Postmortem & Process Improvement Plan | 事后总结,并提出过程改进计划 | 60 |
| 合计 | | 1140 min(19.0 h) |
1.2 PSP2.1 过程阶段 —— 实际时间(实现后)
| PSP2.1 | Personal Software Process Stages | 时间(分钟) |
| Planning 计划 | | 85|
| Estimate | 估计这个任务需要多少时间 | 85 |
| Development 开发 | | 900 |
| Analysis | 需求分析(包括学习新技术) | 70 |
| Design Spec | 生成设计文档 | 40 |
| Design Review | 设计复审(和同事审核设计文档) | 30 |
| Coding Standard | 代码规范(为目前的开发制定合适的规范) | 20 |
| Design | 具体设计(数据库、类图、界面原型) | 100 |
| Coding | 具体编码(Java 后端 + JSP 前端 + uni-app) | 405 |
| Code Review | 代码复审(阅读自查) | 75 |
| Test | 测试(自我测试,修改代码,提交修改) | 160 |
| Reporting 报告 | | 185 |
| Test Report | 测试报告 | 65 |
| Size Measurement | 计算工作量 | 55 |
| Postmortem & Process Improvement Plan | 事后总结,并提出过程改进计划 | 65 |
| 合计 | | 1170 min(19.5 h) |
1.3 预估 vs 实际 对比分析
| 阶段 | 预估(min) | 实际(min) | 偏差 | 原因 |
| Planning | 90 | 85 | -5 | 需求文档较清晰,分析略快 |
| Analysis | 90 | 70 | -20 | 已有现成数据库结构,无需重新设计 |
| Design Spec / Review | 120 | 70 | -50 | 课程项目省略了正式文档化过程 |
| Coding Standard | 30 | 20 | -10 | 沿用课程已讲规范,无需额外制定 |
| Design | 120 | 100 | -20 | 架构简单(Servlet+JSP),设计较快 |
| Coding | 360 | 405 | +45 | Servlet 内拼接 HTML 比想象更繁琐;uni-app API 联调踩坑 |
| Code Review | 90 | 75 | -15 | 代码量小,阅读速度快 |
| Test | 60 | 160 | +100 | 发现 4 个缺陷(中文乱码/SQL 类型/分页越界/CORS),修复耗时远超预期 |
| Reporting | 180 | 185 | +5 | 基本一致 |
| 合计 | 1140 | 1170 | +30 | 整体偏差 +2.6%,表现良好;但测试阶段严重超预估 |
关键教训:对编码和测试阶段的预估过于乐观,尤其是"在 Servlet 中手写 HTML"和"数据库编码与分页边界"这些看似琐碎的环节,实际耗时显著超出预期。下次做计划时,应至少给测试阶段留足两倍时间。
二、测试用例(共 12 个,覆盖各功能点)
2.1 功能测试用例(Functional Test)
| 编号 | 模块 | 用例描述 | 输入 | 预期输出 | 实际输出 | 结论 |
| TC-01 | 首页加载 | 首次访问首页是否正常 | 访问 http://localhost:8080/policy/index.jsp | 顶部导航栏、左侧分类树、右侧政策列表正常显示,无 404/500 | 正常 | PASS |
| TC-02 | 分类筛选 | 点击分类树中的"综合" | 点击左侧 综合 链接 | 右侧列表仅显示 type=综合 的政策记录 | 正确筛选 | PASS |
| TC-03 | 关键词搜索 | 输入关键词"碳达峰" | keyword="碳达峰" | 返回所有政策名称或正文中含"碳达峰"的记录 | 返回 12 条匹配记录 | PASS |
| TC-04 | 多条件组合 | 关键词"碳达峰"+ 年份"2021" | keyword="碳达峰", year="2021" | 同时满足两个条件的政策被返回 | 返回 3 条 2021 年关于碳达峰的政策 | PASS |
| TC-05 | 制定机关模糊搜索 | 输入"河北省科技厅" | organ="河北省科技厅" | 返回所有制定机关含该关键字的政策 | 返回 28 条记录 | PASS |
| TC-06 | 政策详情页 | 点击列表中某条政策的"查看详情" | id=1 | 显示该政策完整的分类、发布日期、施行日期、富文本正文 | 内容完整显示 | PASS |
| TC-07 | 分页功能 | 首页点击"下一页" / 直接访问 page=3 | page="3" | 显示第 3 页的 10 条记录,页码高亮为 3 | 正确翻页,数据正确 | PASS |
| TC-08 | 无结果搜索 | 搜索一个不存在的关键词"xyz123" | keyword="xyz123" | 返回"没有找到符合条件的政策"提示 | 正确显示空结果提示 | PASS |
2.2 边界与异常测试用例(Edge / Exception Test)
| 编号 | 模块 | 用例描述 | 输入 | 预期输出 | 实际输出 | 结论 |
| TC-09 | 分页边界 | 输入非法页码 | page="-1"、page="0"、page="abc" | 自动修正为 page=1,展示第 1 页 | 正确兜底处理 | PASS |
| TC-10 | ID 越界 | 访问一个不存在的政策 | id=99999 / id=null | 显示"政策不存在"或参数错误提示,不出现 500 | 友好提示页 | PASS |
| TC-11 | 中文编码 | 搜索全中文关键词并翻页 | keyword="科技创新", page=2 | URL 中中文不乱码,翻页后搜索条件保留 | UTF-8 编码正确,分页带参正常 | PASS |
| TC-12 | 响应式布局 | 使用 Chrome DevTools 切换到手机尺寸 | 视口宽度 375×812 | 左侧分类树隐藏,顶部显示分类下拉菜单,列表单列展示 | 正常自适应 | PASS |
2.3 为什么我能确定程序是正确的
我通过以下 5 个维度的验证确保程序的正确性:
- 功能覆盖完整性:TC-01 ~ TC-08 覆盖了"浏览 → 筛选 → 搜索 → 详情 → 分页"的全部主流程,每个流程的输入/输出都符合需求文档描述。
- 边界与异常测试:TC-09(非法页码)、TC-10(越界 ID)验证了程序对错误输入的鲁棒性,这是程序正确性的关键——不崩溃比功能齐全更重要。
- SQL 注入测试:尝试输入
keyword = " ' OR '1'='1 "这种经典注入载荷,程序返回空结果(因为PreparedStatement将其视为纯字符串参数),证明不存在 SQL 注入漏洞,数据访问安全。 - 中文编码端到端验证:从 JSP 页面输入 → Tomcat 接收 → MySQL 存储 → 再次查询并显示,全链路使用 UTF-8(TC-11),确认无乱码。
- 响应式跨设备:TC-12 在桌面 / 平板 / 手机三种视口下测试,均能正常访问全部功能,符合"多端可用"的正确性目标。
共 12 条测试用例全部通过,主流程、边界条件、异常场景、安全维度均已覆盖,程序的功能正确性得到充分验证。
三、个人项目中学到的东西
3.1 技术层面
- 真正理解了分层架构:从 Policy(Entity)→ PolicyDao(DAO)→ PolicyServlet(Controller)→ index.jsp(View),每一层改代码时互不干扰。以前写代码总喜欢"一个类全写完",现在真正体会到了"高内聚、低耦合"的好处。
- JDBC 资源管理的严肃性:最初漏掉了 finally 块关闭 ResultSet,导致查询 20 次后 MySQL 连接数占满报错。这让我真正记住了"谁打开谁关闭、按 ResultSet → Statement → Connection 逆序关闭"的原则。
- PreparedStatement 不是语法糖,而是生命线:当我真正用 ' OR '1'='1 去测试时,发现如果用字符串拼接 SQL,整个数据库会被完全暴露。这让我对 SQL 注入的危害有了直观、"动手"的理解,而不再是书本上的一句话。
- 响应式前端并不神奇:只要理解了 Bootstrap 的 12 栅格系统和 d-none d-lg-block 这类工具类,就能在不写一行 CSS 的情况下做出专业级界面。
- uni-app 的"一次开发多端发布"真的很香:通过 api.js 封装统一的 HTTP 请求,manifest.json 配置不同平台,同一份 Vue 代码就能跑在 H5 和小程序上,这让我对"跨端开发"有了第一手经验。
3.2 过程与方法层面
- PSP 时间记录的价值:预估时我给 Test 阶段只留了 60 分钟,但实际花了 160 分钟。如果没有 PSP 表格,我永远不会意识到"自己严重低估了测试"——这比多写 100 行代码更有价值。
- 预估偏差 +30 分钟看似不大,但内部极不平衡:Design/Review 省了 70 分钟,Coding 和 Test 却超了 145 分钟。说明"省文档时间换编码时间"是危险的策略,设计不充分,编码必返工。
- 缺陷发现越早成本越低:DEF-02(SQL 类型)如果在 Code Review 阶段就发现,可能 5 分钟就能改完;但因为没认真 review,到 Test 阶段复现 + 调试 + 修复花了 20 分钟。
3.3 项目管理与软技能层面
- 需求文档的价值:拿到《河北省科技政策查询系统需求》文档后,我没有一开始就写代码,而是先读完列了一份功能清单,这个习惯让整个开发过程没有"返工重做"的重大浪费。
- 能用"和"正确"之间隔着一百个细节:程序能显示出数据不等于它就是正确的——中文乱码、分页越界、跨域问题、注入漏洞都是"功能能跑但程序不对"的典型。测试用例是把"能用"推到"正确"的唯一途径。
3.4 下一步改进计划(PSP 过程改进)
| 改进项 | 当前状态 | 下一次计划 |
| 数据库连接管理 | DriverManager 直连 | 引入 HikariCP 连接池 |
| 视图层 | Servlet 手写 println | 切换到 Thymeleaf 或 JSTL |
| 敏感信息 | 硬编码到 DBUtil.java | 抽到 config.properties 并 .gitignore |
| 搜索性能 | LIKE '%xxx%' 全表扫描 | 引入 MySQL FULLTEXT 或 Elasticsearch |
| 日志 | e.printStackTrace() | 引入 slf4j + logback |
| PSP 计划 | 测试时间低估 2.6 倍 | 下次项目测试阶段按"预估 × 2.5"分配 |
总结:这个项目给我的最大收获,不是学会了 Servlet 或 JSP 的语法,而是第一次用工程化的视角看待代码——从时间预估到测试用例,从分层架构到资源管理,每一个细节都在训练我"如何成为一个专业开发者"。在以后的学习和工作中,我会继续使用 PSP 方法记录每个项目,让过程可测量、让改进看得见。

浙公网安备 33010602011771号