尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

SpringBoot+Vue前后端分离实战:古典舞在线交流平台从零到部署全解析

SpringBoot+Vue前后端分离实战:古典舞在线交流平台从零到部署全解析 古典舞这个圈子其实一直很需要线上交流的土壤。线下舞蹈室一关门学员之间想问个动作、老师想发段示范都变得七零八落。我手里这个前后端分离的古典舞在线交流平台就是围绕这个真实痛点来做的——用SpringBootVueMyBatisMySQL把“看视频、发帖子、跟帖评论、用户互动”这一套完整落地既有管理后台也有面向舞者的交流前端。项目本身不算复杂但胜在链路完整从前端页面渲染到后端接口、数据库表设计全部打通非常适合拿来当练手项目也能直接改造成其他兴趣社区的底子。这篇文章我只讲实操从架构到编码再到部署把我动手过程中踩过的坑、想清楚的取舍、最后怎么跑起来都摊开来说。1. 项目思路与整体架构先搞清楚要做什么再做技术选型1.1 古典舞交流平台的核心需求拆解开发任何系统第一步不是写代码而是想清楚用户到底要打开这个网站做什么。古典舞在线交流平台的目标用户很清晰古典舞爱好者、培训学员、舞蹈老师。这群人的需求基本围绕三类动作展开看舞蹈视频学习模仿、发动态分享练功日常或疑惑、在评论区互相交流指正。于是核心模块就定下来了用户中心、视频模块、社区交流模块、后台管理模块。很多初学者容易犯一个错误上来就把需求列得非常大什么直播、预约课程、会员付费全往里塞。实际上一个交流平台最重要的是“内容流通”视频能看、帖子能发、评论能回、用户能管这四条主链路通了系统就立住了。我的建议是先做减法把这四个主链路跑通再考虑扩展功能。标题里的“在线交流”四个字才是整个系统的灵魂不是视频点播也不是电商系统而是以内容为载体的互动社区。1.2 前后端分离架构的数据流与目录规划前后端分离这个词被讲得太多了落到这个项目上其实就是一句话前端Vue负责渲染页面和交互后端SpringBoot只提供JSON接口两边通过HTTP协议通信互不干涉。整体数据流是用户浏览器 → Nginx静态服务(Vue页面) → 后端API(SpringBoot) → MyBatis映射 → MySQL数据库操作结果再原路返回。对应的项目目录规划也很明确。后端按SpringBoot标准分层controller接收请求、service处理业务逻辑、mapper操作数据库、entity映射数据表。前端按Vue的常规结构views放页面组件、router管理路由、api统一封装axios请求、storeVuex或Pinia管理登录态和用户信息。这样划分的好处是前端工程师和后端工程师可以并行开发只要提前约定好接口文档互相不阻塞。我自己平时带人做项目最怕的就是代码全堆在一个包里哪怕只是一个小系统分层清晰也能少掉一半的排查时间。1.3 为什么不用单体模板而坚持前后端分离可能有人会问这种规模的项目用传统的Thymeleaf模板渲染不就行了为什么非要前后端分离我实话实说前后端分离在这个项目里不是炫技而是有实际好处的第一古典舞视频平台会有大量移动端访问需求前端做成纯静态接口化的形式以后套个小程序或者App壳都很方便后端接口完全不用动第二交流社区的交互逻辑相对复杂点赞、评论、动态刷新这些场景用Vue的响应式机制来更新页面体验比整页刷新流畅太多第三部署层面前后端可以各自独立扩容访问量大了哪边吃紧就加哪边的实例。从长远维护的角度看前后端分离是更省心的选择。2. 技术栈选型的核心逻辑每一层选型都有理由2.1 SpringBoot让后端开发聚焦业务而不是配置SpringBoot能成为Java后端的事实标准核心在于它解决了Spring框架最烦人的配置问题。这个项目里我只需要引入spring-boot-starter-web一个内嵌的Tomcat就起来了再引入mybatis-spring-boot-starter或mybatis-plus相关依赖数据源配置写进application.yml就能直接跑起来。我特别看重SpringBoot的自动装配机制比如我引入spring-boot-starter-validation后只需要在实体类字段上加NotBlank注解再配合Valid参数校验逻辑就自动生效了不需要手写一堆if判断。有人会担心SpringBoot的“黑盒”特性让自己看不懂底层我的看法是先会用再深入。做项目阶段完全不需要纠结内嵌Tomcat是怎么启动的遇到问题再去翻源码。用SpringBoot最大的收益是开发节奏变快了你一天能写完的功能多了才有更多时间去理解业务、理解表结构设计、理解前后端交互这些才是做项目真正值钱的东西。2.2 Vue组件化开发与响应式交互是社区类页面的刚需前端选Vue而不用传统jQuery核心原因是交流平台这类页面的状态太多了。登录状态切来切去、评论区折叠展开、点赞按钮的实时变化、视频列表的筛选刷新如果用jQuery手动操作DOM每加一个交互就要写一大段操作节点的代码维护成本极高。Vue的响应式机制把数据和DOM绑定起来数据一变页面自动更新思维模型从“操作页面”变成了“操作数据”这一点对社区类项目是降维打击。在Vue 2和Vue 3之间我建议新项目直接用Vue 3的组合式API。比如写一个视频列表组件用ref定义列表数据用onMounted在页面加载后调用接口逻辑内聚在一个setup里比Vue 2的options写法清晰很多。如果担心生态问题Element Plus、Vite、Vue Router这些都已经是成熟配套了不用纠结。前端部分的工程化也是一样用Vite创建项目npm install装依赖npm run dev本地调试npm run build产出静态文件链路非常顺。2.3 MyBatisSQL可控性比全自动ORM更适合业务查询选MyBatis而不选JPA/Hibernate对这个项目来说是深思熟虑的。社区交流平台有一个特点查询逻辑复杂多变。视频列表要联动分类、要按时间或热度排序帖子列表要带出作者信息、要统计评论数首页聚合推荐要关联多张表。这种场景下MyBatis的XML映射文件给了你写SQL的完全控制权一个多表关联查询写清楚性能就是可控的。JPA那种通过方法名推导SQL的机制简单查询很爽一旦遇到复杂条件拼接就会非常难受而且生成的SQL往往不够直观。当然MyBatis也不是没有坑最典型的是动态SQL。多个筛选条件组合查询时用 标签拼条件比如视频列表有可能按分类过滤有可能按标题关键词搜索用动态SQL就优雅得多。还有一个问题是结果映射表字段下划线user_name和实体类属性驼峰userName需要开启map-underscore-to-camel-case配置不然查出来的数据全是null这个我先放在这里后面部署环节还会专门提。2.4 MySQL表结构设计与索引取舍决定接口响应速度数据表设计是社区项目的隐形地基。用户表、分类表、视频表、帖子表、评论表、点赞记录表这六张表基本覆盖了系统的所有核心数据。设计过程中的核心思路是遵守第三范式减少冗余存储同时为了查询效率适当设置一些冗余字段。比如帖子表里我加了一个comment_count计数虽然理论上这个数据可以从评论表count出来但每次列表接口都要count一次压力全在数据库上不如在发表评论和删除评论时同步维护这个数字查询时就一个字段的事。索引设计方面我踩过一次很明显的坑帖子列表按创建时间倒序一开始没索引数据量到几千条以后接口明显变慢。后来在create_time字段加了普通索引响应时间立刻降下来了。核心经验是where条件中频繁出现的字段、order by排序用的字段都要建索引但索引不是越多越好每张表一般三到五个就够写操作频繁的表更要克制加索引的冲动。3. 分模块的核心功能实现与实操细节3.1 用户模块JWT登录鉴权的完整落地用户模块是整个系统的基础逻辑不复杂但链路长。我的实现方案是用户注册时用MD5加盐或者BCrypt加密密码存入数据库登录成功后后端生成一个JWT Token返回给前端前端把Token存到localStorage里后续每次请求在axios拦截器中把Token放进请求头的Authorization字段后端通过拦截器统一校验。SpringBoot端实现JWT鉴权核心是两个地方一个是登录接口里用jwt工具类生成token另一个是写一个HandlerInterceptor实现preHandle方法从请求头里取出token并解析用户信息解析失败就返回401。这个拦截器注册到WebMvcConfigurer里时要记得给登录、注册、首页公开接口放行用excludePathPatterns配置好不然用户还没登录连首页都打不开就是典型的逻辑顺序搞反了。前端这边其实有个小细节最容易被忽略页面刷新后用户登录状态会丢失。解决办法是在Vue的路由守卫router.beforeEach里每次跳转前检查localStorage里有没有token有token就从store里恢复用户信息。如果后端提供了“根据token获取用户信息”的接口刷新时调一次就行。这个环节做不好用户一刷新页面就变成未登录整个体验直接崩掉。3.2 视频模块分类、上传、播放地址的处理方案古典舞交流平台的视频内容主要有两个来源一是后台管理员上传的教学视频二是用户个人分享的舞蹈短视频。为了不搞得太复杂我没有引入专门的对象存储服务而是把视频文件和视频封面图存到后端服务器的静态资源目录下通过配置静态资源映射路径来实现访问。这个方案在小规模项目里非常实用省去了对接OSS的麻烦缺点是文件只能存在单机上以后真要上量了再迁移对象存储就行。视频存储的实现细节是在后端配置类里继承WebMvcConfigurer重写addResourceHandlers方法把本地磁盘某个目录映射成URL路径比如把E:/dance/videos映射成/videos/**。这样前端拿到的视频地址就是一个完整的URL直接用video标签的src属性就能播放。我建议视频文件命名直接用UUID避免中文文件名乱码和重名覆盖的问题。至于视频格式目前主流浏览器对mp4兼容性最好上传务必做格式限制后端接口里加一个后缀名校验就能挡掉大部分问题。数据库层面视频表的核心字段有title视频标题、category_id分类id、cover_url封面图、video_url播放地址、description视频简介、view_count观看次数、status状态上架/下架。分类表存古典舞的不同风格流派像汉唐舞、敦煌舞、昆舞这样。查询视频列表时关联分类表显示分类名称也是一个常规的左连接查询列出SQL如下SELECT v.*, c.name AS category_name FROM video v LEFT JOIN category c ON v.category_id c.id WHERE v.status 1 ORDER BY v.create_time DESC3.3 社区模块发帖、评论、点赞的数据库关联查询社区模块是用户活跃度的重头戏也是前后端交互最频繁的部分。用户在社区首页能看到所有帖子列表点击进入详情页后能看正文、看评论、发评论、点赞。这个模块的数据表设计我采用了最经典的三层结构帖子表post存标题和正文评论表comment存楼层内容和父评论id点赞表like_record记录用户和帖子/评论的点赞关系。帖子和用户信息是多对一关系所以帖子列表的查询必然是一次join用户表拿昵称和头像。评论表的设计有一个关键点用parent_id字段支持楼层回复如果parent_id为null表示顶层评论不为null表示对某个评论的回复。前端渲染评论时需要判断这个字段来区分层级。查询评论列表时用ORDER BY create_time ASC保证楼层顺序不乱。点赞这块最需要留心的是幂等性。用户反复点击点赞按钮前端要控制状态禁止重复提交后端接口里应该先查like_record表判断是否已经点过赞已点赞则执行取消点赞并减少计数未点赞则插入记录并增加计数。我建议点赞记录表加一个UNIQUE索引约束(user_id, target_type, target_id)从数据库层面防止重复数据双保险比单纯靠代码判断稳妥得多。3.4 后台管理分类管理和内容审核的最小闭环一个交流平台如果只有前台没有后台运营起来会非常痛苦。我在系统里做了一个极简后台管理员账号登录后可以进入后台管理页面对视频进行分类管理新增分类、排序、对视频进行上下架操作、对违规帖子做删除处理。后台和前台共用同一套后端接口只是接口路径上加了/admin前缀通过拦截器做角色权限判断——只有管理员角色的用户才能访问这些接口。这个最小闭环的意义在于它让从前台到后台的数据管理链路变成完整的。你可以理解为后台就是给你自己留了一扇后门内容出了问题随时能兜底。很多学习项目只做前台页面一到答辩或者演示就会被问到“如果用户发了违规内容你怎么处理”有了后台这个答案就顺理成章了。4. 从零到一的部署实录前后端打包装配一次跑通4.1 环境准备三件套的版本选择与安装部署之前先把环境准备好。Java环境我用的JDK 8SpringBoot 2.x系列MySQL用的8.0版本Node环境用来构建前端建议14以上版本。JDK安装很简单配好JAVA_HOME环境变量就行MySQL要注意初始密码和字符集建议安装时直接选utf8mb4字符集不然中文数据容易乱码Node直接官网下载安装包没有特殊坑。我用三件套版本做个对照参考组件推荐版本关键注意事项JDK1.8或11配置JAVA_HOME后命令行验证java -versionMySQL8.0.x安装时选utf8mb4端口默认3306Node.js14npm install时注意镜像源国内建议配置淘宝镜像Maven3.6仓库镜像建议用阿里云依赖下载快很多前端环境配置有句话值得单独强调npm install慢或者报错99%是网络问题而不是代码问题。我习惯先把npm镜像注册表指到国内镜像源然后再执行依赖安装基本一分钟内能完成。Node版本也不要太激进Vue 3项目用16或18版本比较稳太新的Node偶尔会和某些依赖出现兼容问题。4.2 后端打包Maven打包与外部配置分离后端项目我用的Maven做构建打包命令就一行mvn clean package -DskipTests。运行时会先生成target目录下的jar包但这里有一个我从一开始就坚持的原则配置文件不写死在jar包里面。application.yml里的数据库账号密码、文件存储路径这些容易变的内容用spring.config.location外部配置方式指定。具体做法是把application.yml复制一份放到jar包同目录下的config文件夹里然后用如下命令启动java -jar dance-platform.jar --spring.config.locationfile:./config/application.yml这样做的好处是显而易见的以后要换数据库、改文件路径只需要编辑外部的yml再重启服务完全不用重新打包。这个习惯是从实际运维摔出来的有一次我把数据库密码落在代码里后来泄露风险排查时只能重新打包发版非常折腾。外部化配置表面上只是一个小习惯实际上对项目的可维护性提升巨大。后端启动成功会监听8080端口验证方法是浏览器访问http://localhost:8080/api/user/info之类的接口能看到JSON返回就说明后端活着。如果启动直接报错九成是数据库连接失败或Redis连接失败如果引入了Redis按报错日志逐行排查即可不要瞎猜。4.3 前端构建Vite打包与Nginx托管前端部署相对简单核心是npm run build生成dist静态目录然后把dist目录里的文件拷贝到Nginx的html目录下。但这里有一个非常关键的配置点Nginx要配置反向代理把前端的API请求转发到后端的8080端口。因为浏览器直接访问后端接口会面临跨域问题而通过Nginx转发前端和后端在浏览器看来是同源的跨域问题直接从根源上消失。Nginx的server配置块我习惯这样写前端静态资源和接口转发一起配置server { listen 80; server_name localhost; location / { root /usr/share/nginx/html/dist; index 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; } }这个配置要特别注意两点第一location /里要加try_files指令像这样try_files $uri $uri/ /index.html否则刷新非首页路由时会报404因为在vue-router的history模式下前端路由是虚拟的Nginx找不到真实文件就会404第二location /api/里的proxy_pass末尾要不要带路径斜杠会直接影响转发后的URL拼接效果建议按上面的写法保持路径不变。我用hash模式可以跳过这个坑但项目体验不如history模式好还是建议直接history加try_files一步到位。4.4 视频文件存储目录的映射配置再强调一次视频存储的坑。视频文件不能也放到dist打包目录里因为前端打包是一次性的发布会清空重来。正确做法是服务器上单独建一个数据目录比如/opt/dance/files/videos后端通过配置类把这个磁盘目录映射为URL。Nginx侧同样可以增加一个location指向这个目录实现前端直接加载视频文件而不用经过Java后端转发location /files/ { alias /opt/dance/files/; }这样做的好处很明显视频加载是纯静态文件访问不占用后端Tomcat的线程资源并发访问视频时后端接口不会被打挂。一个典型的线上拓扑就是Nginx接管/前端页面、/api/后端接口、/files/视频文件三类流量职责清晰每一路都很快。4.5 Linux远程部署的常用检查命令很多人第一次在Linux上部署Java项目会出现“本地是好的一上服务器就不行”的奇怪问题。我的经验是先按顺序检查三样东西端口是否监听、防火墙是否放行、数据库网络是否通。常用命令如下# 查看后端进程和端口 netstat -tlnp | grep 8080 ps -ef | grep java # 测试服务器到数据库的网络连通性 mysql -h 数据库IP -P 3306 -u root -p # 查看后端日志 tail -f nohup.out后端进程最好用nohup命令后台运行并输出日志到文件nohup java -jar dance-platform.jar nohup.out 21 。这样即使SSH断开服务也不会停下次排查问题直接看nohup.out日志即可。线上排错日志是唯一可信的依据所以我始终建议让日志完整输出而不是默认只在控制台显示。5. 常见问题与排查技巧实录亲测有效的避坑手册5.1 MyBatis缓存、分页和SQL日志那些事MyBatis的缓存机制用得不好会在小项目里埋大雷。一级缓存是SqlSession级别的默认开启问题不大二级缓存是Mapper级别的如果开启了但没有做好缓存刷新策略很容易出现用户发了一条新帖子别人刷新列表却看不到的诡异现象。我个人做这类交流平台强烈建议直接在配置里关掉二级缓存用不着为了那点性能提升增加数据一致性的风险。项目火了、并发上去了再引入Redis做缓存也不迟。分页插件是我最常用的MyBatis增强点。在SpringBoot中集成PageHelper只需要引入pagehelper-spring-boot-starter然后在查询前调用PageHelper.startPage(pageNum, pageSize)紧跟其后的第一条查询SQL就会自动带上limit条件。这里有一个隐坑startPage和查询之间不能穿插其他SQL操作否则分页会失效因为PageHelper是通过ThreadLocal绑定当前线程的SQL实现的中间穿插SQL会改变拦截目标。前端传pageNum和pageSize两个参数即可接口返回时用PageInfo包装数据里面就有总条数、总页数、当前页数据列表这些现成的字段。关于SQL日志在开发阶段一定要开启MyBatis的SQL打印。配置就一行logging.level.com.example.dance.mapperdebug。开启后每次执行SQL都会在控制台打印出来联调时接口数据不对先看控制台里这句话SQL语句和参数值对不对。很多“数据查不出来”的问题一打日志就真相大白不用瞎猜哪里逻辑错了。5.2 Vue侧接口联调和跨域处理的三个办法前端开发时Vite的devServer请求后端接口必然遇到跨域问题。我在开发阶段用Vite的proxy配置来解决而不是在后端加一堆CrossOrigin注解因为后端的跨域注解如果配置不好会和部署时的Nginx反向代理产生冲突。开发时不建议直接改后端允许跨域还是建议交给代理解决// vite.config.js export default { server: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } }这个配置的意思是前端开发服务器收到以/api开头的请求就自动转发到后端8080端口。前端代码里写axios.get(/api/video/list)开发环境能通生产环境通过Nginx也能通前端代码完全不用区分环境。如果个别接口在部署后还是报跨域错误优先检查Nginx的proxy配置是否正确而不是急着去改后端代码。要记住生产环境有Nginx兜底一般情况下后端不需要开启CORS配置。前端接口联调还有一个非常实用的排查技巧打开浏览器的Network面板点击一个请求看它的URL、请求方法、状态码。如果状态码是404说明请求路径拼接错了如果是500说明后端报了运行异常去后端看日志如果是401/403说明拦截器拦了检查Token有没有传。按照这个思路排查95%的接口联调问题几分钟内就能定位。5.3 数据库连接、字符集和数据初始化的那些坑MySQL 8.0和SpringBoot连接时驱动类名和URL和旧版本不同最常见的错误是com.mysql.jdbc.Driver已废弃新版本要改用com.mysql.cj.jdbc.Driver。连接URL里也要注意时区和编码参数标准的写法是jdbc:mysql://localhost:3306/dance_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai。缺少serverTimezone参数高版本MySQL会直接报时区错误这是我在搭建环境时遇到的一个高频问题。字符集方面数据库、数据表、连接URL三层都要保证utf8mb4。utf8mb4和utf8的区别是前者能存emoji和一些特殊字符古典舞圈的用户名字和帖子里很容易出现特殊符号所以直接用utf8mb4更省心。建库语句统一用CREATE DATABASE dance_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci一劳永逸。最后说数据初始化。每次重新部署环境最麻烦的就是把表结构和初始数据导入进去。项目里我放了一个sql脚本目录包含建表语句、分类初始数据、管理员账号数据这些都要手动执行导入。执行时注意先后顺序先建用户表和分类表这些基础表再建视频表和帖子表这些依赖外键的表。用Navicat或者命令行source命令导入都可以关键是保证脚本能重复执行而不会报错所以建表语句建议带上IF NOT EXISTS分类数据插入前先判断是否已存在。5.4 冷门但能救命的部署细节整理部署阶段还有一个非常容易忽略的点服务器的文件上传大小限制。SpringBoot默认的单次请求最大上传限制是1MB视频文件动辄几十MB不配置的话上传接口直接报错。需要在application.yml里把限制调大比如spring.servlet.multipart.max-file-size: 500MB和spring.servlet.multipart.max-request-size: 500MB。同时Nginx侧也有默认的client_max_body_size限制同样需要调整为对应的值两个地方都改才是完整的。另外如果用的是阿里云或腾讯云服务器安全组规则里没有放行80、8080这些端口外部访问依然不通。这个坑非常隐蔽因为服务器本地上网没问题但外网就是访问不了我当年第一次部署就卡在这个问题上折腾了整整一下午才醒悟过来。以后碰到“服务器上本地访问正常、外部访问不通”的情况先检查云控制台的安全组入方向规则而不是先怀疑程序问题。5.5 运维监控的朴素经验日志、进程和磁盘项目上线稳定运行以后不是高枕无忧了。我自己有一个非常朴素的运维清单每周看一眼后端日志有没有异常堆积、查一下进程是否正常存活、磁盘空间是否快满了。视频文件是存储空间消耗的大户特别是用户持续上传的情况下磁盘满会导致上传接口直接挂掉。我在服务器上写了一个简单的磁盘监控脚本空间使用率超过85%就发提示邮件这个习惯直接帮我避免了一次生产事故。磁盘清理也不能乱删要先看哪些视频是下架状态或者长期无人访问确认无价值后再手动清理对应的文件和数据库记录。这个清理流程看起来操作简单但特别能反映出工程意识的差别——很多开发者喜欢一股脑把服务器上的文件全删了结果前端页面上的视频全部变成死链。凡是涉及线上数据的操作务必先确认再执行宁可少删一次也不鲁莽删错。6. 一点没写进代码里的心得这个古典舞在线交流平台从零到部署运行一整套落地后我个人的收获可能比代码本身更多。前后端分离听起来是个技术概念但它真正的价值在于让团队的开发和维护模式变得更清晰前端不需要关心数据从哪来后端不需要关心界面长什么样两边只需要盯住接口协议就行。技术选型方面SpringBoot、Vue、MyBatis、MySQL这一套组合在今天仍然是中小型平台项目非常务实的选择稳定、生态成熟、招人也好招不用为了追赶新框架而承担不必要的风险。如果你正准备用这个项目去面试或者做毕业设计我建议你一定亲手把部署流程完整走一遍。很多人代码写得溜但一说到怎么把项目跑在服务器上就含糊了。其实部署才是填空标准答案的环节部署多走几遍很多关于配置、环境、架构的知识不需要背自然就印在脑子里了。还有一个小建议做项目时一定要习惯写README把启动步骤、表结构、接口说明都记录下来你会发现过两周再回来看自己的项目时全靠这份文档救命。技术栈会过时但解决真实问题的能力永远不会。古典舞在线交流平台只是一个小小的壳你对用户需求的理解、对数据流转的把握、对部署运维的把控这些才是真正属于自己的内功。
返回列表