基于Spring Boot的游戏分享网站毕设全流程指南:从需求拆解到部署上线
最近身边好几个做毕设的同学都在问同一个问题Java 后端毕设到底选什么题目既能顺利过审又能顺手把该学的技术都练一遍我自己带完一批项目后答案始终是“基于Spring Boot的管理/分享类网站”其中游戏分享网站是出现频率最高、最容易做出完整demo的之一。这个题目业务贴近现实场景规模不大不小一个学生毕业设计既不会因为功能太少被老师挑战又不会因为工作量太大做不完。更重要的是它把用户登录、列表分页、文件上传、评论互动、后台管理这些后端开发日常要碰的东西几乎全串了一遍用来撑起一篇合格的毕设论文完全足够。这篇就把我做这个项目、以及帮同学调试过程中踩过的坑和优化后的方案一次写清楚从需求拆解讲到部署上线给后面选这个题的同学一份可以直接照着走的参考。1. 项目定位与需求拆解1.1 为什么选“游戏分享网站”这个题目很多同学对毕设题目的理解有偏差觉得越“大厂风”越好结果选了个电商平台或者“智能推荐系统”最后发现要么业务逻辑复杂到收不了尾要么数据量根本撑不起推荐算法的“学习效果”答辩现场十分尴尬。游戏分享网站这个题的优势在于它属于典型的“内容展示 用户互动”型业务游戏玩家需要在这里浏览游戏资源、查看游戏详情、发表自己的评论、收藏喜欢的游戏这些诉求映射成技术语言就是一堆互相之间有清晰关系的实体和接口既好设计数据库又好写代码。另一个实际原因是游戏分享类型的网站素材天然非常丰富。随便选一批热门游戏做示例数据整个页面就很有说服力不用像“校园二手交易平台”那样满屏假数据。更重要的是这类题目对开发环境、服务器资源要求极低普通八代 i5 16G 内存的电脑跑一个 Spring Boot 项目毫无压力下载安装配置半天以内就能搞定环境对要同时准备论文和实习的同学非常友好。1.2 核心功能模块拆解如果直接用“游戏分享网站”这个名字去答辩老师第一句很可能是“那你这个网站解决什么需求”。所以在做设计之前一定要把需求拆成清晰的功能模块表达成教科书式的语言。一个合格的游戏分享网站至少要包含以下模块前台用户模块注册、登录、个人信息查看修改、退出登录。游戏信息模块游戏列表展示、多条件搜索分类、关键字、游戏详情页、游戏封面上传。互动模块用户对游戏发表评论、点赞/收藏。后台管理模块管理员登录、游戏分类管理、游戏内容管理、用户管理、评论审核。从工作量来看这些模块并不算多但每个都刚好能映射到一个 Spring Boot 的核心知识点注册登录对应数据校验和加密游戏列表对应分页查询与条件拼接评论收藏对应多表关联和事务后台管理对应拦截器和权限控制。答辩时你完全能说清楚“每个功能用了什么技术、为什么这么设计”这就是好毕设题目的核心价值——可讲述、可展示、可维护。注意很多同学喜欢一开始就把“导航栏、轮播图、友链、每日签到”全加上建议不要这么干。功能要做好减法只要核心业务闭环完整老师在验收时看到的不是功能数量而是每个功能是否真正健壮可用。2. 技术选型与架构设计2.1 Spring Boot 版本选择及理由这一节是我帮不少同学排查问题时最想写的一节因为版本踩坑实在太常见了。搜一下网上的教程很多还在用 Spring Boot 2.2、2.3而有些同学刚上手就直接在官网把 3.2 下载下来技术选型里第一行就写了错的版本最后连启动都过不去。我对致命版本问题的建议很直接如果是毕业设计场景不考虑新特性展示优先选 Spring Boot 2.7.x 系列搭配 JDK 8。Java 8 Spring Boot 2.7 MyBatis Plus 3.5.x 这套组合网上资料最多、兼容性最稳大部分老师自己的开发环境也是这个组合拿到哪台电脑都能跑。Spring Boot 3.x 虽然是趋势但它强制要求 JDK 17以前的很多第三方库和 demo 代码都需要调整对时间紧张的毕设阶段来说完全不值得。具体版本对照可以参考下表组件推荐版本说明JDK1.8 (8u201)稳定、主流避免高版本环境问题Spring Boot2.7.14资料丰富兼容性好MyBatis Plus3.5.3.x自动填充、分页插件都稳定MySQL5.7 / 8.0生产常用二者均可8.0 需要配置驱动或时区Maven3.6.3建议内嵌的 Maven 仓库也可但独立 Maven 更好排查依赖前端模板Thymeleaf 3.0服务端渲染完成简单页面效率很高2.2 数据表设计的完整思路游戏分享网站的数据表不需要太多但每张表的关系要想清楚。我的表结构设计如下user用户表字段包括id、username、password、nickname、avatar、role、create_timerole用整数区分普通用户和管理员就不需要单独建权限表了。category游戏分类表id、name比如动作、冒险、角色扮演、休闲等。game游戏信息表id、category_id、title、cover、intro、download_url、view_count、create_time游戏封面保存的是文件上传后的访问路径不是二进制。comment评论表id、game_id、user_id、content、create_time用来实现用户对某个游戏的评论。favorite收藏表id、game_id、user_id、create_time收藏功能是一张独立表后面统计“多少人收藏”非常方便。这几张表之间就是最简单的外键关系game多对一categorycomment和favorite多对一game、多对一user。毕设阶段不要动辄设计中间表、父子级联、冗余字段逻辑越清楚代码写起来越快。2.3 MyBatis Plus 根据实体类生成建表 SQL 的实践这里特地提一个热搜关键词里出现频率很高、新手基本都遇到过的问题“MyBatis Plus 根据 Java 实体类生成创建表的 SQL 语句”。很多同学用 MyBatis Plus 主要是冲着 CRUD 接口去的忽略了它本身可以通过实体类注解自动生成建表能力。在application.yml中开启相关配置后实体类上写好TableName、TableId、TableField启动时框架就能按实体字段自动维护表结构。这样做的好处是当你后知后觉发现要加一个字段时不用自己手动写ALTER TABLE去维护两套东西实体定义就是唯一可信来源。不过坦白讲毕设项目我更推荐“实体类 手动 SQL”双保险先用数据库客户端建好表然后在实体类里一一对应字段。原因很现实团队协作和毕设答辩都更喜欢你展示出“你会写 SQL、理解表结构”的能力而不是全丢给框架。MyBatis Plus 自动建表适合自己快速跑 demo但要保证数据库字段类型精确可控手动建表依然最稳妥代码里使用TableField和你手动建表字段完全对齐即可。3. 核心功能实现与实操要点3.1 用户注册登录与密码安全注册登录是几乎每个毕设都跑不掉的模块也是面试和答辩必问的“安全”环节。很多初学教程还在用明文或简单的 MD5 保存密码这放在自己练手没问题但论文里写“用户密码采用 MD5 加密存储”会被老师一票否决。推荐的做法是使用 BCrypt 密码哈希Spring Security 里自带的BCryptPasswordEncoder可以直接拿来用不用真的引入整套 Security 过滤链。注册流程里的核心代码如下Service public class UserServiceImpl implements UserService { Autowired private UserMapper userMapper; private static final BCryptPasswordEncoder ENCODER new BCryptPasswordEncoder(10); Override public Result register(String username, String password, String nickname) { // 1. 唯一性校验 if (userMapper.selectByUsername(username) ! null) { return Result.error(用户名已存在); } // 2. 加密存储 User user new User(); user.setUsername(username); user.setPassword(ENCODER.encode(password)); user.setNickname(StringUtils.hasText(nickname) ? nickname : username); user.setRole(0); user.setCreateTime(new Date()); userMapper.insert(user); return Result.success(注册成功); } Override public User login(String username, String password) { User user userMapper.selectByUsername(username); // 注意BCrypt 的 matches 方法做密码比对 if (user ! null ENCODER.matches(password, user.getPassword())) { return user; } return null; } }登录成功后的会话管理我建议直接用HttpSession保存用户对象再写一个简单的LoginInterceptor做登录态拦截很多页面请求被拦截时通过UserUtil.getCurrentUser()就能拿到当前登录用户。这样一个从零实现的方案比直接上 Spring Security 更能在答辩时讲清楚“session 是什么、拦截器是什么、为什么拦截静态资源放行”技术含量足够但不会给自己挖坑。提示注册登录接口里必须做好参数非空校验、长度校验。我把这些写在Controller层做的原因很简单毕设代码量不大没必要为了用Valid注解再额外生成一堆校验类只要行为正确就可以。但答辩时可以主动说一句“正式项目建议用 JSR 303 注解校验”反而加分。3.2 游戏发布、封面上传与列表分页游戏分享网站里最核心的实体是游戏信息普通用户在前台主要浏览游戏管理员在后台负责发布和维护游戏内容。发布游戏时涉及封面图片上传这属于 Spring Boot 文件上传的经典题目。我的实现思路是在application.yml里配置一个自定义的上传目录比如file.upload-folderD:/upload/game-cover/。Controller 接收MultipartFile生成随机文件名并保存到目录。数据库里只存/files/cover/xxx.jpg这样的相对访问路径。写一个本地资源映射WebMvcConfigurer把本地路径映射为 URL 访问。这样做的好处是不依赖任何第三方对象存储单机部署完全够用。下面是我常用的映射配置片段Configuration public class WebConfig implements WebMvcConfigurer { Value(${file.upload-folder}) private String uploadFolder; Override public void addResourceHandlers(ResourceHandlerRegistry registry) { // 将磁盘路径映射到 /files/** 访问路径注意最后要有分隔符 registry.addResourceHandler(/files/**) .addResourceLocations(file: uploadFolder); } }游戏列表的分页则直接使用 MyBatis Plus 的分页插件。配置一个MybatisPlusInterceptor在Configuration类里注册PaginationInnerInterceptor然后 service 层调用page(new Page(current, size), wrapper)就能拿到分页数据。这里有一个细节容易忽略数据库里的view_count是统计访问量的每次用户打开详情页时不要直接 UPDATE 一个随机数字而是使用UPDATE ... SET view_count view_count 1这种 SQL 原子递增写法在并发场景不会因为并发丢数据答辩时提出这一点会很加分。3.3 评论与收藏功能的表关联实现评论和收藏很适合放在同一个章节里讲因为它们都是典型的“你需要联表查询当前登录用户是否操作过”的场景。先说评论功能前台展示游戏详情页时要同时查“这个游戏下的所有评论 每条评论的发表人昵称”这天然是一个多表关联需求。MyBatis Plus 中我习惯的做法是在CommentVO里添加nickname字段在 Mapper XML 里写一个SELECT c.*, u.nickname FROM comment c LEFT JOIN user u ON c.user_id u.id WHERE c.game_id #{gameId} ORDER BY c.create_time DESC。收藏功能更简单但要注意唯一约束。favorite表要建UNIQUE KEY uk_user_game (user_id, game_id)这样在代码层面执行“点赞/取消收藏”切换动作时不需要先查询再判断直接用INSERT ... ON DUPLICATE KEY UPDATE或者业务层里“先查再插”都可以。我实际开发中用了带事务的deleteOrSave逻辑代码可读性更好Transactional public boolean toggleFavorite(Long userId, Long gameId) { Favorite favorite favoriteMapper.selectOne(new LambdaQueryWrapperFavorite() .eq(Favorite::getUserId, userId) .eq(Favorite::getGameId, gameId)); if (favorite ! null) { favoriteMapper.deleteById(favorite.getId()); return false; // 已收藏本次操作取消收藏 } Favorite newFavorite new Favorite(); newFavorite.setUserId(userId); newFavorite.setGameId(gameId); newFavorite.setCreateTime(new Date()); favoriteMapper.insert(newFavorite); return true; // 本次操作为收藏 }评论和收藏的数据都在用户交互后实时变化所以在 controller 层的返回体里设计一个ResultT统一返回数据、提示信息和状态码前端就能用同一个逻辑处理接口回包。统一的返回结构对毕设特别重要因为后面写论文画系统时序图的时候能非常清晰地表述每个接口的请求与响应路径。3.4 后台管理做减法用拦截器实现权限控制后台管理不要做成“一个庞大的 vue 项目”对毕设来说一个独立的/admin前缀页面集合就很好。这里的技术要点是权限控制推荐用拦截器而不是 Spring Security因为拦截器足够简单且容易在论文里画图描述。在WebConfig中注册自定义拦截器public class AdminInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { User user (User) request.getSession().getAttribute(currentUser); if (user ! null Integer.valueOf(1).equals(user.getRole())) { return true; } // 未登录或非管理员重定向回登录页 response.sendRedirect(/admin/login); return false; } }注册时只需要拦截/admin/**注意放行/admin/login否则会形成重定向死循环。后台管理的功能我最终只保留了游戏分类管理、游戏信息管理、用户列表、评论列表四个页面。很多同学会把后台做成“用一堆统计图表展示注册用户、浏览量、评论数量”的大屏这是典型过度设计因为数据量不足时这些图表毫无意义。4. 部署全流程与环境适配4.1 本地环境准备与数据库初始化部署部分往往是整个项目里最琐碎的但也是很多同学第一次面对“我的代码在别人电脑上跑不起来”的根源。先说环境准备按推荐版本装好 JDK 8、Maven 3.6 和 MySQL 5.7/8.0。数据库初始化时不要在图形化工具里手动点按钮创建库而是把建表和测试数据的 SQL 文件直接从项目里导出来用命令行执行CREATE DATABASE IF NOT EXISTS game_share DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE game_share; -- 后面跟建表语句和 INSERT 语句使用utf8mb4是必须的细节否则后面插入玩家的中文昵称、游戏简介里的 emoji 表情都可能出现乱码或报错。推荐把schema.sql和data.sql分开放这样答辩时可以展示“项目使用 SQL 脚本初始化数据方便部署”。之后需要在application.yml里配置数据源spring: datasource: url: jdbc:mysql://localhost:3306/game_share?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: root password: 你的密码 driver-class-name: com.mysql.cj.jdbc.Driver注意 MySQL 8.0 的驱动名是com.mysql.cj.jdbc.Driver如果你看的老教程写的是com.mysql.jdbc.Driver启动时大概率会报驱动类找不到或者时区错误。这是我反复帮人改过的问题。4.2 使用 Maven 打包并启动 Jar毕设项目的交付物我强烈推荐打成可执行 jar 包部署而不是在 IDEA 里点运行给别人看。因为“把 IDEA 里的项目跑到别人的电脑上”是新手很难说清楚的事情而一个java -jar命令任何人都能复现。在终端里执行mvn clean package -DskipTests打包产物在target/目录下是一个以项目名命名的.jar文件。启动时记得确认端口没被占用java -jar target/game-share-0.0.1-SNAPSHOT.jar如果希望端口改掉用启动参数设置java -jar target/game-share-0.0.1-SNAPSHOT.jar --server.port8081Spring Boot 的spring-boot-maven-plugin默认会把依赖一起打进 fat jar所以这个单文件包就可以脱离 IDEA 运行。我实际测下来Windows 和 Linux 环境下都能直接运行只要 JDK 版本匹配。打包出一个 jar 后再去做部署视频后续同学照着视频配环境、导数据库、跑包成功率会高很多。注意如果启动时报 “Error: A JNI error has occurred, please check your installation and try again”基本就是 jar 包编译用的 JDK 和你运行用的 JDK 版本不一致务必统一成 JDK 8。还有一种情况是 Maven 编译时依赖没下载完先确认本地的repository目录是完整的最好用阿里云镜像仓库下载依赖。4.3 演示视频录制的核心节奏标题里提到了“演示视频”这点我单独拿出来说几句因为它经常被误解成“随便录个半小时的冗长视频”。毕设演示视频的核心价值不是展示每一行代码而是展示“项目在真实环境里跑起来的样子”所以最好的节奏是片头展示项目基本信息 → 启动 jar 包 → 浏览器打开前台首页 → 演示注册、登录、浏览、关注、评论 → 切换到后台登录 → 添加一个游戏 → 审核/删除评论 → 结束。总时长控制在 8 到 12 分钟最合适。录制时注意浏览器窗口不要出现其他无关标签、桌面文件、聊天窗口也不要在操作时打开代码里没有任何说明的页面。我会先把 Windows 的通知提醒全部关闭再用 OBS 或 EV 录屏画质选择 1080P视频中如果操作失误不要犹豫直接重新录制这一段后剪辑也能做但毕设视频我建议一镜到底真实感更强。5. 常见问题排查与避坑实录5.1 Spring Boot 版本太高引发的连锁问题这个坑真的是我见到的数量最多的。某同学自己从 Spring Initializr 上选了 Spring Boot 3.2 Java 17然后搜到的教程全部是 2.x 时代的代码于是出现一堆诡异的报错javax.servlet变成了jakarta.servlet导致各种HttpServletRequest引用不对MyBatis Plus 的自动配置失效spring.factories自动配置的方式改成了AutoConfiguration.importsThymeleaf 的很多属性写法也变了。我的建议前面已经提到直接用 2.7.x。但已经用了 3.x 的同学也不是非要推倒重来至少要把代码里的import javax.servlet.*全局替换成import jakarta.servlet.*同时检查 MyBatis Plus 是否升级到支持 Spring Boot 3 的版本。这些细节在论文里的技术选型部分也要讲清楚不要出现论文写 2.7 而代码是 3.x 的“文不对码”情况答辩时非常减分。5.2 MyBatis Plus 自动填充常见错误很多教程都会教你在插入实体时自动填充create_time使用 MyBatis Plus 的MetaObjectHandlerComponent public class MyMetaObjectHandler implements MetaObjectHandler { Override public void insertFill(MetaObject metaObject) { this.strictInsertFill(metaObject, createTime, Date.class, new Date()); } Override public void updateFill(MetaObject metaObject) { this.strictUpdateFill(metaObject, updateTime, Date.class, new Date()); } }但这里有个极易踩坑的点如果你的实体类createTime字段没有加TableField(fill FieldFill.INSERT)这个自动填充方法永远不会生效。而且如果你想在插入后返回自动生成的id必须在数据库主键设置为AUTO_INCREMENT同时实体主键字段上标注TableId(type IdType.AUTO)。遇到插入成功但getId()拿不到值时十有八九是主键策略没配对。5.3 数据库中文乱码与分页查询性能数据库中文乱码是最容易排查又最容易复发的问题。代码层面已确认用了utf8mb4的前提下表的默认字符集也要检查如果是 MySQL 5.7直接在客户端执行ALTER TABLE game CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;如果是 MySQL 8.0默认字符集基本正常重点检查连接 URL 是否带了characterEncodingutf8。分页查询这块新手最容易写成“查出全表再在内存里截取”比如直接用selectList再加list.stream().skip(pages).limit(size)。这样在数据量几十条时看不出问题但答辩时如果老师质疑你会非常被动。MyBatis Plus 的分页插件是数据库层limit分页性能上完全站得住。另外分页参数要直接从Page对象中取total用于前台分页组件不要在前端再写一个“首页、上一页、下一页”的硬编码逻辑。5.4 端口占用与静态资源 404 问题开发时最常遇到的报错之一是Port 8080 was already in use。Windows 下我一般用三条命令搞定netstat -ano | findstr 8080 taskkill /PID 进程号 /F如果是静态资源 404多半是前面提到的资源映射路径没配置对。控制台里的访问路径和磁盘路径之间的斜杠方向、末尾分隔符都很敏感Windows 下推荐把上传目录配置在D:/xxx/这种绝对路径可以少碰反斜杠在字符串里被转义的坑。总之遇到问题先看控制台完整异常堆栈大多数问题都比想象中简单不要一上来就怀疑框架坏了。6. 经验心得与后续扩展这个项目做下来我个人最深的体会是毕设不在于题目多新、功能多多而在于每个功能是否都经得起问。游戏分享网站这个题目我可以很负责地说只要按“需求分析 → 数据库设计 → 后端接口 → 前台页面 → 后台管理 → 部署测试”这条路一步步走代码基本都能在两到三周内完成剩余的时间应该重点打磨论文里的系统架构图、功能模块图、时序图和部署说明。有几个小技巧分享给后面再做这个题的人。第一开发一开始就写在本地启动jar包的方式验证功能不要一直依赖 IDEA 运行按钮。这样你才能尽早暴露出“别人拿到项目后能不能跑起来”的真实问题。第二数据库测试数据至少准备 15 到 20 条覆盖所有分类页面展示效果会明显更有说服力。第三答辩用到的演示文档和说明文档把每个功能点和技术点做一张对照表老师问哪个都能迅速找到对应页心态完全不一样。如果做完基础版还想再往上拔一拔有几个扩展方向可以选引入 Redis 做热门游戏排行榜和浏览量缓存引入 Elasticsearch 做搜索提示不过这个对毕设来说工作量有些大不推荐硬上或者把下载链接改成虚拟路径并增加文件下载次数统计。这些扩展会用到缓存、消息队列、全文检索技术对于找 Java 相关工作而言是不错的亮点但前提是基础功能一定要先做到无懈可击。回到标题里的那句话所谓“全 bao 一条龙”落到项目里其实就是一套完整可交付的产物清晰的设计思路、合理的技术选型、能跑起来的源码、完善的部署说明和演示录屏。这篇写完如果你也准备做这个题目照着这些步骤走下来项目完成度和答辩质量大概率不差。最后再啰嗦一句遇到环境问题别慌先看日志再查版本最后才是问别人独立解决问题的能力永远是做毕设最值钱的收获。