1. 为什么我选"网络安全趣味答题"这块硬骨头:选题动机与需求拆解
做毕设选题的时候,我翻了一整天的网上的历届题目汇总,发现绝大多数所谓的"在线考试系统""知识竞赛系统"走的都是同一个套路:用户登录、选试卷、答选择题、提交、出分。换一个专业名称,比如"Java网上考试系统""基于SSM的在线答题平台",本质上是同一套代码换皮。这种项目确实稳妥,但答辩的时候老师一眼就能看出工作量和思考深度。
我当时给自己定了一个标准:系统内核还是答题系统,但业务场景必须有差异化,至少让评委看到这个题目时能多问两句。综合考虑技术掌握的熟练度和业务的可玩性之后,我锁定了"网络安全知识趣味挑战赛"这个方向。原因有三:
第一,网络安全知识的受众面比想象中广。职场员工需要做安全培训考核,高校里有网络安全意识测评的需求,普通用户也需要了解防钓鱼、防诈骗、个人信息保护这类常识。所以系统不只是"写给自己玩的",它有实际的应用场景。
第二,题目自带内容张力。别的答题系统题目内容是数学公式、历史年份、英语单词,而安全知识题库天然可以按多个维度切分——密码学基础、社会工程学防范、恶意软件识别、隐私保护、应急响应、安全法规。这些维度恰恰能支撑起"测评报告"的功能,而不只是给一个冷冰冰的分数。
第三,这个方向和计算机专业毕业设计的技术契合度很高。系统涉及用户体系、题库管理、随机抽题、限时答题、自动判分、排行统计,到后面的缓存设计、防作弊逻辑,每一块都有可以深挖的点,不会出现"技术点撑不起一篇论文"的尴尬。
1.1 先拆需求:这是一套"轻量化测评系统",不是考试系统
我在需求阶段反复确认了一件容易被忽略的事:考试系统和测评系统的产品逻辑完全不同。
考试系统追求公平和严谨,题目固定、时间统一、成绩存档,用户是被考核的对象;测评系统追求覆盖面和即时反馈,题目随机、难度递进、答完立刻知道对错和解析,用户是来"参与挑战"的。我做的这个平台更偏向后者,所以最初需求文档里就写清楚了几个关键字:趣味挑战、即时反馈、排行激励、多维度素养评估。
功能边界定下来之后,需求矩阵大概是这样的:
- 游客可以浏览平台介绍、查看公开排行榜,但必须注册登录才能参与答题
- 答题者可以选择"随机混战"或者按分类挑战,题目由系统按难度比例随机抽取
- 答完一道题立刻显示对错、解析和得分,而不是全部提交后再批改
- 每次挑战结束生成一份"安全素养简报",按维度展示正确率和薄弱项
- 排行榜分总分榜、周榜和分类榜,靠积分和连续答题天数双重激励
- 管理员可以维护题库、用户列表、公告,并查看所有答题记录
这套需求直接决定了后面的数据表设计和技术选型。
1.2 和普通在线答题系统的本质区别在哪里
我对比过一堆同类项目,最后总结出三处真正的差异点:
随机抽题策略。普通考试系统是固定试卷,题序和选项顺序可以做扰动。测评系统必须保证同一场挑战里题目不重复、难度分布合理,而且每次进入挑战题都不一样。这个对SQL写法有讲究,后面专门讲。
即时反馈闭环。很多毕设的答题系统只记录"对/错",不展示详细解析和知识点归类。我这个系统在每次提交后立刻返回正确项、错误项、解析说明和对应知识点,相当于把"答题"和"学习"结合了,这个体验上的设计答辩时很加分。
测评报告的可视化。普通系统结束就出个分数。我额外做了一个按维度统计的"安全素养雷达",从账号安全、社交网络安全、终端安全、隐私保护、应急响应五个维度计算正确率,并对薄弱维度给出改进建议。虽然实现只是简单的聚合查询加前端图表,但这让"测评"两个字落地了。
2. SpringBoot轻量化架构——怎么把技术栈控制在够用且可控的范围内
毕设项目的技术选型有一个隐形考核点:你是不是真的理解为什么选它。如果一问"为什么用SpringBoot",回答"因为大家都这么用",那评委基本不会给高分。我当时整理选型逻辑时,是按"业务规模—开发效率—部署成本"三条线来推的。
系统预期用户量在校园或企业小规模培训场景下,并发峰值也就是几十人同时刷题,任务调度、消息队列、分布式锁这些完全不需要。单体应用加分层结构已经是这种规模下最清晰的形态。SpringBoot 2.7.x加上Java 8,足够支撑整个项目,而且环境配置简单,任何一台笔记本都能直接跑起来——对毕设答辩现场的演示来说,这一点特别重要。
前后端方案我选了Thymeleaf模板引擎加原生JavaScript,没上前后端分离。原因很实际:项目时间有限,如果拆Vue和SpringBoot两套工程,光是联调接口、处理跨域、部署两套服务就要多花不少时间。而这次系统的页面复杂度并不高,挑战答题页、排行榜页、管理后台,用模板引擎加少量Ajax调用完全能胜任。
说实话,如果项目能多两个月时间,我可能会选Vue3加SpringBoot的分离架构。但毕设的核心是完成度,不是技术炫技。模板引擎做出来的系统在表现力上确实朴素一点,但所有功能闭环、稳定可运行,比半吊子的前后端分离强得多。
2.1 依赖清单和版本选择笔记
项目的核心依赖我只保留了必要的部分,避免pom文件膨胀:
- spring-boot-starter-web:Web基础和内置Tomcat
- spring-boot-starter-security:登录认证和权限控制
- mybatis-plus-boot-starter:数据持久化,减少大量SQL样板代码
- mysql-connector-j:连接MySQL 8
- spring-boot-starter-data-redis:排行榜缓存和答题频控
- lombok:简化实体类代码
- spring-boot-starter-validation:表单参数校验
选MyBatis-Plus而不是Spring Data JPA,是因为毕设规模的表关联查询场景比较多,比如联表查用户的答题统计、按分类聚合正确率。MyBatis-Plus的QueryWrapper和LambdaQueryWrapper写起来直观,复杂查询直接用注解SQL兜底,控制力更强。
Spring Security我一度想换成自己写的拦截器,但后来发现要用到BCrypt密码加密、登录会话管理、角色区分这些现成能力,自己造轮子容易出漏洞,还是保留了Security。答题接口的权限控制用@PreAuthorize("hasRole('USER')")搞定。
2.2 表结构设计:支撑测评和排行榜的最小模型
数据库我设计了六张核心表,每张表的字段都是反复斟酌过的,尽量不冗余但要够用:
用户表(t_user),除了账号密码基础字段,还加了total_score累计积分、answer_count累计答题数、correct_count累计正确题数、level等级。这几个聚合字段初期可能觉得没必要,但排行榜和用户中心频繁要用,每次实时统计代价很大,冗余字段配合更新才是轻量级项目的正确做法。
题库表(t_question)的主要内容是:
- question_text(题目内容)
- option_json(选项以JSON数组存储,四个选项或六个选项都支持)
- answer(正确选项索引,如"A"或"0,2"用于多选)
- analysis(答案解析)
- category(分类编码:account_security、social_engineering、malware、privacy、emergency_response)
- difficulty(1到3的难度等级)
- score(基础分值)
设计和教训:answer字段绝对不能暴露到前端,后面会细说这个问题。
答题记录表(t_answer_record)是记录每次提交答案的明细表,字段包含user_id、question_id、user_answer、is_correct、duration(本题用时)、answered_at。这张表是测评报告的统计来源。
挑战场次表(t_challenge_session)记录每一次完整的挑战:user_id、category(NULL代表混战)、question_count、correct_count、total_score、duration_seconds、start_time、end_time。一次挑战对应多道答题记录,是一对多的关系。
排行榜没有单独设计,因为排行的数据是从用户表的聚合字段实时查出来的。后来量大了才用Redis zset做缓存榜单,这部分后面专门展开。
2.3 为什么要"轻量化":系统的核心服务模块切分
立项的时候有个朋友建议我把系统拆成微服务,再搞个消息队列。我直接否了——这就是典型的看着高大上、实则撑不起的项目架构。微服务解决的问题是多人协作和独立部署,单机单体能搞定的事情硬拆微服务,只会增加网络开销和运维复杂度。
我按照业务职能切了五个核心服务模块:
- 用户模块:注册登录、个人信息、积分与等级变更
- 题库模块:题目管理、分类维护、按指定规则的题目抽取
- 挑战模块:创建挑战、逐题答题、自动判分、挑战结果结算
- 报告模块:从答题记录聚合出维度正确率,生成测评简报
- 排行模块:积分榜、分类榜、周榜的查询与缓存刷新
模块之间通过Spring的Service层互相调用,控制层保持轻薄,所有的业务判断都下沉到服务里。答辩的时候如果有人问"某个功能在哪里实现的",你能直接定位到具体的Service类,这种清晰的边界是最大的底气。
3. 答题核心流程的实现:抽题、倒计时、判分与测评报告
整个系统最核心的流程就是挑战答题。我把它拆成四个阶段:开赛抽题、逐题作答、交卷判分、结果报告。每个阶段都有一些"写代码时踩到才知道"的细节。
3.1 随机抽题的正确姿势:别上来就ORDER BY RAND()
最容易犯的错误,是抽题时直接用SELECT * FROM t_question ORDER BY RAND() LIMIT 10。这个写法在小数据量下没问题,比如题库几千题的时候跑起来也还行。但逻辑上有个隐患:数据库会对全表每一行生成随机数,然后排序取前N条。当数据量到了几万,这个查询的时间会显著增长,而且在并发请求的场景下,每个用户抽题都触发一次全表排序,数据库压力瞬间拉满。
我采用的方案是先查出符合筛选条件的题目ID列表,然后在Java代码里用Collections.shuffle打乱,再取前N个ID去批量查询。对于几千条的题库规模,这个做法性能完全够,而且代码逻辑直观、可控性强。如果题库真的到了几十万条的规模,可以用WHERE id >= RAND() * (SELECT MAX(id) FROM t_question)这种主键随机策略,但那需要主键连续且均匀,是后话。
抽题时还要处理"难度比例"这个参数。我的做法是保证一道题只出现在一个难度档位,抽题时先按难度分组抽出对应数量的ID,再把三组ID合并打乱。这样每一场挑战的题目难度配比都是稳定的,比如混战模式固定为3道简单、5道中等、2道偏难。
3.2 判分逻辑放服务端,答案字段绝不进前端
答题流程如果做成"前端比对答案、后端只存结果",那系统就是纸糊的。我这边是这么设计的:
前端只能看到题目文本和选项内容,正确选项永远不传输到浏览器。用户选择答案后,前端把选项索引POST到后端接口/api/challenge/answer,后端拿着用户答案去比对数据库里的answer字段,然后返回一个统一结构的结果:
{ "isCorrect": true, "correctAnswer": "B", "analysis": "钓鱼邮件通常伪装成官方机构...", "currentScore": 10, "remainQuestions": 5 }这里有一个看似"打脸"的点:判分接口的响应里带了correctAnswer。有人会问:这不就等于答错之后告诉你正确答案了吗?其实这正是测评系统的设计意图——即时反馈学习。它和考试系统的区别就在这:考试怕作弊,测评怕用户不学。用户答完立刻看到正确答案和解析,下次遇到同类型题正确率就会上去。
重要提示:判断题和单选题的答案如果以明文存在数据库,管理后台和数据库客户端都能看到。所以至少要把answer字段和题目内容分表管理,或者对answer做一层可逆加密存储。我在实际项目里用的是Spring自带的Jasypt加密依赖,对answer字段做了加密,配置项只留一个加解密密钥。这个细节在答辩时讲出来,能体现出安全意识不是只在题目里,还落实在系统设计里。
3.3 限时答题:倒计时在前后端的双重保障
答题页面有个倒计时,倒计时数值由前端展示,但真正的时间限制在后端控制。
每道题的答题时限是60秒。用户点击"下一题"时,前端记录出题时间戳,提交答案时带上clientTimestamp。后端会额外检查duration是否小于(当前时间减出题时间),如果超过60秒就标记为"超时未作答",猜测前端有没有改代码都拦不住这个判定。
前端倒计时的作用是"提醒用户",后端超时判定是"规则底线"。这两个各有分工,不能混为一谈。我当时还遇到一个体验问题:如果用户卡在60秒的临界点提交,网络延迟一高,后端可能已经判超时了,用户界面却还在倒计时。解决办法是提交时放宽1秒的容忍窗口,后端超时判定设为61秒,这种细节在多人实测时很关键。
3.4 安全素养测评报告:让分数变成可执行的建议
挑战结束之后,系统会从t_answer_record表聚合本次挑战涉及题目的分类分布,计算每个安全维度的正确率。测评报告页面展示五个维度的进度条,外加一个简陋但实用的雷达图,用的是ECharts的雷达图组件。
聚合逻辑大概是这样的:查出本次挑战的答题记录,在Java里按category分组,统计每个类别的作答数和正确数,最后生成一个报告对象:
账号安全:作答8题,正确6题,正确率75% 社交工程防范:作答6题,正确5题,正确率83% 终端安全:作答4题,正确2题,正确率50% 隐私保护:作答6题,正确4题,正确率67% 应急响应:作答4题,正确3题,正确率75%正确率低于60%的维度会在报告下方推荐对应分类的练习,比如"建议加强终端安全方向训练,可进入'恶意软件识别'分类挑战"。这个"错哪练哪"的闭环逻辑,让测评结果有了产品价值,而不是仅仅展示一个数字。
4. 排行榜系统的实现:从数据库查询到Redis缓存的三层演进
排行榜是这个系统最吸引眼球的功能,也是最容易做"假"的功能。很多项目的排行榜就是在用户表里按分数排序然后查出来,页面一刷就慢,并发一高数据库就扛不住。我这边分了三个阶段思考榜单问题。
4.1 需求边界:到底需要几张榜
开发之前我列了一下榜单需求,发现排行榜不能只做一张。这个"榜单细化"的过程特别能体现产品思维:
- 总分榜:反映用户的历史累计积分排名,是用户综合实力的体现
- 周榜:反映本周累计获得的积分,刺激用户每周都有动力参与
- 分类榜:只统计某个安全分类下的答题积分,让专精某个方向的用户也有上榜机会
每个榜单的统计口径不同,所以存储和计算方式也不同。总分榜因为数据量不大,直接查用户表排序完全够用;周榜和分类榜如果也每次实时查,就要在大表上做聚合过滤,性能账完全算不过来。
4.2 引入Redis zset:有序集合才是排行榜的正解
Redis的有序集合(Sorted Set,简称zset)天生就是为排行榜设计的。每个成员有一个分数,按分数自动排序,在百万级数据下增加、查询、排名操作都是毫秒级。
我在项目里的做法是设计三个zset键:
rank:total:成员是用户ID,分数是累计积分,对应总分榜rank:week:202405:成员是用户ID,分数是本周积分增量rank:category:malware:成员是用户ID,分数是恶意软件分类的累计得分
每次答题判分结束,积分结算完成后,通过两个Redis命令把分数同步到对应的zset:
stringRedisTemplate.opsForZSet().incrementScore(RANK_TOTAL_KEY, userId, score); stringRedisTemplate.opsForZSet().incrementScore(RANK_WEEK_KEY + weekNum, userId, score); stringRedisTemplate.opsForZSet().incrementScore(RANK_CATEGORY_KEY + category, userId, score);incrementScore这个方法非常好用,它把"读取旧分数再写新分数"这个过程变成了原子操作,天然避免了并发加分时的数据丢失问题。数据库里的用户积分我用了UPDATE t_user SET total_score = total_score + #{score} WHERE id = #{userId}这种SQL原子更新,和Redis的incr思路一致。
4.3 榜单的定时归档与一致性补偿
zset方案解决了实时计算的问题,但引入了新麻烦:如果Redis挂了或者数据被清空,榜单就丢了。我在项目里用定时任务做兜底,每天凌晨2点执行一次:
- 从数据库统计昨天的周榜积分明细,算出准确排名
- 把结果写进MySQL的
t_rank_history历史榜单表 - 如果Redis中的周榜key不存在或者数据量异常,用数据库数据重新构建
关于周榜积分,还有一个容易忽略的细节:每周一零点,周榜要清零重新计数。最简单的做法是周榜key按周命名,下周自然生成新key,旧key设置过期时间自动淘汰。这样既不用手动清空,还能保留历史数据做周对比分析。
实际部署后我观察到的数据是:题库约两千道题、注册用户上百人时,Redis zset的排名查询几乎感受不到延迟,排行榜页面响应稳定在50毫秒以内。这个成绩比纯数据库方案快了一个数量级,答辩演示的时候特意用Chrome开发者工具截过图,很有说服力。
4.4 防作弊:不只是技术问题,更是规则问题
排行榜上了线,就有人想刷分。我在项目里做了几层防护:
答题最短用时校验:一道题正常阅读加思考至少需要8秒,如果一道题目用户不到3秒就提交,判定为异常答题,本次得分折半。规则可以在后台配置调整。
连续答题频控:Redis记录用户1分钟内的提交次数,超过20次就提示"答题过于频繁请休息一下",并临时禁用答题接口15分钟。这个限流用的是Redis的
INCR加EXPIRE命令,简单有效。IP维度监控:同一IP注册多个账号刷分的情况,通过每天定时统计同IP注册数量来识别,超过5个就拉提示。这个不阻断但留痕,后台管理员可以看到异常IP列表。
没有任何排行榜系统能百分之百防作弊,但四层规则叠加之后,刷分的成本和难度都提高了,至少普通用户不会轻易尝试。答辩讲到这部分,评委通常都会追问"you怎么权衡用户体验和风控力度",我的回答是:优先保证正常用户的体验,异常规则宁可宽松也不要误伤,发现刷分再收紧。
5. 实战中的那些坑:并发提交、时间竞争、数据一致性
写这个系统前后耗时三个月,踩过的坑不少。挑几个最有代表性的写出来,都是我在测试和真实使用中遇到的具体问题,不是文档里的标准答案。
5.1 用户连点两次提交,产生重复答题记录
我最初写答题接口时,前端提交答案后没有做按钮防重复。测试阶段发现,用户快速点击提交按钮,后端会同时收到两个一样的请求,数据库里同一个用户、同一道题产生了两条答题记录,积分也被加了两次。
解决分两层。前端先做按钮置灰,submitBtn.disabled = true,这能挡掉大多数连点。但前端只能防误操作,挡不住恶意请求或网络重试。后端我做了两层防护:
第一层是Redis的幂等控制。以用户ID加题目ID为key,提交时先setIfAbsent,如果key已经存在说明这道题已经处理过,直接返回老结果。这个key设置2分钟过期,给足网络重试的时间窗口。
第二层是数据库的唯一约束。在t_answer_record表上建(user_id, question_id, session_id)的唯一索引,就算并发请求穿透了Redis层,数据库的约束也会拒绝第二条记录。有人觉得这个索引是冗余的,但我在实际调试中发现,网络超时导致的客户端重试极其常见,索引兜底让我睡得踏实多了。
5.2 倒计时结束的提交:前端和后端对"超时"认定不一致
这个问题前面提到过,但值得单独展开。用户界面显示还剩15秒,结果用户卡在最后一秒提交,网络延迟200毫秒,到后端时倒计时的第60秒已经过去了,后端判定超时,前端却显示用户"按时"提交了。
解决思路是后端在做超时判定时,使用"出题时间+时限+宽容窗口"的公式。出题时间在ChallengeSession里存了questionStartTime,后端比较的时候用当前时间 - questionStartTime >= 60 + 1才判定超时,这1秒的宽容窗口覆盖了大部分网络延迟。同时前端倒计时结束的瞬间不允许再提交,并强制跳到下一题,两家各退一步,体验就顺畅了。
5.3 多选判分的"坑":正则匹配和集合比对的坑
选择题里最麻烦的是多选题。我把多选的答案设计成一个列表,比如[0, 2, 3],表示A、C、D是正确项。前端把用户勾选的选项索引数组也传上来。
最初我用字符串拼接再比较是否相等,结果发现用户选了[0, 2, 3]和[0, 3, 2]明明是同一种答案,但字符串不相等,被判错。后来改成把用户答案数组排序再比较,或者直接用CollectionUtils.isEqualCollection判断两个集合的元素是否一致。这个小坑花了我一个下午,写完才知道:凡是涉及选项集合的比较,一律用集合工具做无序相等判断,不要碰字符串。
5.4 答案字段的暴露隐患:测试的时候发现的胆战心惊
系统联调时我用浏览器开发者工具抓接口,发现一个严重问题:题目接口返回的数据里竟然带了answer字段。原因是我直接把数据库实体类序列化返回给了前端,而实体类里有answer和analysis两个字段,本意是管理端需要,但用户端的题目接口也继承了同一个实体。
解决方式是把用户端返回的DTO和数据库实体彻底分离。用MapStruct或者手写一个转换方法,只把questionId、questionText、optionJson、analysis(注意,解析在提交后才展示)传给前端,answer字段永远留在服务端。
这个短板暴露得越早越好。因为项目里但凡向前端暴露过一次答案,用户就会很快把题库所有答案都抓下来,排行榜就彻底失去公平性了。
5.5 浏览器刷新导致Session丢失:登录态不稳定
Spring Security默认的会话管理是Session存储在服务端内存,应用重启后所有用户都要重新登录。毕设答辩时如果现场重启了项目,登录状态全没了,非常尴尬。
我把会话存储迁移到了Redis,即spring.session.store-type=redis,这样应用重启后Session不丢,用户刷新页面也能保持登录。另外开启了Remember-Me功能,给了30天的cookie有效期,实测体验好了很多。这个小优化很不起眼,但对演示的顺畅度影响很大。
6. 这套系统的可扩展方向与答辩加分项
如果只是"做完了、能跑、交上去",那这个项目和网上几百个SpringBoot毕业设计没有区别。我做完主体功能之后,额外做了几个扩展设计,这些设计不一定全部实现了,但在论文和答辩里都作为"后续改进"写清楚了,这反而成了亮点。
6.1 闯关制模式的构想
当前系统是"每场挑战随机抽题",玩法比较单一。我的扩展方案是设计一条技能树路径,把安全素养的五个维度做成五道关卡,用户必须按顺序解锁。每个关卡内部有3小关,每小关答对一定数量的题才能进入下一关。关卡通过后发放徽章,徽章展示在个人主页。
技术实现上其实比想象中简单:用户表加一个unlocked_level字段,挑战接口创建session时检查当前难度是否小于等于unlocked_level + 1,通过后更新字段。但"关卡内容编排"的工作量主要在题目运营上,需要设计剧情化题干和递进的难度梯度。这个方向很适合扩展成论文的"研究展望"部分。
6.2 对抗赛模式
另一个我特别想做的功能是用户之间的1对1对抗赛。两个用户同时进入同一个比赛房间,共用同一套题目,比拼答题速度和正确率。这需要引入WebSocket或者SSE做实时状态同步。技术难点在于"同时开始"的控制,以及掉线重连的状态恢复。
做的话需要新增房间表、对抗记录表,并在Redis里维护房间状态。评估了一下工期,至少需要两周,我最后没有在毕设版本里实现,但把设计文档写进了附录。答辩时如果被问到"系统还有什么不足",就可以顺势说"目前只做了单人挑战,实时对抗模式的技术方案已经设计好,后续可扩展",这个接话的底气一下就出来了。
6.3 测评报告导出PDF
目前的测评报告只在网页端展示,我做了导出功能的设计:用itext库把用户的安全素养报告生成PDF文件,用户可以下载保存或者提交给单位培训部门作为考核凭证。这在企业安全培训场景下是刚需,也是把"测评"的价值从线上延伸到线下的关键一步。
实际代码不复杂,就是先查到报告数据模型,再用模板拼出PDF。但请注意,中文字体的注册要提前处理,否则PDF里的中文全是方块。
7. 写给我的同龄人:如果你也准备拿这个题目做毕业设计
最后一部分不讲技术了,聊点实际的。如果你正在纠结要不要选这个题目,或者已经选了但不知道从哪入手,我掏心窝子说几句。
这类"轻量级业务系统"毕设项目有一个共同的评审潜规则:技术上不求新,但求完整和自洽。你把SpringBoot、MyBatis-Plus、Redis、Spring Security这几样用得明明白白、表结构设计合理、边界功能完整(登录、权限、增删改查、统计、异常处理),分数不会低。最怕的是什么都写"了解""会一点",答辩一问细节就露馅。
我的开发顺序建议是这样的:
- 第一周:确定需求清单,画出角色流程图和核心页面原型,建库建表。这一周的工作决定了后面所有功能的走向,值得多花点时间。
- 第二到三周:搭好SpringBoot工程,跑通登录注册和用户权限。这是骨架,先把地基打牢。
- 第四到五周:做题库管理和题目增删改查。管理员功能是工作量的大头,先做掉心里有底。
- 第六到八周:做答题主流程和判分逻辑。这是核心功能,多测试异常情况。
- 第九到十周:做排行榜、测评报告和前端页面美化。这阶段系统开始"像样"了,成就感上来,后面就会越做越顺。
- 最后两周:全面测试、修复bug、写论文、做PPT。
题目和答案的录入是一个大坑,两千道题如果全靠手敲,一周都敲不完。我是自己先整理了三百道核心题,再从公开的安全知识题库里筛选整理成符合分类和难度要求的题目。注意题库内容要选择正能量、符合主流价值观的题目方向,重点放在防护意识和安全常识上。
最后再分享一个答辩技巧:演示的时候不要只演示"正常流程"。你先正常答一场,然后在评委面前表演一个错误操作,比如超时不做答、快速连点提交、未登录就访问答题接口,让系统把防护效果展示出来。做完这套动作,评委马上知道你不是只写了增删改查,而是真的考虑过系统的真实使用场景。我当时就是这么做的,效果可以说立竿见影。
这个项目让我最有成就感的地方,不是跑通的瞬间,而是看到一个完全不关心安全的同学在连续刷了几场题之后,主动跟我说"原来公共WiFi真的有这么大风险"。答题系统的价值不在排行榜,而在每一次"答错 + 看到解析"的瞬间。如果做出来的东西真的能让别人学到点什么,那这个毕设就值了。