
做毕设选了这个“国产动漫网站平台”的同学或者正在犹豫要不要选这个题目的同学这篇东西就是给你写的。我会从项目结构、核心代码、数据库设计、部署上线到论文写作完整拆解这套 SpringBoot Vue MySQL 的技术方案。全程不整虚的全是能直接落地的思路和踩坑记录。先交代一下背景这类“XX动漫网站”在每年的JavaWeb课程设计和毕业设计里出现频率极高因为它兼容了电商系统的商品逻辑番剧展示、社交产品的用户逻辑评论收藏、管理后台的权限逻辑管理员审核覆盖面广工作量适中只要架构清晰拿个不错的成绩很稳。1. 项目整体设计与技术选型思路1.1 为什么是 SpringBoot Vue MySQL 这个组合先说后端。SpringBoot 在校园项目里几乎是统治级的原因有三一是自动配置省掉了大量 XML 配置一个带内嵌 Tomcat 的 jar 包就能跑起来二是生态成熟MyBatis-Plus、Spring Security、Redis 这些常用的轮子接入成本极低三是网上资料太多遇到报错随便一搜就有答案这一点对赶工期的同学来说太重要了。前端选 Vue 而不是 JSP 或 Thymeleaf核心是前后端彻底分离。你这个动漫站如果做成服务端渲染页面跳转要么刷新要么用模板引擎硬拼交互体验接近十几年前的网站答辩时老师一旦点开页面就觉得缺了点“现代感”。用 Vue Element Plus 后列表页、详情页、播放页之间完全无刷新跳转配合懒加载和路由守卫整个站点的体验会明显高出同龄人一截。数据库用 MySQL 没什么悬念开源的、免费的、课程里教的、面试常问的都是它。需要注意的是一开始就统一版本比如本地用 8.0部署到服务器也尽量用 8.0避免 5.7 和 8.0 的认证插件差异导致连接报错。这个后面部署章节会展开讲。1.2 功能模块怎么划分才像“正规军”很多同学拿到这种题目第一反应是“做几个页面就有界面了”这恰恰是最危险的想法。一个合格的毕设项目核心是功能闭环不能只有表单和列表。我建议把整个平台拆成四个端前台用户端Vue 页面首页轮播图加推荐番剧、番剧列表筛选按类型/热度/年份、番剧详情简介/剧集列表/相关推荐、播放页、评论区一级和二级评论、个人中心收藏列表/浏览记录/修改资料。前台搜索端可以根据关键字搜索番剧支持按名称模糊匹配也可以按标签筛选搜索结果要有高亮反馈。后台管理端Vue 页面管理员登录、番剧管理增删改查、上下架、封面上传、剧集管理每部番剧下挂多个播放地址、分类标签管理、评论审核或删除、用户封禁/解封、数据统计日活、播放量 Top10。后端接口端SpringBoot提供 RESTful APIJWT 鉴权统一返回结构全局异常处理文件上传下载拦截器校验管理员身份。这四个端不是各干各的而是要打通。用户在前台点“追番”要写入收藏表后台能看到收藏量用户在播放页观看后端要记录播放量后台的播放榜才能有数据管理员可以删除违规评论前台列表要实时少掉那条记录。这样前后端联动的贯穿关系才是答辩时能拿高分的关键。1.3 前期需要准备的工具和环境我把自己当时用的工具清单列在下面版本以稳定为主别追新。工具/环境推荐版本说明JDK1.8 即可不要用 17 或 19部分兼容问题会浪费你大量时间Maven3.6管理后端依赖Node.js14 或 16支持 Vue CLI 和 Vite 均可IDEIDEA VSCode后端用 IDEA前端用 VSCode 更轻量数据库工具Navicat 或 DataGrip推荐 Navicat导入 SQL 方便Vue2.x 或 3.x建议 Vue3 Element Plus更现代SpringBoot2.7.x稳定且 MyBatis-Plus 兼容性最好提示SpringBoot 3.x 虽然已经出了很久但如果你用的是 MyBatis-Plus 老版本会出现接口不兼容的情况。除非你已经很熟否则老老实实 2.7.x省得在环境上耗掉一个周末。2. 数据库设计好表结构是项目的半条命2.1 核心表怎么建动漫网站的数据模型不像电商那么复杂但也不能说简简单单三张表就能搞定。我负责地讲下面这六张表是底线用户表useruser_id主键、username、password加密后、avatar、email、role0普通用户 1管理员、status是否封禁、create_time。这里的 role 字段是给后台准备身份边界的封禁状态则用于登录时校验。番剧表animeanime_id、title、cover_url、description、type_id关联分类、status0连载中 1已完结、region、year、play_count、favorite_count、create_time。播放量和收藏量这两个冗余字段建议直接存在表里前台排行榜直接按这个字段排序省去每次 count 聚合。剧集表episodeepisode_id、anime_id、episode_num、title、video_url。如果后续支持多线路播放可以再加一个 video_source 字段或单独开表。注意视频地址尽量不要存完整的服务器本地路径存可访问的 URL 或相对路径更好迁移。分类表categorycategory_id、name、sort。番剧与分类是简单的一对多关系不需要中间表。收藏表favoritefavorite_id、user_id、anime_id、create_time。这个表要加唯一索引 (user_id, anime_id)防止用户重复收藏。评论表commentcomment_id、user_id、anime_id、content、parent_id0为一级评论非0为回复、create_time。用 parent_id 实现二级评论是省事且高效的做法比做独立的回复表简单得多。下面是番剧表和评论表的简化建表 SQL照着改直接能用CREATE TABLE anime ( anime_id int NOT NULL AUTO_INCREMENT, title varchar(128) NOT NULL COMMENT 番剧名称, cover_url varchar(255) DEFAULT NULL COMMENT 封面图片地址, description text COMMENT 简介, type_id int DEFAULT NULL COMMENT 分类ID, status tinyint DEFAULT 0 COMMENT 0连载中 1已完结, region varchar(32) DEFAULT NULL, year int DEFAULT NULL, play_count int DEFAULT 0, favorite_count int DEFAULT 0, create_time datetime DEFAULT NULL, PRIMARY KEY (anime_id), KEY idx_type (type_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT番剧表; CREATE TABLE comment ( comment_id int NOT NULL AUTO_INCREMENT, user_id int NOT NULL, anime_id int NOT NULL, content varchar(500) NOT NULL, parent_id int DEFAULT 0, create_time datetime DEFAULT NULL, PRIMARY KEY (comment_id), KEY idx_anime (anime_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT评论表;2.2 字段类型与字符集的坑字符集一定要用 utf8mb4不要用 utf8。原因很简单utf8 在 MySQL 里最多存 3 个字节而 emoji 表情是 4 个字节评论区一旦有人发表情就报错或者变成问号。用 utf8mb4 是从源头规避这种问题。字段类型方面标识番剧状态的 status 用 tinyint 而不是 boolean方便以后扩展更多状态描述型字段 description 用 text封面路径用 varchar(255)时间字段用 datetime 而不是 timestamp省去时区换算的麻烦。不要过度使用 varchar(5000) 这种大字段索引和查询效率都会受影响。2.3 索引设计别把数据库全表扫穿评论表的核心查询是“查某部番剧下的所有评论”所以 anime_id 必须有索引。收藏表的核心查询是“查某个用户收藏了什么”user_id 必须有索引。番剧表的筛选条件经常是 type_id、year、region可以建联合索引。很多人不在乎这些数据量少得几千条确实无所谓但老师一问“这个字段为什么加索引”“数据量大之后怎么办”答不上来就尴尬了。把每个索引的用途说清楚属于答辩加分项。3. 后端核心实现从 Controller 到过滤链3.1 项目分层与包结构后端的包结构建议直接抄成熟项目的写法一目了然com.example.anime ├── controller // REST接口层 ├── service // 业务逻辑层 ├── mapper // MyBatis-Plus的Mapper层 ├── entity // 数据库实体类 ├── common // 统一返回体、全局异常、常量 ├── config // 配置类跨域、拦截器、WebMVC ├── utils // 工具类JWT、MD5等 └── security // 过滤器链、用户上下文controller 只负责参数接收和返回service 承载业务规则mapper 只做数据库操作。这条依赖方向不能乱一旦倒了后面改需求时会发现一个文件牵连七八个地方。3.2 统一返回体与全局异常前后端分离项目最烦的一件事就是接口返回格式不一致前端回调里一会儿处理 data一会儿处理 code开发到后面谁写的接口谁自己都记不清。我强烈建议一开始就统一Data public class ResultT { private Integer code; private String message; private T data; public static T ResultT success(T data) { ResultT result new Result(); result.setCode(200); result.setMessage(success); result.setData(data); return result; } public static T ResultT error(Integer code, String message) { ResultT result new Result(); result.setCode(code); result.setMessage(message); return result; } }配合全局异常处理器把参数校验异常、业务异常、数据库异常统一转换成 Result 结构前端 axios 响应拦截器只要判断 code 为 200 就正常拿数据否则弹出 message。这样一搞所有接口的返回值都长一个样前端写起来极度顺畅。3.3 登录鉴权JWT 怎么接进 SpringBoot很多课程设计还在用 Session我建议用 JWT好写也好讲。流程是用户登录成功 - 后端生成 token 返回 - 前端存到 localStorage - 每次请求在 header 里带 Authorization - 后端拦截器解析 token 并获取用户信息。生成 token 的工具类核心代码如下public class JwtUtils { private static final String SECRET your-secret-key; public static String createToken(Integer userId, String username, String role) { return Jwts.builder() .setSubject(username) .claim(userId, userId) .claim(role, role) .setExpiration(new Date(System.currentTimeMillis() 7 * 24 * 3600 * 1000L)) .signWith(SignatureAlgorithm.HS256, SECRET) .compact(); } public static Claims parseToken(String token) { return Jwts.parser() .setSigningKey(SECRET) .parseClaimsJws(token) .getBody(); } }这里有个重要细节JWT 的有效期我设了 7 天短了用户要频繁重新登录长了有安全风险。如果还想更好一点可以做双 token 机制但毕设嘛7 天有效期加上拦截器校验已经足够了不用过度设计。3.4 拦截器实现登录校验和管理员校验写一个 HandlerInterceptor 子类在 preHandle 里执行逻辑Component public class AuthInterceptor implements HandlerInterceptor { Autowired private StringRedisTemplate redisTemplate; Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token request.getHeader(Authorization); // 如果是预检请求直接放行 if (OPTIONS.equalsIgnoreCase(request.getMethod())) { return true; } // 白名单里的路径直接放行 String uri request.getRequestURI(); if (uri.contains(/auth/) || uri.contains(/anime/list)) { return true; } if (token null || token.isEmpty()) { throw new BusinessException(401, 未登录); } try { Claims claims JwtUtils.parseToken(token); request.setAttribute(userId, claims.get(userId)); request.setAttribute(role, claims.get(role)); // 管理员接口二次校验 if (uri.contains(/admin/) !1.equals(String.valueOf(claims.get(role)))) { throw new BusinessException(403, 无权限); } } catch (Exception e) { throw new BusinessException(401, token失效); } return true; } }然后在 WebMvcConfigurer 里把这个拦截器注册进去再把不需要鉴权的接口放白名单比如用户注册、登录、番剧列表、番剧详情这些公开数据。要注意的是拦截器处理不了注解权限如果你想做细粒度的权限控制可以再结合自定义注解 AOP但毕设级别没必要。维护一个简单的白名单数组就能覆盖全部需求了。3.5 文件上传封面图到底存哪封面图上传有几个选择存服务器本地、存云存储 OSS、存七牛云。考虑到毕设评审时没有固定的云环境我建议本地存储 Nginx 映射这样在本地、服务器都能跑通。实现方案后端接收 MultipartFile 后用 UUID 重命名文件按日期分目录保存到 /upload/cover 下文件路径存数据库启动类里或配置类里写一个静态资源映射把 /upload/** 映射到物理磁盘路径部署时通过 Nginx 将 /upload 前缀专门指向文件目录。Override public String uploadCover(MultipartFile file) { String originalFilename file.getOriginalFilename(); String suffix originalFilename.substring(originalFilename.lastIndexOf(.)); String fileName UUID.randomUUID() suffix; String dateDir new SimpleDateFormat(yyyyMMdd).format(new Date()); String relativePath upload/cover/ dateDir / fileName; String absolutePath uploadRoot relativePath; File dest new File(absolutePath); if (!dest.getParentFile().exists()) { dest.getParentFile().mkdirs(); } try { file.transferTo(dest); } catch (IOException e) { throw new BusinessException(500, 文件上传失败); } return relativePath; }这个接口的代码量不大但涉及的细节多比如后缀名校验、文件大小限制、目录权限答辩时都很容易成为提问点。3.6 播放量计数怎么防刷这个其实在毕设里很加分。实现思路是用户进入播放页时调用一个“观看记录”接口后端从 token 里拿用户ID先在 Redis 里查这个用户是否已经看过这部番没看过就把播放量加一并设置一天的过期时间。这样可以粗略防同一用户反复刷量。没有 Redis 的情况下也可以用 MySQL 记录观看日志查询时再 count但效率很低。毕设阶段我还是建议在你的pom.xml里引入 spring-boot-starter-data-redis代码量不大答辩讲出来很撑场子。public void recordPlay(Integer userId, Integer animeId) { String redisKey play:user: userId :anime: animeId; Boolean isExist redisTemplate.hasKey(redisKey); if (Boolean.FALSE.equals(isExist)) { animeService.incrementPlayCount(animeId); videoService.saveRecord(userId, animeId); // 可选存观看记录 redisTemplate.opsForValue().set(redisKey, 1, Duration.ofDays(1)); } }4. 前端关键页面与交互实现4.1 前端项目结构与路由设计前端我建议用 Vue3 Vite Element Plus Axios。项目结构如下src ├── api // 每个功能模块的接口封装 ├── router // 路由配置 ├── store // Pinia状态用户信息、token ├── views // 页面 │ ├── home // 首页 │ ├── anime // 番剧列表与详情 │ ├── user // 个人中心 │ └── admin // 后台管理 ├── components // 公共组件 ├── utils // 请求封装、工具函数 └── App.vue路由配置里要加上路由守卫这是前后端分离项目鉴权的前端侧和后端拦截器形成双保险router.beforeEach((to, from, next) { const token localStorage.getItem(token) if (to.meta.requiresAuth !token) { next(/login) } else if (to.meta.requiresAdmin localStorage.getItem(role) ! 1) { next(/) } else { next() } })4.2 Axios 请求封装与拦截器请求封装的思路统一 baseURL统一在请求头里带 token统一拦截返回的 code 做错误处理。这样所有页面不用重复关注这些逻辑。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) { return res.data } else { ElMessage.error(res.message || 请求失败) if (res.code 401) { router.push(/login) } return Promise.reject(new Error(res.message)) } }, error { ElMessage.error(网络异常请稍后重试) return Promise.reject(error) } ) export default request4.3 首页、列表页、详情页的实现要点首页想要出效果轮播图必做。用 Element Plus 的 el-carousel数据接口用一条 banner 推荐接口管理员可以在后台设置哪些番剧上轮播。这里建议在 anime 表加一个 is_recommend 字段用起来比单独建 banner 表省事。列表页的重点是筛选条件联动。类型、地区、年份三个下拉筛选项改变任何一个就重新请求列表接口。建议用 URL query 参数同步筛选项比如/anime/list?type1region日本year2023这样用户刷新页面后筛选状态还在体验会好很多。详情页是功能聚合点左侧番剧封面和简介下方评论列表右侧剧集列表和“追番收藏”按钮。这块建议把剧集列表做成 el-collapse 折叠面板的形式不然几十集叠起来页面太长了。收藏按钮要判断当前用户是否已收藏已收藏则显示“已收藏”点击可取消。4.4 管理员后台表格操作不要太爽快后台管理页面主要用 el-table 展示数据配合 el-dialog 做新增和编辑表单el-pagination 做分页。这里有个坑修改和删除操作一定要二次确认用 Element Plus 的 ElMessageBox.confirm不然误删了一条数据管理员又没备份那不是尴尬是灾难。管理员可以管理的对象番剧增删改查、封面重新上传、上下架切换。剧集对某部番剧增删改剧集填写集数和视频链接。用户查看用户列表禁用或解封用户。评论查看所有评论删除违规内容。这部分的功能逻辑没什么难度重点是考验你对 ElTable、ElDialog、ElForm 这几个组件熟练不熟练。写的时候多注意表单校验 rules避免没填名称就提交了。4.5 评论功能的父子组件设计评论分两级一级评论是“这部番好看”这种主题回复二级是“楼上说的对”这种楼中楼。实现时注意两点评论组件做成递归组件一级评论下挂若干二级评论后续想加更多层级也能扩展。加载策略每部番剧的评论可以一次性返回也可以按页返回。毕设数据量小一次性返回即可。核心诉求是在评论区发布新评论后要局部刷新不要整个页面跳转重载。5. 项目部署从本地到 Linux 服务器的完整实操5.1 后端打包与启动后端在 IDEA 里运行没问题后要先在application.yml里把数据库地址改成服务器的 MySQL 地址然后执行 Maven 打包mvn clean package -DskipTests打出来的 jar 包在 target 目录下比如anime-server-0.0.1-SNAPSHOT.jar。在服务器上启动nohup java -jar anime-server-0.0.1-SNAPSHOT.jar --spring.profiles.activeprod server.log 21 nohup 和是让你关闭 SSH 后进程还能继续跑。日志重定向到 server.log方便排查问题。可以配合tail -f server.log实时看启动状态。提示如果服务器配置不高启动参数里可以加-Xms256m -Xmx512m限制堆内存防止内存溢出。5.2 前端打包与 Nginx 配置前端先要把接口地址改成服务器的公网 IP或者已解析的域名// vite.config.js server: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } }开发环境走 Vite 代理解决跨域非常舒服。生产环境打包后需要 Nginx 来处理两件事一是把 Vue 的静态文件配好二是把/api的请求反向代理到后端服务。npm run build打包后会生成 dist 目录把 dist 目录完整上传到服务器/usr/share/nginx/html路径可自定义。Nginx 配置如下server { listen 80; server_name your-domain.com; location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; # 前端路由history模式刷新不404的关键 } 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 /upload/ { alias /usr/local/anime/upload/; } }这个配置里三个 location 缺一不可/负责页面/api/负责接口代理/upload/负责图片视频访问。特别提醒try_files这一行如果漏掉在 Vue 使用 history 模式时刷新子页面会 404。5.3 服务器 MySQL 导入 SQL先在服务器上装好 MySQL然后创建数据库并导入别人提供的或者你自己导出的 SQL 文件mysql -u root -p create database anime character set utf8mb4 collate utf8mb4_general_ci; exit; mysql -u root -p anime /data/anime.sql导入完成后用 Navicat 远程连接测试一下如果连接被拒绝检查防火墙是否开放 3306 端口以及 MySQL 是否允许远程连接GRANT ALL PRIVILEGES ON *.* TO root% IDENTIFIED BY 你的密码 WITH GRANT OPTION; FLUSH PRIVILEGES;这一步最容易翻车的是 MySQL 8.0 的默认认证插件是 caching_sha2_passwordNavicat 老版本可能连不上升级客户端或者改认证方式ALTER USER root% IDENTIFIED WITH mysql_native_password BY 你的密码;即可解决。5.4 部署文档到底应该怎么写很多人把部署文档写成了“先装 JDK再装 MySQL”这种流水账这不算错但显得太单薄。一份能拿得出手的部署文档至少要包含服务器要求CPU/内存/磁盘、操作系统版本。中间件版本矩阵JDK8、MySQL8、Nginx1.20。数据库初始化步骤创建数据库、导入 SQL、验证表数量。前端打包命令及产物说明。后端打包命令及启动命令。Nginx 关键配置说明为什么要这样配。环境变量或配置文件的关键修改点。常见问题排查端口占用、数据库连接失败、静态资源 404。最终验证方式访问首页、登录、上传封面、发布评论。你把自己当成一个从来没有接触过这个项目的人按着这份文档能不能从零装起来能那这份部署文档就算合格。6. 论文写作与答辩重点准备6.1 论文结构怎么排论文建议按照“背景、技术、设计、实现、测试、总结”六章来写但章节名称不要照抄要有自己的语言。比如第一章写“国产动漫发展的背景与平台建设的意义”第二章写“相关技术简介”第三章写“系统需求分析”和“总体设计”第四章写“系统详细设计”第五章写“系统实现”第六章写“系统测试”。需要注意不要写成代码粘贴簿。代码要选关键片段放比如 JWT 拦截器、分页查询、文件上传、前端路由守卫而不是把整个 Controller 粘进去。每段代码后面必须跟一段文字解释“这段代码解决了什么问题”。6.2 需求分析怎么写才不空洞很多人的需求分析就是“系统分为前台和后台前台面向用户后台面向管理员”。这太粗了。你要把需求拆成功能性需求和非功能性需求。功能性需求要写出用例描述用户注册、用户登录、浏览番剧列表、搜索番剧、查看详情、发表评论、收藏番剧、观看剧集、管理员管理番剧、管理评论、管理用户。非功能性需求要写性能页面响应时间小于3秒、安全性密码加密存储、接口鉴权、可用性7x24小时运行。把这些拆开写论文篇幅一下就扎实了而且答辩时你能够就任意一条需求展开说明实现方案。6.3 答辩高频问题清单根据我和周围同学的经验答辩老师最喜欢问的问题主要是这几类为什么用 JWT 而不是 Session这个问题的标准答法是前后端分离架构下JWT 无状态服务端不需要存储会话信息适合分布式部署。密码是怎么存储的答MD5 加了盐再进行加密推荐使用 BCrypt。播放量是怎么计算的答Redis 定时任务或直接内存计数。数据库为什么用 utf8mb4答为了支持表情符号。如果用户量变大了怎么办答数据库读写分离、Redis 缓存热点数据、Nginx 负载均衡。评论的二级结构是怎么实现的答用 parent_id 字段实现父子关系。这些问题都不是死记硬背而是建立在你要真正理解自己写的代码的基础上。如果核心代码是你自己一行一行码出来的这些问题自然都能答上来如果是从别处类的代码至少要把关键几处原理弄明白否则被追问到细节装是装不了的。7. 常见问题与避坑指南7.1 跨域问题总是报错怎么办前后端分离项目开发中跨域是遇到最多的一个坑。所谓的跨域就是页面在 localhost:5173接口在 localhost:8080协议、域名、端口三者只要有一个不同浏览器就会拦截。解决方案有三种前端 Vite 配置代理这是开发环境的解法。后端加 CORS 配置类这是生产环境的解法之一。Nginx 反向代理统一路径这是最正规的解法。后端加 CORS 配置非常简单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); } }一个很重要的点配置了 CORS 不代表万事大吉如果还使用了拦截器校验 token要注意拦截器里对 OPTIONS 预检请求放行否则浏览器预检请求过不了拦截器还是报跨域错。7.2 前端刷新页面 404 的问题这个问题出现的原因是 Vue 路由用了 history 模式刷新时会拿着当前路径去请求服务器而服务器没有对应的路径就返回 404。解决方案就是前面在 Nginx 配置里写的try_files $uri $uri/ /index.html;让所有路径都回退到 index.html由前端路由接管。如果你用的是 hash 模式URL 里会带个 #不会有这个问题但不好看。所以还是建议 history try_files 的组合。7.3 数据库时间差 8 小时这个坑也很常见MySQL 连接串里加一个serverTimezoneAsia/Shanghai就能解决url: jdbc:mysql://localhost:3306/anime?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai同时注意服务器时区也设置为 Asia/Shanghai不然日志时间也会偏差。7.4 内存被 MySQL 吃满如果你的服务器只有 1G 内存MySQL 启动后默认的 buffer pool 可能很大导致系统卡死。解决办法是在 my.cnf 里把 innodb_buffer_pool_size 调到 64M 或 128M[mysqld] innodb_buffer_pool_size128M这是云服务器部署很容易被忽略的一个配置很多同学反映部署后访问很卡结果一看内存全被 MySQL 占了。7.5 视频播放格式与兼容问题动漫网站的视频源一般用 m3u8 格式因为它支持分片加载拖动进度条快兼容 H5 播放器。前端可以用 video.js 或者 hls.js。后端只要提供 m3u8 文件的访问地址即可视频转码属于额外工程不需要自己做。如果视频文件是 mp4 可以直接用 HTML5 video 标签但拖动进度条时可能需要服务器支持 range 请求Nginx 默认是支持的这个不用折腾。7.6 数据库 SQL 导入失败拿到一份 .sql 文件导入时报语法错误大概率是版本不匹配。比如文件是 MySQL 5.7 的格式里面有DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP在 MySQL 5.6 里就会报错。还有可能是字符集问题导入前要检查 SQL 文件头部的 SET NAMES 语句。最好在导入之前先检查一下 SQL 文件里的注释版本信息服务器 MySQL 版本和本机版本尽量保持一致可以省掉很多不必要的麻烦。8. 项目扩展加点什么才能评优如果你的时间还充裕或者想冲刺“优秀毕业论文”可以考虑在基础版本上加这些功能Redis 缓存热点番剧列表首页的推荐位和热播榜单缓存到 Redis设置 10 分钟过期降低数据库压力。这个改动其实不大加个 Spring Cache 注解就行但讲出来很高端。Elasticsearch 全文搜索当前搜索用 LIKE 查询等数据量大之后会慢。可以用 ES 做标题和标签的索引搜索这个工作量不小但如果论文里能写一章“搜索模块优化”含金量会显著提高。QQ/微信扫码登录借助第三方开放平台还需 App ID 和密钥校园项目申请可能有门槛但如果你能实现并展示效果答辩会很抢眼。数据可视化大屏后台加一个统计页用 ECharts 展示播放量趋势图、分类占比饼图、每日新增用户柱状图。这部分前端工作量不大但视觉效果很震撼老师一看会觉得你做了很多东西。这些扩展的核心原则是新增功能必须和现有模块有数据关联。比如缓存必须是缓存你番剧表的数据大屏的图表必须基于你现有的播放记录表统计不能凭空造一套数据。这样论文里才能前后呼应答辩时才能把整个链路讲清楚。9. 拿源码后必须做的三件事很多同学拿到一套源码后直接双击运行能跑就去写论文这是最危险的。你必须做三件事第一改数据库名和密码。可能有些源码包里带的 SQL 里写死了数据库名一些配置里也带了测试环境的密码全部统一改成自己的避免和别人的项目撞车。第二跑通完整链路。找一个老项目按照“前台注册登录-浏览-收藏-评论-后台登录-修改番剧-上传封面”全流程走一遍任何一个环节断了都要自己排查清楚。这个过程就是提前踩坑做完之后你比谁都懂这个项目。第三做一次代码重构哪怕只是重命名不合理的变量名。把源码中晦涩无注释的方法重命名成你能理解的名字加注释删掉无用的 import。这个动作看着简单实际做完之后你对项目的理解会上升一个层级答辩时也会显得你在项目里思考过不是抄来的。我写到这里其实挺感慨的。这套动漫平台的技术栈几乎是当前 Java 后端校招最常见的组合了。如果你的目标不只是毕业而是毕业前多一份能写进简历的项目经历那这个项目的价值就更大了——它帮你把前端 Vue 的组件通信、路由守卫、请求封装后端 SpringBoot 的自动配置、拦截器、JWT 鉴权、MyBatis-Plus 的 CRUD、Redis 的简单使用都串起来了这些知识点每一个单独拿出来都是面试常见题。做完它至少能让你的项目经验这一栏不至于空白。最后再分享一个小技巧部署文档里把每个步骤对应的验证方式写上去比如“执行启动命令后访问 http://ip:8080/api/anime/list若能返回 JSON则后端启动成功”。这一步看上去只是多加了几个字但当你熬夜部署、别人向你请教问题、或者老师一字一句检查部署文档时你会知道它值多少分。按照这套思路去推进不管是验收、评优还是后续扩展你都已经站在了一个让人心安起点的位置动手吧。