资讯动态

SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0教学辅助系统设计与实现

发布时间:2026/10/14 3:52:47 来源:尧图企业网站定制
不知道你有没有带过一届四五十人的课。课程表、作业催交、成绩登记、补考名单、临时通知全挤在一个表格里班委还得来回传达。我接手过一个教学辅助系统的开发任务就是用标题里这套组合——SpringBoot2 Vue3 MyBatis-Plus MySQL8.0把教务管理这件事从手工台账变成了在线协作。做完之后最大的感受是这类系统真正难的点不在增删改查而在权限边界和数据关系怎么设计得让学生、老师都不别扭。这篇博文我会把这套系统的设计思路、核心实现、数据库细节、部署流程以及我实际踩过的坑全部展开希望能给正在做教学管理系统、毕业设计或者企业内部培训系统的你一个能落地的参考。1. 项目整体拆解这套系统到底解决什么问题1.1 教学场景里最耗精力的从来不是上课老师日常要干的活远不止备课和讲课。新学期开始要建课程、导入学生名单每节课可能要记录考勤课后要发布作业、收集作业、批改评分期中期末还要统计成绩、分析及格率。学生这边呢最怕的是作业截止时间记错老师到底改没改我的卷子补交的作业有没有被看到。这些信息如果只靠微信群和Excel一定会出乱子。这套教学辅助系统的定位就是解决这些琐碎又关键的协作问题。它把教务管理中高频出现的流程拆成课程、班级、学生、作业、成绩、公告几个核心模块并且用角色权限将操作边界明确分开。管理员负责基础数据维护老师能够管理自己任教的课程、发布作业与评分学生则只能看到与自己相关的课程、作业和成绩。说白了就是让每个角色在系统里都只看得到自己该看的东西操作路径短误操作也少。我实际做的时候最先画了一张功能脑图。系统没有必要做得像通用OA那么重教学场景里的核心闭环就三条选课与成员管理、作业流转与评分、成绩统计与通知。把这三条跑通再加一个公告板和一个班级分组基本就能覆盖绝大多数课程类教学场景。如果一开始就堆太多花哨功能比如在线直播、支付、复杂论坛开发和维护成本都会失控。1.2 系统角色与功能边界很多初学者会把权限做成用户有一个角色字段前端根据角色隐藏菜单这么做当然能跑但后端如果不去校验接口权限安全隐患很大。在这个项目里我采用三张用户相关表的设计思路管理员表、教师表、学生表公共的登录凭证存在一张sys_user表中用user_type区分角色。角色核心操作不开放的操作管理员维护教师账号、学生账号、学期课程基本信息不能代替老师评分教师创建课程、导入学生名单、发布作业、批改打分、查看成绩统计不能修改其他老师的课程学生查看课程、查看作业、提交作业、查看自己的成绩与排名不能查看其他学生成绩详情这样设计的好处是前端路由守卫可以粗粒度控制页面后端拦截器再做一次细粒度校验双保险。后面的章节我会具体说JWT和拦截器的实现这里只需要记住一个原则权限判断永远不能只靠前端隐藏按钮。1.3 技术选型的基本逻辑为什么用SpringBoot2而不是SpringBoot3这不是说3不好而是对一个教学辅助系统来说SpringBoot2.7.x的生态最成熟。很多公司的内部系统、高校毕业设计题目目前依然建立在2.x基础上相关博客和案例也最多遇到问题搜索解决方案的效率最高。另外SpringBoot2对JDK8的支持非常完美而服务器上JDK8仍然占据主流这就省去了大量环境兼容性问题。Vue3则是现在前端的主流方向。组合式API比Options API更适合中后台系统因为业务逻辑可以按功能划分成组合函数比如useCourse.ts、useHomework.ts而不是把代码扔在mounted和methods里越写越乱。配合Vite的构建速度和Element Plus的成熟组件开发体验比旧时代好一大截。MyBatis-Plus的逻辑就是常规单表操作用内置方法复杂多表查询自己写SQL。教学系统里作业成绩统计、选课名单查询都是典型多表关联需要手写SQL但用户增删改查、课程基础信息的单表CRUD完全可以用BaseMapper自带的接口代码量直接砍半。MySQL8.0则提供了窗口函数、公用表表达式等功能后面讲成绩排名时会展示具体用法。2. 后端从零搭建的核心实现2.1 SpringBoot2 项目骨架与分层思路后端我习惯按controller、service、mapper、entity、common、config分层。不要觉得层多麻烦教学系统业务简单但后续要加功能、换人维护时清晰的分层能省很多嘴皮子。我的做法是controller只做参数接收、调用service、返回统一响应体不写任何业务逻辑。service写事务边界和业务规则比如提交作业时校验是否在截止时间之前就必须放在service层。mapper继承BaseMapperT复杂统计用Select注解或XML文件。common放统一返回结果ResultT、异常处理、枚举、常量。config配置拦截器、跨域、MyBatis-Plus分页插件、WebMvc配置。这样的好处是如果某个接口报错你能直接定位到捣乱的代码在哪一层而不是在一个几百行的Controller里来回翻。尤其是多人协作或拿着源码做二次开发时分层清晰比代码炫技重要得多。启动类上需要加MapperScan注解否则每个Mapper都要写Mapper。我见过不少项目启动失败就是因为忘了在启动类扫描Mapper包报错信息还提示Invalid bound statement非常容易误判成XML文件写错。2.2 MyBatis-Plus 让数据访问化繁为简说几个我实际使用MyBatis-Plus时觉得最提效的点。首先是条件构造器比如分页查询学生名单前端可能传班级、关键词、当前页、页大小原来要自己拼接if判断SQL现在直接LambdaQueryWrapperStudent wrapper new LambdaQueryWrapper(); wrapper.like(StringUtils.hasText(keyword), Student::getName, keyword) .eq(Student::getClassId, classId); PageStudent page new Page(pageNum, pageSize); studentMapper.selectPage(page, wrapper);like的第一个参数是个布尔值为false时自动忽略这个条件。这个设计能让你少写一半的条件判断代码。配合selectCount、selectById等内置方法基础数据维护几乎可以不写SQL。但要注意MyBatis-Plus的LambdaQueryWrapper虽然方便一旦遇到多表关联、子查询、窗口函数就不能硬套。教学系统的成绩排名、课程平均分统计我都改用了自定义SQL。因为MyBatis-Plus毕竟是对单表CRUD的封装把复杂SQL硬塞进包装器里维护起来比直接看XML还要痛苦。分页插件是另一个必须配置的组件。很多人写好了分页代码却发现total永远为0就是因为忘了加分页拦截器。在配置类里注册PaginationInnerInterceptor即可数据库类型选DbType.MYSQL。这里有个小坑分页插件和Select注解的SQL一起使用时Select里不能自己再写LIMIT否则分页插件生成的总数SQL会异常。2.3 统一响应体与全局异常处理前后端分离项目里我最看重的就是接口返回格式一致。如果有的接口返回{code: 200, data: {...}}有的直接返回一个数组前端封装axios时就会被逼疯。我在common包里定义了一个ResultT类三个核心字段code、message、data。成功时code200业务失败时返回例如code400未登录或登录过期返回code401。前端统一判断code再决定是刷新Token还是弹出错误提示。异常处理我建议用RestControllerAdvice配合自定义异常类。比如提交作业时发现已经过了截止时间可以在service层抛出一个BusinessException(作业已超过截止时间)全局异常处理器统一捕获返回给前端的message就是这句话。这样做的好处有三个第一代码里不需要到处写try-catch第二错误信息不会直接暴露500堆栈用户体验好第三排查问题时日志里的异常栈和返回给前端的提示能对应上。全局异常处理器里需要单独捕获MethodArgumentNotValidException和BindException这是Valid参数校验失败时抛出的异常。如果不特殊处理前端拿到的结构会不统一。我还会把DuplicateKeyException转成数据已存在的提示避免用户看到丑陋的SQL报错。2.4 登录鉴权踩坑与 JWT 方案教学辅助系统里登录鉴权是刚需。我选的方案是JWT而不是把登录状态放在Session里。原因很简单前后端分离后后端接口可能同时被Web端、小程序端调用JWT不依赖Cookie和Session扩展性好。具体做法是登录成功后用jjwt生成一个Token将用户ID、角色、登录时间放入Token的声明里设置过期时间比如3小时。前端拿到Token后存入本地缓存每次请求在Authorization头里带上。后端用一个拦截器校验Token有效性。这里有一个很容易忽略的细节拦截器会拦截所有请求但登录接口、静态资源、Swagger文档路径必须放行。我踩过一次坑配置了拦截器后发现前端访问后端接口全部401查了半天才发现是登录接口也被拦截了前端又拿不到Token死循环。后来我在WebMvcConfigurer里维护了一个excludePath列表把/api/auth/login等路径排除掉问题就解决了。还有一个经验JWT秘钥不要硬编码在代码里建议放在application.yml配置文件中部署时用环境变量覆盖。秘钥至少32字节否则指定HS256算法时会报错。JWT的过期时间我设置了可配置项前端axios拦截器检测到401时会跳转到登录页并清掉本地Token这样用户重新登录后就能继续操作。3. Vue3 前端的设计与联调经验3.1 Vite Vue3 工程化初始化前端部分我没有用传统的vue-cli而是直接用Vite创建项目。命令很简单npm create vitelatest teaching-web -- --template vue项目创建后安装路由、状态管理和UI库npm install vue-router4 pinia axios element-plusVite的默认端口是5173后端SpringBoot默认端口是8080开发时跨域问题马上就会遇到。我建议在Vite的配置文件里加server.proxy把/api代理到http://localhost:8080。这样前端代码里请求路径都写/api/course/list这种相对路径生产环境再用Nginx做同域代理可以避免写死的localhost带来的环境切换问题。组件结构上我按目录拆分src/api放所有请求函数src/router放路由配置src/stores放Pinia状态src/views按模块放页面组件src/components放可复用组件。中后台系统的痛点从来不是缺组件而是组件职责不清。比如一个上传作业的弹窗最好就只属于作业模块不要放在全局公共组件里否则组件之间的参数传递会越来越复杂。3.2 路由守卫与用户状态持久化路由配置上我定义了一个meta字段来标记每个路由需要的角色。以/teacher/course为例meta.roles写[teacher, admin]而/student/course的meta.roles写[student]。全局前置守卫中每次跳转前先检查有没有Token有Token再检查用户角色是否匹配不匹配就跳转到401页面。用户状态用Pinia管理。刷新页面时Pinia内存数据会清空需要从本地缓存恢复。我的做法是登录成功后把用户基本信息昵称、角色、ID存到localStorage然后在路由守卫里读取Pinia的userStore如果为空就重新从localStorage初始化。这里有一个细节不要把用户的密码、Token过期时间等敏感信息全塞进localStorage只存非敏感信息Token单独存一个key这样即使XSS攻击拿到了本地缓存泄露的数据也有限。另一个细节是路由守卫必须注意异步问题。如果用户信息是从后端接口拉取的在信息返回之前就放行页面会导致页面渲染时用户角色为空权限判断出错。我建议初始化用户信息时用同步的localStorage方案或者在后端返回Token时一并返回用户信息减少一次请求。3.3 教师端/学生端界面差异化同一套代码能不能同时服务教师和学生当然可以但界面设计必须有所区分。我的做法是布局一致左侧菜单按角色动态生成。比如学生端菜单只有我的课程、作业中心、成绩查询、公告通知。教师端菜单则是课程管理、作业管理、成绩录入、选课名单、公告管理。管理员端还能看到系统管理里的教师账号、学生账号维护。功能差异之外权限细节也要做好。教师端的成绩录入界面我用了Element Plus的el-table内联编辑老师可以直接在表格里填分回车保存。学生端的成绩查询直接禁止显示操作按钮只展示分数和评语。这些看起来是小事但用户体验的差距就是这么一点一点堆出来的。状态管理上我用Pinia存了一个currentUser里面包含userId、userType、realName。页面里的所有可不可以做的判断统一用userStore.hasRole(teacher)这个函数不要到处写死角色字符串。后面如果需要加一个助教角色改配置的地方会非常少。3.4 axios 封装与跨域处理axios封装我推荐统一放在src/api/request.ts里。首先创建axios实例设置基础路径为/api请求超时时间设为15秒。然后加请求拦截器从本地存储取出Token添加到Authorization头。响应拦截器里判断状态码例如code 401时提示登录已过期调用userStore.logout()并跳转登录页code ! 200时ElMessage.error直接弹出后端返回的message。开发环境下最省事的跨域方案是Vite proxy。配置后前端请求/api/course/list会被代理到http://localhost:8080/api/course/list。注意后端接口如果已经统一加了/api前缀代理配置里就不能再重复添加/api路径否则会变成/api/api/course/list。我经常看到有人在这里绕来绕去最后定位到是路径拼接重复了。生产环境的跨域就交给Nginx解决前端打包后的静态文件由Nginx托管接口请求也统一转发到后端服务。这样浏览器看到的所有资源都来自同一个域不存在跨域问题。下面第5章会给出具体的Nginx配置示例。4. MySQL8.0 数据库设计与优化4.1 核心表结构的设计思路教学辅助系统的表不宜设计得过度复杂。我最终保留的表大概有系统用户表sys_user、学生表student、教师表teacher、课程表course、选课表course_selection、作业表homework、作业提交表homework_submission、成绩明细表score、公告表notice。表名核心字段说明sys_userid, username, password, user_type, status统一登录账号user_type区分角色studentid, user_id, student_no, name, class_name学生学号、姓名、班级teacherid, user_id, teacher_no, name, title教师编号、职称courseid, course_name, credit, semester, teacher_id课程归属某位教师course_selectionid, course_id, student_id, selected_time学生选课关系表homeworkid, course_id, title, content, deadline作业截止时间关键字段homework_submissionid, homework_id, student_id, submit_time, file_url, submit_status每人每作业一条状态区分待批改/已批改scoreid, course_id, student_id, score_value, comment成绩记录可来自期末考试或多次作业汇总这里最需要解释的是选课关系表。没有它课程和学生就是多对多关系但在MySQL里必须拆成一张中间表。course_selection就承担了谁选了哪门课的记录。为什么不用外键约束我习惯逻辑外键而不是物理外键因为物理外键在删除重建、批量导入时容易出问题。删除选课记录时在service层用代码保证先删除相关提交记录和成绩记录这样既能保证数据一致性又避免数据库级联操作带来的坑。作业表的关键在于deadline。这个字段必须建索引因为查询所有未截止作业是高频操作。如果表数据量大且没有索引每次都会全表扫描。字段类型用datetimeMySQL8.0里强烈建议统一utf8mb4字符集否则中文姓名和特殊符号可能乱码或报错。4.2 索引与查询优化教学系统的数据量一般不大但索引设计仍然不能随便。我给以下高频查询字段建了索引sys_user.username唯一索引登录查询必用。course.teacher_id普通索引教师查看我教的课程时使用。course_selection.course_idcourse_selection.student_id联合索引同时为student_id建普通索引这样既能查选课名单也能查某个学生选了哪些课。homework.course_id普通索引进入课程作业列表时使用。homework_submission.homework_id普通索引统计提交人数时使用。score.course_id普通索引成绩录入和统计使用。索引不是越多越好。每多一个索引插入和更新时都要额外维护一份B树数据。对于写多读少的小系统宁可少建几个可能有用的索引也要保证基础CRUD不卡顿。成绩统计场景我经常写这样的SQL求某门课程所有学生的平均分、最高分、及格率。用一条SQL可以同时拿到SELECT course_id, COUNT(*) AS total_count, SUM(CASE WHEN score_value 60 THEN 1 ELSE 0 END) AS pass_count, ROUND(AVG(score_value), 2) AS avg_score FROM score WHERE course_id ... GROUP BY course_id;这种统计在Excel里做很麻烦但在数据库里一条SQL就出来了。前端只需要调用一个接口渲染成统计卡片老师体验会非常好。4.3 MySQL8.0 特有的一些好用功能MySQL8.0和5.7相比最实用的进步之一是窗口函数。比如学生想查自己某门课成绩在班级里的排名传统写法要用子查询或者变量模拟很容易写错。在MySQL8.0里可以直接这样SELECT student_name, score_value, RANK() OVER (ORDER BY score_value DESC) AS rank_no FROM score WHERE course_id ...;注意RANK()会出现并列排名跳号的情况比如两个并列第一下一个就是第三名。如果希望并列后不跳号改用DENSE_RANK()。我通常用DENSE_RANK()做班级排名因为跳号会让学生觉得怎么没有第二名用户体验更友好。另一个实用功能是WITH ... AS公用表表达式。在统计多门课程平均分时可以先构造一个临时结果集再关联查询SQL可读性会大幅提升。如果不方便用8.0的窗口函数就得回到子查询嵌套改起来非常痛苦。所以我在项目的前提条件里明确写了数据库需要使用MySQL8.0及以上版本。字符集和排序规则也要在初始化脚本里固定下来。创建数据库时CREATE DATABASE teaching_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;utf8mb4_unicode_ci适合中文场景排序更加准确。时区问题也容易踩坑MySQL连接串上加serverTimezoneAsia/Shanghai否则日期时间字段会差8个小时。5. 文档组织结构与部署上线全流程5.1 配套文档里都有什么这套源码标题里写了【含文档】这一点对学习者太重要了。我拿到一份源码第一件事不是打开IDE而是看文档目录。一份合格的项目文档至少应该包含项目介绍与功能介绍、技术栈说明、数据库初始化脚本说明、启动步骤、目录结构说明、接口文档摘要、常见问题FAQ。我在整理文档时把系统分成了三份核心内容一份是README.md放在项目根目录用于快速了解项目一份是docs/database.md重点说明数据表之间的关系和初始化脚本怎么执行还有一份是docs/api.md用表格列出每个接口的请求方式、路径、参数和返回示例。接口文档不一定要用Swagger只要整理成一个清晰的Markdown表格也能极大提高开发效率。另外我习惯把SQL脚本单独放在sql/目录命名为teaching_db.sql。脚本里包含建库、建表、初始管理员账号、演示教师学生数据的插入语句。这样只要执行一个脚本后端就能直接启动。为了安全初始密码一定要在文档里写明首次登录后请修改。5.2 后端本地启动的五步操作后端启动步骤看起来简单但每一步都可能让新手卡住。我的标准流程是确认本机已安装JDK8及以上终端执行java -version如果版本显示是1.8或11都没问题。用MySQL客户端执行sql/teaching_db.sql这一步会创建数据库和全部表。如果MySQL8安装时端口不是3306需要记录下实际端口。打开application.yml修改数据源的url、username、password。这里的用户名密码要和你本机一致特别是密码如果包含特殊字符要注意转义。在项目根目录执行mvn spring-boot:run或者先在IDE里加载Maven项目再启动Application类。看到Started Application in X seconds的日志之后访问http://localhost:8080/api/auth/login做一个登录测试。这里要强调一个坑Maven默认中央仓库在国内访问很慢第一次拉依赖可能需要很长时间。建议在settings.xml里配置一个速度较快的镜像仓库这样能节省大量等待时间。另外如果你从别处拷贝的源码里包含了target/目录或者IDE配置文件建议先清理掉再重新编译避免旧文件干扰。5.3 前端本地启动的四步操作前端项目需要Node.js环境我用的Node14版本兼容性最好。流程如下在终端进入前端项目目录执行npm install。如果网络不好可以换成npm install --registryhttps://registry.npm.taobao.org。安装完成后执行npm run devVite会启动本地开发服务器默认地址是http://localhost:5173。用浏览器打开地址如果能看到登录页就说明前端工程基本正常。使用文档里提供的测试账号登录。比如管理员账号、教师账号、学生账号各试一遍检查角色路由是否正确。前端开发时出现白屏90%原因可能是npm install中途失败或者依赖版本冲突。建议使用package-lock.json锁定版本不要随便升级大版本。Element Plus升级到2.x之后某些组件的API变了如果项目里用的是旧写法也会报错。5.4 从开发机部署到云服务器的过程开发环境跑通后部署到服务器是另一套思路。后端先执行mvn clean package -DskipTests在target/目录下生成xxx.jar。然后把这个jar包上传到服务器执行java -jar teaching-system.jar --server.port8080最好用nohup后台运行日志输出到文件避免关闭终端导致进程退出。前端执行npm run build生成dist/目录把静态文件上传到服务器任意路径比如/opt/teaching-web/。服务器上Nginx配置的核心思路是所有静态资源由Nginx直接返回所有/api接口请求转发到SpringBoot的8080端口。参考片段server { listen 80; server_name your-domain.com; location / { root /opt/teaching-web; 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; } }特别记得try_files这一行否则前端路由在刷新子页面时会404。我还遇到过一个问题后端接口能通但静态资源不加载最后发现是root路径写错了项目目录没对上。部署时建议先单独访问服务器IP确认Nginx默认页正常再逐层排查。5.5 环境兼容性的一些经验教学系统对部署环境的要求并不高但有几个版本节点必须卡清楚JDK用8或11都行如果遇到某个jar报UnsupportedClassVersionError说明JDK版本和编译版本不匹配。MySQL5.7和MySQL8.0在连接驱动上有区别。MySQL8.0要用com.mysql.cj.jdbc.Driver很多老项目的驱动还是com.mysql.jdbc.Driver需要在pom里升级依赖。Node版本如果太高比如Node17以上某些旧依赖会报OpenSSL相关的哈希错误。解决办法是升级依赖版本或者固定Node版本。我曾经在部署时遇到前端构建失败报错信息指向一个PostCSS插件后来发现是全局Node版本太新。当时直接用nvm切换到Node14问题立刻消失。所以如果目的是快速复现这个项目最好使用和开发环境一致的Node版本。6. 常见问题与排查技巧实录6.1 高频报错速查表我整理了一张自己开发过程中遇到最多的报错速查表基本涵盖了教学辅助系统从开发到部署的高频问题。如果你正在调试这套源码直接对照排查会很快。报错现象可能原因解决方案启动时报Public Key Retrieval is not allowed连接MySQL8时JDBC参数缺allowPublicKeyRetrievaltrue在数据库连接串后加?allowPublicKeyRetrievaltrueuseSSLfalse接口访问返回404但Controller存在类上没有加RestController注解或者类没有放在启动类子包下确认包路径和注解Invalid bound statement (not found)Mapper接口和XML映射没有关联成功检查XML的namespace路径、mapper-locations配置分页查询返回total0没有配置MyBatis-Plus分页插件配置PaginationInnerInterceptor登录接口报401浏览器看到请求被拦截拦截器没有放行/api/auth/login在排除路径列表中加入登录接口前端npm run dev后页面报跨域错误请求路径没有走代理或代理配置不对检查vite.config.js中proxy配置并确认前端请求以/api开头上传作业后找不到文件下载地址文件存储在本地磁盘路径没有做静态资源映射在WebMvc配置中映射/upload/**到本地目录或用对象存储中文乱码数据库字符集不是utf8mb4或前端页面编码不对建库时指定字符集HTML中设置meta charsetUTF-8前端刷新页面出现404Nginx没有配置try_files在location /中配置try_files $uri $uri/ /index.html6.2 三个容易忽略的排查技巧第一个技巧接口出错了先看浏览器开发者工具的Network面板再看SpringBoot后台日志最后才去翻代码。很多时候前端请求根本没发到后端或者是请求头少了Token这时候调试后端纯属浪费时间。第二个技巧遇到MyBatis的执行问题把MyBatis的SQL日志打开。在application.yml里配置logging: level: com.example.mapper: debug这样控制台会打印每条SQL的参数和结果。你会发现很多查不出数据的问题其实是参数没传进去或者表名字段名拼写错误一眼就能看出来。第三个技巧对比老师能正常登录学生一登录就报错这类角色相关问题优先检查路由配置里的meta.roles再检查后端拦截器。前端和后端权限规则必须保持一致但很多项目改了一边忘了另一边。我给用户分配角色的接口和后端校验角色用的是同一个枚举来源比如前端的user_type和后端的UserTypeEnum可以避免手工维护两个字符串列表。6.3 权限与数据隔离的隐藏坑教学辅助系统有一个经常被漏掉的逻辑教师只应该看到自己教的课程数据但很多初版代码写的查询是SELECT * FROM course结果所有老师都看到全校课程。这个问题在后端查询只用条件构造器时特别容易出现。我的处理办法是在service层强制注入当前登录教师的ID。具体来说在CourseController里每一个课程相关接口都需要通过SecurityUtil.getCurrentUser()获取当前登录用户ID再传给courseService.listCourseByTeacherId(teacherId)。简单说不要把权限过滤全部交给前端后端接口必须能识别出谁在调用才能返回对应的数据。同样学生查看自己的成绩时后端也要强制按当前学生ID过滤。否则学生只要把接口路径里的studentId参数改一改就能看到别人的成绩。我用是登录信息里的ID而不是前端传来的ID这样就算请求被篡改数据也不会越权。6.4 写在最后如果你正在做类似项目说实话教学辅助系统并不算一个高难度的项目但想要做得完整、可交付、能应对真实使用场景工作量比想象中大得多。我自己在这一套系统上验证了一个道理技术栈只是骨架真正拉开差距的是对业务细节的理解——作业提交状态怎么流转、教师批改后如何通知学生、选课冲突如何解决、成绩是否允许修改以及修改记录怎么留痕。如果你手头刚好也在开发类似的系统我建议先花半天把业务流程图手绘出来再动手写代码。别嫌这一步麻烦我最初就是因为跳过了设计直接在数据库里建表后来光改表结构就返工了三次。最后脑海中浮现出一句话能跑通演示的代码很容易能经得起真实数据的系统才是要打磨的。希望这篇关于SpringBoot2Vue3MyBatis-PlusMySQL8.0教学辅助系统的拆解能让你少踩一点我当年踩过的坑。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑