免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

SpringBoot+Vue校园健康监测平台:从业务闭环到答辩防坑指南

SpringBoot+Vue校园健康监测平台:从业务闭环到答辩防坑指南 每年到毕业季总能看到一批代码仓库叫“XXX管理系统”的毕设项目点进去一看清一色的增删改查。老师如果追问一句“你的系统怎么处理同一用户重复提交”很多人就愣住了。手头这套基于 SpringBoot Vue 的校园疫情防控系统我更愿意管它叫校园健康监测平台跟大多数“管理系统”的区别在于需求场景足够真实角色边界清晰业务流程里带着提交、审批、流转、统计这样一套完整闭环。源码配套了初始化 SQL 脚本、接口文档和前后端代码整体覆盖 Java Web 全栈开发的关键环节适合三类人正在选毕设题目的同学、想完整跑通前后端分离项目的新手、需要快速交付课设/毕设的开发者。接下来我从选题、技术选型、数据库设计、接口实现、前端工程和部署排查这几个方向把这个项目从头到尾拆一遍。1. 毕业设计选题的底层逻辑为什么这个题目比商城系统更受答辩老师认可1.1 选题的普遍困局与这个题目的破局点毕设选题最常见的几个坑我见过太多次了。第一个是选图书管理、学生管理这类题目。功能就是单表增删改查数据表三张页面五个开发一周结束剩下几个月不知道干什么。到答辩的时候老师随口问一句“你的系统的权限是怎么设计的”就答不上来。第二个是选电商商城。方向没毛病但同质化太严重。一个班里五个人做商城老师看到第三个的时候已经彻底审美疲劳哪怕你的页面做得再花哨也很难留下深刻印象。第三个是选人工智能、推荐系统这种“听起来高级”的题目。很多同学其实撑不起模型训练和调优的工作量最后从开源社区找个项目跑一下写个论文就算完事答辩时被问到细节漏洞百出。而这个校园健康监测平台的选题价值在于它是一个“看起来不复杂但业务链完整”的系统。从技术角度看它是标准的前后端分离 Web 系统SpringBoot 提供 REST APIVue 负责页面交互MySQL 存储数据技术栈主流从业务角度看它有一个完整的“数据采集 — 异常发现 — 逐级审批 — 汇总统计”流程不是单纯的增删改查而是有业务状态变化的系统从展示角度看它有可视化统计、审批流、权限控制在答辩时能清清楚楚讲出“为什么这么设计”。换句话说这个题目难度适中但是有足够多的“讲述点”。对老师来说这比看十个商城系统有意思得多。1.2 三条核心业务线与角色权限的对应关系我拿到的这套源码里系统分了三个角色这在毕设里是非常合适的设计角色太多业务复杂度会失控角色太少权限设计没东西可讲。学生普通用户每日健康上报、查看通知公告、提交进出校/请假申请、查看审批结果辅导员/教师审批角色查看本班级或本学院学生的上报数据、处理请假审批、查看异常记录、登记处理结果系统管理员最高权限用户管理、院系管理、公告管理、数据统计、系统参数配置围绕这三个角色整个系统可以抽象成三条核心业务线每条业务线都对应一套完整的状态流转健康上报流程学生打开上报页面系统校验今天是否已上报提交体温、身体状况、位置等信息数据落库后管理员和辅导员在统计页面看到汇总。这条链路最基础但也是最容易出并发问题的链路。请假/进出校审批流程学生提交申请辅导员收到待办可以选择通过或驳回学生端同步看到状态从“待审批”变为“已通过”或“已驳回”。这条链路的核心是状态机管理也是答辩时展示业务逻辑的好素材。异常处理流程学生上报异常情况体温偏高、咳嗽、乏力等系统自动生成异常记录辅导员处理并填写处理结果异常记录进入统计报表。这条链路把“日常数据”和“人工干预”串在了一起。有了这三条主线整个系统的功能设计就有据可依不会出现“不知道为什么要做这个功能”的情况。我当时把这三条业务线画在论文的用例图里答辩老师一看就知道这个同学是真的做过需求分析的。2. SpringBootVue 技术选型的版本陷阱与避坑原则2.1 后端版本SpringBoot 2.7.x 才是多数毕设的最优解打开源码的 pom.xml第一件事是确认 SpringBoot 版本。很多同学一看有新版本就想用 3.x但 SpringBoot 3.x 有一堆隐藏成本JDK 要求 17 以上而很多学校机房和云服务器还停留在 JDK 8javax.servlet 命名空间全部改成了 jakarta.servlet网上大量的老教程代码直接报错部分 starter 组件的兼容版本也没完全跟上。对一个以“顺利运行 答辩通过”为目标的毕设来说这些额外成本完全没有必要。我建议的版本组合如下这也是我自己跑这类项目时的基准配置组件推荐版本说明JDK1.8兼容性最好学校机房和服务器基本都有SpringBoot2.7.x2.x 最后一个稳定大版本生态成熟MyBatis-Plus3.5.x简化单表 CRUD自带分页插件MySQL5.7 或 8.0两者都行注意驱动类名差异Node.js14.x ~ 16.xVue CLI 项目最稳的版本区间这里多说一句SpringBoot 版本不是越高越好而是“稳定、教程多、踩坑资料全”最好。如果你真的想用 3.x 也不是不行但要做好所有依赖和代码都得适配 jakarta 命名空间的心理准备光是项目里跨域配置、拦截器这些基础代码就够你折腾一阵子。2.2 前端版本Vue 2 还是 Vue 3 取决于你手中的源码前端同样存在版本选择问题。手头源码如果是 Vue 2 Element UI我建议别急着升级到 Vue 3 Element Plus。这两个版本之间有不少破坏性差异Vue 3 全面转向 Composition API组合式 APIElement UI 和 Element Plus 的组件用法也有细微区别。如果源码本身是 Vue 2 写的硬改到 Vue 3等于把前端重写一遍工作量直接翻倍。反过来如果源码是 Vue 3 Vite 或 Vue 3 Vue CLI也不要强行降级到 Vue 2因为你拿到的组件封装、路由配置、状态管理写法都是围绕 Vue 3 设计的硬切版本会引入一堆莫名其妙的兼容问题。从答辩角度考虑Vue 2 Element UI 依旧能打稳定、文档全、网上问答多而且 Vue 2 的 Options API 对初学者更友好。Vue 3 Element Plus 的优势是更现代化、性能更好适合你想在论文里写“使用 Composition API 进行逻辑复用”这种亮点的情况。核心原则只有一个以源码里的 package.json 为准配套安装对应版本不要在毕设阶段搞大版本迁移。2.3 配套组件MyBatis-Plus、Knife4j、Redis 的取舍这套源码的后端选型非常“毕设友好”。MyBatis-Plus 把单表 CRUD 从几十行 XML 变成了 BaseMapper 内置方法直接调用特别是分页查询一个 selectPage 就能拿到分页数据不用像原生 MyBatis 那样自己写 PageHelper 或者手写 limit 计算。为什么毕设用它能省时间因为日常增删改查没必要手写 SQL真正需要手写完整 SQL 的地方是后面的统计报表把这些精力留给业务查询才是合理的分配。Knife4j 是基于 Swagger 的接口文档增强工具页面比原生 Swagger UI 好看中文支持也好还能直接在线调试接口。源码里的接口文档如果是以 Knife4j 形式存在的启动后端后访问 /doc.html 就能看到所有接口的在线文档非常方便。Redis 在这套系统里的作用一般是缓存 token、缓存热点统计数据和限制接口调用频率。如果只是跑通项目不引入 Redis 也能运行——JWT 无状态认证完全可以脱离 Redis 工作。但引入 Redis 之后你在答辩时就有了更多可讲的点怎么处理 token 过期、怎么用 SETNX 做每日一报的防重、怎么缓存热点数据降低数据库压力。这几个话题全都是加分项。选型的整体原则就一句话一切以能跑通、能讲清楚为优先不要在毕设阶段追求技术炫技。你用 Caffeine 做本地缓存可能比 Redis 更适合单机部署但讲起来没有 Redis 那么“标准”。3. 数据库表结构与 SQL 脚本设计的六个关键决策3.1 核心表的字段设计与关系梳理拿到 SQL 脚本后不要急着执行先花半小时读懂表结构。这套系统的数据表数量在 8 张左右规模属于“不大不小刚刚好”核心表我梳理如下表名中文含义核心字段关键约束sys_user用户表id, username, password, name, role_id, dept_id, statususername 唯一sys_role角色表id, role_name, role_key, permissions预置三条数据sys_dept院系/班级表id, dept_name, parent_id树形结构health_report健康上报表id, user_id, report_date, temperature, health_status, location, remark(user_id, report_date) 唯一索引leave_apply进出校/请假申请表id, user_id, start_time, end_time, reason, status, approver_id, opinionstatus 默认 0abnormal_record异常记录表id, user_id, report_id, abnormal_type, handle_status, handle_result与上报表关联notice通知公告表id, title, content, publisher_id, create_time内容发布sys_config系统配置表id, config_key, config_value按需保留这几张表的关系非常清晰sys_user 通过 role_id 关联角色通过 dept_id 关联院系health_report 记录学生每天的常规情况abnormal_record 记录异常情况leave_apply 记录需要人工审批的情况。三条数据流从不同维度反映学生状态也对应前边说的三条核心业务线。3.2 唯一索引、逻辑删除、公共字段的处理SQL 脚本里有两个细节答辩时可以专门展开讲。第一个是 health_report 表的复合唯一索引。为什么必须加一个 (user_id, report_date) 的唯一索引因为“每日一报”的业务规则必须由数据库兜底。前端可以禁用按钮后端可以先查再插但这两个方案都有并发漏洞——如果同一毫秒内两个请求同时到达后端两次查询都查不到记录就会执行两次插入导致同一个人同一天出现两条上报数据。加了唯一索引后第二个 insert 直接抛 DuplicateKeyException数据安全性有保障。这种“业务幂等 数据库约束”的双保险思路是很多面试官都认可的设计。第二个是逻辑删除。学生账号、历史上报记录这类数据不要用 DELETE 物理删除而是加一个 deleted 字段默认 0做逻辑删除。原因很简单健康数据是审计类数据如果学生误操作被删掉历史记录就永久丢失了。逻辑删除虽然要额外维护条件但 MyBatis-Plus 的 TableLogic 注解能自动处理成本极低。公共字段方面建议每张表都带上 create_time、update_time 两个时间字段。MyBatis-Plus 可以配置自动填充插入和更新时不需要手动 set 时间统一维护表结构也规范。这套源码如果在实体类里已经用了 TableField(fill FieldFill.INSERT)说明这个细节已经处理过了。3.3 初始化数据的预置策略SQL 脚本里预置的数据也很有讲究它保证了“项目拿到手就能登录”三个角色管理员、辅导员、学生管理员账号一个、辅导员账号一个、学生账号一个方便演示院系和班级各一条测试数据若干条演示用的上报记录和公告这里有一个常见坑很多同学拿到的 SQL 脚本里密码字段可能是明文也可能是一串已经加密的固定值。如果是明文记得在项目初始化时把默认密码统一改掉如果是 BCrypt 密文登录时拿用户输入的密码去 matches 验证即可不要自己再额外 MD5 一次否则会出现“明明密码看着是对的但是登录就是失败”的诡异问题。提示如果要自己重置密码建议用 BCryptPasswordEncoder 加密后再替换脚本里的密文。SpringBoot 的 spring-security-crypto 包可以直接提供这个类。4. 后端接口从文档到实现的完整链路鉴权、上报幂等与统计4.1 统一返回体与接口文档的协作价值前后端分离的项目里接口约定是协作的“契约”。这套源码里的接口文档不管是在线 Knife4j 还是 Markdown、Postman 文档都遵循同一个返回结构{ code: 200, message: 操作成功, data: { } }code 为 200 表示成功401 表示未登录或 token 过期500 表示服务器异常。所有接口都返回这个结构前端 Axios 拦截器拿到响应后先看 code再决定是取 data 渲染页面还是弹出错误提示。这样做的价值在于前端不需要针对每一个接口单独处理错误逻辑全局统一兜住。接口文档的另一层价值是把“前端需要什么数据、后端返回什么数据”提前定义清楚。拿到源码后把接口文档通读一遍重点看几张核心业务相关的接口登录接口、每日上报接口、审批接口、统计接口。文档里会标注请求方式POST/GET、请求参数、返回示例你甚至不用看代码就能知道这个系统对外暴露了哪些能力。这也是毕设论文里“接口设计”一章的直接素材。4.2 JWT 登录鉴权与拦截器实现登录是整套系统的入口。这套源码用的是 JWT 无状态认证大概流程是前端把 username 和 password 发送给 /api/auth/login后端校验账号密码通过后生成一个 token包含用户 id、用户名、角色等信息用密钥签名前端把 token 存到 localStorage 或 Vuex/Pinia之后每次请求前端在请求头里带上 Authorization: Bearer后端拦截器校验 token合法则放行不合法则返回 401后端实现上一般有一个 JwtUtil 工具类负责生成和解析 token有一个 AuthInterceptor 拦截器负责校验。拦截器只拦截 /api/** 下除登录接口以外的请求。校验通过后把当前用户信息放到 ThreadLocal 里Service 层就能通过工具方法直接获取当前登录人的 id不用每个接口都手动接收 user_id 参数。这里有一个很多人没注意到的细节为什么拦截器不像老项目那样每次都去数据库查一遍用户因为 JWT 本身就是自包含的token 里已经有用户 id 和角色信息解析出来直接用即可。每次请求都查数据库等于把无状态认证做回了有状态性能开销白白增加了。如果引入了 Redis还能进一步在 Redis 里维护 token 与用户状态的对应关系达到“管理员强制下线某人”的效果这部分可以作为扩展点写进论文。4.3 每日一报的幂等设计唯一索引 先查后插健康上报是核心接口它的难点不是“插入一条记录”而是“保证一个人一天只能报一次”。我在第 3 部分已经讲了唯一索引的兜底作用这里说完整链路。第一层是前端控制。上报按钮提交成功后置灰显示“今日已上报”。这一层解决的是普通用户手滑连续点击的问题。第二层是后端 Service 层控制。先查一次 health_report 表看当天有没有记录没有才执行插入有就直接返回“今日已上报”。这一层解决的是绕过前端正常操作流程的重复请求。第三层是数据库唯一索引兜底。哪怕前两层被绕过两个并发请求同时到达第二次 insert 也会因为唯一约束失败而抛出异常。Service 层捕获 DuplicateKeyException 后统一返回友好提示而不是让用户看到一串英文堆栈。三层一起做才算一个完整的幂等方案。不少同学只写了前端判断这是最不稳的方案。答辩时把三层方案讲清楚老师会马上对你刮目相看。插入之前的参数校验也别省体温范围比如 35.0 ~ 42.0、上报日期不能是未来日期、备注长度限制等。SpringBoot 里可以用 Validated 实体字段上的校验注解实现一行一个规则方便又规范。4.4 数据统计接口的 SQL 聚合写法统计功能是这类系统的“彩蛋”也是答辩展示时最出效果的地方。源码里统计模块一般会提供几个常用接口每日上报人数与上报率按院系统计近 7 天上报趋势给折线图提供数据异常记录分类统计给饼图提供数据待审批数量给待办角标提供数据这些接口的底层其实是聚合 SQL。比如“近 7 天各院系上报人数”核心 SQL 类似SELECT DATE_FORMAT(h.report_date, %Y-%m-%d) AS report_date, d.dept_name, COUNT(DISTINCT h.user_id) AS report_count FROM health_report h LEFT JOIN sys_user u ON h.user_id u.id LEFT JOIN sys_dept d ON u.dept_id d.id WHERE h.report_date BETWEEN DATE_SUB(CURDATE(), INTERVAL 6 DAY) AND CURDATE() GROUP BY DATE_FORMAT(h.report_date, %Y-%m-%d), d.dept_name ORDER BY report_date DESC;这里有几个细节值得注意用 COUNT(DISTINCT user_id) 是为了去重防止同一个人在同一天重复上报导致统计虚高日期范围筛选要建立在索引字段上避免全表扫描如果表的数据量变大可以在 report_date 上单独建索引。MyBatis 里写成注解 SQL 或 XML 都行带动态条件的统计 SQL 建议放 XML 里可读性和维护性更好。5. Vue 前端敲代码前的工程化构思路由守卫、请求封装与后台布局5.1 Axios 实例与拦截器Token 注入和 401 处理前端部分第一件事是找到 src/utils/request.js有的项目叫 http.js。这里一般会创建一个 axios 实例设置 baseURL 和超时时间然后注册两个拦截器。请求拦截器的作用是“给所有请求自动带上 token”service.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers[Authorization] Bearer token } return config })响应拦截器的作用是“统一处理错误码”service.interceptors.response.use( response { const res response.data if (res.code ! 200) { if (res.code 401) { localStorage.removeItem(token) router.push(/login) } return Promise.reject(new Error(res.message)) } return res }, error { return Promise.reject(error) } )有了这一层页面里只需要关心业务数据不需要每个请求都写一遍“if (code 401) 就跳登录页”的判断。这个封装是前端工程化的基本功面试问到 axios 封装时聊这个是最有说服力的。5.2 动态菜单与路由守卫角色权限在前端的落地前端权限设计的核心是路由守卫。这套系统中不同角色登录后看到的菜单是不同的学生看到“每日上报”“我的申请”“通知公告”辅导员多了“审批中心”管理员看到全部菜单。这个需求通常有两种实现方式。第一种是把所有路由都注册进 Vue Router在路由 meta 里标记需要的角色每次跳转前用 router.beforeEach 判断当前用户角色是否在允许列表里。这种方式实现简单适合角色数量少的项目代码量也少而且出问题容易排查。第二种是后端登录时返回当前用户的菜单权限和角色 key前端根据这个动态 addRoute。这种方式更“动态”权限模型扩展性更强但实现复杂度也更高。很多开源的后台脚手架比如若依的前端权限控制就是这个思路。毕设源码如果用的是第一种完全够用如果答辩被问到“角色继续增加怎么办”你就可以说第一种方式配合后端菜单权限表也能扩展动态路由是优化方向。菜单渲染上侧边栏一般通过遍历菜单配置生成菜单项的名称、图标、路由地址都由配置控制。这种“配置驱动页面”的思路答“系统扩展性”时可以重点提。5.3 通用后台页面三板斧表格、搜索、弹窗表单前端的业务页面虽然多但套路高度一致表格展示数据、搜索表单筛选、弹窗承载新增和编辑。我建议你拿到源码后随便挑一个页面分析比如“学生管理”基本就是这样的结构页面顶部搜索条件输入框 查询/重置按钮页面中间el-table 展示用户列表操作列放编辑/删除/重置密码按钮页面底部el-pagination 分页组件点击新增或编辑时el-dialog 弹窗里包一个 el-form提交前校验再调接口这个页面的模板代码几乎可以复制到院系管理、通知公告、上报记录等所有列表型页面。理解了这一层你会发现整个前端页面数量虽多但其实都是同一个模式的变体真正的新知识点没几个。有一个容易忽略的小坑表格数据里的时间字段建议在后端统一格式化为字符串返回或者在前端统一做格式处理。很多同学遇到“时间显示成 2024-03-01T12:00:00.00008:00 这种格式”的困惑根源就是 LocalDateTime 序列化后默认输出 ISO 格式。解决办法很简单在后端加一个 Jackson 的日期格式统一配置即可。6. 从源码到本地跑通的完整流程与环境疑难排查6.1 前置环境清单与版本对照表跑通项目之前先把环境检查一遍避免在安装环节消耗太多热情。我自己跑这类项目时的建议版本就是第 2 部分那张表这里补充几个容易遗漏的细节Maven 最好配阿里云私服镜像否则第一次加载 SpringBoot 依赖会非常慢甚至卡住。修改 settings.xml 的 mirror 配置即可。IDEA 创建 SpringBoot 项目时Spring Initializr 的 Server URL 可以改成阿里云的地址能避免部分网络环境下初始化失败。前端依赖如果下载慢优先把 npm registry 切到镜像源npm config set registry https://registry.npmmirror.com。这些前置工作看起来琐碎但恰恰是新手最容易卡住的地方。很多同学连项目代码都没跑起来就先被环境打败了很可惜。6.2 SQL 脚本导入与后端启动最容易翻车的几个点SQL 脚本的导入用 Navicat 或命令行都可以。导入之后先做三件事确认表是否全部创建成功尤其是 health_report 表的唯一索引是否建立。初始化数据是否齐全特别是 sys_user 表里三个角色的账号是否都在。数据库编码是否是 utf8mb4否则中文会乱码。然后打开后端的 application.yml或 .properties核对数据库连接信息server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/campus_health?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 你自己的密码 driver-class-name: com.mysql.cj.jdbc.Driver后端启动失败的原因我整理过一份排查清单基本能覆盖绝大多数情况现象原因解决Access denied for user数据库账号或密码不对核对 yml 配置Unknown database数据库不存在或库名不匹配先创建数据库再导表Port 8080 was already in use端口被占用改 server.port 或释放端口java.sql.SQLSyntaxErrorExceptionSQL 版本差异检查 MySQL 版本与脚本是否匹配Cannot load driver class驱动类写错MySQL 8 用 com.mysql.cj.jdbc.Driver6.3 前端依赖安装、代理配置与启动失败处理后端启动成功后再启动前端。流程一般是cd frontend npm install npm run devnpm install 失败是重灾区。常见处理方式我排个优先级换镜像源后重装删除 node_modules 和 package-lock.json 后重新 install检查 Node 版本是否和项目匹配Vue CLI 4 在 Node 17 环境下容易报 OpenSSL 相关错误启动成功后如果你直接用前后端分离的方式联调会遇到跨域问题。跨域的解决方式有多种我最推荐 Vue CLI 的 devServer 代理在 vue.config.js 里配置module.exports { devServer: { port: 8081, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } }这样前端请求 /api/login 会被代理到后端 8080 端口浏览器看到的始终是同源请求不会有 CORS 报错。这种配置方式比在后端写一堆跨域过滤器更干净而且只在开发环境生效不影响生产部署。6.4 打包部署时的两个经典陷阱publicPath 和 history 路由毕设如果要求部署上线或者要在实验室服务器上演示会用到前端打包。执行 npm run build 后生成 dist 目录这里有两个坑特别常见。第一个坑是资源路径。如果你把 dist 部署到服务器的子路径比如 http://ip:8080/health/而项目里静态资源引用的是绝对路径 /就会出现页面白屏或样式全丢。解决办法是在 vue.config.js 里设置module.exports { publicPath: ./ }改成相对路径后打包出来的 index.html 引用资源时就不会写死根路径了。第二个坑是路由模式。如果 Vue Router 用了 history 模式直接访问 http://ip:8080/health-report 这类子路由地址服务器会返回 404因为后端没有这个路径对应的资源。解决办法有两条一是把路由模式改成 hash 模式URL 里会带 #不容易丢二是在部署的 Web 服务器里配置 try_files把所有路径都指向 index.html。对毕设演示来说直接换 hash 模式最简单不容易再踩新的坑。后端打包就不多说了Maven 执行 clean package生成 target 目录下的 jar 包java -jar xxx.jar启动即可。如果是单机部署演示推荐把前端 build 出来的 dist 复制到后端的 src/main/resources/static 目录下再重新打包这样 SpringBoot 会把前端页面也托管起来启动后访问 http://localhost:8080 就能打开整个系统前后端一体“一个 jar 跑全部”答辩现场会省掉很多网络和设备上的麻烦。7. 答辩前必须吃透的五个问题并发、安全与架构追问7.1 为什么用 JWT 而不用 Session这个问题几乎必问建议用一句话概括然后再展开。JWT 是无状态认证token 本身携带用户信息服务器不需要保存会话状态天然适合前后端分离和分布式部署。而 Session 方案需要服务器保存会话数据集群部署时要额外处理 Session 共享比如粘滞会话或 Redis 存储。JWT 的缺点也很明显token 签发后没法立即失效所以生产环境一般要配合 Redis 做黑名单或短过期时间或者用 refresh_token 做双 token 机制。把 JWT 的优缺点都说清楚就显得你不是背概念而是真的理解。7.2 同一学生同一天重复提交健康信息如何处理这个问题对应的就是第 4.3 节的三层方案前端按钮置灰、后端先查后插、数据库唯一索引兜底。回答时最好强调“我是从业务层和数据库层两个层面做了幂等控制”这就把普通实现和严谨实现区分开了。如果再补一句“数据库层抛出的 DuplicateKeyException 会被全局异常处理器转成友好提示”老师就知道你连异常链路都想过了。7.3 200 人同时提交你的后端扛得住吗这个问题看着吓人其实考的是基础概念。一个 SpringBoot 应用内嵌的 Tomcat 默认最大工作线程数是 200数据库连接池 HikariCP 默认最大连接数是 10。200 个请求进来应用层能接收但数据库连接很可能成为瓶颈。回答时可以分几个层面数据库连接池参数可以调大比如 maximum-pool-size 调到 20 或 50热点表的索引要建好避免慢查询占住连接接口层面可以做限流比如用 Redis 计数器实现简单的接口限流再往上就是消息队列削峰。毕设阶段能答出“连接池、索引、限流思路”这三点已经远超大部分同学的水平了。7.4 密码直接存数据库安全吗安全问题也是高频追问。答案是不能存明文。后端使用 BCrypt 对密码加密后再存储BCrypt 是自适应哈希算法自带盐值相同密码每次加密结果也不同能有效抵御彩虹表攻击。登录校验用 BCryptPasswordEncoder 的 matches 方法对比原始密码和密文。除了密码还可以补充几个安全措施用 MyBatis-Plus 的 #{} 预编译防止 SQL 注入、统一异常处理避免堆栈信息直接暴露给前端、管理端对输入内容做 XSS 过滤。这些点都覆盖到安全问题就能答成加分项。7.5 前后端分离和不分离有什么区别简短回答不分离时后端是用 JSP、Thymeleaf 这类模板引擎渲染 HTML返回的是整个页面前后端代码耦合在同一个工程里所以有一种很经典的 JSP 编译产物排查问题叫“改完 JSP 找不到对应的 Java 类”。分离以后后端只返回 JSON 数据前端负责页面渲染两者独立开发、独立部署。对这套系统来说分离带来了三个实际好处前端可以单独部署后端接口可以被 App 等其他客户端复用开发时前后端通过接口文档并行推进效率更高部署时也能各自扩容。回答里把 JSP 和前后端分离的对比带出来等于把你对整个 Java Web 技术演进的理解都展示出来了。最后再说点实际的。我见过太多同学把源码克隆下来npm install、启动、截个图就以为万事大吉结果答辩老师心血来潮翻到某个上报页面问一句“如果学生一天上报两次系统会发生什么”就露馅了。拿到这套源码后请花一个下午时间从数据库表结构看到后端 Controller再从前端页面看到接口调用把“学生提交健康上报”这条最基础的链路完整走一遍。这个系统本身不难但每个环节都吃透之后你收获的绝不只是一份能交差的毕设而是一套能直接拿出去面试谈的 Java Web 全栈能力。
返回列表