这次我们不聊 AI 绘画,也不聊大模型推理。回到 Java 全栈开发,看一个很典型的工程:基于 SpringBoot + Vue3 的前后端分离电影网站系统。这类项目在毕业设计、课程设计、Java 求职项目里出现频率非常高,核心价值不在于“电影资源”本身,而在于它覆盖了一条完整的前后端分离开发链路:用户端与管理员端双端分离、JWT 登录鉴权、文件上传与回显、分类检索、轮播图管理、评论留言,以及 Vue3 组合式 API + Element Plus 后台界面的落地。
这个系统的技术标签很明确:SpringBoot 负责后端 Api 服务,Vue3 + Vite 负责前端页面,MySQL 存业务数据,MyBatis Plus 做数据访问。从实战角度看,它适合准备 SpringBoot 面试项目、写 Vue3 毕设、或者想系统梳理前后端联调流程的开发者。同时我们也会把 SpringBoot 配置、Vue3 路由、Axios 请求封装、JWT 拦截器、跨域处理这些高频技术点串起来看。
这篇文章会按四个层次展开:先给项目功能与能力速览,再讲系统模块设计,然后走一遍环境准备、后端工程搭建、前端工程搭建和联调验证,最后给接口调用与批量任务设计、常见排查思路和工程化管理建议。全文以可复现为主,不写空概念。
1. 核心能力速览
| 能力项 | 说明 |
|---|---|
| 项目类型 | 前后端分离的 Web 管理系统(电影网站) |
| 后端技术栈 | SpringBoot、MyBatis Plus、MySQL、JWT、Lombok |
| 前端技术栈 | Vue3、Vite、Vue Router、Pinia、Axios、Element Plus |
| 端口规划 | 后端常见 8080,前端 Vite 开发端口常见 5173,需开启跨域 |
| 核心功能 | 用户端电影浏览与检索、电影详情、收藏与评论;后台端电影管理、分类管理、轮播图管理、用户管理、管理员登录 |
| 数据库 | MySQL 5.7 或 8.x,具体版本看实际工程 |
| 启动方式 | 后端 SpringBoot 启动类 + 前端 npm run dev,或前后端分别打包部署 |
| 是否支持接口 API | 支持,后端暴露 RESTful 接口,前端通过 Axios 调用 |
| 是否支持批量任务 | 可在后台实现电影批量上架的接口设计与事务控制 |
| 适合读者 | Java 后端入门、Vue3 前端入门、毕业设计开发、前后端联调学习者 |
注意一点:本文不会虚构某个源码仓库的完整目录和真实运行截图,只给出一套通用的实现思路、配置模板和验证流程。你拿到的实际项目如果结构不同,应对照具体代码调整路径与参数。
2. 适用场景与使用边界
这类电影网站系统最常用的场景有三个:
第一是毕业设计和课程设计。SpringBoot + Vue3 是目前比较稳妥的组合,既能体现后端接口设计能力,又能展示前端工程化能力。功能上加入用户登录、轮播图、分类查询、电影详情、评论收藏,再配上后台管理界面,满足演示和答辩要求。
第二是前后端分离项目练手。很多人从单体 JSP 项目转向前后端分离时,最大的卡点不是语法,而是理解不了前端如何调后端、token 如何存、接口 401 怎么办、跨域又是怎么回事。电影网站系统复杂度适中,比图书管理丰富,又比商城系统简单,适合作为第二个或第三个练手项目。
第三是简历项目素材准备。如果你把 JWT 登录、拦截器配置、文件上传、分页查询这些点真正吃透,面试时可以围绕“遇到跨域如何处理”“token 过期怎么办”“分页插件原理是什么”展开回答,比背简历要有说服力。
但也要说清楚边界。这类系统本质是管理平台,并不等于真正的视频点播平台。它通常存的是“电影信息 + 预告片/封面资源”或播放链接,不涉及大规模流媒体分发;如果涉及真实影片素材、用户上传内容和人脸实名信息,必须注意版权授权、内容审核和数据隐私合规,个人练习时也应该使用演示数据,不要拿未授权资源做商业化发布。
3. 系统功能模块设计
在设计一个电影网站系统时,建议按“用户端 + 管理端 + 公共服务”三层来拆。这样后端 Controller 不会堆到一起,Vue3 前端页面也方便用路由做权限区分。
3.1 用户端模块
用户端是访客或注册用户看到的部分,典型页面包括:
- 首页:轮播图推荐、热门电影、最新电影、分类快速入口。
- 电影列表:按分类筛选、按名称搜索、分页展示。
- 电影详情:封面、导演、主演、简介、上映年份、播放/预告入口、收藏按钮。
- 用户登录与注册:基于 JWT,登录后可以收藏电影和发表评论。
- 个人中心:查看我的收藏、我的评论。
页面规划在 Vue3 里对应为<router-view>包裹的布局页,例如Layout.vue中有顶部导航栏和右侧主内容区,子页面通过children配置进入。
3.2 后台管理端模块
管理端设计为独立路由前缀,例如/admin,使用后台布局。常见功能如下:
- 仪表盘:显示电影总数、用户总数、评论总数、分类数。
- 电影管理:新增、编辑、上下架、删除电影,支持封面上传和批量上架。
- 分类管理:维护电影类型,支持排序。
- 轮播图管理:设置首页展示位与跳转链接。
- 用户管理:查看注册用户、禁用或启用账号。
- 管理员权限:管理员登录与用户端登录分离,后端做角色判断。
3.3 数据库表设计参考
后端表设计不需要特别复杂,常用的核心表有:
| 表名 | 核心字段 |
|---|---|
| user | id、username、password、nickname、avatar、role、status、create_time |
| film_category | id、name、sort、status |
| film | id、title、cover、video_url、director、actors、area、language、category_id、description、publish_time、status、create_time |
| banner | id、image、title、target_url、sort、status |
| user_favorite | id、user_id、film_id、create_time |
| film_comment | id、user_id、film_id、content、create_time |
密码字段建议使用 BCrypt 加密,库存放密文;status 字段用于逻辑上下架。表结构以实际项目为准,本文只给常规切分思路。
4. 技术栈与版本选型要点
SpringBoot 项目高频问题之一是版本匹配。SpringBoot 3.x 要求 JDK 17 及以上,SpringBoot 2.7 可以配合 JDK 8 使用。如果你拿到项目源码后启动报错,优先看 pom.xml 里的 spring-boot-starter-parent 版本和本机 JDK 是否匹配。
一个常见的组合是:
| 组件 | 示例版本区间 | 说明 |
|---|---|---|
| JDK | 1.8 或 17 | 与 SpringBoot 主版本对应 |
| SpringBoot | 2.7.x 或 3.x | 3.x 使用 jakarta.servlet 包 |
| MySQL | 5.7 或 8.0 | 注意驱动坐标差异 |
| Vue | 3.4+ | 使用 Vite 创建 |
| Vite | 5.x | 需要 Node 18+ |
| Element Plus | 2.x | Vue3 桌面端组件库 |
| MyBatis Plus | 3.5.x | 降低单表 CRUD 成本 |
前端创建命令一般格式:
npm create vite@latest movie-web -- --template vue如果只想要一个可运行骨架,这一步会生成包含 main.js、App.vue、vite.config.js 的 Vue3 项目。后面前端工程在此基础上增加 router、pinia、axios 封装和页面组件。
5. 环境准备与前置条件
在克隆或新建项目后,先准备环境。下面是通用检查清单。
5.1 后端环境
- JDK:推荐 JDK 8 或 17,对应 SpringBoot 版本。
- Maven:3.6+ 或直接使用 IDE 自带的 Maven。
- MySQL:本地安装或 Docker 运行。
- IDE:IDEA 社区版也可以,Ultimate 对 Spring 初始化支持更好。
- 启动前检查 8080 端口是否被占用。
Linux / macOS 上查看端口:
lsof -i:8080Windows PowerShell 上查看端口:
netstat -ano | findstr :80805.2 前端环境
- Node.js:建议 18 或 20 LTS,Vite 5 需要 Node 18+。
- npm 或 pnpm、yarn。
- 前端开发端口默认 5173,如果被占用 Vite 会自动换端口,控制台会提示。
5.3 准备数据库
新建数据库,例如:
CREATE DATABASE IF NOT EXISTS movie_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;然后在 application.yml 中确认数据库名、用户名、密码是否正确。最常踩的问题就是建库字符集不是 utf8mb4,导致电影名或评论里的 emoji 无法入库。
5.4 检查配置
后端典型配置如下,需要按实际环境替换数据源参数:
server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/movie_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: 123456 servlet: multipart: max-file-size: 100MB max-request-size: 200MB mybatis-plus: configuration: map-underscore-to-camel-case: true global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 06. 后端工程搭建与启动
后端工程的核心任务是提供接口、管理数据、处理登录鉴权和文件存储。
6.1 创建 SpringBoot 项目
可以在 Spring Initializr 选择依赖:Spring Web、MySQL Driver、Lombok,然后在 pom.xml 中加入 MyBatis Plus 和 JWT 相关库。
MyBatis Plus 坐标参考:
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency>JWT 相关代码通常使用 jjwt 库,但要注意版本。使用较新的 jjwt 0.11.5 时依赖由三个模块组成:api、impl、jackson。低版本 0.9.1 在较新 JDK 上可能会因为 javax.xml.bind 缺失而出问题。
6.2 项目结构分层
后端建议按标准分层:
com.example.movie ├── controller ├── service │ └── impl ├── mapper ├── entity ├── dto ├── vo ├── config ├── common └── utilsController 只做参数接收和结果封装,业务逻辑放 Service,数据库操作在 Mapper。这样代码虽然多几层,但后续维护和答辩讲解都更容易。
6.3 JWT 登录鉴权思路
登录流程:用户提交用户名密码,后端校验通过后生成 token 返回给前端。前端把 token 存在 localStorage 或 Pinia 中,并在每次请求的请求头里带Authorization: Bearer <token>。后端通过拦截器或过滤器校验 token。
一个简单的 JWT 工具类核心方法:
public String generateToken(Integer userId, String username, String role) { return Jwts.builder() .setSubject(username) .claim("userId", userId) .claim("role", role) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24)) .signWith(SignatureAlgorithm.HS256, SECRET_KEY) .compact(); }拦截器做 token 校验,注意不要拦截登录接口,否则属于自己把自己锁在外面。
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { return true; } String authHeader = request.getHeader("Authorization"); if (authHeader != null && authHeader.startsWith("Bearer ")) { String token = authHeader.substring(7); try { Claims claims = JwtUtil.parseToken(token); request.setAttribute("userId", claims.get("userId")); return true; } catch (Exception e) { response.setStatus(401); return false; } } response.setStatus(401); return false; }在开发环境调试 Swagger 或接口文档时,如果不想每次都带 token,可以把 swagger 相关路径加进白名单。如果使用 Knife4j,还需要注意 SpringBoot 3.x 下配置类路径发生了变化。
6.4 跨域配置
前后端分离开发时,前端 http://localhost:5173 访问后端 http://localhost:8080,浏览器会拦截跨域请求。推荐在后端配置全局跨域:
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .allowCredentials(true) .maxAge(3600); } }如果使用 allowCredentials(true),allowedOrigins 不能设置为"*",需要改用 allowedOriginPatterns。
6.5 封装统一返回结果
前后端联调要约定统一格式,例如:
{ "code": 200, "message": "success", "data": {} }对应的 Java 类可用泛型实现:
@Data public class Result<T> { private Integer code; private String message; private T data; public static <T> Result<T> ok(T data) { Result<T> result = new Result<>(); result.setCode(200); result.setMessage("success"); result.setData(data); return result; } public static <T> Result<T> error(Integer code, String message) { Result<T> result = new Result<>(); result.setCode(code); result.setMessage(message); return result; } }统一返回结果的好处是前端 Axios 拦截器可以只判断一次 code,不需要每个页面单独处理错误分支。
6.6 启动后端
在 IDEA 中找到主启动类,右键 Run。如果启动成功,控制台会出现 SpringBoot 启动日志。之后访问:
http://localhost:8080/api/ping如果返回 JSON,说明后端基本可用。如果启动失败,先看日志中的APPLICATION FAILED TO START提示,重点排查数据源连接失败和端口被占用。
7. 前端工程搭建与启动
Vue3 前端工程不只是一个页面集合,它要承担路由管理、登录状态保持、请求封装、组件复用和页面交互。
7.1 安装依赖
进入前端目录后安装依赖:
npm install如果安装速度慢,可以切换为国内镜像后再次执行。在工程内新增 .npmrc 也是一种方式,但以实际环境为准。
7.2 目录规划
src ├── api // 存放接口请求模块 ├── assets // 静态资源 ├── components // 公共组件 ├── layout // 布局组件 ├── router // 路由配置 ├── store // Pinia 状态 ├── views // 页面组件 │ ├── home │ ├── film │ ├── user │ └── admin ├── utils // 工具函数 ├── App.vue └── main.js7.3 路由配置
Vue3 使用 Vue Router 4。路由配置中可以做登录守卫:进入需要登录的页面之前,检查本地有没有 token;没有 token 则跳转到登录页。这个逻辑放在 router.beforeEach 中。
7.4 Axios 请求封装
Axios 封装是前端工程的关键。在 Vue3 项目中,Axios 的使用方式与 Vue2 差别不大,但建议用 ES Module 方式导出实例。一个基础封装要点如下:
- 设置 baseURL,例如
/api,开发环境通过 Vite 代理转发到后端 8080。 - 请求拦截器:从 localStorage 或 Pinia 中取 token,加入请求头。
- 响应拦截器:如果返回 code 非 200,抛出提示;如果 HTTP 状态是 401,清除本地登录信息并跳转登录页。
import axios from 'axios' const request = axios.create({ baseURL: '/api', timeout: 10000 }) request.interceptors.request.use(config => { const token = localStorage.getItem('token') if (token) { config.headers.Authorization = `Bearer ${token}` } return config }) request.interceptors.response.use( response => { const res = response.data if (res.code !== 200) { return Promise.reject(new Error(res.message || '请求失败')) } return res }, error => { if (error.response && error.response.status === 401) { localStorage.removeItem('token') window.location.href = '/login' } return Promise.reject(error) } ) export default request开发时最常见的跨域方案是前端 Vite 代理,而不是在后端依赖 CORS。Vite 配置需要在 vite.config.js 中开启:
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, rewrite: path => path.replace(/^\/api/, '') } } } })这里假设后端接口前缀没有/api,所以做了一次重写。如果你的后端接口本身带/api前缀,就把 rewrite 去掉。
7.5 Vue3 核心组合式 API 应用
页面中使用 Vue3 组合式 API,以电影列表为例:
<template> <div class="film-list"> <el-card v-for="item in filmList" :key="item.id" class="film-card"> <img :src="item.cover" alt="封面" /> <h3>{{ item.title }}</h3> <span>{{ item.categoryName }}</span> </el-card> </div> </template> <script setup> import { ref, onMounted } from 'vue' import { getFilmList } from '@/api/film' const filmList = ref([]) const loadFilms = async () => { const res = await getFilmList({ current: 1, size: 12 }) filmList.value = res.data.records } onMounted(loadFilms) </script>注意 Vue2 里常用的this.$route、this.$store写法在 Vue3 组合式 API 中要换成useRoute()、useStore()(Pinia 为useUserStore())。computed在 Vue3 中需要显式导入,这也是面试常问的一个点:Vue3 的响应式系统基于 Proxy,而 computed 是懒执行的计算属性。
7.6 启动前端
npm run dev启动后访问 http://localhost:5173。打开页面后按 F12 打开开发者工具,切到 Network 面板,刷新页面观察接口请求状态。如果接口 404,检查代理路径和后端 Controller 请求映射;如果接口报 CORS,检查代理是否生效、后端是否重复配置跨域导致冲突。
8. 核心业务功能实现思路
下面把电影系统的几个核心功能拆开,逐个说实现思路。这一段不贴整份项目代码,只讲设计关键,实际开发时对照项目代码调整。
8.1 电影列表分页与筛选
后端使用 MyBatis Plus 分页插件:
@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }接口接收参数:pageNum、pageSize、categoryId、keyword。实现时使用 LambdaQueryWrapper 动态拼接查询条件:
LambdaQueryWrapper<Film> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(StringUtils.hasText(categoryId), Film::getCategoryId, categoryId); wrapper.like(StringUtils.hasText(keyword), Film::getTitle, keyword); wrapper.eq(Film::getStatus, 1); wrapper.orderByDesc(Film::getCreateTime);这里强调一个点:如果 keyword 为空,like条件不应该拼进 SQL,否则会导致全表扫描且返回空。使用条件构造器时精确传入 condition 参数。
8.2 登录注册与用户管理
用户端注册接口接收用户名、密码、昵称等参数,入库前用 BCrypt 加密。登录成功后生成 token 并返回用户基本信息。
后台管理员的账号可以提前在数据库初始化,或者由项目自带 SQL 脚本初始化。管理员接口与普通用户接口共用同一个用户表也行,用 role 字段区分;更严谨的做法是拆分 admin 表,但毕设规模用 role 字段更常见。
前端做权限控制时,路由可以分成:
/login公开路由。/用户端页面。/admin管理员布局与页面。
管理员路由在 beforeEach 中不仅检查 token,还要检查本地存储的 role 是否为 admin。注意,前端权限只能隐藏入口,后端的接口级别权限才是真正的安全边界。
8.3 轮播图与封面上传
轮播图和电影封面都涉及文件上传。前端 Element Plus 的el-upload组件提供 action 地址,通常指向上传接口:
const uploadUrl = '/api/admin/file/upload'后端接收 MultipartFile,保存到指定磁盘目录,并返回文件访问 URL。为了能在网页中直接访问,需要配置静态资源映射:
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { String uploadPath = System.getProperty("user.dir") + "/upload/"; registry.addResourceHandler("/upload/**") .addResourceLocations("file:" + uploadPath); } }在部署时,不建议把上传目录放到项目 classpath 中,这样重新打包会丢失。更稳妥的是在配置文件中指定独立目录,比如/data/movie/upload。
8.4 收藏与评论
收藏和评论要关联用户 ID,因此接口要求登录。登录后从请求头 token 中解析 userId,而不是让前端把 userId 传过来,避免越权风险。
设计接口时建议:
- POST /api/film/favorite,参数 filmId。
- DELETE /api/film/favorite/{filmId},取消收藏。
- GET /api/film/favorite/list,当前用户收藏列表。
- POST /api/film/comment,参数 filmId、content。
- GET /api/film/{filmId}/comments,评论列表。
8.5 首页数据聚合
首页往往需要同时展示多组数据。一个方案是前端并行请求多个接口,另一个方案是后端提供一个聚合接口。对于电影网站,首页推荐、最新、分类数据用/api/home/data一个接口返回更高效,也可以减小前端请求数量。
public class HomeDataVO { private List<BannerVO> bannerList; private List<FilmVO> hotFilmList; private List<FilmVO> latestFilmList; private List<CategoryVO> categoryList; }9. 接口 API 调用与批量任务设计
电影网站系统虽然本身不是高并发项目,但接口调用规范和批量任务设计是工程化的重点。
9.1 接口调用约定
后端接口尽量遵循 RESTful 风格。前端 API 模块对应后端的 Controller,每个模块一个 JS 文件,例如 film.js、user.js、category.js。这样接口地址改动时只调整一个文件。
管理员端批量上架电影时,Controller 接口通常接收 List 类型:
@PostMapping("/admin/film/batch") public Result<Void> batchCreateFilm(@RequestBody List<Film> filmList) { filmService.saveBatchFilm(filmList); return Result.ok(null); }为了使事务对多数据操作生效,批量保存方法上要加@Transactional,注意方法必须是 public,并且不能同类内部调用失效。
9.2 Python 调用接口示例
即使不启动前端,也可以直接使用 Postman、curl 或 Python requests 来验证接口。这样可以快速判断问题定位在前端还是后端。
import requests base_url = "http://localhost:8080" login_data = { "username": "admin", "password": "123456" } resp = requests.post(f"{base_url}/admin/login", json=login_data, timeout=10) print("登录返回:", resp.json()) token = resp.json().get("data", {}).get("token") headers = {"Authorization": f"Bearer {token}"} film_data = { "title": "测试电影", "cover": "https://example.com/test.jpg", "categoryId": 1, "description": "用于接口联调的测试数据", "status": 1 } resp2 = requests.post(f"{base_url}/admin/film", json=film_data, headers=headers, timeout=10) print("新增电影返回:", resp2.json())这里只做演示,接口路径需要根据你的后端 Controller 实际映射调整。
9.3 批量任务设计建议
如果要做电影数据的批量导入,有三种常见方式:
- 管理页面上传 Excel,后端解析并逐条校验入库。
- JSON 数组一次提交,适合接口联调和小批量数据。
- 定时任务扫描某个目录下的资源文件,这种情况适合内部平台。
三种方式在生产中都要做三件事:幂等处理、失败日志、部分成功回滚或标记。批量导入过程中如果有一条数据分类不存在或缺少必填字段,最好在返回结果中给出失败明细,而不是直接抛异常中断全部任务。
9.4 curl 快速验证
curl -X POST http://localhost:8080/admin/login \ -H "Content-Type: application/json" \ -d '{"username":"admin","password":"123456"}'响应中拿到 token 后,再调受保护接口:
curl -X GET http://localhost:8080/admin/film/list?current=1&size=10 \ -H "Authorization: Bearer <token>"把<token>替换成实际 token 即可。如果返回 401,先确认 token 是否过期、请求头是否带对格式。如果返回 403,往往是角色权限校验不通过。
10. 开发调试中的资源占用与性能观察
SpringBoot + Vue3 项目对硬件要求很低,但开发调试中仍有几个观察点。
10.1 内存占用观察
启动后端后,SpringBoot 默认 JVM 内存根据本机配置自动调整。如果本机内存紧张,可以手动限制:
java -jar movie-admin.jar --spring.profiles.active=prod -Xms256m -Xmx512m如果启动多个微服务,每个服务建议单独限制内存。前端 Node 开发服务占用内存也不高,但如果 node_modules 安装异常或运行多个终端,也可能出现内存不足。
10.2 接口响应时间的判断
前后端分离项目中,接口响应慢要先分清瓶颈在哪个环节:
- Network 面板看接口耗时,如果耗时高而在数据库执行很快,可能是后端逻辑有循环查询。
- MyBatis Plus 开启 SQL 日志后,每个查询都会打印在控制台,可以观察是否有 N+1 查询。
- 如果首页同时查了轮播、分类、电影列表,建议合并接口或加缓存,减少网络往返。
10.3 构建优化
Vue3 项目打包后,首屏加载大小可以通过路由懒加载来优化:
const Home = () => import('@/views/Home.vue')这是 Vue3 + Vue Router 联合常用的技术点。另一个常见问题是 Element Plus 全局引入导致包体积偏大,可按需引入:
npm install unplugin-auto-import unplugin-vue-components配置由实际工程决定,但思路是:组件自动导入,避免在 main.js 中全量注册 Element Plus。
11. 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 后端启动失败,提示数据库连接失败 | MySQL 未启动、密码错误、数据库不存在 | 检查 MySQL 服务状态和 application.yml | 启动 MySQL,修正账号密码或建库 |
| 后端启动失败,提示端口占用 | 8080 端口被其他进程占用 | netstat 查看端口占用 | 关闭占用进程或修改 server.port |
| 前端启动失败,提示 Node 版本过低 | Vite 版本与 Node 版本不兼容 | 执行 node -v 查看版本 | 升级 Node 到 18 或 20 LTS |
| 登录后调用接口返回 401 | token 过期或请求头未携带 | 查看浏览器 Network 中请求头 | 重新登录,检查 Axios 请求拦截器 |
| 页面请求接口返回 404 | 代理路径或后端映射不匹配 | 查看后端日志和 Network 请求 URL | 调整 Vite proxy rewrite 规则或 Controller 映射 |
| 接口报 CORS 错误 | 后端未开启跨域或前端未走代理 | 确认使用的是代理还是直接请求 | 开发环境用 Vite 代理,生产环境由 Nginx 代理 |
| 文件上传成功但图片不显示 | 静态资源映射路径不对 | 访问资源 URL 看是否能直接打开 | 检查 addResourceHandlers 和文件存放路径 |
| 中文乱码或评论 emoji 无法入库 | MySQL 表字符集不是 utf8mb4 | 查看表结构字符集 | 修改表和数据库字符集为 utf8mb4 |
| 启动前端后页面空白 | 路由配置错误或某个页面导入报错 | 打开控制台查看报错 | 根据报错文件修改 import 路径 |
| 前端代码改了不生效 | 开发服务未正确启动或浏览器缓存 | 强制刷新或重启 npm run dev | 清缓存,确认控制台编译成功 |
| SpringBoot 3 项目报 javax 包不存在 | JDK 8 代码在 JDK 17 运行 | 查看异常堆栈 | 使用 JDK 17 重编译或降级到 SpringBoot 2.7 |
排查技巧:任何接口行为异常,先不猜,直接看后端控制台日志。SpringBoot 默认日志已经足够定位 80% 的启动问题和接口异常。如果日志没输出 SQL,再看 MyBatis Plus 是否开了 SQL 日志:
mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl12. 最佳实践与合规提醒
12.1 工程化管理建议
第一,第一次跑通项目时不要追求修改很多功能。先把后端启动、前端启动、登录、电影列表、详情页、后台管理这几条主链路走通。主链路没问题后再去改功能,这能避免把环境问题和代码问题混在一起。
第二,保留一套最小可运行配置。数据库脚本、后端配置、前端 .env 文件、README 都要放进版本管理。别人 Clone 项目后在 10 分钟内能启动,这个项目才是可交付的。
第三,模型和配置文件分离。不要把 upload 目录和建议配置文件写死在代码里,用 application-dev.yml、application-prod.yml 做环境隔离更合理。
第四,批量导入要做前置校验。批量上架电影前,先校验完整表格数据再入库,而不是逐条插入时才发现问题。
第五,接口服务要限制访问范围。生产环境不要把后端端口直接暴露到公网,使用 Nginx 做反向代理,只开放 80/443,并对上传接口做大小和类型限制。
12.2 授权与合规边界
电影网站系统涉及影片、海报、预告片或评论内容时,务必确认授权情况:
- 演示和本地学习使用官方公开的示例图片、海报和个人拍摄素材。
- 不把爬取的收费视频、未授权影视资源、盗版影片链接集成进系统。
- 如果系统面向公众开放,需要在用户协议中明确禁止违法内容,并保留内容审核能力。
- 如果系统采集用户登录信息或上传文件,要求遵循数据安全和个人信息保护要求,测试阶段使用虚拟数据。
- 如果后续接入真实在线视频,要优先选择有正规版权的内容源。
这类合规提醒不是套话。很多毕业设计项目因为演示视频或电影素材使用了未授权资源,在公开演示和简历展示阶段遇到不必要的风险。建议把所有图片、封面换成程序生成的占位图或自己有权限的素材,代码里不留下侵权链接。
12.3 如何做二次开发
如果你拿到这个项目的源码,想把它改成自己的毕设或练手项目,建议按这个顺序改:
- 换项目名和数据库名。
- 改系统 Logo 和页面标题,删除多余测试数据。
- 增加一个与电影业务相关的小亮点功能,比如电影榜单、每日推荐、词云标签,避免和原项目完全一致。
- 把自己实现的功能整理成 README 中的技术说明,减少答辩时讲不清的点。
13. 总结与下一步
SpringBoot + Vue3 的前后端分离电影网站系统适合用四个关键词概括:双端分离、数据管理、鉴权联调、工程落地。它不像算法项目那样需要很高的数学基础,也不像 AI 推理项目那样依赖显卡,只要能理清表关系、接口约定和请求链路,就拥有了一个可以不断扩展的 Web 项目底座。
拿到项目后最先做的事不是看每一行代码,而是先跑通两条链路。第一,用户端首页到电影列表到登录到收藏;第二,管理员登录、新增电影、轮播图配置、用户列表。这两条链路覆盖了 JWT 鉴权、分页查询、文件上传、权限判断、数据关联这些 SpringBoot 和 Vue3 方向的高频考点。
最容易踩的坑集中在三个方面:数据库连接配置错误、SpringBoot 与 JDK 版本不匹配、前端代理与后端跨域配置冲突。这三个问题在环境检查阶段提前确认,后面联调可以省下很多时间。
下一步可以按业务需求扩展三块内容:一是接入 OSS 或本地对象存储,解决封面和预告片文件的长期保存问题;二是引入 Redis 缓存首页热点数据和登录 token,逐步脱离“毕设感”;三是增加评论点赞、观影记录、每日推荐等交互功能,让系统的完整度更高。本文适合先收藏,实际开发时对照功能模块、接口设计表和问题排查清单来用。