SpringBoot+Vue+MySQL毕设项目:视频点播系统从源码到部署全解析
每年到三四月份,就会有一批计算机专业的同学开始四处找毕业设计。要么是实验室项目做不下去,要么是工作实习两头烧,实在没精力从零写一套系统。我接触过好几套市面上的毕设源码,其中SpringBoot+Vue+MySQL这套组合出现的频率最高,比如这套“光影平台”,本质上就是一个视频点播管理系统。今天不吹不黑,就从实际跑通这套项目的角度,把整个技术拆解、部署流程、常见坑位一次说清楚,给拿到同款源码的同学趟趟路。
这套项目典型的做法是:SpringBoot做后端接口,Vue做前端页面,MySQL存业务数据,再配上Maven、Node.js、Nginx这些周边工具,组成一个完整的前后端分离应用。它能做的功能不外乎用户注册登录、视频分类浏览、视频播放、后台管理、轮播图管理、评论管理这些。你说它多高大上?不见得。但作为一个毕业设计,它的模块完整度、技术覆盖面、工作量展示,恰好卡在答辩老师最满意的位置上。
我用几天时间完整跑通了这套源码,包括前端依赖安装、后端环境配置、数据库初始化、本地联调、服务器部署。这篇文章把每一步的关键细节都写出来,重点说那些文档里不会写、但实际操作中一定会遇到的事。如果你想拿这套项目做毕设,或者想搞清楚SpringBoot+Vue项目到底怎么从源码变成能跑的系统,这篇可以帮你省掉大部分试错时间。
1. 项目底细:这套“光影平台”到底是什么
1.1 一套标准的视频点播系统包括哪些模块
先把项目边界画清楚。所谓光影平台,说白了就是一个带后台管理的视频点播网站,和B站、腾讯视频那种大型平台肯定没法比,但功能骨架是一致的:前台用户能看视频、搜视频、发评论;后台管理员能传视频、管分类、管用户、配轮播图。
从前端视角看,用户端页面一般包含:首页(轮播图+推荐视频)、视频列表页(按分类筛选)、搜索页(按关键词匹配标题)、视频详情页(播放器+视频信息+评论列表+点赞收藏)、个人中心(我的收藏、我的评论、个人信息修改)、登录注册页。管理端页面则包含:数据概览(总用户数、总视频数、总播放量)、视频管理(增删改查、上架下架)、分类管理、用户管理、轮播图管理、系统设置。
从后端视角看,接口按业务域划分就很清晰:认证模块负责注册、登录、Token签发与校验;用户模块负责个人资料查询与修改;视频模块负责视频列表、详情、上传、上下架;分类模块负责分类树的维护;评论模块负责评论的增删查;收藏模块负责收藏与取消收藏;还有轮播图模块和统计模块。每个模块对应一张到几张数据表,接口风格一般走RESTful,用JSON传数据。
这套项目的典型之处在于:它不是一个只有一个CRUD的“空壳系统”,而是真的有视频上传、有播放、有权限区分、有数据统计,每个模块都能在答辩时被问到,每个模块也都能扩展出很多可以聊的技术点。这就是它作为毕设项目最值钱的地方——工作量既能被看见,讲解时也有内容可以展开。
1.2 为什么是SpringBoot+Vue+MySQL,而不是别的
很多同学会纠结:别人用Python+Django写的,或者用Go写的,我非要用Java吗?这里面的道理很简单:SpringBoot是目前国内企业级Java开发的事实标准,社区资料最多,遇到问题随便一搜就有答案;Vue在国内前端的普及率同样很高,Element Plus、Ant Design Vue这些组件库直接把后台管理页面的开发效率拉满;MySQL则是开源数据库里最通用、面试问得最多的那一款。
这三个技术栈叠在一起,意味着答辩现场不管老师从哪个方向追问,你都能找到大量现成的学习资料和技术博客。而且这套组合在招聘市场上也最对口,简历上写“熟悉SpringBoot+Vue+MySQL全栈开发”,比写某些小众框架更有说服力。
当然,每个技术选型都有取舍。SpringBoot的优点是好上手、生态丰富、自动配置省心,缺点是内存占用偏高,打出来的jar包动不动几十上百MB;Vue的特点是响应式开发快、组件化程度高,但前端依赖安装和构建过程对新手不太友好;MySQL胜在稳定通用,但在大规模高并发场景下不如PostgreSQL或分布式数据库。对于毕设这种规模的项目,这些缺点完全够不上威胁,反而是优点更突出。
1.3 资料包里到底有什么,先盘清楚
拿到这套项目,第一步不是急着运行代码,而是先拆开压缩包,看清楚里面有几样东西。一套完整的“光影平台”毕设资料,通常包含四类内容:源码(分前端和后端两个目录)、数据库脚本(一个SQL文件或一组SQL脚本)、论文文档(Word或PDF格式,一般是开题报告、任务书、毕业论文三件套)、部署文档(说明如何配置环境、初始化数据库、启动前后端)。
先花半个小时把目录结构过一遍:前端目录里找package.json和src目录,确认是不是Vue项目;后端目录里找pom.xml(Maven项目标志)或build.gradle(Gradle项目标志),确认Spring Boot版本和Java版本要求;数据库脚本要看SQL文件里的建库语句,确认数据库名是什么;部署文档先看它要求的环境版本,比如JDK要求1.8还是17,Node要求14还是18,MySQL要求5.7还是8.0。
这一步特别重要,因为不同版本之间兼容性问题非常多。我见过最典型的例子是:人家用Spring Boot 2.7 + JDK 8写的代码,你本地装了JDK 17,一编译就报错;或者代码里用的是MySQL 5.7的方言写法,你装的是MySQL 8.0,跑起来各种报错。先把版本对应关系摸清楚,后面能省掉一大半折腾时间。
2. 系统架构与数据库设计拆解
2.1 前后端分离架构下的请求流转
“前后端分离”这个词几乎每个毕设论文里都会写,但很多同学并不真正理解它意味着什么。简单说,就是把原本“服务器渲染页面”的模式,拆成两个独立应用:后端只负责提供数据接口,前端只负责渲染页面和发送请求。两者之间通过HTTP协议的JSON数据交互,前端开发时用Vite或Webpack做本地代理转发请求,部署时用Nginx做反向代理把两个应用串起来。
拿“用户登录”这个最简单功能举例,整个请求链路是这样的:用户在Vue页面上输入用户名密码,点击登录按钮,Axios发送POST请求到
/api/user/login
,后端Controller接收到请求,调用Service层校验用户名密码,校验通过后用JWT生成一个Token字符串返回给前端,前端把Token存到localStorage或Pinia状态管理里。之后前端发任何需要登录的请求,都会在请求拦截器里自动带上这个Token,后端通过拦截器验证Token有效后,才放行请求到对应接口。
这里有个很容易被忽略的细节:跨域问题。前端页面跑在
localhost:5173
,后端接口跑在
localhost:8080
,当浏览器直接从前端页面发起请求到后端接口时,会因为同源策略被浏览器拦截。解决办法常见有两种:一种是在后端CORS配置类里加允许跨域的设置,另一种是开发时用Vite的proxy代理,把
/api
开头的请求转发到后端地址上。两种方案各有优劣:后端CORS配置简单粗暴,适合快速联调;Vite proxy更贴近生产环境,适合练习真实部署,二者的实现方式我在后面的章节展开。
2.2 核心数据表设计与关系梳理
数据库设计是一套系统的地基。光影平台的核心表我梳理了一下,至少有五到六张:用户表、视频表、分类表、评论表、收藏表,再加一张可选的管理员表。
用户表(user)的核心字段通常有:id(主键)、username(用户名,唯一索引)、password(加密后的密码)、nickname(昵称)、avatar(头像URL)、phone(手机号)、email(邮箱)、role(角色标识,区分普通用户和管理员)、status(账号状态,启用/禁用)、create_time(创建时间)、update_time(更新时间)。
视频表(video)是整个系统最核心的表,字段一般包括:id、title(视频标题)、cover(封面图URL)、url(视频播放地址)、category_id(所属分类ID,外键关联分类表)、description(视频简介)、play_count(播放次数)、like_count(点赞数)、status(发布状态:草稿/已发布/已下架)、user_id(上传者ID,外键关联用户表)、create_time、update_time。
分类表(category)比较简单:id、name(分类名)、parent_id(父分类ID,用于支持两级分类)、sort_order(排序权重)、create_time。评论表(comment)有:id、video_id(评论所属视频)、user_id(评论者)、content(评论内容)、create_time。收藏表(favorite)记录用户和视频的收藏关系:id、user_id、video_id、create_time,一般还会给
user_id
和
video_id
建联合唯一索引,防止重复收藏。
这些表之间的关系画出来就是一个标准的关系型数据库模型:一个分类下有多个视频,一个用户上传多个视频也能收藏多个视频,一个视频下有多条评论。在MyBatis-Plus中体现为实体类之间的关联查询:比如查视频详情时需要把分类信息和上传者昵称查出来,就用表连接或者MyBatis-Plus的关联查询来实现。
2.3 建表与索引的几个心得
数据库设计这块,很多毕设是直接把SQL文件里的建表语句复制过来就完事了,但答辩时老师一定会问“你这个表为什么这么设计”“索引加在哪几个字段上”。所以光会导入SQL不够,你得理解背后的设计逻辑。
第一,主键统一用自增id,不要花里胡哨搞雪花算法。毕设这种量级用自增id完全够用,代码简洁,性能也最好。“选主键策略”时有一个通行的判断逻辑:单机并发量不高就用自增id,分布式高并发才会引入雪花ID或UUID,这是面试和答辩时很加分的表述方式。
第二,外键关系怎么处理。常见做法是逻辑外键而不是物理外键——也就是在代码层面维护关联关系,不真正在数据库里建FOREIGN KEY约束。理由很直接:物理外键在数据量大时会拖慢插入和更新速度,而且不方便分库分表,互联网公司普遍废弃物理外键。如果老师问“为什么删除分类时视频表里的category_id不会报错”,你就用这套说法回答。
第三,索引不是越多越好。视频表的title字段经常被搜索,建议加普通索引;用户表的username字段用于登录,要加唯一索引;收藏表的user_id和video_id组合要加联合唯一索引。但那些几乎不会出现在WHERE条件里的字段,比如description、content,就别加索引了,纯属浪费磁盘空间和写入时间。
3. 后端实操:SpringBoot项目的关键落地细节
3.1 版本选择与项目初始化,先避掉SpringBoot 3的坑
第一步先把后端环境对齐。以这套光影平台为例,强烈建议用下面这组版本组合:JDK 1.8、Spring Boot 2.7.x、MySQL 8.0、MyBatis-Plus 3.5.x、Maven 3.6+。为什么特意避开Spring Boot 3?因为Spring Boot 3强制要求JDK 17,而且把原本的
javax
包全部换成了
jakarta
,很多老代码和网上搜到的大量教程完全不兼容。
如果你打开pom.xml发现spring-boot-starter-parent的version是2.x,就老老实实配JDK 8。如果项目用到了Spring Boot 3,那就要确认JDK 17已经装好。判断代码里的包路径最准:代码里import的是
javax.servlet
就是Spring Boot 2,是
jakarta.servlet
就是Spring Boot 3。
后端项目的分层结构是固定的套路:controller(接收请求、返回结果)、service(业务逻辑、事务控制)、mapper(数据持久化,一般继承MyBatis-Plus的BaseMapper接口)、entity(数据库实体类)、config(各类配置类,比如CORS配置、拦截器配置、Knife4j接口文档配置)、common或utils(统一返回结果类、异常处理类、JWT工具类)。第一次接触的同学,建议先按这个目录结构把每个文件扫一遍,理解每个类大概干什么,再动手启动项目,不然连报错都不知道去哪里看。
3.2 application.yml配置里的门道
后端跑起来之前,配置文件要先搞定。核心配置文件是
src/main/resources/application.yml
,如果拆成多环境,还会有
application-dev.yml
和
application-prod.yml
。一个典型的yml配置大概长这样:
server:
port: 8080
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/guangying?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 123456
servlet:
multipart:
max-file-size: 200MB
max-request-size: 200MB
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
这里面有几个容易被忽略的坑。第一,
serverTimezone=Asia/Shanghai
不能省,否则连接MySQL 8.0时会报时区错误。第二,MySQL 8.0的驱动类是
com.mysql.cj.jdbc.Driver
,不是老版本的
com.mysql.jdbc.Driver
。第三,视频系统的上传上限一定要调大,Spring Boot默认只有1MB,不改成200MB以上,传个视频直接报
FileSizeLimitExceededException
。第四,如果代码里做了逻辑删除,MyBatis-Plus的全局逻辑删除配置必须和实体字段对应上,不然删除数据会直接变成物理删除。
数据库密码这一块,有些做得好一点的毕设会用Jasypt做yml密文加密,配置里的密码是一串密文,启动时用密钥解密。这个可以作为论文里的一个安全亮点来写,哪怕是用了jasypt-spring-boot-starter写两行配置,也体现出你对配置安全的考虑。
3.3 JWT登录鉴权的完整思路
光影平台的登录模块一般用的是JWT(JSON Web Token)方案。JWT的三个部分——Header(头部)、Payload(载荷)、Signature(签名)——分别存放加密算法、用户信息、签名结果。服务端签发Token时把用户id、用户名、过期时间写进Payload,用密钥做签名,客户端拿到Token后每次请求放在请求头
Authorization
字段里带着,后端拦截器验证签名和过期时间通过后,解析出用户信息,放行请求。
核心实现分成几块。第一块是JWT工具类,负责生成和解析Token,常用库是
io.jsonwebtoken
的jjwt。第二块是拦截器,实现Spring的
HandlerInterceptor
接口,在
preHandle
方法里从请求头取Token,解析异常就返回401状态码。第三块是配置类,把拦截器注册到WebMvcConfigurer里,并设置哪些路径需要拦截:登录、注册、验证码、视频列表这些接口要放行,
/admin/**
、
/user/**
这类接口要拦截。
还有一个细节:前后端分离下,后端拿到Token后怎么知道当前登录用户是谁?常见做法是在拦截器里把Token解析出的userId放到
request.setAttribute("userId", userId)
,Controller里再加一个注解或工具类取出来。用ThreadLocal存当前用户信息是更优雅的方案,答辩时可以主动提,体现出你理解线程隔离和变量传递的机制。
3.4 视频上传与文件存储策略
视频上传是光影平台里最带“业务感”的功能。前端用element-plus的上传组件
el-upload
,设置
action
为后端接口地址,或者用
http-request
自定义上传逻辑。后端收到MultipartFile后,用UUID重命名文件,防止文件名冲突,然后保存到本地磁盘指定目录,最后把访问路径存入数据库。
本地存储的代码框架大概是:
String originalFilename = file.getOriginalFilename(); // 原文件名
String ext = originalFilename.substring(originalFilename.lastIndexOf(".")); // 扩展名
String newFileName = UUID.randomUUID().toString().replace("-", "") + ext; // 新文件名
String datePath = new SimpleDateFormat("yyyy/MM/dd").format(new Date()); // 按日期分目录
String rootPath = fileUploadProperties.getPath(); // 自定义上传根路径
File dir = new File(rootPath + "/" + datePath);
if (!dir.exists()) dir.mkdirs();
file.transferTo(new File(dir, newFileName)); // 保存
两个关键点需要特别说明。第一,文件不能直接丢到
项目根目录/static
下面,打包成jar之后这个目录不在可写范围里,最好配置一个独立的绝对路径,比如
D:/upload/
或服务器上的
/data/upload/
,用@ConfigurationProperties注解定义一个上传路径配置类。第二,要解决“上传后怎么访问”的问题。本地开发时前端要用
http://localhost:8080/文件路径
访问,但Spring Boot默认访问不到静态资源目录之外的磁盘文件,所以要写一个静态资源映射配置,把本地的上传目录映射到
/files/**
路径上。
如果以后想把项目部署到云服务器,还可以换成对象存储(OSS/COS/S3)。把上传策略抽象成一个接口,本地实现和OSS实现切换调用,论文里就能写“基于策略模式的文件上传方案,支持扩展分布式存储”,这一个设计模式就能让系统设计评分往上走一档。
4. 前端实操:Vue项目的搭建与视频播放
4.1 环境准备与依赖安装,npm报错全实录
前端技术栈一般是Vue 3 + Vite + Pinia + Vue Router + Element Plus(或Ant Design Vue)+ Axios。开始之前,本机必须装好Node.js,并且注意版本要求:Vite 4以上要求Node 14.18+或16+;如果用的Vite 5,Node版本至少要16.14,推荐直接用Node 18长期支持版。
进入前端目录,第一件事是:
npm install
如果你用的是淘宝镜像源,有些旧的包版本会报错,建议把镜像源切换成官方源再装。网上很多同学在这个环节卡很久,我建议直接把源配死:
npm config set registry https://registry.npmmirror.com
npm install
安装完成后启动开发服务器:
npm run dev
默认地址一般是
http://localhost:5173
。开发时会有一个很常见的需求:前端请求
/api/xxx
,后端接口在
localhost:8080
,如何不写死完整URL?在
vite.config.js
里配置proxy代理:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
server: {
port: 5173,
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true
}
}
}
})
这样配置之后,前端请求
/api/user/login
就会被自动转发到
http://localhost:8080/api/user/login
,浏览器里看不到跨域报错。这种方式比后端CORS设置更接近生产环境,Nginx部署时也是同样的反向代理逻辑。
4.2 路由设计与权限控制
Vue Router是单页应用的核心。一个典型的用户端路由配置会区分“公开路由”和“需要登录的路由”:
const routes = [
{ path: '/', component: Home },
{ path: '/video/:id', component: VideoDetail },
{ path: '/category/:id', component: VideoList },
{ path: '/login', component: Login },
{ path: '/register', component: Register },
{ path: '/user', component: UserCenter, meta: { requiresAuth: true } },
{ path: '/admin', component: AdminLayout, meta: { requiresAuth: true, role: 'admin' } }
]
路由传参的两种方式在毕设里都常用:一种是路由路径参数,比如
/video/1001
,用
route.params.id
获取;另一种是查询参数
/video?id=1001
,用
route.query.id
获取。详情页推荐用路径参数,因为URL更直观,刷新后能保留,而且搜索引擎优化也更友好。
登录鉴权一般配合路由守卫来做。在
router.beforeEach
钩子里检查目标路由的
meta.requiresAuth
,如果是true,就取本地存储的Token判断是否登录,没登录就跳转到
/login
页面并带上
redirect
参数。管理员路由还要额外验证当前用户的role字段是不是admin。这套逻辑说给答辩老师听,就是一个标准的“前端路由守卫 + 后端接口拦截”双层权限控制体系。
4.3 m3u8视频播放的完整方案
光影平台播视频,玩法比普通毕设多了一层技术含量——如果视频文件是m3u8格式的,就不能直接用HTML5的video标签播放,因为浏览器原生不支持HLS协议。网上很多同类型毕设所谓的“在线播放”只是把MP4地址塞进video标签里,而用m3u8流媒体播放,是可以在答辩时多讲几句的亮点。
m3u8播放的常见方案有两个:video.js配合videojs-contrib-hls插件,或者hls.js。我推荐hls.js,它更轻量、出错信息更清晰。安装:
npm install hls.js
在VideoDetail.vue里的核心逻辑:
<template>
<video ref="videoRef" controls autoplay class="video-player"></video>
</template>
<script setup>
import { ref, onMounted, nextTick } from 'vue'
import Hls from 'hls.js'
const videoRef = ref(null)
const videoUrl = ref('http://localhost:8080/files/video/2025/03/01/xxx.m3u8')
onMounted(() => {
nextTick(() => {
const video = videoRef.value
if (Hls.isSupported()) {
const hls = new Hls()
hls.loadSource(videoUrl.value)
hls.attachMedia(video)
hls.on(Hls.Events.MANIFEST_PARSED, () => {
video.play()
})
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
// Safari直接支持HLS
video.src = videoUrl.value
}
})
})
</script>
这里还有一个后端的配套操作值得写进论文:如果视频以m3u8文件存放,一般会配套一个ts分片目录和一个m3u8索引文件。把m3u8文件放在静态资源映射目录下,前端可以直接通过URL请求到。如果某些环境对m3u8请求会报跨域,或者内容乱码,注意检查后端静态资源映射的Content-Type是否设置正确,必要的时候写一个接口将m3u8文件内容转码成正确的编码格式返回。这整个HLS切片、索引文件、分片加载流程,比单纯塞一个MP4地址进去能聊的内容多得多。
4.4 Axios封装与请求/响应拦截
前端所有接口调用,建议统一封装在一个
request.js
里,而不是每个页面散着写
axios.get
。一个比较标准的封装包含:基础URL(或走代理时直接写
/api
前缀)、请求超时时间(如10秒)、请求拦截器(自动加token)、响应拦截器(统一处理业务码和HTTP错误)。
import axios from 'axios'
import { ElMessage } from 'element-plus'
import router from '@/router'
const request = axios.create({
baseURL: '/api',
timeout: 10000
})
request.interceptors.request.use(config => {
const token = localStorage.getItem('token')
if (token) config.headers.Authorization = token
return config
})
request.interceptors.response.use(
response => {
const res = response.data
if (res.code !== 200) {
ElMessage.error(res.message || '请求失败')
if (res.code === 401) {
localStorage.removeItem('token')
router.push('/login')
}
return Promise.reject(new Error(res.message))
}
return res
},
error => {
ElMessage.error(error.message || '网络错误')
return Promise.reject(error)
}
)
export default request
这个封装的细节答辩时非常加分:为什么统一拦截401?因为Token过期后所有接口都可能返回401,如果每个接口都单独加判断,代码重复到爆炸。统一在拦截器里处理,一次登录失效,所有接口自动跳回登录页,这就是“面向切面”思想在业务代码里的体现。同理,上传进度、参数错误统一提示、loading统一管理,都可以在拦截器层面解决。
5. 部署上线:从本机跑通到服务器发布
5.1 MySQL 8.0安装与数据库初始化
本机跑通了,下一步就是完整走一遍部署流程。先装MySQL。这里只强调几个毕设部署时最容易踩的坑。
MySQL 8.0安装过程中,一定记住你设置的root密码,且要留意安装类型。Windows上如果用的MSI安装包,一路Next时会要求设置密码,注意选择加密方式:强烈建议选
Use Legacy Authentication
(兼容旧版)那一项,或者后续改配置文件,否则用老版本的Navicat、代码驱动连接时,会因为
caching_sha2_password
认证插件连不上。如果装完已经选了默认的强加密方式,解决办法是登录MySQL执行:
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的密码';
装好后导入数据库脚本。打开Navicat或命令行,创建一个数据库(名字一般和SQL脚本里的库名一致,比如
guangying
),然后选择运行SQL文件,把源码包里那个SQL文件跑一遍。导入成功后,看下表结构能不能对上,user表里有没有初始管理员账号,视频表里有没有测试数据。这一步别偷懒,提前确认数据完整性,后面部署出问题时能快速定位是数据问题还是代码问题。
5.2 后端打包与部署
后端部署很简单,就是打成jar包,丢到服务器上跑。在项目根目录执行:
mvn clean package -DskipTests
打包完成后,
target
目录下会生成一个
xxx.jar
。本地测试可以先执行:
java -jar target/xxx.jar
启动后测试一下
http://localhost:8080/api/video/list
这类接口,能返回数据就说明后端没问题。注意启动时连的是
application.yml
里配置的数据库地址,部署到服务器时要改成服务器本地或云数据库的连接地址。
生产环境跑后端,一般用
nohup
挂到后台:
nohup java -jar guangying.jar --spring.profiles.active=prod > server.log 2>&1 &
--spring.profiles.active=prod
意思是加载
application-prod.yml
这个环境的配置,里面放生产环境的数据库地址、上传路径、端口号等。如果你只配置了一个
application.yml
,这条命令可以不写,但多环境配置这招可以在论文里写上,证明你考虑到了开发环境和生产环境的配置隔离。
5.3 前端构建与Nginx托管
前端部署要两步:构建加托管。先执行:
npm run build
构建完成后,
dist
目录里就是纯静态文件。然后把它扔给Nginx托管。在
nginx.conf
里配置一个server块:
server {
listen 80;
server_name your-domain.com;
root /usr/share/nginx/html;
index index.html;
location / {
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;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /files/ {
proxy_pass http://127.0.0.1:8080;
}
}
这里有三处关键的配置。第一,
try_files $uri $uri/ /index.html;
是Vue Router history模式必须配的——否则刷新页面时Nginx会去磁盘上找
/video/1001
对应的真实文件,找不到就返回404,而实际上这个路径是前端路由路径,所以要全部回退到
index.html
。第二,
location /api/
做反向代理,把前端API请求转发到后端8080端口,和本机开发时的Vite proxy作用一模一样。第三,如果后端文件存储是本地磁盘,
/files/
路径也要代理给后端,否则视频和封面图加载不出来。
5.4 部署自检清单
部署最怕的就是“看起来都配好了,但就是不行”。我把自己排错时常用的一套自检顺序整理成清单,每次上线都按这个查一遍:
| 检查项 | 检查方法 | 常见问题 |
|---|---|---|
| 数据库连接 |
服务器上执行
mysql -u root -p
并用代码里的密码登录
| 密码不一致、端口未开放 |
| 后端进程状态 |
执行
ps -ef | grep java
看进程是否存在
| jar包启动报错后进程退出 |
| 后端日志 | 查看 server.log 里的报错信息 | 端口被占用、数据库连不上 |
| 前端静态文件 | 浏览器访问域名根路径能否打开首页 | dist目录路径配置错误 |
| API反向代理 |
浏览器访问
域名/api/video/list
是否返回JSON
| proxy_pass路径没配对 |
| 视频地址访问 | 在浏览器打开视频完整URL | 静态资源映射缺失、路径拼接错误 |
6. 高频问题排查与答辩准备
6.1 常见的五个部署/运行问题
问题一:前端
npm install
卡住不动或报ELIFECYCLE错误。多数是网络问题,改镜像源,或者删除
node_modules
和
package-lock.json
后重装。还有可能是Node版本过高过低,用
nvm
切换Node版本到18试一遍。
问题二:后端启动报
Failed to configure a DataSource
。这是最常见的数据库配置错误,原因多半是
application.yml
里的url、用户名、密码写错,或者数据库服务没启动。也有可能是pom.xml引入了数据库驱动的依赖但yml没配置数据源,SpringBoot启动时会自动探测。
问题三:前端请求接口报跨域。分两种情况:本地开发就用Vite proxy,别在后端加CORS;如果你改用了后端CORS方案,注意
allowedOrigins
不能用
*
还要带上credentials,否则带Token的请求依然会被拦截。
问题四:视频上传报文件大小超限。Spring Boot默认上传大小只有1MB,必须改
spring.servlet.multipart.max-file-size
和
max-request-size
,同时Nginx的
client_max_body_size
也要调大,比如设置成
200m
,否则Nginx这层就先拦截了。
问题五:前端刷新页面404。原因只有一个:Nginx没有配置
try_files
回退到
index.html
。把location /里的try_files加上去就好了。
6.2 问题排查速查表
实际写这套项目和部署的过程里,我整理了一个速查表,按“先看哪层”来排查,效率非常高:
| 现象 | 优先排查方向 | 排查命令/工具 |
|---|---|---|
| 前端页面白屏 | 浏览器Console报错、Network请求 | F12开发者工具 |
| 登录提示用户名或密码错误 | 数据库初始账号是否正确 | 直接查 user 表 |
| 上传视频失败 | 后端日志、文件目录权限 |
ls -l /data/upload
|
| 视频播放转圈 | 视频文件路径是否真实存在、静态资源映射 | 浏览器直接访问视频URL |
| 接口返回401 | Token是否过期、请求头是否带上Token | Network请求头查看Authorization |
| 接口返回500 | 后端日志堆栈 |
tail -100 server.log
|
6.3 论文与答辩的准备思路
源码跑通了,部署也验证了,但毕设拿高分并不是“能跑就行”,论文和答辩同样关键。大部分同学拿到论文初稿之后喜欢直接交,我的建议是:把论文中“系统实现”部分和你的代码逐条对照,确保每个截图都是你自己运行出来的界面,每条代码思路和你代码里写的一致,因为答辩老师真的会抽查——他让你现场演示某个功能,结果你连按钮在哪都找不到,场面就很尴尬了。
论文里值得重点展开的地方有:需求分析章节把用例图补全,每个角色能做什么要列清楚;系统设计章节画好架构图、功能结构图、E-R图(注意不能用mermaid,要用绘图工具导出图片插到论文里),数据库表要至少列核心的五张表;系统实现章节按模块写,配关键代码片段和界面截图;测试章节至少写功能测试用例表、接口测试结果(Postman截图)、兼容性测试结论,性能测试这块哪怕是JMeter一行代码没写过,也要把测试报告的基本格式学会,填几组并发数、响应时间的测试数据。
答辩的常见问题也要提前准备。比如“为什么用JWT而不用Session”,回答思路是:前后端分离架构下,Session依赖Cookie,跨域和移动端都不友好,JWT无状态扩展性好。“你的系统怎么防止SQL注入”,回答思路是:MyBatis的
#{}
预编译机制能防止拼接注入,尽量避免用
${}
,管理员输入做了白名单校验。“视频上传慢怎么解决”,回答思路是:前端可以分片上传断点续传,后端可以走异步任务转码,这些虽然我没全部实现,但我知道实现方案——把扩展点准备好,既显诚实又显深度。
还有一个细节:部署文档是给谁看的?一般是给答辩老师、查重老师和后续接手的同学看。所以部署文档要写成“小白也能跟着做”的程度:JDK怎么装、MySQL怎么装、SQL文件怎么导入、前端依赖怎么装、后端怎么打包、Nginx怎么配置,每一步都配截图。这套部署文档本身就是你的实践笔记,做完这一步,你对整套系统的理解会比光看代码深一个层次。
写在最后
从拿到源码到完整部署上线,这套光影平台我前后折腾了三四天时间,中间踩得最多的坑就是版本兼容和路径映射。如果你也正在跑类似的SpringBoot+Vue+MySQL项目,我的建议是:先别急着看代码逻辑,先把环境版本对齐,把数据库导进去,让系统先跑起来再说。系统能跑起来之后,你再对着代码一行一行读,每读一个模块,就对应看论文里的那一节,很快就能把整套东西串起来。
最后再分享一个答辩时的实用技巧:把后端启动、前端启动、数据库导入、Nginx部署这四步操作练到闭着眼也能完成,然后用手机录一份三分半钟的完整演示视频,存到U盘里带着。万一现场电脑出问题、投影仪连不上、网络断掉,视频一放,从容不迫。这招我当年就用过,关键时刻真的能救场。
更多推荐

所有评论(0)