尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

SpringBoot+Vue教务管理系统:多端联动实战开发全解析

SpringBoot+Vue教务管理系统:多端联动实战开发全解析 简介这是一套面向教育培训机构的全栈教务管理解决方案适用于Java后端、Vue前端及微信小程序开发者学习与二次开发解决多校区协同、招生分销、直播教学等典型教育数字化场景中的系统集成难题。资源包共359个文件含260个Java核心业务代码涵盖RedisUtils、WxProperties、ExcelUtil等实用工具类、27个PNG界面图标与1张JPG宣传图、4个XML配置及2个YAML服务参数文件辅以.gitignore、LICENSE、README.md等工程规范文件整体压缩包仅6.98MB轻量易部署。目前已有68人学习下载适合中高级开发者快速掌握SpringBootVue小程序三端联动架构设计与教务领域建模方法。读者可直接运行PC后台与小程序双端演示深入理解课程排期、财务稽核、团体报名等模块的接口定义与状态流转逻辑并基于模块化结构灵活裁剪功能。 最近在整理一套实际落地过的教务管理系统刚好有朋友问起整个技术方案和源码结构我干脆把当初从搭建到部署的完整过程沉淀成文。这套系统基于SpringBoot Vue同时集成了微信小程序端和PC管理后台覆盖了学校/培训机构最常见的教务场景——学生管理、教师排课、选课、成绩录入与查询、课表查看、班级管理这些。无论你是想快速搭一套自己的教务系统还是想找一个多端联动的完整落地案例参考这篇文章都能派上用场。先交代一下背景我之前参与过的项目里很多客户一开始的需求只有做个课表管理但真正用起来之后往往发现PC后台管理排课简单学生和老师不可能天天守着电脑他们更需要手机端查课表、查成绩、请假。所以这套系统在设计之初就按PC管理后台为管理侧、微信小程序为师生侧的思路来拆。后端统一提供RESTful API前端两套各自消费数据模型完全共用整体架构不算复杂但胜在实用能覆盖真实业务流。整体系统设计与技术选型1.1 为什么选SpringBoot Vue这套组合技术选型这块我当时没有太多纠结核心原因就三点。第一SpringBoot在Java生态里几乎是企业级后端的事实标准生态成熟、资料多、团队招人容易遇到问题能搜到的解决方案数量级比别的框架高太多。第二Vue在国内前端圈的渗透率极高尤其是管理后台类项目Element UI / Element Plus这种组件库直接把后台页面开发效率拉满不需要从零造轮子。第三前后端分离的架构可以让PC后台和微信小程序端共用同一套API移动端不需要单独再写一套后端逻辑这是多端系统能高效维护的前提。教务系统这种业务本质上就是人和数据的关系管理。后端要做的是把学生、教师、课程、班级、选课关系、成绩记录等实体之间的关系理清楚并提供一组稳定的CRUD和业务接口。前端要做的是把这些数据以不同的视角展示给不同角色。PC后台管理端是上帝视角管全局小程序端是个人视角看自己的课表和成绩。这套视角分离的思路直接决定了我后面数据库表结构和接口设计的方式。1.2 系统整体架构前后端分离下的多端复用整体架构我按经典的三层方式拆表现层PC管理后台 微信小程序、接口层SpringBoot RESTful API、数据层MySQL。表现层和接口层通过HTTP JSON通信JWT做身份认证。有人会问为什么不用Spring Cloud那套微服务教务管理系统在高并发上并没有那么极端的压力单体应用配合合理的缓存和索引完全够用。而且越是多端项目越要控制后端复杂度微服务带来的分布式事务、服务治理成本对这种业务体量来说是负收益。整个请求链路是这样一个流程小程序端或PC端发起请求带上JWT Token后端通过拦截器校验身份并解析角色权限然后调用Service层业务逻辑最终通过MyBatis-Plus操作MySQL。业务上涉及到的核心模块有用户认证、学生/教师管理、课程管理、班级管理、选课、排课、成绩管理、课表查询、公告通知。前端Vue3 Element Plus / 微信小程序原生 ↕ HTTP JSON JWT SpringBoot Spring Security MyBatis-Plus ↕ MySQL核心业务数据 Redis缓存/验证码/Token黑名单这里Redis不是必需品但建议加上。教务系统虽然并发不高但选课高峰期会有短时集中访问用Redis缓存热点数据比如课表、公告效果非常明显。另外验证码、Token刷新这些场景用Redis也比数据库存储方便得多。1.3 核心功能模块拆解整个系统的功能模块我按用户角色来划分。PC管理后台的管理员拥有最高权限可以管理所有基础数据和系统配置。教师端PC后台或小程序可以查看自己的授课课表、录入学生成绩、发布课程通知。学生端小程序为主可以选课、查看课表、查成绩、请假申请、接收公告。具体的功能清单大致如下系统管理用户管理、角色管理、菜单管理、操作日志教务管理学期管理、班级管理、课程管理、教室管理、排课管理学生管理学生信息维护、学籍状态、班级分配教师管理教师信息维护、授课安排选课中心学生选课/退课、选课时间控制、选课统计成绩管理成绩录入、成绩审核、成绩查询与导出课表模块按班级/教师/教室维度生成课表视图个人中心小程序端登录、查看通知、请假审批这套模块拆分的核心逻辑是基础数据先行业务动作在后。先把课程、班级、教室、教师、学生这些基础数据维护好选课、排课、成绩这些业务动作才有意义。很多新手开发教务系统容易一上来就写选课逻辑结果发现班级和课程关系没定义清楚程序里全是补丁这点要特别注意。后端核心实现与关键细节2.1 SpringBoot项目结构与依赖配置后端我用的SpringBoot 2.7.x版本为什么不用3.x原因很实在3.x要求JDK17起步很多生产环境的服务器还停留在JDK8而且部分老牌库对Jakarta命名空间的适配还有坑。2.7.x是2.x的终极版本稳定性和生态兼容性都相对理想适合直接部署到客户机器上。JDK用的1.8这在企业项目里仍然是最稳妥的组合。项目结构按模块分包清晰比花哨重要com.example.edusystem ├── config // 配置类MyBatis-Plus、Cors、Interceptor、Redis ├── controller // 接口层 ├── service // 业务逻辑层 ├── mapper // MyBatis-Plus的Mapper接口 ├── entity // 数据库实体 ├── dto // 前端请求/响应对象 ├── vo // 视图对象 ├── utils // 工具类JWT、日期处理等 ├── exception // 统一异常处理 └── EduApplication.java核心依赖没搞太多花活就是SpringBoot Web、Spring Security、MyBatis-Plus、MySQL驱动、Redis、JWTjjwt、Lombok、Hutool工具库。Hutool是个好东西日期处理、Excel导出、加密这些工具方法直接拿来用少写很多重复代码。2.2 MyBatis-Plus配置与多表查询设计数据库操作这块我选了MyBatis-Plus说实话主要是懒。单表CRUD完全不用写SQL内置的LambdaQueryWrapper写条件查询非常舒服比如按照班级ID查学生列表、按照学期查课程列表几行代码就搞定。多表关联查询还是老老实实写XML里的自定义SQL因为教务系统里像学生选课列表——带出课程名、教师名、学分这种场景关联查询用SQL表达最清晰也最容易优化。举个例子查询某学生某学期的选课列表对应SQL大致是SELECT c.id AS course_id, c.course_name, c.credit, t.teacher_name, sc.status, sc.score FROM t_student_course sc INNER JOIN t_course c ON sc.course_id c.id INNER JOIN t_teacher t ON c.teacher_id t.id WHERE sc.student_id #{studentId} AND c.semester_id #{semesterId} ORDER BY c.course_name这种SQL建议写在Mapper XML里用Select注解也行但项目一大还是XML好维护至少格式化、看执行计划都方便。有个实际经验关联查询尽量只查需要的字段不要SELECT *尤其是课程表字段多的时候能省不少IO。分页用的MyBatis-Plus自带的分页插件配置一个PaginationInnerInterceptor就行。需要注意分页插件必须配置数据库类型否则生成的count语句可能不兼容。2.3 JWT认证与Spring Security权限控制教务系统涉及三种角色——管理员、教师、学生权限必须严格区分。学生不能去调删除课程的接口教师不能改其他教师的课程信息。我是用Spring Security JWT做认证和授权的。认证流程这样走用户登录管理员/教师走PC端学生走小程序端后端校验用户名密码校验通过后签发JWT Token把用户ID、角色、过期时间放进去前端拿到Token后每次请求放在Header的Authorization字段里后端写一个JwtAuthenticationFilter解析Token并设置SecurityContext在接口上用PreAuthorize(hasRole(ADMIN))这类注解做细粒度权限控制JWT有个坑要提醒一下Token一旦签发在过期之前是无法主动失效的。用户修改密码、被封禁这些场景Token还是有效的。解决办法是我在Redis里维护了一个Token黑名单登出接口把Token加入黑名单并且设置和Token相同的过期时间每次请求过滤器先查一次黑名单。多一次Redis查询但安全性提升明显值得。Spring Security配置这块我不建议用默认的登录页和表单登录还是走无状态模式关闭Session所有接口除了登录、验证码等少数几个白名单一律要认证。http.csrf().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() .antMatchers(/api/auth/login, /api/captcha).permitAll() .antMatchers(/api/admin/**).hasRole(ADMIN) .antMatchers(/api/teacher/**).hasAnyRole(TEACHER, ADMIN) .antMatchers(/api/student/**).hasAnyRole(STUDENT, ADMIN) .anyRequest().authenticated();小程序端的登录是个特殊场景。学生没有用户名密码直接用它微信登录后的code后端调用微信接口换openid再拿openid查学生表查到就自动注册/登录。第一次登录时如果学生已经由管理员导入到系统里就绑定openid和学号如果没有导入我当时的做法是拒绝登录提示联系管理员导入信息避免陌生人随便注册进来。2.4 小程序接口的幂等与防重复提交教务系统里有一个典型的并发问题——选课。学生选课时前端会先查询可选课程列表然后点击选课提交。如果网络卡顿用户连续点了两次就可能产生两条选课记录。解决思路是在后端做一个幂等控制选课接口先查t_student_course表里是否已有该学生和该课程的记录有就返回已选过没有才插入。同时数据库层面给student_id和course_id建联合唯一索引双保险哪怕并发穿透到了数据库也会因为唯一约束只插入一条成功记录。这一条经验其实适用范围很广凡是用户手动提交的操作比如报名、下单、提交申请都要考虑重复提交的问题。用唯一索引兜底是最简单可靠的方案没有之一。PC管理后台与Vue前端实现3.1 Vue3 Element Plus搭建管理后台PC管理后台用的是Vue3 Vite Element Plus Pinia Vue Router。Vite比Webpack快太多了开发体验完全是两个世界Pinia作为Vue3的官方推荐状态管理库比Vuex的语法简洁不少改起来也顺手。管理后台整体布局就是左侧菜单栏 顶部导航栏 右侧内容区。菜单根据登录用户的角色动态生成这里的数据来自后端接口菜单表和角色菜单关联表前端根据返回值渲染侧边栏。这样做的好处是新增菜单不用重新发版管理员配一下菜单表就行。路由权限控制是这类后台项目的核心点。我的做法是在Vue Router的全局前置守卫里做两件事一是判断是否已登录没登录跳转到登录页二是根据后端返回的权限码权限标识集合用router.addRoute动态添加该用户有权限访问的路由。这样做到了菜单显示和路由跳转的双重控制用户就算在地址栏手动输入一个无权限的URL也会被拦下来跳到404页面。3.2 核心页面实现要点课表管理是教务系统里最有技术含量的页面。PC后台的课表展示我用的是Element Plus的el-table把星期作为列、节次作为行每节课的格子合并显示课程信息支持点击课程单元格弹出编辑窗口。这里用到了el-table的span-method方法实现单元格合并逻辑不难但要注意计算开始节次和持续节次后合并行数要正确不然课表格子错位调试起来很麻烦。动态刷新这块我用Vue的watch监听当前选中的班级ID变化后重新请求课表数据。学生选课这个高频操作前端做了两个限制选课时间段显示不在开放时间内按钮置灰学分上限控制已选学分超过上限时提示不能再选。这两个校验前端做一遍后端接口再做一遍。前端做是为了用户体验后端做是为了数据安全千万别指望前端校验能挡得住什么。PC管理后台涉及大量表单页面比如学生信息录入、课程信息维护。这类页面我抽了一套通用的form-dialog组件传入配置项自动渲染表单控件减少重复代码。实践中非常好用新加一个模块的录入页面基本半小时能搞定。3.3 与后端联调技巧封装请求与拦截器管理后台的HTTP请求统一封装在request.js里基于Axios。请求拦截器做两件事从Pinia里取Token并加到Header的Authorization字段如果是FormData格式的请求设置正确的Content-Type。响应拦截器做了统一错误处理后端返回的约定格式是{ code: 200, data: ..., message: ... }code不是200时Toast提示messageHTTP状态401时说明Token过期或无效清除本地登录态并跳转到登录页。请求拦截 config.headers.Authorization Bearer token 响应拦截 if (res.data.code ! 200) { Message.error(res.data.message); return Promise.reject(); } if (status 401) { logout(); router.push(/login); }这套封装要尽早做好。项目开发期接口来回改如果每个页面都单独写一遍请求和错误处理后期重构的时候你会想哭。微信小程序端开发实战4.1 小程序端技术选型与页面结构微信小程序端我没有用uni-app而是直接用的原生小程序开发。原因有两个一是项目里微信小程序的功能相对固定不需要跨平台二是原生小程序对微信API的支持最及时学起来也直接。当然如果你考虑将来还要做支付宝小程序那用uni-app更合适这个可以根据实际需求取舍。小程序端页面结构分这几块登录页微信一键登录调后端接口换Token首页当前学期课表卡片、最新公告、待办事项请假审批等课表页按周展示课程时间表选课页可选的课程列表、已选课程列表、选课/退课操作成绩页学期成绩查询、成绩统计我的页面个人信息、请假申请、设置底部TabBar我用的是三个Tab首页、课表、我的。选课和成绩放在首页的快捷入口避免TabBar太挤。4.2 小程序登录与Token管理小程序登录链路相对特殊这里详细说一下。wx.login()拿到临时code把code传给后端后端用code向微信接口换openid和session_key然后查数据库绑定学生账号。绑定成功后签发自己的JWT Token返回给前端。前端把Token存入wx.setStorageSync后续所有请求的Header都带上。有个细节小程序的wx.request不支持像Axios那样直接设置请求拦截器必须封装一层。我写了一个request工具函数内部统一做Token注入、响应拦截、错误提示这样页面里调用请求跟用Axios差不多不用每个页面重复处理Token和错误码。4.3 分包异步化与加载性能优化这里要单独说说分包。随着课程图片、课件资料加进来小程序主包体积很容易超过2M限制。我的做法是主包只放TabBar对应的页面和公共组件选课详情、成绩详情、请假申请这些低频页面全部放到分包里在用户进入时按需加载。实践中还用了微信的分包异步化能力在分包页面里通过require.async动态引用子包中的公共模块避免同步引用导致的分包体积冗余。我还观察到一个新手常踩的坑把图片资源也放在项目文件夹里这会让包体积瞬间爆炸。正确做法是把图片全部上传到CDN或后端OSS页面里只存URL。项目里我建了一个config.js集中维护CDN域名和API基础地址不同环境改这一个文件就行。4.4 小程序端适配问题的处理经验小程序适配最容易出问题的就是顶部导航栏。不同机型刘海屏、挖孔屏的安全区域不一样我用wx.getSystemInfoSync()获取状态栏高度和胶囊按钮位置动态计算导航栏高度。封装了一个nav-bar组件所有页面统一使用避免每个页面各写一套导致高度不一致。还有一个常见需求视频课件播放。如果课件视频是m3u8格式的小程序原生video组件不支持这种流媒体格式。解决思路有两个一是后端转码成MP4但对服务端有额外压力二是集成第三方播放器插件比如腾讯云的播放器SDK或者ByteDance播放器它们支持HLS协议。考虑到集成成本我直接在后端做了转码方案课件上传时用FFmpeg转成HLS并输出m3u8和ts分片小程序端用第三方组件播放。这一块如果你的业务涉及视频建议提前规划别等上线了再补。4.5 小程序表单与交互细节小程序端的学生请假功能表单里有几个常用的组件日期选择器、文本输入框、单选框请假类型这些用小程序原生组件就够了。不过有一个细节要注意原生表单组件在不同机型上的样式差异比较大尤其是单选框。我的做法是隐藏原生radio用自定义样式的view模拟选中态视觉统一且不容易出现样式错乱。另一个容易被忽略的细节是表单提交的防重复点击。小程序里按钮的loading状态要好好利用提交时按钮显示loading并禁用点击防止用户重复提交产生多条申请。提交成功后再跳转不要提前跳避免后端还在处理请求页面却关了。部署、环境配置与常见问题排查5.1 前后端分离部署方案后端部署在生产环境我用的Linux服务器 Docker Compose。数据库MySQL、Redis各起一个容器SpringBoot应用单独一个容器。nginx直接部署在宿主机上负责三件事托管PC管理后台的静态文件反向代理/api请求到SpringBoot容器处理HTTPS证书。小程序端不需要部署但它的API请求要走HTTPS并且域名必须在小程序后台配置到request合法域名里。docker-compose.yml的大致内容如下简化version: 3 services: mysql: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: xxx volumes: - ./mysql-data:/var/lib/mysql redis: image: redis:6-alpine app: build: . depends_on: - mysql - redis ports: - 8080:8080SpringBoot的配置文件里要注意生产环境的数据库地址、Redis地址不要用localhost要用服务名mysql、redis这样容器间才能互相访问。用Docker部署还有个好处服务器换环境时一条docker-compose up -d就把全套服务拉起来了不用手动装JDK、MySQL、Redis省了很多运维精力。5.2 跨域问题排查前后端分离开发时最常遇到的就是跨域。在开发环境Vite配置proxy代理把/api开头的请求代理到后端8080端口浏览器不会产生跨域问题。但生产环境如果用小程序的请求它没有跨域的概念只有PC后台的浏览器访问才会触发。如果你在生产环境发现浏览器访问接口报CORS错误先确认浏览器实际请求的URL是不是nginx转发后的地址再看后端是否配置了CorsFilter。我后端的跨域处理是在config里写一个CorsFilter放行所有来源并设置允许的Header包含Authorization。注意如果用了Spring SecurityCORS配置必须在Security过滤链之前生效否则请求在安全过滤器就被拦了CORS配置等于白写。排查步骤 1. 浏览器F12查看请求URL确认是否走了代理 2. 看请求头Origin是否正常 3. 确认后端CorsFilter是否配置了Access-Control-Allow-Origin 4. 确认Spring Security是否放行了OPTIONS请求5.3 小程序抓包与联调技巧小程序联调时我强烈建议学会抓包。微信开发者工具自带的Network面板能看到请求和响应但对于排查一些真机上的问题开发者工具模拟不出来。要抓真机小程序的包可以用Charles或Reqable这类工具在电脑上开启HTTPS代理手机WiFi代理指向电脑再给手机安装Charles的CA证书就能看到小程序发的每一个请求。实际操作中第一次抓包最后一步有个常见坑Android 7.0以上的系统默认不信任用户安装的CA证书需要把证书安装到系统证书目录里要求已经root或者小程序开发版勾选不校验合法域名。所以最简单的方式是在微信开发者工具中勾选详情 - 本地设置 - 不校验合法域名开发阶段这样大大降低联调成本。5.4 常见问题速查表实际开发和后期维护中我把碰到的高频问题整理成了一张速查表方便团队新成员快速定位现象可能原因解决方案登录后请求401Token过期或Header未正确携带检查请求拦截器确认Authorization字段格式为Bearer 空格 Token小程序加载白屏分包引用路径错误或基础库版本过低检查分包异步化引用确认页面路径在小程序app.json中正确注册课表格子错乱el-table span-method计算的行列数不对打印合并的行列索引逐个核对节次边界前端请求跨域nginx未配置代理或CorsFilter缺失检查nginx location /api的proxy_pass确认CorsFilter放行数据库连接超时容器IP变化或连接池配置偏小使用服务名代替IP调大HikariCP的maximum-pool-size导出Excel乱码Hutool导出时未处理响应头编码设置Content-Type为application/vnd.ms-excel编码UTF-8选课并发重复前端重复提交且后端无唯一约束后端加幂等校验和联合唯一索引开发过程中踩过的坑与经验总结有不少问题在写代码的时候根本想不到只有等数据量上来、并发上来才会暴露。这里分享几个亲身经历希望能帮你少走弯路。关于数据库设计我一开始把学生、用户、教师三个表拆得太细后来发现联表查询很麻烦。学生和用户其实可以合并成一张user表用role字段区分学生扩展信息单独一张student_profile表。教务系统的核心查询场景是按人查数据用户表拆得太碎每个查询都要多join一次性能和开发效率都不理想。JWT过期时间这个坑也值得说说。当初图省事把Token过期时间设置成了7天学生不用频繁登录体验是好了但安全隐患也大了——Token泄露后7天内都能被冒用。后来我把Token改成2小时过期配合RefreshToken机制刷新Token保存在Redis里有效期7天过期前自动换取新Token。安全性好了用户体验也没降太多。小程序端的资源加载还有一个容易忽略的点图片懒加载。课表、公告里的图片比较多如果一次性全加载小程序页面的onShow会明显卡顿。使用image组件的lazy-load属性配合CDN上的合理尺寸压缩首屏加载速度快很多。真机上测试最明显同一个页面优化前加载要三秒多优化后基本秒开。关于日志我强烈建议后端把关键业务操作都记录下来。我在系统里写了一个简单的AOP切面用Log注解标注需要记录的方法自动记录操作人、操作类型、请求参数、耗时。这个日志功能看起来不起眼但在线上排查问题时简直是救命稻草。比如学生反馈我明明选了课为什么选课记录没了查一下操作日志发现是管理员在后台误删了记录责任清晰不用互相扯皮。最后说一句运维方面的经验。教务系统一般都涉及学期切换每次新学期的开始课表要重新排、选课要重新开放、成绩期次要更新。我在系统里设计了学期复制功能管理员可以一键把上学期的班级、课程结构复制到新学期再手动微调排课。这个功能开发成本不高但能让系统上线后第一次换学期省掉大量重复录入工作实用性非常高。如果你准备基于这套架构做二次开发我建议优先扩展以下几个方向消息推送新公告、成绩发布时通过微信订阅消息通知学生、数据报表成绩分布、选课热度分析、在线考试模块。这些都是教务系统后续最常见的需求点而且完全可以在现有架构上平滑增加不需要推到重来。回到最初的问题——为什么一定要做多端因为教务系统的使用场景天然是分裂的管理者在办公室用PC、教师在教室用手机、学生在宿舍用小程序。一个系统要真正被用起来必须让每个角色都在最顺手的地方完成操作。PC管理后台负责复杂管理操作小程序负责高频轻量查询两边共用同一套后端逻辑这也是现在大多数业务系统的理想形态。希望这篇实战总结能给你一些参考。本文还有配套的精品资源点击获取
返回列表