开题季刚过,又是一年中最热闹的毕设周期。今年问得最多的题目里,“SSM+Vue教学日志管理系统”至少出现了十几次。说句实话,这个题目能在“Spring Boot + Vue”大行其道的今天依然坚挺,靠的不是噱头,而是实实在在的稳妥——技术栈经典、业务流程清晰、论文好写、答辩好过,几乎所有本科阶段的考核点都覆盖到了。
这篇就把我当时做这个题目的完整思路和过程还原出来。你不是在做一个简单的“增删改查”,而是在搭一套包含角色权限、审核流转、数据统计的完整闭环系统。后端用SSM(Spring+SpringMVC+MyBatis),前端用Vue全家桶,前后端分离部署。从环境配置、系统设计、前后端核心代码,到论文章节怎么和代码对应、答辩前怎么自检,我全给你捋清楚。
1. 选题定调:为什么“SSM+Vue教学日志管理系统”值得做
1.1 这个题目背后的能力考察点
本科毕设评审,导师和答辩老师最看重的其实不是系统有多炫、用了多新的框架,而是看你是否完整经历了一次“需求分析→系统设计→编码实现→测试部署→论文撰写”的软件工程流程。SSM+Vue教学日志管理系统恰好在“难度适中”和“考点齐全”之间找到了一个非常好的平衡。
从功能上说,它不只是简单的数据维护。教学日志管理有明确的业务规则:教师需要填写日志(课程名称、授课班级、授课节次、教学内容、教学反思),提交之后要经过教研室或教务审核(通过/驳回),审核后的日志要支持按学期、按教师、按课程汇总统计。这个流程天然涉及多角色权限控制、状态流转、条件查询、统计报表,每一个都是答辩时老师喜欢追问的点。
从技术考察上说,SSM覆盖了MVC分层思想、IoC/DI依赖注入、AOP事务管理、MyBatis持久层映射这些JavaWeb的“老本行”;Vue端覆盖了组件化开发、路由管理、状态管理、axios异步请求、前后端联调。把这些问题吃透,你答辩时基本是从容的。
1.2 技术方案比选:SSM还是Spring Boot?
很多人纠结:现在企业都用Spring Boot了,毕设还用SSM是不是过时了?
我的建议很直接:如果学校题目库给的是“SSM”,你就踏实做SSM。原因有三点:
第一,SSM这个缩写本身就是围绕Spring框架组织的,你把它研究透,Spring Boot不过是一个自动装配的壳子,底层完全相通。答辩老师问起“Spring IoC是什么”“事务传播行为有哪些”,你在SSM框架里手动配置过,答得有实感,而用过Spring Boot的同学反而容易答散。
第二,SSM项目结构更“显性”。配置类、XML映射、拦截器、视图解析器都是手工写出来的,论文里可写的东西非常丰富,篇幅容易撑起来,技术分析部分也更有深度。
第三,从实际运行环境来说,教学日志管理系统这种课设/毕设级别的项目,并发量很低,SSM+Tomcat单机部署的架构完全不构成性能瓶颈。硬上微服务反而是“杀鸡用牛刀”,还会引入一堆分布式问题给自己挖坑。
说句公道话,如果你是从零开始、导师没指定框架,那我建议直接Spring Boot+Vue,效率更高、资料更多。但如果你目标就是“2026毕设ssm+vue”这个赛道,那就安心走SSM,思路完全不吃亏。
1.3 系统边界:教学日志到底“管”什么
很多同学拿到题目第一反应是“教学日志不就是老师写日记吗”,然后开始做笔记软件。这是典型的没有做需求挖掘。教学日志管理系统里的“日志”是一份带审批流程的业务单据,核心参与者有两种角色:教师和审核者(教研室主任/教务管理员)。
教师端的主要动作包括:新建日志、填写授课信息、保存草稿、提交审核、查看自己的历史日志和审核结果、按条件检索。审核者端的动作包括:查看待审核日志列表、查看日志详情、通过/驳回操作、按教师/课程/时间组合筛选、查看统计报表(如某教师某学期授课总学时、日志驳回率等)。
系统管理员的设计上常见有两种做法:一种是独立的管理员角色去管理教师账号,另一种是让审核者兼任账号管理。做毕设的话我建议把用户管理放在审核者的功能菜单里,减少一张表和一个角色的维护成本,论文里解释为“系统设置了教师、教研室审核两种角色,审核者可同时承担系统维护职能”,逻辑完全通。
明确了业务边界之后,数据模型就很好设计了。我当初设计了四张核心表:用户表(sys_user)、日志主表(teach_log)、课程信息表(course_info)、系统参数表(sys_config)。课程信息表主要解决“日志里选的课程是哪里来的”这个问题,避免教师每次手输课程名导致的统计口径混乱;系统参数表用来存学期开始日期等配置。这一个小设计在论文的数据库设计章节里就能多写一页,而且答辩时能体现你对业务的理解。
2. 后端骨架搭建:SSM三层架构与核心业务实现
2.1 开发环境与版本锁定(这个坑坑过很多人)
SSM属于“老组合”,最大的坑不是写作难,而是版本匹配。很多同学IDEA里新建Spring项目自带一堆依赖,结果跑起来各种ClassNotFoundException,就是因为版本混了。我直接把我用的版本号给你,照抄可跑:
- JDK:1.8(毕设圈绝对的稳定基石)
- Maven:3.6.3
- Tomcat:8.5.x(注意,Tomcat 10及以上用了Jakarta命名空间,和SSM常见的javax.servlet冲突,新手不要碰)
- MySQL:5.7(8.0也兼容,但5.7对SSM兼容性更好,驱动用8.0的也没问题)
- IDEA:2021/2022/2023都行
Maven核心依赖就这五个方向:Spring全家桶(spring-webmvc、spring-jdbc)、MyBatis本体(mybatis、mybatis-spring)、数据库驱动与连接池(mysql-connector-java、druid)、JSON序列化(jackson-databind)、工具类(lombok可选、pagehelper分页插件)。
<!-- SSM核心依赖参考,版本号均为实测可用 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.22.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.22.RELEASE</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.13</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.7</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.8</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.28</version> </dependency>特别提醒,spring-webmvc和spring-jdbc的版本号必须完全一致,否则容器启动时会报BeanCreationException。这种问题搜报错信息可能半天找不到方向,其实就是Spring的模块版本不统一导致的。
2.2 Spring、SpringMVC、MyBatis的XML配置要点
SSM虽然是老技术,但说实话,每次我重搭骨架还是会翻旧笔记。核心就三个配置文件:applicationContext.xml(Spring主容器)、spring-mvc.xml(控制器容器)、mybatis-config.xml(MyBatis全局配置),另外还有一个web.xml把前两者串起来。
我的经验是分容器写,不要图省事把MapperScannerConfigurer和组件扫描全塞在spring-mvc.xml里。因为SpringMVC的容器只负责扫描@Controller和@RestController,而@Service、@Repository、@Mapper应该交给Spring根容器管理。混在一起会导致事务和AOP在某些场景失效,尤其你后面接Shiro或自定义拦截器时,组件扫描范围一乱,各种诡异问题都会出现。
数据源配置用Druid:
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/teachlog?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai"/> <property name="username" value="root"/> <property name="password" value="123456"/> </bean>这里serverTimezone=Asia/Shanghai一定要加,MySQL 8和SSM连的时候不指定时区经常会报“The server time zone value”异常,属于遇到特别多的高频报错。
MyBatis的Mapper文件我习惯放在src/main/resources/mapper目录下,文件名与接口同名,映射检查也方便。还有一个细节:Mapper XML文件如果放在resources目录,target目录会正常编译;如果手欠放在java包目录下,必须要在pom.xml的<build>里配置resource标签把xml包含进去,否则运行时一直报“Invalid bound statement (not found)”。
2.3 教学日志的CRUD与审核状态机
核心表teach_log我设计了这些关键字段:log_id(主键)、teacher_id(教师ID)、course_name(课程名)、class_name(班级)、teach_date(授课日期)、teach_section(第几节)、teach_content(授课内容)、teach_reflection(教学反思)、status(状态:0草稿/1待审核/2通过/3驳回)、audit_opinion(审核意见)、submit_time(提交时间)、audit_time(审核时间)。
这里最有技术含量的不是增删改查,而是状态流转的控制。简单地把status作为int字段然后UPDATE,会出现问题:已通过的日志理论上不应该能再次编辑提交,但如果你只在Controller里判断status,万一并发或者越权调用接口,数据就脏了。我建议把状态流转收敛到Service层的一个方法里,加上前置校验:
- 只有status=0且当前用户是日志所属教师,才能执行“编辑”和“删除”
- 只有status=0才能“提交审核”,提交后状态变为1
- 只有status=1且当前用户有审核权限,才能“通过”(变为2)或“驳回”(变为3)
- 被驳回的日志(status=3)重新编辑后,再次提交时回到状态1
这段逻辑在Service里用一个switch方法统一管理,比在Controller里散着判断要干净得多,答辩演示时也有话可说:“我参考了工作流引擎中状态机的设计思路,把日志的流转规则集中管理,避免业务状态被非法篡改。”
分页查询我用了PageHelper。导入com.github.pagehelper:pagehelper-spring-boot-starter在SSM里不太合适,正确姿势是引入pagehelper本体,在applicationContext.xml里配置new PageInterceptor()的拦截器插件。然后查询代码里直接写:
PageHelper.startPage(pageNum, pageSize); List<TeachingLog> list = teachLogMapper.selectListByCondition(condition); PageInfo<TeachingLog> pageInfo = new PageInfo<>(list);返回值里带上total、pages这些分页字段,前端Element UI的el-pagination直接就能对接上,不需要自己写count查询。
2.4 权限控制:从登录拦截到越权防护
教学日志系统有两种核心角色,只做前端Vue路由守卫是不够的,后端必须配合拦截器做接口级别的访问控制。
我的设计是:登录成功后,生成一个token存到HttpSession,同时存一个user对象(含role标识)。后端写一个LoginInterceptor,重写preHandle方法,检查Session中是否存在user;如果没有,用ObjectMapper写JSON返回“请先登录”,而不是重定向到登录页,因为前后端分离的项目前端拿到非2xx状态码时会走axios的拦截器统一弹出提示。
角色鉴权我是在Controller层用自定义注解+拦截器实现的。做一个@RequireRole("auditor")注解标记在需要审核权限的Handler方法上,拦截器里再校验当前用户的角色。这种方法比在业务代码里写大量if (user.getRole() != 1) return error要优雅得多,论文里写“基于自定义注解实现细粒度权限控制”也很加分。
还有一类容易被忽视的越权:教师A访问/log/detail?logId=某条数据,这条数据是教师B的。接口层面如果只校验“是否登录”而没有校验“是否拥有这条日志”,那A就能看到B的授课内容和反思。正确做法是Service里查询日志时先带上传入的teacherId,用where log_id=#{} and teacher_id=#{currentUserId}去查,查不到就直接返回无权限。这种“越权读取”问题在答辩演示时一旦被老师试出来就会很尴尬,务必提前堵住。
3. 前端集成:Vue生态下最容易翻车的几个环节
3.1 Vue环境安装与项目初始化版本匹配
SSM+Vue项目的前端,我建议用Vue 2.x而不是Vue 3。原因很实在:Element UI(不是Element Plus)在Vue 2下最成熟,各种教程和组件示例都在Vue 2体系下,你网上搜到的问题解决方案会多得多。如果你不是对Composition API已经很熟练,不建议在这个节骨眼上为了“追新”选Vue 3,因为Element Plus的部分组件属性和事件和旧版不一样,调试成本会明显更高。
先确认Node环境,推荐装Node 14.x或16.x,这两个版本和Vue CLI 4/5兼容性很好。太新的Node 20在某些老依赖上会有node-sass一类的兼容报错。安装Vue CLI后:
node -v npm -v # 全局安装vue-cli npm install -g @vue/cli@4.5.15 # 创建项目 vue create teachlog-web创建时选择“Manually select features”,勾选Babel、Router、Vuex、ESLint。其中Router要选hash模式(后面部署的时候不用配置nginx的history重写规则,能少踩一个坑)。Vuex建议勾选,虽然这个项目的全局状态不算多,但登录用户的账号信息、姓名、角色这些放在Vuex里管理比在路由里反复传参清爽。
如果你在install时网络慢,可以提前设置淘宝镜像npm config set registry https://registry.npmmirror.com。但注意不要全局把Node官方源也改了,有些后期工具镜像同步不及时,反而会拿到旧版本。
3.2 路由、状态管理与axios封装
路由上我分了这几块:/login(登录)、/layout(主布局,含侧边栏和顶栏),下面挂/layout/logs(日志列表)、/layout/create(填写日志)、/layout/audit(审核列表)、/layout/statistics(统计报表)。/layout这个父路由是核心,它通过children来加载子页面,子页面渲染在<router-view>里。
路由守卫用beforeEach钩子做登录校验:
router.beforeEach((to, from, next) => { const token = localStorage.getItem('token') if (to.path === '/login') { next() } else if (!token) { next('/login') } else { next() } })需要注意的是token的存储位置。同时刷新页面时Vuex状态会清空,localStorage不丢。所以正确做法是登录成功后将用户信息存到localStorage,启动时再读出来恢复Vuex里的state。有很多人在刷新页面后侧边栏菜单“闪一下”就消失,基本都是这个环节没处理好。
axios封装方面,核心是统一设置baseURL和请求头,并在响应拦截器里统一处理状态码:
axios.interceptors.response.use( res => { // 业务层code为200为成功 if (res.data.code === 401) { localStorage.clear() router.push('/login') } return res.data }, err => { Message.error('网络异常') return Promise.reject(err) } )这样每一页的请求代码只需要关注业务数据,认证失效自动踢回登录页。
3.3 跨域代理与接口联调
前后端分离项目开发期必然遇到跨域。最容易掉进去的坑是去后端Controller里加@CrossOrigin注解然后发现“偶尔有用偶尔没用”。我推荐的做法是前端开代理,在项目根目录下vue.config.js里配置:
module.exports = { devServer: { proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true, pathRewrite: { '^/api': '' } } } } }这样前端请求/api/log/list,本地开发服务器会代理转发给后端的http://localhost:8080/log/list。后端不需要做任何跨域处理,两边干干净净,部署到生产环境后可以直接把前端构建产物放到nginx里,再配一个proxy_pass指向后端服务,同一套联调逻辑在线上继续复用,非常顺。
很多人会问为什么接口要统一加/api前缀。真实原因是前端部署后可能由nginx托管,你要让nginx精确匹配并转发后端服务和让前端静态资源区分开,加前缀是最常用的约定,也方便后端打日志时路径清晰。
3.4 页面细节:插槽、样式冲突、日期组件适配
前端页面看起来“简单”,但新手的坑往往藏在细节里,这里集中讲三个出现频率特别高的问题。
第一个是插槽。Element UI的表格列自定义(比如审核操作按钮、状态标签)必须用<template slot-scope="scope">。Vue 2.6之后的语法是<template v-slot:default="scope">,在el-table-column里更常见的是slot-scope。如果写了插槽不生效,先检查Vue版本和语法是否一致,这是Element UI表格组件里最奇怪也最常见的“不报错但页面空白”问题。
第二个是样式冲突。Vue单文件组件的<style>默认是全局的,如果你在A页面里写了.input { width: 200px },可能会把B页面同样类名的输入框也改了。全程给<style>加scoped,并且组件内的顶层容器类名保持命名空间化,比如log-list-page这种。这能避掉绝大多数样式串扰,尤其是项目里还引了第三方组件库的情况。
第三个是日期组件格式对接。el-date-picker默认返回的是一个Date对象或数组,直接提交给后端会得到一串“2026-06-10T12:00:00.000Z”这种格式,SpringMVC用@DateTimeFormat(pattern="yyyy-MM-dd")接起来也麻烦。我是在前端提交前统一用dayjs或手写的格式化函数转成yyyy-MM-dd字符串,后端字段统一用String/StringBuffer来接收,查询时直接按字符串比较。教学日志场景下日期不需要精确到时分秒,这样处理既简单又不容易出时区问题。
3.5 课堂实录m3u8播放的落地处理
这个需求在热搜词里反复出现,说明不少同学做的版本里带了“课堂实录上传与播放”这类扩展功能。如果你想加这个模块,flows很直接:教师端上传视频,转码服务输出HLS切片(m3u8文件),前端用video.js加载。这里的关键点在于后端返回的视频地址和m3u8文件、ts切片的访问需要可跨域且路径可访问,我当时的做法是加了一个独立前缀/media/直接映射到服务器上存放视频的目录。
前端播放m3u8有两个主流选择:video.js+videojs-contrib-hls,或者原生hls.js。我最推荐的是用hls.js,因为它在PC端对m3u8的兼容性和稳定性比video.js的hls插件好很多,尤其是在Chrome下,快进、切换清晰度都很顺。基础用法:
import Hls from 'hls.js' if (Hls.isSupported()) { const video = document.getElementById('player') const hls = new Hls() hls.loadSource(videoUrl) // 形如 http://xxx/media/lesson/lesson01.m3u8 hls.attachMedia(video) }还有一个容易忽略的点:后端tomcat默认对.mp4的Content-Type映射没问题,但对m3u8和ts文件的MIME映射可能不规范,导致浏览器下载而不是播放。需要在web.xml里显式配置mime-mapping,比如.m3u8映射到application/vnd.apple.mpegurl,.ts映射到video/mp2t。不然你前端代码写得再对,播放器也是白屏报错。
4. 论文写作与程序如何一一对应
4.1 论文六章结构与每个章节对应的素材
“论文+程序”是这套毕设的交付物,论文不能“写完程序再憋”,而是要“边做边攒素材”。按常见的教学日志管理系统论文结构,每一章和代码的对应关系如下:
- 第一章 绪论:写选题背景(教育信息化、教学质量监控需求)、国内外研究现状(这部分要去知网找几篇教育教学系统的论文参考,提炼两三句);技术栈选定SSM+Vue的理由。
- 第二章 相关技术介绍:Spring、SpringMVC、MyBatis、Vue、Element UI。每节不要只写“是一个开源框架”,要结合本项目写:比如“Spring在本系统中承担Bean管理和事务控制,用户Service、日志Service等业务对象均通过Spring容器装配”。
- 第三章 需求分析:写可行性分析(经济、技术、操作三方面),然后画角色用例图和核心用例描述。用例图直接对应你前端菜单的拆分。
- 第四章 系统设计:总体架构图(浏览器-Vue-axios-SSM-MySQL)、功能模块图(按你侧边栏的设计画)、数据库ER图和表结构设计(四张表的字段、类型、主外键必须和SQL脚本一致)。
- 第五章 系统实现:这是大头,每个功能模块配一张效果截图+一段核心代码+一小段文字说明。截图就用你自己跑起来的效果,不用多精美,重在真实。
- 第六章 系统测试:写测试环境、功能测试用例表(输入条件、预期结果、实际结果),性能测试如果你没做压测,就写简单的接口响应时间统计,不要编造离谱的并发数据。
如果你做完功能后时间紧张,优先把第五章的截图和代码整理好,因为答辩评委翻论文时首先看的就是实现章节和截图。
4.2 系统设计图的绘制规范
很多人的架构图画得像“积木堆放”——几个方框叠一起,框里没有连线逻辑。画系统架构图时,建议垂直分层画:最上层“表现层(Vue页面组件)”,第二层“网络层(axios/路由守卫/proxy代理)”,第三层“后端控制层(SpringMVC Controller)”,第四层“业务层(Service/事务管理)”,第五层“数据访问层(MyBatis Mapper)”,底层“MySQL数据库”。层与层之间用箭头标注“调用”或“SQL操作”。
画ER图时,实体用矩形,属性用椭圆,关系用菱形,这个标准格式不要在论文里发挥创意。教学日志系统的ER图核心实体就是“用户”和“教学日志”,用户是1对N拥有日志。如果加了课程信息表,用户通过课程维度间接关联日志,画出来关系更完整。
工具上我推荐draw.io,完全免费且离线可用,导出的svg放到word里是矢量的,打印和缩放都清晰。不要用photoshop手画,到时候改了需求你还会想重画一张,非常浪费时间。
4.3 边做边攒素材的实操建议
写论文最痛苦的事是“最后两周突击回忆”。我自己的经验是建立一个“论文素材清单”,每做完一个模块就往里面塞三项东西:功能截图、关键代码片段、遇到的问题。你调试Bug时踩过的ClassNotFoundException、跨域、分页total拿不到——这些都是系统测试章节的绝佳素材。真实遇到的问题写出来是“系统在XX场景下出现XX报错,分析原因是XX,最终通过XX解决”,比硬编十个用例有说服力得多,答辩时老师还会觉得你做了足够深度的调试工作。
数据库建表SQL脚本也存到一个名为database.sql的文件里,论文附录直接放进文档。注意让表字段的中文注释(COMMENT)完整,导师一眼能看懂表设计。
5. 打包部署与答辩前的自检清单
5.1 前后端打包部署(Tomcat+nginx)
到了部署阶段,我采用的是前端nginx托管+后端Tomcat独立运行的方案。把后端工程用IDEA的Maven面板执行clean package,生成war包(别忘了pom.xml里设置<packaging>war</packaging>),把war包扔到Tomcat的webapps目录下,启动Tomcat时会自动解压部署。这里的坑是:如果你的SSM工程里有静态资源(比如上述的m3u8视频目录)被拦截器拦截了,一定要在spring-mvc.xml的<mvc:resources>里放行对应的路径。
前端执行npm run build之后,在dist目录下生成静态文件,我把整个dist目录复制到nginx的html/teachlog下面,然后nginx里配置一个location转发/api到http://localhost:8080:
server { listen 80; server_name yourdomain; root /usr/share/nginx/html/teachlog; index index.html; location /api/ { proxy_pass http://localhost:8080/; } }注意proxy_pass后带不带斜杠是有区别的:带斜杠会去掉uri里的/api,不带斜杠则原样透传。这里我前端axios的baseURL配的是/api,后端接口不含/api前缀,所以proxy_pass末尾带“/”才能正确去掉前缀。
5.2 高频线上问题排查清单
部署和自测阶段,我整理了一个高频问题清单,效率很高:
- 启动Tomcat能访问但接口404:先看Controller类是否被Spring容器扫描到(启动日志里有没有“RequestMappingHandlerMapping”注册记录);再确认
DispatcherServlet的url-pattern是不是配成了/,如果配成/*就会拦截JSP导致视图解析异常。 - 前后端联调时跨域但代理没生效:确认前端请求前缀是
/api,并且vue.config.js在项目的feng目录下(不是外层),代理配置改了要重启npm run serve。 - 数据库连接报错 Access denied:检查Druid连接池的账号密码配置是否与本地MySQL实际账号一致;MySQL 8还要求url里加
useSSL=false&serverTimezone=Asia/Shanghai,不然时区报错常有。 - 分页查询total一直是0:PageHelper在需要分页的查询中,startPage和select必须是紧跟着的两行,中间不能插入其他数据库操作;另外PageHelper 5.x的dialect要配置为mysql。
- 前端页面刷新后登录状态丢失:前面提过,localStorage持久化token必须在main.js启动时同步到Vuex。
- 日期显示变成一串数字或NaN:大概率是Java返回的
java.util.Date被Jackson默认序列化成Timestamp数字。在SpringMVC的jackson配置里增加spring.jackson.date-format=yyyy-MM-dd HH:mm:ss和spring.jackson.time-zone=GMT+8,或者在字段上添加@JsonFormat(pattern = "yyyy-MM-dd")。
5.3 答辩高频问题与作答思路
答辩问题基本围绕“技术原理”和“为什么这么设计”两个方向,提前准备这些问题的作答思路:
- “SSM中你的请求是怎么流转的?”——答:前端发起axios请求→SpringMVC的DispatcherServlet接收→根据HandlerMapping找到Controller→Controller调用Service→Service调用Mapper→MyBatis执行SQL→结果逐层返回并转成JSON响应给前端。
- “MyBatis中#{}和${}的区别?”——这是面试经典也是答辩高频,答:#{}是预编译参数占位符,会转成JDBC的PreparedStatement参数,能防SQL注入;${}是简单的字符串替换,有注入风险,我们写SQL时排序字段、表名这类无法预编译的少数场景用${}且必须校验白名单。
- “Vue组件之间怎么通信?”——答:父子组件用props和
$emit;跨级或兄弟组件用Vuex;页面跳转传参用路由query/params;还可以用EventBus处理简单的跨组件事件。 - “日志审核状态管理怎么做?”——答:状态字段+Service层集中状态校验,不允许不同角色越权操作;同时更新时用乐观锁或唯一查询条件避免并发提交。
- “为什么用Druid连接池?”——答:自带监控页面和SQL拦截,扩展能力强,学习成本低;重要一点是可以在答辩中展示Druid监控后台的截图。
这五个问题基本覆盖了系统核心设计。把思路理清楚,比背长段代码片段有效得多。
整套走下来,你会发现SSM+Vue教学日志管理系统这个题目的核心收益正是“稳”:框架老但知识体系完整,业务不复杂但能讲出状态机和权限控制的深度,论文素材每做一个模块都在积累,答辩问题也能提前圈定范围。别把这个题目当做一个“快写完交差”的破系统,把它当成一次完整的小型软件交付来做,你拿到的不只是一份毕设成绩,而是一套可以写进简历的“前后端分离管理系统开发经验”。最后再提醒一句:数据库的表字段里记得加统一的前缀和注释,真到了答辩演示的时候,给老师展示你的SQL脚本是干净的,印象分能一次性拉满。