2. 网上家教平台的核心业务
2.1 三类角色的核心需求
2.2 家教员服务质量控制
2.3 课时费结算与系统安全
3. 数据库设计与核心表关联
3.1 用户与教员实体的抽象
3.2 预约业务的状态机设计
3.3 MyBatis表关联与常见坑
4. 基于SSM+Vue的模块实现要点
4.1 RABC权限控制
4.2 课程搜索与预约流程
4.3 媒资管理
5. 部署上线流程与注意事项
5.1 本地开发环境准备
5.2 服务器安全组配置与远程部署
5.3 HTTPS与CDN加速
6. 常见问题排查与调试技巧
6.1 数据库中文乱码
6.2 Vue请求跨域
6.3 高并发下的预约超时
7. 答辩亮点总结与文档撰写建议
7.1 答辩常问的几个问题
7.2 毕业论文重点章节的设计
7.3 项目扩展与能力提升方向
8. 安全防护与合规运行
8.1 前后端安全设计
8.2 用户认证机制
8.3 数据备份与监控
这个项目适合用来学习完整的全栈开发、毕业设计选题,甚至可以作为团队兼职家教产品的起点。如果有想自己动手从头写一遍的朋友,接下来的内容会比较对你有用。
作为两个大方向来说,SSM框架在服务端层面提供了清晰的 MVC 分层思路,而 Vue 则弥补了传统 JSP 页面交互笨重、前后端耦合严重的问题。所以这套组合在最近几年的毕业设计、和个人小项目中非常流行,选它完成一个网上家教平台,技术难度正好在“有深度、能讲清楚”的区间,不会过于简单,也不会难到无法落地。
2. 网上家教平台的核心业务
2.1 三类角色的核心需求
“家教平台”这个业务模型本质上是一个双边交易平台。与我们熟悉的电商平台非常相似:一端是有学习需求的学生/家长,另一端是有授课能力的家教员,平台方在这两者之间充当中介、评审和服务保障的角色。
所以,必然存在的三种角色分别是:学生用户、家教员、平台管理员。围绕这三类角色来设计功能模块,整个平台的业务脉络就清晰了。
学生/家长端的核心动作是“找课、预约、上课、评价”。他们需要最直观的操作路径:
- 按学科、年级、教学方式,快速筛选出合适的家教员
- 查看家教员的主页信息,包括教学资历、过往评价、可预约时间段
- 发起预约,填好期望上课时间、学习目标,等待确认
- 上课后进行评价、查看历史预约记录、对不满意的课时进行申诉
家教员端的核心动作是“发课、接单、上课、收款”。家教员需要:
- 维护个人主页,包括教学经历、教学科目、试听安排
- 查看收到的预约订单,选择接受或拒绝,沟通上课时间
- 管理自己的课时安排,避免时间冲突
- 查看自己的收益记录与学员评价
管理员端的核心动作是“护航”和“数据管理”,包括:
- 审核家教员入驻资质,避免不称职的人混进平台
- 审核平台课程信息、以及学科分类的维护
- 处理用户间的投诉与退款,管理订单状态
订单学费管理是这个平台经济闭环的关键,核心在于“预付款托管”。我见过很多初做家教平台的同学,会把订单金额在预约成功时直接转给教员,结果当学生觉得课不满意时,矛盾就会变得很尖锐,平台也失去了调节的依据。
正确做法是做一个“确认等于收款”的逻辑设计:用户支付后,资金停留在平台虚拟账户中,价签“待评价确认”,只有学生完成该次课程并确认后,资金才会正式进入教员的账户余额可供提现。这套逻辑本质上就是电商的三方支付托管。数据表里用一个订单状态字段表示,避免了复杂的资金实时结算。
平台或者个人项目初期如果要接入第三方支付系统,大多还可以用最朴素的方式处理:充值到自己的余额,或者干脆用模拟支付,保留接口位置便于后续扩展。
2.2 家教员服务质量控制
一个纯信息撮合的家教平台如果缺乏质量控制机制,两极分化很严重:水平高的教员被埋没,不负责的教员泛泛而谈还会带差平台口碑。橘子平台做的其中一个细节就是教员评分体系和试听课制度。
试听课的存在很有必要。线上家教和线下不同,双方是“搜索引擎+即时通讯”式的协作,教员的教学风格能不能让学生接受,是难以通过任何单一指标预测的。允许教员自行设置时长30分钟左右的试用课时,费用为零或极低,既能让学员感知老师风格,也能帮助教员获取更多生源。
评分体系则要关注多维评价这个细节,只提供“五星好评”太单薄了,容易刷出来虚假高评分。比较合理的拆法是:
- 教学态度(礼貌、准时、有准备)
- 沟通能力(表达是否清晰、善不善于互动)
- 教学效果(是否有效解决了不懂的问题)
三次评价维度合起来才能生成一个有说服力的综合评分。学员写评价时如果只给满分,却没有文字,前台显示时评级权重可以适当降低,以此鼓励真实反馈。
另外需要特别注意的是:家教平台这种“资金+服务”双敏感的系统,需要设计黑名单机制。遇到未按时上课、被多次投诉的教员,管理员要能封禁账号、强制下架课程。学生如果对已购买的课程不满意,也需要开通申诉入口。这块逻辑费时不多,但对平台的口碑树立意义很大。
2.3 课时费结算与系统安全
结算涉及的另一个点是“退款和提现”。在实际开发中,学费托管后,教员会要求将自己账户的余额提现到银行卡或支付宝。毕业设计可以简化,通过生成一个提现记录表来实现,后台管理员审核之后,手动模拟打款即可。这个设计如果讲得好,在答辩时是可以拿分的点——因为它将现实中的金融风控问题清晰地映射到了技术实现上。
接下来是安全须知,尤其当系统里牵扯到金钱交易,就不能只想着功能能跑通,安全和合规要提前考虑:
- 支付内容:真实项目的支付环节是需要相关资质与牌照的,个人项目或毕设不建议去碰真金白银。正确做法是写清楚“模拟支付”,完整保留调用逻辑,但要交代清楚真实的业务场景和现实约束。
- 敏感信息脱敏:教员身份证号、手机号、银行卡号这类字段,不能明文存数据库。至少要用主流的加密算法做加密存储,前端也要做掩码展示(比如
138****8888)。 - 日志留痕:订单资金变动的关键节点都必须记录操作日志,方便出现纠纷时回溯。
- 权限隔离:普通用户和教员角色绝对不能跨权限访问管理接口,后台接口不能只靠“前端隐藏按钮”来防护,必须有后端级别的校验。
这一块需要储备好,答辩的时候老师通常很关注“你有没有考虑系统安全性”这类问题,能讲出以上几点,就有了区分度。
3. 数据库设计与核心表关联
3.1 用户与教员实体的抽象
我用一个简单的思维模型来解释SSM项目的数据库设计,用一句话就是:把“人”“事”“物”转成表和表之间的关系。网上家教平台的基础库至少需要这几张核心表:
- 用户表(t_user):主键id,用户名、密码(加密后存储)、手机号、角色类型(学生/教员/管理员)、注册时间、是否封禁等
- 教员信息表(t_teacher):主键id、用户id外键、姓名、教学年限、学历、擅长学科、教学简介、封面头像、审核状态
- 课程分类表(t_category):教育阶段(小学/初中/高中/成人)、学科(数学/英语/语文/物理等)
- 课程表(t_course):家教员id、分类id、课程标题、课程介绍、课时时长、单价、封面图、上架/下架状态
- 预约订单表(t_booking):使用人id、教员id、课程id、预约时间段、订单状态、支付金额、投诉备注
- 评论表(t_comment):订单id、评分、三维度分数、评价内容、评论时间
其中有一个容易出错的设计问题:“用户”和“教员”是应该分成两张表,还是合在一张表里加个角色字段?我在第一次写这种平台时习惯于把所有的角色都塞进一张“用户表”,但后来发现不对劲。用户表承载了登录、注册、权限,而教员表里面是教学资历、授课科目、审核状态这些更垂直的字段,两者职责差异较大,合并会导致表字段冗长、大量字段可空,项目后期扩展困难。
所以正确的方案是分离设计:共用同一个账号体系(用户表),但垂直扩展出独立的教员表,靠用户id来关联。这样做的好处是:后期如果加入“家长”角色,学生用户依然可以复用同一套账号逻辑,不需要重新建表。
3.2 预约业务的状态机设计
订单状态是网上家教平台数据流转的心脏,这块如果设计乱了,后面做功能时最容易出各种“逻辑矛盾”的bug。常规的预约订单应该有以下几个状态:
| 状态 | 含义 |
|---|---|
| 0 待付款 | 用户发起了预约,订单已生成但未支付 |
| 1 待确认 | 用户已支付,等待家教员接受或拒绝 |
| 2 已确认 | 教员接受预约,等待上课 |
| 3 已完成 | 课时结束,用户确认后资金解锁至教员余额 |
| 4 已取消 | 用户或教员单方面取消,且通过审核 |
| 5 申诉中 | 因争议进入平台干预阶段 |
建议写一个status_history表,把每一次状态变更(谁、从什么状态、改到什么状态、时间、原因)记录下来。很多刚写代码的同学会忽略这个表,只在order表中单纯改一个数字,一旦哪天查问题发现某笔订单“去哪了”,就无从下手。相信我,作为在线平台,状态历史永远不要省。
前端控制按钮的逻辑也依赖这个状态值。比如:用户端只在状态为“待付款”时显示“去支付”,状态为“待确认”时显示“提醒教员”,状态为“已完成”时显示“评价”和“申请售后”。把它做成一个前端过滤器,结合后端接口的校验,整体体验就会干净不少。
3.3 MyBatis表关联与常见坑
SSM项目中的持久层是MyBatis,手写XML映射是常态。表关联的写法其实比较固定,但有几个坑在校生经常踩:
第一个坑:字段名与实体属性驼峰映射问题。数据库命名字段常用下划线风格,比如teacher_name,而Java实体类普遍使用驼峰风格teacherName。如果你不使用MyBatis的驼峰映射开关,查出来的字段就全是null。需要在全局配置中加入:
mybatis: configuration: map-underscore-to-camel-case: true如果不方便改全局配置,那就只能在resultMap里一个一个手写字段映射,容易漏且今天改A明天忘B。
第二个坑:多表查询时注意列名冲突。当用户表join教员表,两个表都存在status字段时,查询结果集中就是同名列,resultMap必须使用别名或显式字段:
SELECT u.id AS user_id, u.username, t.id AS teacher_id, t.status AS teacher_status FROM t_user u LEFT JOIN t_teacher t ON u.id = t.user_id WHERE u.username = #{username}不要小看这个问题,很多NPE(空指针异常)就是从这里来的。SQL的别名和DTO的属性名保持一致可以省很多事。
第三个坑:分页。如果不想引入PageHelper插件,就需要自己在SQL中用limit和offset,或使用PageHelper.startPage(pageNum, pageSize)配合MyBatis插件拦截。用PageHelper时有一个必须注意的点:startPage之后必须紧跟第一条要执行的查询语句,中间不能插入其他查询逻辑,否则分页会作用在错误的SQL上。这类坑很隐蔽,但排查时又很浪费时间。
数据库设计如果可以画一张ER图,配合文档里展示,会显得很严谨。纸张、图表工具大家可以自行选择,只要是清晰地表达了表间关系,在答辩环节都是加分项。
4. 基于SSM+Vue的模块实现要点
4.1 RABC权限控制
权限设计做不好,一个很大的后患就是:普通用户直接通过URL访问管理员页面,或者调用管理员接口。前端Vue技术栈中可以在路由导航守卫上做拦截,但更关键的,还是要在后端把接口的权限卡死。SpringMVC允许用拦截器或AOP做权限验证,用传统一点的方式就是HandlerInterceptor:
public class AuthInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 从请求头或session里拿登录态 User loginUser = (User) request.getSession().getAttribute("loginUser"); if (loginUser == null) { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "请先登录"); return false; } // 再来判断这个角色是否有权访问该路径 return true; } }这里的逻辑是:某些接口需要登录才能访问,某些接口(如管理员后台的接口)只允许指定角色访问。权限模型不一定要像Shiro或Spring Security那样配一大套,但核心的思路要一样:后端必须有校验,不能只依赖于前端隐藏按钮。
Vue前端这边也要配合做一个路由守卫:
router.beforeEach((to, from, next) => { const token = localStorage.getItem('token') if (to.meta.requiresAuth && !token) { next('/login') } else { next() } })前后端配合后,才算形成了完整的权限闭环。
4.2 课程搜索与预约流程
作为家教平台,搜索是用户最常用的功能,做得好不好直接影响用户体验。后端一般提供一个综合搜索接口,参数大致包括:关键词、学科分类、年级、价格区间、评分排序。用MyBatis作为持久层,查询SQL需要支持动态拼接,有条件就追加where条件。这里给出一个简化的mapper示例:
<select id="searchCourses" resultMap="CourseVOMap"> SELECT c.*, t.teacher_name, t.avatar FROM t_course c LEFT JOIN t_teacher t ON c.teacher_id = t.id <where> <if test="keyword != null and keyword != ''"> AND (c.title LIKE CONCAT('%', #{keyword}, '%') OR t.teacher_name LIKE CONCAT('%', #{keyword}, '%')) </if> <if test="categoryId != null"> AND c.category_id = #{categoryId} </if> <if test="minPrice != null"> AND c.price >= #{minPrice} </if> <if test="maxPrice != null"> AND c.price <= #{maxPrice} </if> </where> ORDER BY <choose> <when test="sortBy == 'rating'">c.rating DESC</when> <otherwise>c.created_time DESC</otherwise> </choose> </select>这里要注意优化:简单的学生项目可能数据量只有几千条,用户感觉不到差别,但大促时真上了几万条数据,没有索引的LIKE查询就会很痛苦。建议在t_course表的title、category_id字段上做索引,同时检索时限制只能从上架状态的课程中找,避免下架课程还出现在列表里。
一句话感受一下细节:预约流程用状态驱动,整个环节从C端到S端形成闭环。用户点击“预约”按钮时,前端将courseId、selectedTime、remark发送给后端;后端做两件事,第一是检查该教员的这个时间段是否已经被其他人预定,第二件事是创建一条订单记录,状态为待付款。这里特别要注意拼接的时间段不能只按时间比较,要把时区问题、结束时间、缓冲时间一起考虑,不然会出现“明明这个老师下午两点有课,却又同时被约了下午两点半”的缝隙冲突。
前端可以选择日期加时间段的交互形式。传值的时候建议直接传时间戳或标准日期字符串,数据库用datetime类型保存,避免界面显示和数据库存储之间的格式差异。
4.3 媒资管理
家教平台里一定会涉及到一个固定的技术点:图片与文件上传。用户要传头像、课程封面,教员要传资质证书。在SSM项目里,如果用常规的FileUpload,代码写起来非常累,而且还有文件大小限制、文件路径问题。
我推荐一个比较省力的做法:用后端提供一个简单的上传接口,接收MultipartFile,把文件写入本地磁盘或云对象存储,然后把生成的URL保存到数据库。这里有一个重要注意事项:本地存储的路径必须和项目部署路径解耦,不能把图片直接写在Webapp目录下,否则项目重新打包部署后,所有图片都会丢失。
比较稳妥的做法是:在服务器特定目录存图片,然后通过一个静态资源映射的配置,将/files/**这样的请求映射到服务器目录。以SpringMVC为例:
@Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/files/**") .addResourceLocations("file:D:/edu-platform-upload/"); }对于毕业设计而言,这个方案完全够用。如果以后想做得更专业一点,把图片传到阿里云OSS或腾讯云COS,也只是把本地写文件替换成调用SDK的差别,接口层不变。
另外还要注意的是文件类型校验。不能光靠前端input标签的accept属性,后端也要校验扩展名和文件头,阻止上传jsp、jspx这类危险文件,这是全栈里最容易考到的安全知识点。
5. 部署上线流程与注意事项
5.1 本地开发环境准备
很多同学在部署SSM项目的时候常常卡在环境问题上,容易产生“代码没问题,但是跑不起来”的挫败感。这里我按顺序捋一下:
本地需要的工具一般为:JDK 8、Maven 3.6+、MySQL 5.7或8.0、Tomcat 8.5或9、Node.js 14+、微信开发者工具可选。
后端打包的时候有一个容易忽略的小点:如果用了Lombok,需要确保IDE安装了Lombok插件,同时pom里的依赖版本要和JDK版本兼容。例如JDK8用较新的Lombok版本时会有警告,但问题不大。
启动顺序也要严格按照“先基础设施、后应用服务”来:
- 启动MySQL,把项目的
init.sql导入 - 修改jdbc.properties或application.yml中的数据库账号、密码
- 拿IDEA打开后端代码,等Maven下载完依赖,启动SpringMVC项目(Tomcat内嵌或外部)
- 确认后端能访问,再启动Vue前端
npm install+npm run serve
这一步日常遇到的问题是端口冲突。8080端口被占,通常在IDEA的console里看到Port 8080 was already in use。可以用netstat -ano | findstr 8080看是谁占用的,然后去application.yml改端口,同时对Vue侧的vue.config.js代理也要改一致。
5.2 服务器安全组配置与远程部署
本地能跑通就够了,但如果需要作为完整的毕业设计展示,很多同学希望部署到云服务器上给答辩老师看演示链接。也有人会把项目面对面跑在本地,压缩包丢在虚拟机里,各有各的做法。这里我讲服务器部署的通用流程,供参考:
第一步:在云服务商控制台,擦亮眼睛看好安全组入站规则。端口必须统一管理,不要图省事放通所有端口。通常需要:22(SSH)、80(HTTP)、443(HTTPS)、3306(MySQL,仅限内网或临时调试)。这里必须提醒:3306千万不能对全网开放,否则数据库被爆破是分分钟的事。
第二步:安装环境。传统方式是yum install或apt install,建议直接用宝塔面板或类似管理工具,方便可视化管理。虽然毕设答辩时有些苛刻的老师会问“用了什么工具”“为什么用”,但能合理讲出原因还是能圆过去的。
第三步:前端的部署。Vue项目打包后生成的是纯静态资源,放在Nginx的html目录就行。后端的SpringMVC项目打war包丢到Tomcat的webapps目录,或者直接打成可执行jar包用systemd守护。一般SSM项目是war包,放到Tomcat即可。
最关键的配置在于Nginx反向代理。前端静态资源和后端动态接口需要在同一个域名下协作,所以我们用Nginx把/api前缀的请求代理到后端服务的地址:
server { listen 80; server_name your.domain.com; location / { root /home/www/edu-frontend; index index.html; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }这个用法相当于把8080端口藏在Nginx后面,外部只需暴露80端口。try_files那一行是为了支持VueRouter的history模式,否则刷新子页面就会出现404。
5.3 HTTPS与CDN加速
如果是真实运营的个人网站或产品demo,现在比较推荐直接上HTTPS。申请免费的SSL证书,比如使用Let's Encrypt或云厂商的免费证书,签发后在Nginx中加入:
listen 443 ssl; ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem;同时把80端口的HTTP请求通过301跳转到HTTPS。这个小细节非常提升专业感,也保护用户隐私。
如果你的平台面向的人群分布广、图片资源多,还可以顺手开通CDN加速静态资源:把/files/**这类请求指到CDN,不常更新的静态资源都从CDN分发。项目初期人不多,其实可以不用,后端本地存储加一个七牛或又拍云的对象存储,足以应对日常使用。
不过实际部署时要注意,CDN缓存会导致用户上传的图片更新延迟,需要配置缓存刷新或基于版本号的URL。比如文件名带上时间戳,就完美规避了这个问题。
6. 常见问题排查与调试技巧
6.1 数据库中文乱码
数据库中文乱码是SSM项目的高频问题,症状要么是数据库里存入的是“???”,要么是查询出来的中文在页面上变成了乱字符。
排查分三层:字符集、连接串、页面编码。
MySQL建库时要显式指定utf8mb4(注意不要只用utf8,为了兼容emoji):
CREATE DATABASE edu_platform DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;JDBC连接串要加上characterEncoding=utf8和useSSL=false:
jdbc.url=jdbc:mysql://localhost:3306/edu_platform?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false页面编码方面,在web.xml里配置CharacterEncodingFilter:
<filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter>这个坑排查一个流程下来,常常发现是某一环漏了,只要是三层都对齐,乱码就能从源头根除。
6.2 Vue请求跨域
Vue开发环境的跨域问题基本是必踩的坑。前端跑在localhost:8080,后端跑在localhost:9090,两边端口不同,直接fetch就是跨域。正确比较省事的方式是在vue.config.js中配置devServer代理:
module.exports = { devServer: { proxy: { '/api': { target: 'http://localhost:9090', changeOrigin: true, pathRewrite: { '^/api': '' } } } } }请务必要学会区分代理和CORS的区别。代理是前端开发环境的妥协,生产环境更多交给Nginx解决;而CORS是后端主动允许跨域,两种方式各有场景。在毕设里很多同学两个方案一起上反而造成混乱,其实只要掌握一种就好。
在生产环境里,如果Nginx已经做了反向代理,前后端就等于同源了,不需要额外写CORS,写错了反而可能出错。这一点答辩时能讲出来,老师会觉得你理解得通透。
6.3 高并发下的预约超时
真正上线后如果有一两个热门老师的课被反复预约,就会遇到并发问题:同一时间段被多个用户同时选中,如果代码只有简单的“查一下有没有被占,没有就插入”,大概率两条请求都检查通过、都插入成功。这就是典型的超卖问题。
解决方案有很多,从重到轻:
- 使用数据库的
SELECT ... FOR UPDATE给课程行加锁 - 在预约表上建唯一索引(课程id+时间段),插入时谁先插谁成功,第二个插会抛异常
- 用Redis的分布式锁
毕业设计要求看深度,但也要控制度。推荐方案是第2个,简单有效,不需要引入额外中间件。只要在t_booking表加上UNIQUE KEY uk_teacher_time (teacher_id, slot_start_time),同时在后端捕获DuplicateKeyException并给用户提示“该时段已被预约”,就达到目的了。
面试和技术答辩时能说出这个设计,是很容易加分的“亮点”,大家记好这套思路。
7. 答辩亮点总结与文档撰写建议
7.1 答辩常问的几个问题
每次答辩老师问的问题其实都是有套路的,提前准备等于拿分。常见的几个高概率问题:
为什么要选SSM和Vue这套技术栈?回答要点:SSM结构清晰,生态成熟,适合中小型管理系统;Vue前后端分离提升了交互体验和并行开发效率。把它说成经过调研和对比分析后的选择,不要只说“因为熟悉”。
系统有哪些角色,权限是怎么控制的?回答要点:先讲后台用了拦截器或Spring Security,再讲前端路由守卫。把第4节的方法说清楚,比很多人只说“用JSP判断”要强得多。
遇到最大的难点是什么?回答要点:可以提并发下预约冲突的问题,以及解决方案。组员和老师通常都想听到真实解决问题的能力,不要说“没有难点”。
平台的盈利模式是什么?回答要点:可以提到课时费分成、试听课引流、广告位或会员服务。不用深入,一两句话说明白商业逻辑就好。
还有一类高频提问是关于“数据安全性”和“防SQL注入”。SSM中MyBatis的#{}预编译已经天然防了一部分SQL注入,但如果写了${}做字符串拼接,这是明显的扣分点,答辩前一定要检查是否全部使用#{}。
7.2 毕业论文重点章节的设计
LW文档(论文文档)的写作质量直接决定了答辩老师的第一印象,结构上建议用如下骨架:
- 绪论:研究背景与意义、国内外研究现状、主要研究内容
- 相关技术介绍:SSM框架、Vue.js、MySQL、前后端分离架构
- 需求分析:功能需求、非功能需求、用例图
- 系统设计:总体架构图、功能模块设计、数据库设计
- 系统实现:核心功能界面截图+核心代码块
- 系统测试:测试用例表、测试结果分析
尤其重点是数据库设计E-R图、系统架构图、时序图,这类图形化表达最能让老师快速抓到整个项目的脉络。建议把“系统功能结构图”做成树状图,每一层都能对应到代码实现的模块,不要画了图但代码里没有对应功能,那是很要命的。
关于时序图,我的建议是只画一张最核心的:用户预约课程的完整交互时序。这张图画清楚了,业务逻辑的完整度就表达清楚了,其他场景用文字描述即可。
7.3 项目扩展与能力提升方向
这个项目做到这里其实已经可以称为“完整可运行的业务系统”了,如果想进一步升级,还有几个方向可以考虑:
- 在线音视频直播:将纯约课平台升级为在线实时授课,需要接入WebRTC或第三方IM服务。如果时间允许,可以先把信令流程写清楚。
- 推荐系统:根据用户搜索历史和购买记录,推荐合适的家教员。大学毕业设计场景不要求做到多高深的算法,简单的基于标签的用户喜好重合度计算就够了。
- 消息通知:订单状态变化后自动发短信或邮件提醒。可以灵活使用消息队列或简单的定时任务扫描表实现。
- 移动端:将Vue项目通过移动端适配或打包成小程序,适配场景更广阔,答辩演示也更方便。
这些扩展不是必须的,但如果一个项目能明确说明“当前实现了什么,以后能扩展什么”,老师会明显感受到思考深度。
8. 安全防护与合规运行
8.1 前后端安全设计
毕业设计如果是演示用途,确实不会有多少人真的来攻击,但从项目规范性的角度来说,没有安全设计是硬伤。
后端接口的防刷、防枚举是常见的安全关注点。比如用户信息的接口通过id去查,很容易导致越权。同一体系的用户查看别人的订单详情,就是典型的水平越权问题。代码上要注意,在service层查数据之前,先判断当前登录用户的id和数据归属id是否一致。
前端也要尽量杜绝用户输入导致的安全隐患,比如Vue的模板默认就会自动转义插值表达式的内容,只要不滥用v-html,XSS的风险就可控。
8.2 用户认证机制
SSM时代的登录态管理者最简单的是用Session和Cookie,但也有不少项目开始使用JWT。我的建议是:毕业设计写Session就已经完全够用,如果写了JWT,要能解释清楚优缺点。
Session方案的优点是实现简单、依赖服务端存储、退出登录时销毁方便。缺点则是水平扩展时共享不便。JWT的优点是适合前后端分离和微服务,缺点是遇到退出和拉黑时要额外维护黑名单。
一个成熟的网上家教平台前端可以用axios拦截器自动附上Token:
axios.interceptors.request.use(config => { const token = localStorage.getItem('token') if (token) { config.headers['Authorization'] = 'Bearer ' + token } return config })后端加一层解析Token的拦截器,将用户信息放入ThreadLocal,供后续业务调用。这样代码整洁,可读性也好。
8.3 数据备份与监控
数据是一切服务的基础,尤其是含有支付订单和用户档案的平台。部署环境至少要做到每天备份数据库,最简单的方式是写个cron定时任务执行mysqldump:
mysqldump -u root -p edu_platform > /backup/edu_platform_$(date +%Y%m%d).sql find /backup -type f -mtime +7 -delete后面那行意思很直观,备份文件只保留7天,防止占满磁盘。
监控方面做个最简但有效的方案:用Spring Boot Actuator(如果是Spring Boot)或一个简单的定时任务去检查核心接口的通断,并把状态暴露给运维。个人项目这一块非常受老师好评,因为从运维视角来做了。
我在实际操作中发现,很多看起来极易被忽略的小毛病都会在“线上环境”被无限放大。比如后端有个接口,可能因为服务器时区问题导致预约时间错乱,或者因为Nginx的client_max_body_size默认限制太小导致课程封面上传失败。这些只有在真正经历过一遍部署才会懂。所以我的建议是:无论时间多紧张,一定自己从零走一遍打包、部署、联调的过程,这个过程的收获比多抄几个功能代码都更有价值。
这个网上家教平台如果继续滚动开发,其实完全有机会从一个毕设演进成一个真正能试用的小产品:先把模拟支付换成真实的签约聚合支付,添加一个小程序端,再设计一套教员入驻审核流程,就能覆盖教学机构的基本运转需求。技术框架不必换,在现有基础上迭代就够了。
最后再分享一个小技巧:写文档时,把每个核心接口的请求参数、返回参数和业务时序图对齐贴好,看似不起眼,但在答辩时,老师随手翻到哪一页都能看懂系统逻辑,这比堆上一堆截图要有效果得多。