在校招季帮别人调试过的 Java 毕设里,就业信息平台这个题目出现得极其频繁,光“学生就业信息推送系统”这个变体,我至少接触过十来个版本。这个题目之所以经久不衰,是因为它功能边界清晰、贴近真实业务场景、又天然包含了前后端交互、权限控制、站内消息、数据推送这些面试官爱问、答辩老师爱听的考点。很多同学拿到这类题目后急急忙忙开写,最后代码能跑,但一问原理就卡壳,文档更是拼凑产物。
这篇东西不是通用的“Spring Boot 入门教程”,我就围绕“某校大学学生就业信息平台”这个具体题目,把从选题拆解、技术选型、核心推送链路、前后端权限设计,到最后的论文包装和答辩准备,完整串一遍。无论你是打算自己从零写这个毕设,还是手上已经有一套类似的模板项目需要二次开发和写文档,这篇应该都能帮你在思路上省不少时间。
1. 从毕设选题到可答辩交付:需求边界怎么定
1.1 这类“信息平台”真实要管的三类角色
很多同学看到“就业信息平台”第一反应是:这就是个展示招聘公告的网站,后台发发文章,前端列表展示,然后加个搜索。如果真按这个思路做,你的系统顶多算个新闻网站,根本撑不起“就业信息推送系统”这个题目,答辩时老师一句“你的推送体现在哪里”就能问倒你。
就业信息推送系统的核心,是用“线上化流转”的方式替代传统就业工作的线下信息分发。它至少要覆盖三类角色:
- 学生端:注册登录、维护在线简历、按关键词搜索招聘职位、浏览宣讲会和双选会信息、投递简历、接收就业通知消息。
- 企业端:注册入驻、提交资质材料、发布和管理招聘岗位、查看收到的简历、愿意的情况下还可以发起面试邀请沟通。
- 管理员端:审核企业和职位信息、管理新闻公告、配置发布推送任务、查看就业数据统计。
这三类角色之间有一条完整的信息流:企业发布职位 -> 管理员审核 -> 职位上线 -> 学生搜索/系统匹配 -> 学生投递 -> 反馈结果推送。而你标题里提到的“就业信息推送”,实际上承担的是整条链路里“主动触达”的角色,不是简单的站内信,而是要根据学生和职位的属性做匹配,再通过不同通道触达。
1.2 功能清单怎么列才算“饱满又不至于失控”
毕设最忌功能堆砌。有的同学在需求说明书里洋洋洒洒写了三十多个功能点,实际做出来一半是假的,一半是复制粘贴的,答辩时被追问细节马上就露馅。我见过通过率最高、整体完成度也高的做法,是把功能控制在能用“一页权限表”说清楚的范围内。
下面这个功能清单是我根据多个同题项目整理后觉得比较合适的模板,供你参考:
| 模块 | 学生端 | 企业端 | 管理员端 |
|---|---|---|---|
| 账号体系 | 注册/登录/找回密码 | 注册/登录/资质上传 | 账号管理/禁用/审核 |
| 简历 | 在线填写、预览、导出 | 查看简历、标记意向 | 数据统计时查看脱敏数据 |
| 职位 | 搜索、筛选、收藏、投递 | 职位发布、编辑、上下架 | 职位审核、分类管理 |
| 宣讲会/双选会 | 查看日历、报名 | 发起宣讲会申请 | 审核、发布、排期 |
| 消息推送 | 站内信、邮箱接收、已读 | 投递反馈消息、审核结果 | 创建推送任务 |
| 数据统计 | 个人投递记录 | 职位浏览/投递数据 | 就业率、高热度职位分析 |
按这套清单去做,需求文档能写实,代码量也不会失控。前后端加起来大概 40 个左右的接口,属于一个能在三四周内认真完成的量。
1.3 把非功能需求写进开题报告里
答辩老师除了看“能做什么”,还会问“做得怎么样”。这就是非功能需求的分量。对于毕设来说,不需要你去扛高并发,但至少要体现出“我考虑过这些问题”。
我在写这类项目的说明文档时,一般会在需求分析章节里安排一段非功能需求描述,包括:系统响应时间(普通服务在 2 秒内返回)、安全性要求(密码加密存储、接口鉴权、防 SQL 注入)、可维护性要求(包结构分层、统一返回结果、日志规范)以及并发简单校验(重复提交控制)。这一段不用过长,但它的存在能让论文的完整感和理论高度一下子不一样。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术选型为什么是 Spring Boot + Vue + MySQL:一套保守且稳妥的组合
2.1 后端生态的版本组合“公式”
Spring Boot 是当前 Java 后端项目的事实标准,对于学生就业信息平台这个场景,它最大的优势不是上手快,而是“约定大于配置”,能在极少的配置下把常规 Web、持久层、消息、定时任务全部拉通。但版本选型上有个很实际的问题:是选 Spring Boot 2.7 还是 3.x?
我的建议是,如果没有人强制要求,优先选择 Spring Boot 2.7.18 + JDK 8 + MyBatis-Plus + MySQL 8.0 的组合。理由有三点:一是网上可查的资料最多,遇到报错随便一搜就有答案;二是 Spring Boot 3.x 从 javax.servlet 换成了 jakarta.servlet 包名,很多老博客里的代码直接复制会编译失败,对新手不友好;三是学校实验室环境里,Java 8 的使用率仍然非常高,避免本地环境和机房环境不一致。
如果学校明确要求了 Spring Boot 3 或高版本,那你就需要注意兼容问题。第三方的整合比如 Sa-Token 当前版本对 Jakarta 的支持已经比较完善,而部分老版本的工具类在 Boot 3 下必须更换。
下面是一份常用的 application.yml 配置骨架,兼容多数就业平台场景:
yaml复制server:
port: 8080
servlet:
context-path: /
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/job?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: 123456
servlet:
multipart:
max-file-size: 10MB
max-request-size: 50MB
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
global-config:
db-config:
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
jwt:
secret: your-secret-key
expire-hours: 24
2.2 前端组件与交互路线
前端部分,就业信息平台这种“管理后台 + 门户页面”混合形态的项目,最成熟的搭配是 Vue 3 + Vite + Element Plus + Pinia + Axios。Vue 3 的 Composition API 写起来比 Options API 更有利于功能区分,Element Plus 的表格、表单、对话框组件能覆盖后台百分之八九十的页面需求,而且它自带的表单验证规则,能直接对应后端 Spring Boot 的 @Validated 参数校验。
需要提醒的是,很多网上模板用的是 Vue 2 + Element UI,原因是 Vue 2 时期的教程多。如果你已经有一定基础,建议还是用 Vue 3。但如果你的目的是快速出活,并且已有模板项目是 Vue 2,那就别折腾升级了,运行稳定的老版本照样能拿到不错的成绩。关键不在于“哪个版本新”,而在于“你能不能讲清楚它的路由配置、状态管理和接口封装”。
前端的接口交互层,我习惯在 request.js 里封装一个 Axios 实例,统一配置 Base URL、请求头自动携带 Token、响应拦截器处理 code 状态。这段代码后面讲登录鉴权时会再提到。
2.3 总要处理好的三个“基础设施”问题
写这类项目时,有三个基础设施问题哪怕优先级不高,也迟早要面对:
第一,Redis 要不要引入。如果只是做求职平台,不引入 Redis 完全可以,用数据库存储和定时任务也能实现功能。但引入 Redis 有非常现实的加分点:验证码缓存 5 分钟过期、热门职位缓存减少数据库压力、用户 Token 黑名单控制。这个项目里 Redis 的主要场景就是缓存和验证码,不用特意去搞分布式锁那些复杂用法。
第二,图片和附件上传。企业发布职位时要传企业 Logo,学生要传简历附件,这是刚性需求。最简单做法是上传到本地磁盘目录,通过 WebMvcConfigurer 配置虚拟路径映射;更正式的做法是使用 MinIO 或阿里云 OSS。毕设项目里,本地存储 + 虚拟路径映射就够用,能把上传和回显流程完整跑通即可。
第三,接口文档。有些人说毕设不用接口文档,我不同意。用 knife4j 集成 Swagger,打开页面就能看到所有接口的出入参,不管是自己调试还是答辩演示,都比你临时翻代码高效得多。而且,写论文的“系统设计”章节时,直接截接口文档的图也能充实篇幅。
3. 就业信息推送的核心链路拆解
3.1 数据从哪来:最容易被忽略的录入与审核流程
推送的前提是平台里有“数据内容”。很多同学一上来就写推送代码,结果前端没数据可展示,推了个寂寞。就业信息平台的数据流入路径其实很长:企业注册后填写资料上传资质 -> 管理员审核企业资质 -> 企业发布招聘职位 -> 管理员审核职位 -> 职位进入可展示列表。这中间任何一个环节丢了,后面的推荐和推送都无从谈起。
这里有个现实问题:演示阶段学校不一定真的有企业入驻,所以你需要一个“管理员代录”功能。管理员可以直接录入一批模拟企业、模拟职位和模拟宣讲会记录,并给它们打上“演示数据”标记。这样无论是演示、录屏还是跑测试,都能有真实可见的数据效果。
我建议把职位信息表设计好状态字段:
sql复制create table job_info (
id bigint primary key auto_increment,
company_id bigint not null comment '发布企业ID',
job_name varchar(100) not null comment '职位名称',
job_type varchar(50) comment '职位分类',
salary_range varchar(50) comment '薪资范围',
edu_require varchar(30) comment '学历要求',
major_require varchar(100) comment '专业倾向',
work_city varchar(50) comment '工作城市',
description text comment '职位描述',
status tinyint default 0 comment '0待审核 1已上线 2已下线',
create_time datetime,
update_time datetime
);
3.2 推送依据:简历标签与职位标签如何匹配
就业信息推送的核心不是“群发”,而是“精准”。学生就业信息平台如果只是把所有招聘信息一股脑发给所有人,那就是垃圾邮件。要让推送有说服力,你得有一个简单的匹配机制。
实现方式不需要多高级,标签匹配即可。学生在简历里维护自己的专业方向、期望城市、期望薪资区间、学历水平,职位发布时管理员也要给职位维护岗位类别、专业要求、学历要求、城市和薪资范围。推送时逐项匹配计分:
java复制public int matchScore(Resume resume, JobInfo job) {
int score = 0;
if (StringUtils.hasText(job.getMajorRequire())
&& resume.getMajor().contains(job.getMajorRequire())) {
score += 3;
}
if (StringUtils.hasText(job.getWorkCity())
&& job.getWorkCity().equals(resume.getExpectCity())) {
score += 2;
}
if (StringUtils.hasText(job.getSalaryRange())
&& job.getSalaryRange().equals(resume.getExpectSalary())) {
score += 1;
}
if (StringUtils.hasText(resume.getDegree())
&& resume.getDegree().equals(job.getEduRequire())) {
score += 1;
}
return score;
}
得分大于等于 5 的职位进入推送候选池,再按得分排序取前 5 条生成站内信推送。这个匹配逻辑虽然简单,但你把规则讲清楚以后,答辩老师的反应普遍是“虽然不复杂,但思路完整”,这就够了。真要用机器学习做推荐,反而超出了毕设的技术范围,也不好解释。
3.3 推送通道:定时任务 + WebSocket / 站内信 / 邮件
推送通道是整个系统里最展示技术含金量的地方。我见过的项目里,最多最稳妥的做法是三条通道并用:
第一是站内信。学生登录后在“消息中心”查看,数据表结构就是主流的消息模板 + 消息记录。每条消息有 is_read 字段,EXTRA 字段可以存业务ID,比如职位主键或投递ID,点击消息可以跳转详情。这个是基础,必须做。
第二是邮件。Spring Boot 里集成 spring-boot-starter-mail,在匹配任务执行时发送邮件到学生注册邮箱。邮件内容不用设计得太复杂,把职位名称、公司、薪资、城市列出来即可,关键是演示时能让人信服“邮件真的发出去了”。实际测试用 QQ 邮箱或者 126 邮箱的 SMTP,配置文件如下:
yaml复制spring:
mail:
host: smtp.qq.com
port: 465
username: your_email@qq.com
password: your_auth_code
properties:
mail:
smtp:
auth: true
ssl:
enable: true
第三是 WebSocket 实时提醒。宣讲会或双选会开始前 30 分钟,给报名的学生推送一条实时提醒。这部分用 Spring 自带的 WebSocketHandler 加拦截器就能做,登录后从 Token 里拿到用户 ID,放到 WebSocketSession 的管理 Map 中,定时任务发送时定向发送给在线用户。如果学生不在线,则降级为站内信存库。
下面是一个简单的 WebSocket 连接管理示意:
java复制@Component
public class UserWebSocketHandler implements WebSocketHandler {
private static final Map<Long, WebSocketSession> SESSION_MAP = new ConcurrentHashMap<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
Long userId = (Long) session.getAttributes().get("userId");
SESSION_MAP.put(userId, session);
}
public void sendToUser(Long userId, String message) {
WebSocketSession session = SESSION_MAP.get(userId);
if (session != null && session.isOpen()) {
session.sendMessage(new TextMessage(message));
}
}
}
定时任务用 Spring Task 的 @Scheduled(cron = "0 0 8 * * ?") 每早 8 点触发一次“新职位匹配推送”,再用一个 cron 每分钟扫一次宣讲会开始前 30 分钟的提醒。
注意:如果要展示实时推送效果,光靠定时任务在演示时很难等到触发时刻。解决办法是在管理端做一个“立即推送”按钮,手动指定学生标签和职位范围直接触发推送,演示时点一下屏幕,浏览器里的 WebSocket 立刻弹出消息,这个效果远比讲代码生动。
3.4 已读未读与消息过期
消息推送还有一个细节,就是已读未读状态的设计和消息过期策略。我见过有人把已读状态直接放在用户表的字段里,这是明显不合理的设计。正确做法是独立消息表,每条记录对应一个用户的一条消息:
sql复制create table user_message (
id bigint primary key auto_increment,
user_id bigint not null,
msg_type varchar(20) not null comment 'SYSTEM/JOB/INTERVIEW',
title varchar(200),
content text,
business_id bigint comment '关联业务ID,如职位ID',
is_read tinyint default 0,
read_time datetime,
create_time datetime,
index idx_user_read (user_id, is_read)
);
消息过期策略用定时任务解决,比如每天凌晨删除 6 个月前的已读消息,保留未读消息。这个细节在做“系统设计”文档的时候,可以放到数据库设计章节作为索引和清理策略的说明,也算一个加分点。
4. 前台用户端与后台管理端要拆开设计
4.1 页面级的核心清单与路由设计
就业信息平台天然分为前台门户和后台管理两大部分。如果混在一个项目里开发,路由和组件会越来越乱。我推荐在一个 Vue 工程里用目录和路由做物理隔离:
text复制src/
views/
portal/ # 前台:首页、职位列表、职位详情、宣讲会、消息中心、个人中心
backend/ # 后台:用户管理、企业审核、职位审核、消息推送、数据统计
前台门户的页面组件不需要太多,但每个都要有真实场景支撑。比如“首页”展示推荐职位列表,“职位列表页”支持按类别、城市、薪资筛选和搜索,“职位详情页”包含公司信息、职位要求、投递按钮,“宣讲会页”是一个卡片列表和报名入口。
后台管理端则围绕“审核”和“配置”展开:企业资质审核、职位发布审核、用户管理、公告发布管理、推送配置。这块用 Element Plus 的表格 + 弹出编辑框就能覆盖。
整个项目里的关键页面可以控制在 14-18 个之间,这是一个适合毕设规模的量。如果超过 25 个页面,大概率是设计过度了。
4.2 权限控制不只在按钮上
权限是就业信息平台这种多角色系统的命门。企业用户绝对不能看到学生列表,学生也不能看到企业的审核管理页面。在前后端分离架构下,最标准的方案是 JWT + 拦截器 / 切面,在 Spring Security 或者 Sa-Token 里做接口鉴权。
如果从零开始写,你不一定非要引 Spring Security,因为学习曲线陡;但答辩老师大概率会问“你是怎么做到不同角色看到不同页面的”,所以必须有一个能讲清楚的权限方案。我的推荐是使用 Sa-Token,它对新手友好,核心 API 就三个:StpUtil.login(id)、StpUtil.getLoginId()、@SaCheckRole("admin")。配合拦截器,代码量很小,还能把会话管理和权限校验讲清楚。
权限数据模型部分,经典 RBAC 五张表就够了:
- 用户表 user
- 角色表 role
- 菜单表 menu
- 用户角色关联表 user_role
- 角色菜单关联表 role_menu
后端接口示例:
java复制@SaCheckRole("company")
@PostMapping("/job/publish")
public R<Long> publishJob(@RequestBody @Valid JobPublishDto dto) {
Long companyId = StpUtil.getLoginIdAsLong();
return R.ok(jobService.publish(companyId, dto));
}
前端路由守卫配合角色标识做页面级控制,比如企业端路由要求角色是 company,管理端路由要求角色是 admin。菜单按钮的显隐用自定义指令 v-permission 控制。这样整体权限链路就是:登录拿角色 -> 前端控制页面和按钮 -> 后端拦截非法访问 -> 数据库查询限定数据范围,四层都讲通,答辩基本没什么缺口。
4.3 数据权限的简易做法
很多同学做了接口鉴权,却忘了数据权限。举一个常见的翻车例子:企业 A 的企业用户,调一个 /job/list 接口,能查到企业 B 发布的职位。这接口是通了,但逻辑是错的。
数据权限的简易做法,就是给查询接口强制注入当前登录用户的 ID。企业用户发布、编辑、删除和查看职位时,所有 SQL 都要带上 company_id = 当前登录企业用户ID 的条件。MyBatis-Plus 中可以重写查询条件,也可以用 @SaCheckRole + 手动设置查询条件,两种方式都行,关键是必须把这条规则落实到每个接口。学生端同理,只能查看自己的简历和投递记录。
从代码的味道上来讲,你在答辩时说“我们不仅在接口层做了角色权限控制,还在数据查询层做了行级数据隔离”,这句话比说一百句“系统安全性高”都有力。
5. Spring Boot 毕设里最容易翻车的五个坑
5.1 跨域与本地联调
前后端分离项目,本地开发时前端跑在 5173 端口,后端跑在 8080 端口,跨域问题百分之百会出现。解决办法要么在后端写跨域配置,要么在前端 devServer 配置代理。我推荐两个都配,但在论文里只重点写后端跨域配置即可,理由是好解释,不容易被问死。
后端跨域配置通常写一个配置类实现 WebMvcConfigurer:
java复制@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);
}
}
注意,如果用了 Spring Security 或 Sa-Token 的拦截器,跨域预检请求(OPTIONS)必须在拦截器里放行,否则前端那边看着像“请求失败”,其实是被拦截器挡了。这个坑非常经典,遇到前端报 CORS 错误时先确认拦截器配置。
5.2 Token 过期后的“假死”体验
演示时最容易出现的尴尬场面是:页面放着没操作,再点按钮发现请求报 401,前端毫无反应,页面像死了一样。实际上就是 Token 过期了。
比较好的处理方式是在 Axios 响应拦截器里统一处理 401:
js复制service.interceptors.response.use(
(response) => {
return response.data;
},
(error) => {
if (error.response && error.response.status === 401) {
localStorage.removeItem("token");
localStorage.removeItem("userInfo");
router.push("/login");
}
return Promise.reject(error);
}
);
同时在登录接口返回的 token 上设置合理的过期时间,一般设 24 小时比较合适。演示前一天登录,第二天开会如果忘了重新登录,顶多被弹到登录页,不至于现场写代码调试。
5.3 密码、SQL 注入与 XSS
密码存储是基础中的基础。Spring Boot 里主流选择是 BCrypt。用 Spring Security 的话直接注入 BCryptPasswordEncoder,不用 Spring Security 也可以单独引入 spring-security-crypto 做加密。关键点是:数据库里绝对不能出现明文密码,这一点务必在论文里强调。
SQL 注入方面,MyBatis 里要用 #{} 而不是 ${}。如果是 JDBC 拼接字符串的场景,必须用 PreparedStatement。XSS 防护上,企业发布的职位描述如果是富文本,一定要做过滤,最简单的做法是对 <script> 标签做转义,再入库,或者使用开源的 Jsoup 清理 HTML。
5.4 时间拿到手少 8 小时
这是时长发生的经典问题。MySQL 的 DATETIME 类型本身不带时区概念,而 Java 侧的 LocalDateTime 在同一项目里通常按系统默认时区处理。如果数据库连接串没有指定 serverTimezone=Asia/Shanghai,可能会有 8 小时偏移;如果项目部署在 Linux 服务器上时区没同步,也会有类似问题。
我通常会用一套组合拳解决:数据库连接串显式指定 serverTimezone=Asia/Shanghai,JVM 启动参数加 -Duser.timezone=GMT+8,Spring Boot 配置里统一 jackson.time-zone。三处统一后基本不会再出偏差。
5.5 数据库性能与模糊搜索
就业信息平台的数据量通常不会很大,性能压力有限,但数据统计页面如果用了多表 COUNT 和 GROUP BY,在没有任何索引的情况下,数据积累多了会明显变慢。建议在职位表的 job_type、work_city、status 字段上建组合索引,在用户表的 email 字段上建唯一索引。
模糊搜索关键字,比如职位名称搜索,如果用 LIKE '%keyword%',在最左侧加 % 会让索引失效。非要用这种模糊查询的话,在数据量可接受范围内直接全表扫描问题也不大;但如果你想在答辩时展示一点优化意识,可以说将搜索分词拆分,对关键词最左侧不带 % 的字段走索引查询,其余走搜索引擎或缓存。这个说法点到为止即可,不必真的引入 Elasticsearch。
6. 从“能跑”到“能答辩”:文档、LW 与演示包装
6.1 LW(论文/说明文档)的章节框架
代码写完了,文档和 LW(通常指毕业论文或设计说明书)才是决定分数的重要部分。很多同学代码功能挺完整,但文档是网上拼的,前后矛盾,答辩时老师随便翻两页就能看出来。
我给这类系统写说明文档时,推荐的章节框架是:
- 绪论:背景与意义、国内外研究现状、主要工作内容
- 需求分析:业务需求描述、功能需求(用例图 + 用例说明)、非功能需求
- 系统设计:总体架构(B/S 架构、前后端分离图)、功能模块设计、数据库设计(ER 图 + 数据表结构)
- 系统实现:按关键模块逐块贴代码和运行效果图,每个模块配一段说明
- 系统测试:功能测试用例表、测试结论
其中最容易写崩的是第三章的“数据库设计”。如果自己画 ER 图有困难,先用数据库建模工具生成,再自己理解着重画一版。不要直接截图导出,那样会让指导老师觉得你没有参与设计。
6.2 录屏演示脚本
答辩演示环节,提前准备录屏比现场操作稳妥得多。哪怕现场准备演示,也要有一条“演示脚本”,避免东点一下西点一下、五六分钟过去讲不出重点。
我的建议是按三个业务闭环来演示,每条线讲清楚“谁 -> 做了什么 -> 系统如何响应”:
- 学生线:注册登录 -> 完善简历 -> 浏览职位 -> 投递简历 -> 在消息中心看到投递反馈。
- 企业线:企业注册 -> 等待管理员审核 -> 审核通过 -> 发布职位 -> 审核通过 -> 在收到的简历列表里标记意向并发送面试邀请。
- 推送线:管理员在后台选择目标职位和推送范围 -> 点击“立即推送” -> 学生端登录状态下的 WebSocket 弹出实时消息,未登录用户登录后看到站内信。
录屏时建议把浏览器控制台打开一半,这样可以顺便展示前端请求正常返回 200,后端日志里打印出推送条数和匹配分数,技术含量当场就有了。
6.3 答辩常见提问与应答准备
准备好这些高频问题,你就能在答辩时少一点紧张感:
“为什么用 Spring Boot 而不用传统 SSM?”——Spring Boot 自动装配简化了配置;内嵌容器让部署更方便;生态完善,适合快速搭建独立服务。
“JWT 和 Session 有什么区别?”——Session 是服务端状态,需要存会话数据;JWT 的无状态特点适合前后端分离和多端访问,但要控制过期时间。
“消息推送为什么没有用第三方 SDK?”——毕设场景使用 WebSocket 和邮件协议的标准实现更利于讲解原理;如果对接第三方,后续论文和演示会受外部环境制约。
“数据一致性和事务怎么保证?”——凡是涉及投递、审核这类写操作,都加 @Transactional,在数据库层面再用外键或逻辑约束保证关键数据正确。
“如何防止接口被恶意刷?”——可以用拦截器统计 IP 访问频次,或对特殊接口加验证码。只要你能答出这个思路,老师不会期待你真的实现了一套限流系统。
把这些问题的答案提前整理成文字稿放在 LW 的附录里,临场即使紧张,也能按要点应答。
最后再分享一个我做这类项目时比较在意的点:很多人把精力全放在“写新代码”上,结果越写越偏,最后连最初的需求文档都对不上了。正确的节奏是先把需求说明书写清楚,再设计数据表,再定接口,最后写页面。如果手头已经有模板代码,也不要先急着改功能,先把表结构整理清楚、把接口跑一遍、把权限链路走通,再在这个基础上动细节。这个顺序能直接决定你的项目是“花架子”还是“真能演示真能答辩”。
就业信息平台的精髓不在页面多漂亮,而在那条从“职位发布”到“精准触达学生”的推送链路是否完整。把这个链路吃透,代码、文档、答辩就都有了主心骨。真要遇到某个具体功能调试不动的地方,多看日志、多看接口返回,比漫无目的地改代码有效得多。
