ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

SpringBoot+Vue+MyBatis+MySQL前后端分离实战:古典舞在线交流平台源码解析

SpringBoot+Vue+MyBatis+MySQL前后端分离实战:古典舞在线交流平台源码解析 最近在梳理一套比较有代表性的实战项目源码时发现很多初学者对SpringBoot、Vue、MyBatis、MySQL这一整套前后端分离架构的理解还停留在“单个Demo跑通”的阶段。这次拿到的是一套完整的“企业级古典舞在线交流平台管理系统源码”技术栈正好是SpringBootVueMyBatisMySQL而且不是简单的CRUD而是围绕古典舞在线教学、交流、会员管理、课程内容分发做了完整业务闭环很适合用来拆解企业级项目到底该怎么搭、怎么写、怎么上线。这篇博文我会从项目整体设计、数据库建模、后端核心实现、前端交互、部署上线、常见坑点这几个维度展开把源码里的关键思路和实操细节都翻出来讲清楚。不管你是Java后端想补前端还是前端想搞懂后端业务逻辑或者是正在准备课程设计、毕业设计、找工作项目经验这篇内容都值得认真看完。1. 项目整体设计与架构拆解1.1 技术选型为什么是SpringBootVueMyBatisMySQL很多人上来就问“这个项目为什么不用Spring Cloud”或者“为什么不用MyBatis Plus而是用MyBatis”。先说结论这套技术栈是当前中小型企业管理平台最稳、最容易招人、也最容易维护的组合。SpringBoot解决的是后端快速启动和生态整合问题内嵌Tomcat、自动配置、starter机制让项目从零搭建到跑起来只需要几分钟。Vue解决的是前端交互体验问题尤其是古典舞在线交流平台这类需要课程展示、视频播放、社区互动、后台管理的场景组件化开发能大幅度提升页面复用性。MyBatis解决的是SQL控制精度问题虽然MyBatis Plus更省事但原生MyBatis对SQL的可控性和优化空间更大尤其在分页查询、动态SQL、复杂报表统计这些场景下手写SQL反而更清晰。MySQL则是绝大多数Java项目的标配数据库开源免费、性能稳定、运维生态成熟。这套组合还有一个隐藏优势招聘市场上SpringBoot和Vue的熟练度几乎是后端和前端岗位的硬门槛。用这套技术栈做项目不管是课程设计、毕业设计还是往简历上写的项目经验辨识度都很高面试官也容易切入提问。1.2 前后端分离与项目目录规划这套源码采用的是标准的前后端分离结构后端是一个SpringBoot工程前端是一个Vue工程两者通过RESTful API交互。目录规划上做得比较规范这里我拆一下要点。后端核心包结构大概是这样的controller接口层负责接收请求、参数校验、返回结果service业务层负责核心业务逻辑和事务管理mapper数据访问层对应MyBatis的Mapper接口和XML映射文件entity实体类对应数据库表字段dto数据传输对象用于接口入参和出参的封装config配置类解决跨域、拦截器、WebMvc配置等问题utils工具类比如JWT工具、日期处理、文件上传工具common统一返回结果、异常处理、全局异常捕获前端Vue工程的目录则按照视图层、状态层、路由层分开views页面级组件components可复用业务组件router路由配置storeVuex状态管理api接口请求封装utils前端工具函数前后端分离的好处不用多说开发效率高、前后端可以并行开发、部署上也支持独立扩展。但要注意一点分离后最核心的问题就变成了接口规范和跨域处理。这套源码里用了一个统一的Result返回类所有接口返回格式都是code、msg、data三段式这样前端处理起来非常统一不需要每个接口单独判断返回状态。1.3 业务模块划分古典舞垂直场景的核心链路古典舞在线交流平台不是简单的视频网站它有一个完整的业务链路。官方源码里模块划分得比较细我整理成一张逻辑图来理解。平台核心用户是古典舞学员和舞蹈教师围绕这两类用户构建的业务模块包括用户模块注册、登录、个人信息、角色权限课程模块古典舞课程发布、课程分类、上下架管理、课时列表视频模块课程视频上传、在线播放、播放进度记录社区模块帖子发布、评论回复、点赞收藏、舞友交流订单模块课程购买、订单状态管理后台管理模块用户管理、内容管理、数据统计这个链路设计其实很值得学习它不是把功能简单堆砌而是围绕“用户-课程-互动”这个核心三角来构建。用户在平台上找课程、学课程、在社区交流、再回到课程形成业务闭环。企业级项目和课程设计的最大区别就在这课程设计往往是一堆功能点并列而企业级项目一定是有一条业务主线贯穿的。2. 数据库设计与MyBatis落地2.1 古典舞平台的核心表结构设计数据库设计是整个项目的地基表结构理不清后面写代码全是坑。这套源码的MySQL数据库我梳理下来大概有十几张核心表这里挑重点的几张讲一下设计思路。用户表是最基础的一张表字段包含用户ID、用户名、密码、真实姓名、手机号、角色类型、头像、状态、创建时间这几个核心字段。这里有个细节很多人会忽略角色类型字段千万别用String类型存什么“admin”“user”建议用tinyint类型的数字枚举0表示管理员、1表示教师、2表示学员这样查询效率高代码里也好做权限判断。课程表的设计需要多考虑一下业务扩展字段包含课程ID、课程名称、课程封面、课程简介、适用舞种、难度等级、价格、教师ID、上下架状态、总课时数、创建时间。古典舞课程和普通课程不太一样舞种、难度等级这些维度对学员选课很重要数据库里单独用字段存会比用标签表更简单高效查询的时候where条件直接过滤就行。课程视频表记录的是每一个课时的视频信息包含视频ID、课程ID、课时名称、视频地址、视频时长、排序号、是否免费试看。这种设计的好处是支持一个课程挂多个课时视频也方便后续做视频进度管理。社区帖子表和评论表是交流功能的数据核心。帖子表包含帖子ID、用户ID、标题、内容、图片列表、点赞数、评论数、创建时间。这里点赞数和评论数建议冗余存储也就是在帖子表里直接维护这两个计数而不是每次查count因为社区场景的列表页要频繁展示这两个数字实时count会拖慢查询速度。订单表则包含订单ID、订单编号、用户ID、课程ID、支付金额、支付方式、订单状态、创建时间。订单编号一般用时间戳加随机数生成避免并发重复。支付这块如果接第三方支付会把项目复杂度拉高不少这套源码里是用模拟支付的思路做的核心在订单状态流转这个方式反而更适合学习。2.2 MyBatis的Mapper接口与XML映射配置MyBatis这块是很多人容易踩坑的地方。这套源码采用的是接口加XML的经典写法把SQL语句统一放在resources目录下的mapper文件夹里Java接口只定义方法签名两者通过namespace和id关联。举个例子用户Mapper的接口可能是这样public interface UserMapper { User selectByUsername(String username); int insertUser(User user); int updatePassword(Param(userId) Integer userId, Param(password) String password); }对应的UserMapper.xml里是这样的select idselectByUsername resultTypecom.example.entity.User SELECT * FROM user WHERE username #{username} LIMIT 1 /select这里有一个关键细节#{}和${}的区别。我的建议是永远优先使用#{}因为#{}是预编译传参能有效防止SQL注入${}是字符串拼接只在动态表名、动态排序字段这类场景下使用而且必须经过白名单校验否则就是SQL注入漏洞。XML映射配置还有一个容易忽略的点是resultMap。当表字段命名是下划线风格比如create_time而实体类是驼峰命名比如createTime时如果没做映射查询出来的字段就是null。解决办法有两个一是用resultMap显式映射二是在application.yml里开启驼峰命名自动映射mybatis: configuration: map-underscore-to-camel-case: true这个配置开启后MyBatis会自动把下划线字段名转成驼峰属性名省掉大量resultMap配置。这套源码里就是用这种方式处理的代码确实简洁很多。2.3 MyBatis分页插件与缓存的正确用法分页查询是管理平台绕不开的需求。这套源码用的分页方案是PageHelper不是手写LIMIT。PageHelper的用法很简洁在Mapper查询方法执行前调用一次PageHelper.startPage即可然后查询结果会自动被封装成PageInfo对象里面有total、pageNum、pageSize等分页信息。常规用法如下PageHelper.startPage(pageNum, pageSize); ListCourse courseList courseMapper.selectCourseList(); PageInfoCourse pageInfo new PageInfo(courseList);PageHelper虽然好用但有一个著名的坑不能在startPage之后紧接着执行无关的查询否则分页参数会被应用到下一次查询上导致数据错乱。源码里比较好的做法是在Service层启动事务把分页查询和结果封装放在一个方法里避免中间插入其他查询。再聊聊MyBatis缓存。一级缓存是SqlSession级别的默认开启同一个SqlSession内相同SQL会命中缓存。二级缓存是Mapper级别的需要手动配置。这套源码里没有过度依赖二级缓存因为在管理平台这种场景下数据实时性要求比较高缓存失效策略设计不好反而容易查到脏数据。我的建议是默认用一级缓存就好二级缓存除非你非常清楚业务缓存的失效策略否则别乱开。把这个道理讲清楚在面试里其实是一个加分的点。3. SpringBoot后端核心实现3.1 项目初始化与关键配置说透这套源码的后端工程是基于SpringBoot 2.x版本构建的相比3.x2.x在兼容性和资料丰富度上更适合学习使用。application.yml配置文件中数据源、MyBatis和文件上传这三块是最核心的。数据源配置方面用的连接池是Druid这个选择很合理。Druid除了基本的连接池管理还带监控页面和SQL防注入过滤。后端上线的项目数据库连接池配置有几个关键参数要注意initialSize初始化连接数建议5minIdle最小空闲连接建议5maxActive最大活跃连接建议20。这些参数不是越大越好要根据实际并发量调整配置太大反而浪费数据库资源。yml里核心配置可以这样写spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/dance_platform?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456 druid: initial-size: 5 min-idle: 5 max-active: 20 max-wait: 60000数据库连接URL里的参数不是随便加的。useUnicodetrue和characterEncodingutf8保证中文不乱码serverTimezoneAsia/Shanghai解决MySQL 8.x版本下时间差8小时的问题。这些细节在调试时经常会遇到配置好了一劳永逸。文件上传配置也很重要古典舞课程视频体积不小必须限制上传大小。SpringBoot默认单文件上传大小是1MB肯定不够用需要在yml里改配置spring: servlet: multipart: max-file-size: 1024MB max-request-size: 1024MB把上传大小放大到1024MB只是第一步更重要的是上传后文件的存储策略。这套源码的做法是把文件存储到服务器本地指定目录然后把访问URL返回给前端。这种方式简单直接适合学习阶段和中小型项目。生产环境中更稳妥的方案有FastDFS、MinIO、阿里云OSS但核心思路都一样文件和数据分离数据库中只存文件的访问路径。3.2 登录认证与权限控制怎么做在线交流平台涉及用户体系和后台管理登录认证方案在这套源码里用的是JWT。相比Session方案JWT天然适合前后端分离架构无状态、跨域友好、扩展性好。实现思路不复杂用户登录成功后后端利用用户的ID和角色生成一个Token返回给前端。前端把Token存储在localStorage中后续每次请求都放在请求头的Authorization字段里。后端通过拦截器过滤所有需要登录的请求解析Token并验证验证通过就放行同时把用户信息放入ThreadLocal供后续业务使用。这里要注意Token过期时间的设置。源码里把过期时间设置成24小时这个时间不算长但管理平台场景下足够用了。同时设计了Refresh Token的雏形当Token过期时前端会跳转登录页让用户重新登录。真正的企业级项目还会做刷新令牌但学习阶段先明白这个链路即可。权限控制用的是拦截器加权限码的方式。每个接口需要的权限码写死在注解或拦截器配置里访问时进行校验。比如课程发布接口要求教师或管理员角色评论删除接口要求管理员角色。这种基于角色的权限控制在中型项目里完全够用RBAC的表结构都设计起来反而会增加复杂度。一个加分细节是统一异常处理。这套源码用RestControllerAdvice配合ExceptionHandler实现全局异常捕获业务里抛出ServiceException后前端拿到的是统一的code和msg提示而不是满屏的堆栈信息。用户操作友好排查问题也方便。3.3 视频播放与文件处理方案古典舞在线平台绕不开视频点播。这套源码的视频播放方案值得学习视频文件上传后通过前端Vue组件播放video标签直接读取后端返回的视频URL。后端处理视频的核心是提供一个流式访问的接口。SpringBoot中可以直接利用Resource的流式输出把视频文件以流的形式响应给前端。视频播放的过程其实就是浏览器边下边播所以视频格式必须是浏览器可以直接播放的MP4H.264编码或者WebM格式。这一点在课程视频上传环节要做格式校验源码中在前端做了文件扩展名的限制而实际生产环境里更稳的做法是后端对视频做转码处理可以用FFmpeg转成统一编码格式否则有些浏览器会黑屏无法播放。视频播放进度记录也是一个很关键的交互点。当用户从列表继续上一次学习时可以直接跳到上次看到的进度位置。实现方式很简单前端监听video元素的timeupdate事件每隔几秒把当前播放时间发送到后端保存下次打开课程视频时查询播放记录把视频起始时间设置成上次记录的位置。代码层面核心逻辑就这一句this.$refs.video.currentTime this.playRecord.progress;另外要提醒一点视频文件的访问权限也要控制尤其是付费课程不能让没购买的用户直接获取视频地址。简单方案是视频接口走权限校验发现用户没有购买该课程就拒绝请求更精细的方案是给视频URL签名加时间戳但学习阶段先做好权限校验就行。4. Vue前端与接口交互实现4.1 Vue项目搭建与路由设计前端这块源码用的是Vue 2.6配合Vue Router和Vuex。很多人纠结Vue 2和Vue 3我的观点很直接如果是在学习和面试阶段Vue 2和Vue 3的核心思想没有本质区别选项式API和组合式API的差异并不影响你对业务逻辑的理解而Vue 2的资料和岗位存量依旧庞大把Vue 2打好基础再上手Vue 3是非常顺畅的路径。路由设计决定了一个前端项目的结构质量。对比一下清晰设计和混乱设计的差距清晰的设计是路由嵌套、权限控制、懒加载、统一守卫都安排得明明白白混乱的设计是所有页面平铺一个router.js里堆几百行没有嵌套、没有守卫、没有懒加载。这套源码的路由设计用了动态路由思路。基础路由是登录页和注册页通过beforeEach全局前置守卫统一处理页面访问权限router.beforeEach((to, from, next) { const token localStorage.getItem(token); if (!token to.path ! /login) { next(/login); return; } if (token to.path /login) { next(/); return; } next(); });除了登录守卫还要按角色动态添加菜单路由。比如管理员能看到后台管理菜单教师能看到课程发布管理学员只能看课程学习和社区交流。这样既保证权限安全也提升用户体验。4.2 状态管理与接口请求的统一封装Vuex的状态管理在大型项目中是必不可少的不管数据量多少用户信息、菜单列表这种东西都该放进去。源码中Vuex的store分成了多个module有user模块管理用户信息有common模块管理系统通用状态结构清晰。表单提交和校验是前端开发里高频场景这套源码没有引入Element UI的form校验之外的东西但每个页面的表单校验写得比较认真。我特别赞同这个做法尤其是用户注册、课程信息编辑这种核心表单后端还需要做二次校验前端校验只是提升体验。接口请求封装是必须重点讲的部分。源码在utils/request.js中基于axios做了统一封装有几个核心设计值得好好学习。第一个是请求拦截器每次请求自动带上Token。代码如下service.interceptors.request.use(config { const token localStorage.getItem(token); if (token) { config.headers[Authorization] token; } return config; }, error { return Promise.reject(error); });第二个是响应拦截器统一处理业务状态码和HTTP状态码后端返回的code为200时直接返回datacode为401时清除Token并跳转登录页。这样各个业务页面就不用重复写错误提示逻辑了。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.msg)); } return res.data; });这套封装的好处是前端业务代码只管拿数据渲染页面接口成功的判断、错误码的统一处理都是收敛在封装层里这是所有企业级前端项目都会用的模式。4.3 古典舞课程播放与社区交互细节课程详情页和在线播放页是学员端最核心的页面。课程详情页要展示课程封面、讲师信息、课时列表、课程简介点击课时后跳转到播放页。播放页用video标签集成播放器关键点在于播放地址的动态获取和当前课时的切换。课时列表的交互细节很容易被忽略但其实很影响体验。当前播放的课时要高亮显示已学完的课时要打上已完成标记未购买用户则提示先购买。这些状态判断可以在前端根据课程列表的字段来做清晰又高效。社区交流模块在这套平台里也很有特色。古典舞学员群体有比较强的社交需求大家喜欢晒练习照片、交流舞蹈心得。源码里社区模块的帖子发布支持图片上传列表页用卡片式布局展示点击进入详情页可以查看评论并回复。帖子详情页的评论采用树形结构设计一级评论下面展示二级回复。实现的思路是把所有评论一次性查出来在前端根据parentId组装成树形结构渲染。这个方案在小数据量场景下很高效数据库查询简单前端逻辑也好控制。评论数据量大了以后再考虑按需加载和懒加载这个从简到繁的演进路径也代表了真实项目的成长节奏。5. 部署上线与问题排查实录5.1 本地环境准备与打包部署项目拿到手之后第一步一定是在本地跑通。环境方面需要准备JDK 1.8、Maven 3.6、Node.js 14、MySQL 5.7或8.0。数据库导入是第一个常见坑点。源码里的SQL文件是一个整体脚本直接用source方式导入或者用Navicat运行整个SQL文件都行。这里我要特别提醒导入数据库之前确认一下MySQL的版本和字符集。MySQL 8.0以上版本默认字符集是utf8mb4而很多老SQL脚本里库表是latin1或者utf8导入后中文会乱码。最简单的做法是导入前创建数据库时明确指定字符集CREATE DATABASE dance_platform DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;后端启动前要做三件事配置application.yml里的数据库账号密码、确认Maven依赖能正常拉到、查看启动类是否被IDE正确识别。SpringBoot启动报错90%都是数据源配置不对或者端口被占用。前端启动相对简单先npm install安装依赖再npm run serve启动开发服务器。npm install时如果网速慢可以切换淘宝镜像源。启动后访问localhost:8080前后端联调时要确认Vue的代理配置是否有效开发环境下通常用devServer的proxy把/api转发到后端8080端口避免跨域问题。5.2 高频报错与排查思路这套源码在跑通过程中有几个问题几乎是必踩的我把排查思路整理出来供大家参考。前端请求接口报跨域错误这种问题分两种场景。开发环境加proxy代理生产环境用Nginx反向代理或者后端开启CORS配置。很多初学者前端配了代理还报跨域原因是没重启前端服务代理配置改完必须重启Vue的开发服务器才会生效。后端启动报数据库连接失败大概率是MySQL服务没启动、驱动版本不匹配、URL参数配置错误。MySQL 8.x版本要用com.mysql.cj.jdbc.DriverMySQL 5.7用com.mysql.jdbc.Driver。对应Driver如果用错了启动直接报ClassNotFound或者连接超时。页面中文乱码先看数据库表字符集再看后端代码里的编码配置最后看前端meta标签。这个链条里的任何一环设置错了都会乱码。npm install卡住或者失败先删除node_modules文件夹和package-lock.json再换镜像源重装。热门框架的依赖包有冲突时用npm install --legacy-peer-deps兜底解决。启动时端口被占用用netstat或lsof找出占用进程然后杀掉。还有一种更隐蔽的情况是前端8080和后端8080冲突两个服务都写死了端口。建议后端统一用8080前端在vue.config.js里把端口改成8081或者9090减少冲突概率。5.3 安全加固与性能优化经验一个能拿到台面上说的项目不能只满足于功能能跑安全和性能这两个维度的处理也决定项目质量。这套源码里有些地方已经做了安全处理但也有些地方可以在实际应用中做得更细。密码存储方面源码用的是MD5加密这在教学场景可以接受但真实企业级项目至少要用BCrypt或者PBKDF2。MD5的碰撞成本太低了配合彩虹表基本等于裸奔。如果你要把这个项目写进简历强烈建议把密码加密方案升级成BCrypt这也是面试官很爱问的一个点。SQL注入防护方面只要坚持用MyBatis的#{}传参基本就能守住底线。刚才提到的${}要谨慎实际编码中还存在一个容易被忽视的风险Order By后的排序字段。排序字段如果直接用字符串拼接就存在SQL注入风险。正确做法是前端传排序字段名后端用白名单映射成安全字段再拼接比如String safeOrderBy orderFieldMap.getOrDefault(userField, create_time);性能优化这块有三个方向值得动手做。第一个是数据库层面给用户表的user_name字段、帖子表的create_time字段加索引查询性能提升是立竿见影的。第二个是前端层面首屏加载时会议图片、课程封面统一做懒加载减少不必要的接口请求。第三个是后端缓存课程分类、舞种列表这类低频变化的数据查完放Redis能省下大量数据库查询压力。还有一个容易忽略的点是文件清理策略。上传的临时图片和视频如果只增不删服务器磁盘很快会满。源码里没有完整的清理机制实际部署时建议配合定时任务把周期超过30天的临时文件定期清理。写在最后的体会把这套古典舞在线交流平台源码完整跑通之后我的感受很深一个好的实战项目价值不在于功能多花哨而在于它是否覆盖了一条完整的业务链路以及每个技术点是否能解释清楚“为什么这么做”。这个项目从用户登录、课程发布、视频播放到社区交流、订单管理前后端加数据库的配合已经能模拟出一个真实上线产品的核心骨架。读源码、改源码、再动手写源码这条路径比只看文档学得快太多。如果你目前正想找个方向练手或者需要项目经验我的建议是踏踏实实把这套项目吃透理解每一层代码为什么这么写再动手把某一模块重新实现一遍。这个过程比刷一百道面试题都更有价值。
返回列表