每年这个时候都能看到不少同学在为毕业设计发愁,尤其是前后端分离这种"看着简单、做起来全是细节"的项目。我手头刚好整理了一个SpringBoot+Vue的防诈知识在线学习系统完整实现思路,这里面的东西其实很多都是通用套路:课程学习、互动答题、积分排行、管理后台,换一层皮就能变成普法平台、安全教育培训系统,所以整个拆解过程对想快速搞定毕设或者想入门全栈的同学都有参考价值。今天我不画饼,直接把从选型到落地的全过程和那些网上搜不到的坑一次性讲清楚。
1. 项目整体设计与技术选型思路
1.1 为什么选SpringBoot+Vue前后端分离
先聊点实在的。我见过太多人一上来就想上微服务、上SpringCloud、上分布式,对一个毕设来说这完全是给自己挖坑。答辩的时候老师问"为什么用SpringCloud",大部分人根本答不上来。防诈知识在线学习系统这种项目,本质上是典型的CRUD加业务闭环系统,SpringBoot单体完全够用,而且SpringBoot生态成熟,资料多、排错容易,答辩时还能理直气壮地说"我选择了适合业务规模的架构"。
选Vue做前端的原因也很简单:Vue在国内社区活跃度极高,Element Plus组件库能让你在几天内拼出一个像模像样的管理后台,Vue Router的拦截器机制做登录鉴权非常顺手。至于为什么不选React,不是React不好,而是Vue的中文资料对毕设场景的覆盖更全,出问题时能更快找到解决方案。
这套选型的核心逻辑是:稳定 + 熟悉 + 能讲清楚。当老师问"为什么不用Flask/为什么不用JSP"时,你可以回答:Flask适合轻量接口服务,但SpringBoot内置了更完整的生态(Spring Security、MyBatis-Plus、Validation),开发效率更高;JSP是前后端耦合的老技术,不符合现代工程化趋势。这个回答既体现了技术选型的思考,又展示了知识广度。
1.2 功能模块与需求拆解
防诈知识在线学习系统的功能设计,不是随便堆功能,而要形成一个完整的学习业务闭环。我拆分了四个端:
用户端核心模块:
- 账号体系:注册、登录、个人信息维护、密码加密存储
- 课程学习:防诈知识课程分类浏览、课程详情、视频/图文学习、学习进度记录
- 互动答题:单选、多选、判断、情景模拟四种题型,提交后自动判分,立即反馈答案解析
- 激励机制:学习获得积分、答题获得积分、积分兑换等级称号
- 排行榜:按积分维度展示周榜/总榜
管理端核心模块:
- 课程管理:发布课程、上传视频、维护课程章节与学习资料
- 题库管理:维护各类型题目、设置正确答案与解析、管理题目分类
- 用户管理:查看用户信息、管理用户状态(禁用/启用)
- 数据统计:用户学习时长统计、答题正确率统计、每日活跃数据
这里有个容易被忽视的点:防诈科普类内容需要经常更新话术库和案例库,因为诈骗手法是不断翻新的。所以我特意把题库设计成可配置的数据库存储,而不是写死在代码里,这样管理员可以随时新增案例题,系统才有持续运营的价值。
1.3 核心业务流程设计
整个系统的核心闭环我画在脑子里是这样的:用户登录后浏览课程列表,点击进入课程详情开始学习,前端记录学习行为并定期上报进度;学完一个课时后系统判定"完成",自动发放积分并解锁相关答题任务;用户进入答题模块,完成一组题目后系统即时批改,答对按难度加分,答错则展示详细解析;积分累积后在排行榜模块动态更新排名,形成"学习-检验-激励-再学习"的闭环。
这个闭环有两个关键设计点:
第一,学习进度的判定不能只靠前端。有些同学图省事,让前端学习完直接调接口加积分,这很容易被刷。我采用了后端校验逻辑:服务端记录视频播放的进度点,当进度超过阈值(比如80%)且累计时长达到设定值时,才判定为有效学习。这样既防刷,又能真实反映学习情况。
第二,答题判分必须服务端完成。前端判分看着方便,但接口一旦被调用方绕过,积分体系就形同虚设。所有题目答案校验、积分计算都必须在后端处理,前端只负责展示结果。
这里还会涉及并发场景:比如用户快速点击"领取积分"按钮,重复提交会导致积分异常。我的解决方案是在积分接口上加一个简单的防重机制,用Redis存用户ID加业务ID的组合键,设置几秒过期,重复请求直接返回。这个设计不仅是技术亮点,还能写进论文的创新点里。
2. 数据库设计与反诈内容体系构建
2.1 数据表结构设计
数据库是整个系统的地基。我使用MySQL 8.0,设计表的时候遵循了三个原则:一是按业务域拆分,不搞大而全的宽表;二是冗余设计防止过度关联查询;三是关键字段加索引提升查询效率。
核心数据表清单如下:
| 表名 | 用途 | 关键字段 |
|---|---|---|
| user | 用户表 | id, username, password, nickname, avatar, role, status, create_time |
| course | 课程表 | id, title, cover, category, description, difficulty, status, create_time |
| course_section | 课时表 | id, course_id, section_title, video_url, content, sort_order, duration |
| question | 题目表 | id, category, type, content, options, answer, analysis, difficulty |
| learning_record | 学习记录表 | id, user_id, section_id, progress, status, learn_time, update_time |
| answer_record | 答题记录表 | id, user_id, question_id, user_answer, is_correct, create_time |
| points_record | 积分记录表 | id, user_id, source_type, source_id, points, create_time |
| course_collect | 收藏表 | id, user_id, course_id, create_time |
这里我重点说下learning_record表的设计。很多新手会把学习记录设计成只有一条记录,用户学到哪就实时更新,但这样无法体现学习历程。我把它设计成每个用户对每个课时一条记录,学习过程中反复更新progress字段,同时记录累计learn_time。这样管理员后台就能统计出"该用户今天学了多久"、"哪些课时学习完成率低"等有价值的数据,为后续做数据可视化提供基础。
question表的options字段我建议用JSON字符串存储,因为单选和多选的选项结构相同,统一用JSON数组方便前端渲染。answer字段对于多选来说需要存数组的字符串形式,判分时前后端约定好按分隔符拆解就行。这算是表结构与接口联调的协作默契。
2.2 反诈题材内容组织
内容层面,我参考了近年反诈宣传的常见分类,将课程和题库划分为六个主题板块:
- 冒充公检法诈骗
- 刷单返利诈骗
- 杀猪盘(婚恋交友诱导投资)
- 冒充客服退款诈骗
- 虚假投资理财
- 裸聊敲诈勒索
每个主题下配置了图文课程、案例视频和配套题库。相比泛泛而谈的"网络诈骗科普",这种分类的好处是学习路径清晰,用户可以根据自己的薄弱环节选择主题,也便于管理端做内容维护。
题库设计方面,除了常规的单选、多选、判断,我加入了一个场景题类型。场景题的题干是一个完整的诈骗话术或聊天场景,用户需要分析判断对方的意图并选择正确应对方式。这种题比纯知识题更能测出用户的防诈意识,也是项目答辩时可以拿出来讲的亮点之一。
举个例子:
题干:你在社交平台认识一位"理财导师",对方让你下载一款不知名的App进行"内部投资",并承诺"高回报、保本无风险"。你应该怎么做?A. 先小额充值试试;B. 下载注册并跟着操作;C. 立即拉黑并向平台举报;D. 向对方索要更多内部信息。
正确答案是C。这道题测试的正是用户对虚假投资理财类诈骗的识别能力。答案解析会详细说明为什么A选项也存在风险,因为骗子通常用小额收益放长线钓大鱼。
2.3 内容安全与审核机制
这里要提醒一下:涉及防诈、普法类内容,一定要做好内容规范化管理,避免出现任何有争议的表述、真实敏感人物信息或未经脱敏的真实案例。我在管理端做了两级审核机制:内容提交后默认是"待审核"状态,管理员需要人工审核通过才能上线。审核内容主要检查表述是否规范、案例是否脱敏、话术是否可能产生不良引导。
虽然毕设阶段通常是自己管理自己,但这个审核机制写进设计文档里是有加分项的,说明你考虑到了内容安全问题。而且从代码层面也简单,就是给课程和题目表加了一个status字段,查询时只展示"已发布"状态的数据。
3. 后端核心功能实现(SpringBoot篇)
3.1 Maven工程搭建与目录分层
我使用SpringBoot 2.7.18版本。为什么不用SpringBoot 3.x?因为3.x基于Jakarta命名空间,很多老版本教程和依赖会踩坑,而且部分公司在实际项目中还在用2.x,答辩时"稳定版本优先"这个理由站得住脚。如果你的环境只支持JDK17以上,那可以用3.x,但要注意把javax改成jakarta。
工程用IDEA初始化即可,通过Spring Initializr选择Web、MySQL Driver、Lombok依赖。我习惯手动引入MyBatis-Plus和JWT相关包,因为默认模板里没有:
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.5</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.5</version> </dependency>目录结构我按下面这样分,清晰且答辩时好讲:
src/main/java/com/example/fangzha ├── controller // 接口层,只做参数接收与结果封装 ├── service // 业务逻辑层,核心业务闭环都在这里 │ └── impl ├── mapper // MyBatis-Plus的Mapper接口 ├── entity // 数据库实体类 ├── dto // 前端传参的数据载体 ├── vo // 返回前端的视图对象 ├── config // 配置类,如跨域、拦截器、WebMvc ├── common // 统一返回结果、常量、异常处理器 ├── utils // Jwt工具类、日期工具等 └── security // JWT拦截器或Spring Security配置这里有个工程化习惯:接口入参不要直接用entity接收,而是定义DTO,避免前端多传字段导致安全隐患。返回数据用VO对象,可以控制哪些字段不外露(比如密码)。
统一返回结果也很关键。我定义了一个Result类,格式为code、message、data三元组,code用200表示成功、401表示未登录、500表示异常。所有接口都返回这个结构,前端可以统一封装axios拦截器处理错误提示,不用每个接口单独写异常分支。
3.2 JWT认证与权限控制
登录鉴权我选择了JWT配合拦截器的方式。为什么不用Spring Security?因为毕设项目中Spring Security的过滤器链配置对新手容易混乱,而且论文里写起来篇幅很长。直接用拦截器加ThreadLocal的方式更简洁直观,重点是能把Token认证流程讲清楚。
JWT的结构是Header.Payload.Signature三段式。我在Payload中放入userId和role,设置过期时间为2小时,签名密钥自定义。
核心逻辑如下:
public class JwtUtils { private static final String SECRET = "your-strong-secret-key"; public static String createToken(Long userId, String role) { return Jwts.builder() .claim("userId", userId) .claim("role", role) .setExpiration(new Date(System.currentTimeMillis() + 2 * 60 * 60 * 1000)) .signWith(SignatureAlgorithm.HS256, SECRET) .compact(); } public static Claims parseToken(String token) { return Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token).getBody(); } }登录接口在用户验证通过后返回Token,前端存储在localStorage中。后续每个请求在axios请求拦截器里带上Authorization请求头,后端定义一个HandlerInterceptor统一解析:
public class JwtInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("Authorization"); if (token == null || token.isEmpty()) { throw new BusinessException(401, "未登录"); } Claims claims = JwtUtils.parseToken(token); request.setAttribute("userId", claims.get("userId")); request.setAttribute("role", claims.get("role")); return true; } }对于管理员接口,我额外定义了一个@RequireRole注解,在拦截器中校验当前用户的role是否匹配。这样用户端和管理端的接口就被天然隔离了。
这里有个我踩过的坑:JWT解析时如果密钥太短会报WeakKeyException,HS256要求密钥至少256位。同时JWT是无状态的,用户被禁用后已签发的Token在过期前仍然有效,所以我在拦截器里每次请求都查一下用户表status字段,被禁用则直接拒绝访问。虽然多了一次数据库查询,但对毕设系统来说完全可接受,而且逻辑上更严谨。
3.3 学习进度与积分算法实现
学习进度上报接口是用户学习的核心入口,前端在播放视频时每15秒上报一次进度。为了避免频繁请求刷爆数据库,这里有个设计要点:不是每上报一次就更新一次进度,而是获取该课时当前的record,如果新进度小于已记录进度就不更新,只有大于才更新。同时status字段有三个状态:0未开始、1学习中、2已完成。
判定完成的逻辑:
if (progress >= 80 && record.getStatus() != 2) { record.setStatus(2); // 已完成 addPoints(userId, PointsType.STUDY_COMPLETE, sectionPoints); }积分是学习闭环中最关键的激励环节。我只设计了三种积分来源:完成课时学习、答对题目、每日登录。这样就避免了积分规则过于复杂导致代码混乱。
学习完成积分固定每个课时10分,答对题目得分根据难度区分:easy得5分、medium得8分、hard得12分。每日首次登录得2分,用Redis的setnx实现当日判断。
积分发放必须幂等,防止重复领取。我在points_record表中加了source_type和source_id的组合唯一约束,同一用户同一来源只能有一条积分记录,数据库层面兜底,规避并发问题。
排行榜实现上,我直接基于points_record表做SQL聚合:
SELECT user_id, SUM(points) as total_points FROM points_record WHERE create_time >= #{weekStart} GROUP BY user_id ORDER BY total_points DESC LIMIT 10数据量不大时这种即时聚合查询完全没问题,而且还能兼容"周榜"、"总榜"两种维度。等以后数据量真大了再上缓存排行也不迟,这就是"先保证功能,再考虑性能"的现实思路。
3.4 接口设计与跨域联调
前后端分离必然要处理跨域问题。开发环境下Vite默认的5173端口和SpringBoot的8080端口不同源,需要在后端配置CORS:
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .allowCredentials(true) .maxAge(3600); } }接口设计遵循RESTful风格,核心接口清单如下:
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /api/user/login | 用户登录 |
| GET | /api/course/list | 课程列表 |
| GET | /api/course/detail/{id} | 课程详情(含课时列表) |
| GET | /api/course/section/{id} | 课时详情 |
| POST | /api/learn/progress | 上报学习进度 |
| GET | /api/question/list?category=&type= | 题目列表 |
| POST | /api/answer/submit | 提交答案并判分 |
| GET | /api/rank/list?type=week | 排行榜 |
| GET | /api/user/info | 当前用户信息 |
后端接口写完后用Swagger或Knife4j自动生成接口文档,前端可以跟着文档联调,省去不少沟通成本。SpringBoot接入Knife4j只需加一个依赖加一个配置类,对毕设来说属于低投入高回报。
4. 前端交互与学习体验实现(Vue篇)
4.1 环境搭建与项目初始化
前端我选用Vue3搭配Vite。为什么不用Vue CLI?因为Vite启动快、配置简洁,而且Vue官方生态现在的主流方向就是Vite。安装Vue3项目的常用命令:
npm create vite@latest fangzha-web -- --template vue cd fangzha-web npm install基础依赖按需安装:
npm install axios element-plus pinia vue-router@4Element Plus是国内后台管理系统最顺手的组件库,表单、表格、弹窗、消息提示全都有现成组件,能极大提高开发效率。Pinia是Vue3官方推荐的状态管理库,比Vuex更轻量,API设计更符合直觉。
环境配置我习惯建三个环境文件:.env.development、.env.production,分别设置接口地址。
# .env.development VITE_API_BASE_URL=http://localhost:8080/api4.2 路由设计与登录守卫
整套系统的路由分为两部分:普通用户页面和管理员后台页面。由于系统规模不大,我用的是静态路由加嵌套路由组合,不搞动态路由那种复杂玩意,答辩时反而更容易讲清楚。
核心路由配置:
const routes = [ { path: '/login', component: () => import('../views/Login.vue') }, { path: '/', component: () => import('../layout/UserLayout.vue'), children: [ { path: '', redirect: '/home' }, { path: 'home', component: () => import('../views/Home.vue') }, { path: 'course', component: () => import('../views/CourseList.vue') }, { path: 'course/:id', component: () => import('../views/CourseDetail.vue') }, { path: 'answer', component: () => import('../views/AnswerPage.vue') }, { path: 'rank', component: () => import('../views/RankPage.vue') }, { path: 'profile', component: () => import('../views/Profile.vue') } ] }, { path: '/admin', component: () => import('../layout/AdminLayout.vue'), meta: { role: 'ADMIN' }, children: [ { path: 'dashboard', component: () => import('../views/admin/Dashboard.vue') }, { path: 'course', component: () => import('../views/admin/CourseManage.vue') }, { path: 'question', component: () => import('../views/admin/QuestionManage.vue') }, { path: 'user', component: () => import('../views/admin/UserManage.vue') } ] } ]路由守卫是登录鉴权的前端防线:
router.beforeEach((to, from, next) => { const token = localStorage.getItem('token') if (to.meta.role === 'ADMIN') { const role = localStorage.getItem('role') if (role !== 'ADMIN') return next('/home') } if (!token && to.path !== '/login') return next('/login') if (token && to.path === '/login') return next('/home') next() })当然前端守卫只是体验优化,真正的安全控制必须以后端拦截器为准,这一点要在文档里说明白。
4.3 视频播放与m3u8直播流适配
课程系统中视频播放是个核心需求。如果视频直接上传MP4文件,走OSS或本地静态资源映射,用原生video标签就能应付。但很多课程源会输出m3u8格式的视频流,直接用video标签无法播放,而且很多同学不知道Vue环境怎么实现"免安装播放器播放m3u8"。
我的解决方案是使用hls.js这个库,它无需安装浏览器插件,通过JavaScript直接解码并播放HLS流。实现步骤非常简洁:
npm install hls.js<script setup> import Hls from 'hls.js' import { ref, onMounted, watch } from 'vue' const videoRef = ref(null) const videoUrl = ref('') onMounted(() => { if (Hls.isSupported() && videoUrl.value) { const hls = new Hls() hls.loadSource(videoUrl.value) hls.attachMedia(videoRef.value) } }) </script>这里我踩过两个坑。第一个是hls.js在开发环境没问题,打包后如果音频服务地址不是公网可访问的,视频加载会失败。第二个是m3u8的切片如果是加密的,需要在hls配置中设置fetch配置携带头部信息,否则会报解密失败。毕设场景下最简单的做法是:统一用公开可访问的静态MP4文件或标准m3u8测试流,展示学习进度功能完全够用,答辩时提到"本项目同时支持MP4与m3u8格式播放"就已是加分项。
播放进度上报逻辑注意节流,我用的是每15秒上报一次,并且监听pause和ended事件,在暂停或结束时也主动上报一次,保证退出页面时进度不会丢失太多。
4.4 页面设计与数据可视化
页面视觉方面不用花太多心思做原创设计,Element Plus的标准布局足够拿得出手。首页模块我用了卡片式课程列表,展示课程封面、标题、难度、学习进度。课程详情页拆分两个Tab:课时列表和课程简介。
答题页是用户互动体验的核心。我做了一题一答的模式,用户选中选项后点击"提交答案",立即展示对错结果和解析。这种即时反馈的设计比全部答完再显示结果更有学习效果,逻辑实现也更简单。
管理端的数据统计页面用ECharts做图表。重点是学习趋势图和题库正确率分析:
<template> <div ref="chartRef" style="height: 400px"></div> </template> <script setup> import * as echarts from 'echarts' import { onMounted, ref } from 'vue' const chartRef = ref(null) onMounted(() => { const chart = echarts.init(chartRef.value) chart.setOption({ xAxis: { type: 'category', data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'] }, yAxis: { type: 'value' }, series: [{ type: 'line', data: [120, 200, 150, 80, 170, 210, 130], areaStyle: {} }] }) }) </script>ECharts的整合难度不大,但放在毕设里视觉效果非常好。答辩时打开管理后台,看着动态折线图和数据大屏,评审老师的第一印象就会好很多。
5. 系统部署与常见问题排查实录
5.1 本地联调与启动配置
前后端分离项目联调时最烦人的就是端口和代理。Vite开发服务器默认5173端口,请求后端8080的跨域问题虽然在SpringBoot侧配了CORS,但含Authorization请求头时浏览器会发送预检请求,如果预检响应不通过,控制台通常报"Access-Control-Allow-Headers"错误。所以我在CORS配置里必须把Authorization和Content-Type放在allowedHeaders里。
另一个省心做法是配置Vite代理:
// vite.config.js export default defineConfig({ server: { proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } } })这样前端请求/api开头的地址都走代理转发,浏览器的视角全是同源请求,开发体验极佳。
IDEA中配置SpringBoot启动项时,有同学不知道端口怎么改。其实很简单:直接在application.yml里配置即可:
server: port: 8080IDEA的启动配置里如果设置了VM options,优先级可能会覆盖配置文件,这个坑也需要注意。
5.2 常见报错排查速查表
整理一下我做这个项目过程中排查过的问题,按热度排序:
| 现象 | 根因 | 解决方案 |
|---|---|---|
| 前端请求接口报401 | Token过期或未携带;JWT密钥被改会解析失败 | 拦截器日志打印异常;核对localStorage中token是否存在 |
| 跨域请求失败 | 后端CORS未配置allowedHeaders | 在CorsConfig中添加allowedHeaders("*") |
| npm run dev报ESLint错误 | 脚手架默认ESLint规则严格 | 按提示修复或临时关闭ESLint(毕设阶段可接受) |
| 视频播放黑屏 | m3u8地址跨域或切片引用相对路径 | 将视频源修改为公网可访问的MP4;m3u8文件地址改为绝对路径 |
| MyBatis-Plus查询结果字段为null | 数据库字段下划线未映射到驼峰 | 在application.yml配置map-underscore-to-camel-case: true |
| 中文存入数据库乱码 | JDBC连接未指定编码 | jdbc:mysql://localhost:3306/fangzha?characterEncoding=utf8 |
| 项目打包后前端页面刷新404 | Vue Router的history模式需要服务端支持 | 改用hash模式,或在SpringBoot中配置转发到index.html |
| 启动报Port already in use | 8080端口被占用 | IDEA终端执行netstat -ano找到PID并kill,或修改端口 |
这里重点展开两个问题。第一个:Vue打包放进SpringBoot。很多人喜欢把前端打包后的dist目录扔进SpringBoot的resources/static下,然后直接访问8080端口看效果。这确实是最省事的部署方式,但要记得前端请求的API地址不要写死成localhost:8080,用相对路径/api或通过环境变量动态生成。此外,如果用history路由模式,刷新某个子路由页面时会找后端对应路径,然后404。解决方式很简单:改成hash模式,或者在后端加一个资源映射转发。
第二个:数据库表如果不存在会自动建表吗?MyBatis-Plus默认不会建表,需要手动执行SQL脚本,或者引入mybatis-plus-generator生成CRUD代码。毕设我推荐直接用Navicat建库建表,然后配合MyBatis-Plus的BaseMapper和LambdaQueryWrapper写查询,省下大量样板代码。高级查询条件像lik、between,LambdaQueryWrapper都能优雅搞定。
5.3 答辩亮点包装与论文撰写要点
防诈知识在线学习系统的题目本身自带社会价值和现实意义,这是答辩时的天然亮点。但光有题目还不够,需要在系统里真正体现"实战感"。
我总结几个答辩关键点:
第一,强调系统的"闭环学习"设计。从课程学习到答题检验再到积分激励,每个环节都有数据支撑,不是割裂的功能堆叠。
第二,强调"防刷"机制。学习进度阈值校验、积分幂等发放、每日积分上限设置,这些细节体现了对系统稳健性的考虑。
第三,展示数据可视化能力。ECharts图表呈现用户学习趋势、题库正确率等统计信息,让管理端"看得见"系统运营情况。
第四,论文可以按以下逻辑组织:绪论(背景与意义)→ 相关技术介绍 → 需求分析 → 系统设计(架构设计、功能设计、数据库设计)→ 系统实现 → 系统测试。其中技术介绍部分把SpringBoot、Vue、MyBatis-Plus、JWT各写一小节,篇幅很快就能撑起来。核心工作量集中在第4和第5章,也是论文查重的主要关注域。
系统测试部分别只写"功能正常"这种话。要列出测试用例表,写清楚输入数据、预期结果、实际结果。功能测试之外加个性能测试的展示,比如用JMeter压测登录接口,并把吞吐量和响应时间截图放在论文里,显得很有说服力。
6. 写在最后的一些经验总结
这整套系统从搭环境到完全跑通,一个人静下心来开发,大概需要三到四周的业余时间。但要说真正花时间的不是写代码,反而是那些看起来不起眼的细节:JWT密钥的选择、跨域预检的处理、视频播放格式的兼容、打包部署后的路由刷新问题。这些都是网上大把教程不会提到、只有自己踩一遍才能记住的东西。
我个人在实际开发中还有一个体会:毕设项目的本质不是做出一个多么完美的线上产品,而是通过这个项目证明你具备完整的软件开发思维。这个防诈学习系统虽然业务不算复杂,但它覆盖了前端工程化、后端接口设计、数据库建模、安全认证、数据可视化、部署运维等全流程能力,论文素材和答辩亮点都足够丰富。
如果你时间紧张,可以先把用户端的课程学习和答题闭环做扎实,再补管理端的基础维护功能。如果你做完了基础版还有余力,可以尝试把反诈案例库做上导入导出功能,或者把题库和课程加上统计分析报表。这个项目的扩展空间非常开放,把主干打牢之后,剩下的就是按兴趣点长枝叶。
最后再分享一个答辩时的小技巧:被问到"为什么做这个题目"时,不要只说"因为学校要求选题方向"。可以有底气地回答:"电信网络诈骗已成为社会关注的热点问题,反诈宣传教育工作常态化开展,而传统的线下宣讲存在覆盖范围有限、互动性不足的痛点。这个系统希望通过在线课程加互动答题的形式,提升公众对诈骗手法的识别能力,以较低成本实现更广泛的反诈知识传播。"这段话既自然又能体现你的思考深度。
希望这份拆解对正在做毕设的你有实际帮助。照着这个思路走,一个既能运行又能讲清楚的SpringBoot+Vue防诈学习系统并不难拿下来。