每年到了毕业季,Java方向的毕设咨询里,至少有一半都是同一类问题:
“博主,能不能推荐一个难度适中、技术栈主流、能写论文也方便答辩的项目?”
如果你也在找这样的题目,“基于SpringBoot的游戏分享网站”是很稳的一个选择。这个题目表面看是一个内容社区,实际上把JavaWeb开发最常用的技能点全带上了:用户登录、权限控制、CRUD、分页搜索、文件上传、评论收藏。每一个点,也都是面试和答辩的高频问题。更关键的是,它的业务逻辑足够直观,评委老师不需要太多背景知识就能看懂你在做什么。
这篇文章我不打算把一整套源码从头到尾贴一遍,而是从选题到落地,把项目的需求分析、数据库设计、核心功能实现、文档准备和踩坑记录,一条条拆开讲。凡是涉及代码的部分,都尽量给你最简可运行的版本;涉及设计思路的地方,也会说清楚“为什么这么做”。适合正在做毕设的同学,也适合想用SpringBoot练手做个人项目的开发者。如果你手上已经有现成的源码包和文档,更建议你对照这篇文章的模块梳理自查一遍,比跟着网上各种旧教程瞎改配置要靠谱得多。
1. 先想清楚:游戏分享网站到底要做什么
1.1 你做的不是一个游戏下载站
很多同学一看到“游戏分享网站”,第一反应是把项目做成“游戏下载站”:堆游戏文件、放安装包、做下载计费。如果真按这个思路做,先不说版权问题,单说文件存储和下载流量,就能把一台学生服务器压垮,而且答辩时老师大概率会追问“你这些游戏资源从哪来?版权怎么处理?文件存本地还是云OSS?”一旦答得含糊,项目分数直接受影响。
我建议你把“分享”定位成:信息分享和玩家社区,而不是资源分发。系统维护一个游戏库,用户可以发布游戏介绍、截图、玩法攻略,其他用户浏览、搜索、收藏、评论、评分。游戏文件的分享,可以用外链形式简单处理,或者干脆用模拟数据演示。这样既保留“游戏分享”的选题立意,又避开了大文件存储的复杂工程,难度也刚好控制在本科毕设的合理区间。
1.2 前台和后台功能怎么划分
一个能拿良好以上成绩的毕设,功能上一般要能看到“前台展示”和“后台管理”两条线。
前台用户端(面向普通游客和注册用户)通常包括这些模块:
- 用户注册与登录(游客可以浏览,登录后才能收藏和评论)
- 游戏列表浏览,支持关键词搜索和分类筛选
- 游戏详情页,展示封面、简介、所属分类、发布者、发布时间
- 评分功能,用户对游戏打分,系统自动计算平均分
- 评论功能,用户对游戏发表看法,管理员可管理
- 收藏功能,用户可以收藏感兴趣的游戏,在个人中心查看
- 个人中心,维护个人资料、查看自己发布的游戏和收藏记录
后台管理端(面向管理员)则要覆盖:
- 管理员登录,区别于普通用户的角色权限
- 游戏管理:新增、编辑、上下架、删除游戏
- 分类管理:维护游戏分类,比如动作、角色扮演、休闲、竞速等
- 用户管理:查看注册用户列表、禁用异常账号
- 评论管理:删除违规评论
- 基础数据统计:统计用户数、游戏数、总浏览数,用来给论文画图表
这个功能规模,不大不小,刚好能支撑起论文里的业务分析、用例图、时序图和数据库ER图,也不会把自己写死在开发路上。
1.3 技术栈为什么选 SpringBoot + MyBatisPlus
结论先放在前面:如果你对前端不熟,就选 SpringBoot + MySQL + MyBatisPlus + Thymeleaf 模板引擎;如果你会基础的 Vue 和接口调用,就改成前后端分离,后端 REST 接口 + JWT 鉴权,前端用 Vue3 + Element Plus。这两种方案都能拿得出手,差别在于你的时间和精力。
SpringBoot 解决了 SSH/SSM 时代最烦人的配置问题,内嵌 Tomcat 一键启动,非常适合毕业生快速搭建项目。MyBatisPlus 则是在 MyBatis 基础上做了一层增强,把单表 CRUD 全部内置到 BaseMapper 里,不需要写一长串 XML 就能完成绝大部分操作,这对赶毕设的同学来说就是“救命稻草”。再配上 Lombok 减少 getter/setter,配上 Hutool 工具类处理日期和随机数,整体开发效率会高很多。
一定要想清楚的是:技术栈不需要多“新”,但你必须能把每个组件的存在理由讲明白。比如老师问你“为什么用 MyBatisPlus?”你如果说“因为不用写 SQL”,那大概率会被追问“那你 SQL 能力是不是不行?”更合适的回答是:“MyBatisPlus 帮我把单表 CRUD 的基础操作封装好了,我可以把时间花在业务逻辑上,但复杂的多表查询我还是手写了 XML。”这句话在职场上也吃香。
2. 数据库设计决定答辩高度
2.1 核心实体与关系
游戏分享网站的数据库模型核心围绕五个实体:用户、游戏、分类、评论、收藏。它们之间的关系用一句话就能说清:一个用户发布多个游戏,一个游戏属于一个分类,一个用户可以对一个游戏发多条评论、加一次收藏。
用户和游戏是“一对多”,游戏和分类是“多对一”,用户和游戏通过评论、收藏形成两个“多对多”关系。这里注意一个细节:我把收藏设计成单独一张表,而不是在游戏表里加一个收藏数字段。收藏表既能记录“谁收藏了哪个游戏”,后续要扩展“收藏时间排序”“消息通知”都方便。至于游戏表里面的收藏数字段,可以用统计更新来实现,也可以直接每次查询时 count 收藏表,毕设规模下性能完全够。
2.2 关键表的字段设计
我直接给一套经过验证的表结构,你建库时可以参考。用户表建议用 t_user 而不是 user,避免和 MySQL 系统的概念混淆。
| 表名 | 字段 | 类型 | 说明 |
|---|---|---|---|
| t_user | id | bigint 自增主键 | 用户ID |
| t_user | username | varchar(50),唯一索引 | 用户名 |
| t_user | password | varchar(100) | BCrypt加密后的密码 |
| t_user | nickname | varchar(50) | 昵称 |
| t_user | avatar | varchar(255) | 头像URL |
| t_user | varchar(100) | 邮箱 | |
| t_user | role | tinyint | 0普通用户,1管理员 |
| t_user | status | tinyint | 0正常,1禁用 |
| t_user | create_time | datetime | 注册时间 |
游戏表的核心字段如下:
| 表名 | 字段 | 类型 | 说明 |
|---|---|---|---|
| t_game | id | bigint 自增主键 | 游戏ID |
| t_game | game_name | varchar(100) | 游戏名称 |
| t_game | cover_url | varchar(255) | 封面图片地址 |
| t_game | intro | text | 游戏简介 |
| t_game | content | text | 详细内容或攻略心得 |
| t_game | category_id | bigint | 所属分类ID,逻辑外键 |
| t_game | publisher_id | bigint | 发布者ID |
| t_game | avg_score | decimal(3,1) | 平均评分 |
| t_game | view_count | int | 浏览数 |
| t_game | status | tinyint | 0草稿,1上架,2下架 |
| t_game | create_time | datetime | 发布时间 |
| t_game | update_time | datetime | 更新时间 |
分类表很简单:id、category_name、sort_order、create_time。评论表需要记录 id、game_id、user_id、content、create_time,并建议给 game_id 加普通索引,因为查看一个游戏的评论是高频操作。收藏表则用 id、game_id、user_id、create_time,并且给 user_id + game_id 建唯一索引,防止同一用户重复收藏。
2.3 建表阶段最容易踩的坑
第一个坑是字段类型乱用。比如简介和详情用 varchar 硬撑,超过长度就报错;比如布尔值用 char(1) 存 “是/否”,Java 映射时别扭得很。毕设阶段不需要炫技,字符串用 varchar、长文本用 text、数值用 int/decimal、时间用 datetime,规规矩矩来就行。
第二个坑是逻辑外键和物理外键的纠结。我建议不加数据库外键约束,只在 Java 代码里通过 service 层保证关联关系的有效性。原因很现实:你后面写单元测试、造测试数据的时候,物理外键会时常跳出来报“删除被限制”,答辩现场演示时报一个外键错误,场面很难看。逻辑外键配合清晰的代码注释,已经足够在论文里把关系说清楚了。
第三个坑和 MyBatisPlus 有关。如果你希望根据 Java 实体类直接生成创建表的 SQL 语句,可以用 MyBatisPlus 的注解驱动方式,在实体字段上加 @TableName、@TableId、@TableField 注解,然后借助 IDEA 的数据库工具脚本生成。但更推荐的做法是反过来:先把表结构设计好,再在实体类上画等号。这样 SQL 的命名规范和字段注释完全由你控制,后面的测试数据也好造。
3. 从零搭建:核心功能落地方案
3.1 SpringBoot 版本别乱选
这是很多同学一上来就踩的大坑。网上教程一搜一大把,有人用 SpringBoot 2.3,有人用 2.7,还有人直接上 3.x。不同版本之间差异很大,尤其是 SpringBoot 3.x 要求 JDK 17 起步,并且把 javax 命名空间换成了 jakarta。如果你的电脑装的是 JDK 8,强行用新版 SpringBoot 会连项目都启动不起来。
我的建议分情况:
- 如果你要在本机跑通、要稳定,选 SpringBoot 2.7.18 + JDK 8 + MyBatisPlus 3.5.x,这是目前兼容性最好、网上资料最多的组合。
- 如果你的机器已经是 JDK 17 或 21,选 SpringBoot 3.2.x + MyBatisPlus 3.5.5 以上版本,配合对应版本的重置适配包,也完全能跑。
- 不推荐用 Gradle 还是 Maven?毕设优先 Maven,因为最主流的教程、私服配置都是 Maven 的。Gradle 你以后工作再学,完全来得及。
另外,本机装多个 JDK 的同学,记得在 IDEA 的项目结构里统一 Project SDK、Modules SDK、Java Compiler 的版本。只改一个地方,最后编译还是报“invalid source release”的情况我见过太多次了,原因就是三处版本没对齐。
数据库连接层面,如果你跟着教程用 application.properties,建议改成 yml 格式,结构更清晰。下面是一个实用的配置片段:
server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/game_share?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver 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: 0map-underscore-to-camel-case 这个配置一定要开,它负责把数据库的 game_name 自动映射成实体的 gameName,省掉一大波手写映射的麻烦。
3.2 数据访问层:用 MyBatisPlus 高效落地
项目里的数据访问层,建议每个实体对应 Mapper 接口,然后继承 BaseMapper。比如游戏表的 Mapper 就写一行:
@Mapper public interface GameMapper extends BaseMapper<Game> { }这样插入、更新、按ID查、按ID删、按条件统计等操作都是现成的。Service 层建议继承 IService,实现类继承 ServiceImpl,比如:
public interface GameService extends IService<Game> { } @Service public class GameServiceImpl extends ServiceImpl<GameMapper, Game> implements GameService { }不要小看这一套继承关系,它帮你省掉的 CRUD 代码量非常直观,而且当你需要自定义 SQL 时,还能往 Mapper 里加方法、写 XML,完全不影响。
分页是我在毕设里几乎每次都会用到的功能,MyBatisPlus 的分页插件需要手动配置一个拦截器:
@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }配置完这个才可以用 Page 对象做分页查询,否则你传了 Page 进去也会被当成全表查询。这个坑非常典型,我见过不少人说“分页没效果”,打开日志一看,SQL 里压根没有 LIMIT。
3.3 登录鉴权怎么做最简单可靠
这个项目里的登录鉴权,不用一上来就上 Spring Security 那一套复杂流程。如果你用 Thymeleaf 模板方案,直接用 Session + 拦截器即可;如果你走前后端分离,建议用 JWT + 拦截器。
JWT 的思路是:用户登录成功后,服务端生成一个带过期时间的 token 返回给前端,前端在后续请求的请求头 Authorization 中携带它。拦截器里校验 token,能验过就放行。
核心代码可以精简成三个部分。
登录成功后生成 token:
String token = Jwts.builder() .setSubject(user.getUsername()) .claim("userId", user.getId()) .claim("role", user.getRole()) .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24)) .signWith(SignatureAlgorithm.HS256, secretKey) .compact();拦截器校验 token:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("Authorization"); if (StringUtils.hasText(token) && JwtUtil.verify(token)) { return true; } response.setStatus(401); return false; }在 WebMvcConfigurer 中注册拦截器,并放行登录接口、注册接口、首页列表接口等公开地址。
密码存储必须用 BCrypt 加密,不要用 MD5。原因很简单:BCrypt 自带盐值,同一密码每次加密结果都不同,即使数据库泄露,彩虹表也基本无能为力。Spring Security 的 crypto 模块里直接有 BCryptPasswordEncoder,单独引入这个依赖就行,不需要为了它把 Security 全家桶都加进来。
3.4 文件上传:封面图是刚需
游戏分享网站必然涉及封面图上传。如果你不了解文件上传的细节,最直接的表现是“图片上传成功,但页面打不开”。
一个稳妥的上传处理逻辑是:接收 MultipartFile 文件,重命名为 UUID + 原扩展名,然后保存到指定的本地目录,比如项目根目录下的 upload/cover/。重命名是为了防止文件名冲突,也是防止路径穿越的基本姿势。上传接口写完以后,还要写一个静态资源映射,把 /upload/** 这个 URL 前缀映射到本地的 upload 目录。否则 SpringBoot 默认只服务 classpath 下的 static 资源,你上传的图片路径是访问不到的。
为了毕设演示方便,我建议在 yml 里配置一个自定义的存储路径,避免不同电脑之间路径不统一导致图片失效。
upload: path: E:/git-repo/game-share/upload/public String uploadFile(MultipartFile file) { String originalFilename = file.getOriginalFilename(); String ext = originalFilename.substring(originalFilename.lastIndexOf(".")); String fileName = UUID.randomUUID() + ext; File dest = new File(uploadPath + fileName); file.transferTo(dest); return "/upload/" + fileName; }部署到 Linux 服务器时,再把路径改成 /home/app/upload/ 这类目录,并用宝塔面板或者 Docker 挂载持久化目录,就可以直接用于演示。更多部署细节,后文会单独提。
3.5 搜索分页的核心条件构造
搜索是这个网站的灵魂功能。用户在搜索框输入关键词,按下搜索,后台要做三件事:按游戏名称模糊匹配;按分类过滤;按上架状态过滤并且分页返回。
用 MyBatisPlus 的 LambdaQueryWrapper 可以很优雅地写出这个逻辑:
Page<Game> page = new Page<>(current, size); LambdaQueryWrapper<Game> wrapper = new LambdaQueryWrapper<>(); wrapper.like(StringUtils.hasText(keyword), Game::getGameName, keyword) .eq(categoryId != null, Game::getCategoryId, categoryId) .eq(Game::getStatus, 1) .orderByDesc(Game::getViewCount); GameDTO gamePage = gameService.page(page, wrapper);重点在于 like 和 eq 方法前面的条件参数。keyword 为空时,这个条件不拼进 SQL;categoryId 为空时同理。这样就不需要为“有搜索词”和“无搜索词”各写一套查询逻辑,代码也更好读。
前端列表页还要展示平均评分,这个评分建议单独维护在游戏表里,用户打新分时增量更新。如果要做得严谨一些,评分记录表存每一次打分,列表页只查平均值。
4. 文档与答辩准备:源码之外的硬功夫
4.1 项目结构要长成一眼懂的样子
包结构是老师重点看的东西之一。一个清晰的分层,比炫酷的代码技巧更能加分。推荐的项目包结构大致如下:
game-share/ ├── pom.xml ├── sql/ │ └── game_share.sql └── src/main/java/com/example/gameshare/ ├── GameshareApplication.java ├── config/ # 配置类:静态资源映射、MybatisPlus配置、拦截器注册 ├── controller/ # 接口层:UserController、GameController、CommentController ├── service/ # 业务层:接口 + impl实现 ├── mapper/ # MyBatisPlus的Mapper接口 ├── entity/ # 实体类 ├── dto/ # 请求参数封装和返回封装 ├── common/ # 统一返回结果、异常处理、常量 └── util/ # JwtUtil等工具类这样的结构,任何人打开项目都能在三秒内找到“控制器在哪”“启动类在哪”。论文里画系统架构图的时候,直接按这个分层来画,评委看了也不会质疑。
4.2 三份核心文档怎么又快又好地写
毕设文档和代码同样重要。我见过不少同学代码写得很好,但文档一塌糊涂,最后分数被拉下来。重点准备三份东西。
需求文档包含项目背景、用户角色分析、用例图、功能列表和部分原型图。不要抄百度百科式的空话,而要写“本系统面向游戏爱好者,提供游戏信息浏览、评分和评论服务”这类具体描述。功能列表可以用表格列出编号、模块、功能点、优先级、描述,方便老师一眼看到你的工作量。
数据库设计文档要把E-R图放上去,然后逐表列出字段名、类型、约束、说明,最好在每条字段的备注里写清楚业务含义。评审老师很喜欢看这个,因为它能证明你真的设计了系统,而不是从网上扒的现成代码。
部署文档是很多人忽略但实际很重要的一环。里面要写清楚:环境要求(JDK版本、MySQL版本)、数据库初始化步骤、配置文件修改点(数据库账号密码、上传路径)、启动方式和访问地址。如果你出了项目给老师演示,一台新电脑上能按你的文档跑起来,这就是巨大的加分项。
4.3 演示项目的黄金逻辑
答辩演示不是展示代码,而是讲故事。我建议按这条线来演示:登录系统(区分管理员和普通用户)—管理员添加一个游戏分类和一款游戏并上传封面—切到前台,游客看到游戏已上架—注册一个普通用户—用户查看详情、收藏、评论、评分—管理员在后台看到新增评论并完成审核/删除—最后用数据库或后台统计说明数据变化。
这套流程走下来,基本上把核心功能全部覆盖了。提前准备两个测试账号,一个管理员,一个普通用户,最好再预置10条左右分类和游戏数据。演示时注意不要把数据库里的脏数据露出来,页面排版和数据整洁度非常影响第一印象。
如果你做到前后端分离,还要准备解决跨域问题。SpringBoot 侧用 CORS 配置类统一处理即可,不然前端地址和后端地址不一致时,浏览器会拦截所有请求。
5. 常见问题与避坑实录
5.1 SpringBoot 版本太高引发的连锁反应
现在网上许多新教程都是 SpringBoot 3.x,如果你跟着做,又还在用 JDK 8,会先遇到“程序包 javax.servlet 不存在”这类编译错误。这是因为 3.x 已经全面切换到 jakarta.servlet。还要注意,MyBatisPlus 的老版本不兼容 SpringBoot 3,必须用 3.5.5 及以上的版本。
我的处理口诀是:
- 项目用什么 JDK,就选什么 SpringBoot 版本,千万不要乱。
- JDK 8 配 SpringBoot 2.7.18,starter-web 里自带的是 Tomcat 9。
- JDK 17 配 SpringBoot 3.2.x,内部是 Tomcat 10 / 10.1。
- 涉及 javax 的第三方依赖在 SpringBoot 3 里基本不能直接用,能替换就替换。
如果你在切换 JDK 时遇到“Error: java: Invalid source release: 17”,八成是 IDEA 的 Project Structure 里的语言级别没改成对应版本,把它和 Settings 里的 Java Compiler 都改成一样的,就能解决。
5.2 根据实体类生成建表SQL的正确姿势
这个需求我在项目里反复用到:实体类定义好以后,希望自动生成建表SQL,省得手写一遍。MyBatisPlus 本身有一个 MybatisDDL 思路,结合 SpringBoot 启动时扫描指定的实体类路径,可以自动把不存在的数据表创建出来。不过这种方式生成的表字段注释和索引往往不符合预期,更适合快速原型,不适合正规毕设。正规项目我还是建议手写 MySQL 的 DDL 文件,放在项目的 sql 目录下。这样你有完全的控制权,数据库设计文档也顺手有了。
5.3 文件上传后的图片打不开
这是最容易在演示时翻车的坑。表现是上传成功,但页面图片裂开。排查步骤按优先级来:
- 看返回的 URL 前缀,确保映射路径和保存路径一致。
- 看 SpringBoot 静态资源映射,没有配置的话自行补充 WebMvcConfigurer。
- 看启动目录,用相对路径保存时,不同 IDE 的工作目录可能不一样,导致文件实际写在别处。
- 看浏览器控制台,是不是 404 还是(你刚才访问的URL)。
如果部署到 Linux,还要看目录的读写权限。Docker 部署时则要注意,容器内路径必须挂载到宿主机的持久化目录,否则容器一重建,所有上传图片都没了。
5.4 登录失效、跨域和拦截器放行问题
前后端分离项目最常见的报错是“请求被拦截”和“跨域请求被阻止”。拦截器放行接口时,建议把登录校验、注册、获取验证码、首页公开接口全部列入白名单。如果你在拦截器里需要区分用户和管理员,可以单独写一个角色校验拦截器,普通接口只校验登录,管理接口再校验 role。
CORS 配置不要在拦截器里硬写,那样容易和 SpringBoot 自带的处理冲突。更稳的做法是单独写一个配置类:
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .allowCredentials(true); } }不要小看 OPTIONS 预请求。前端带 Authorization 头的跨域请求,会先发一个 OPTIONS 请求,如果你的后端不允许 OPTIONS,前端会一直报跨域错误但你就是排查不出来。
5.5 答辩高频问题速查
把下面的问题背熟,基本能应对绝大多数评委:
| 问题 | 参考回答思路 |
|---|---|
| 为什么选 SpringBoot? | 简化配置、自动装配、内嵌服务器、生态成熟,适合快速交付项目 |
| SpringBoot 自动配置原理? | 通过 @EnableAutoConfiguration + META-INF/spring.factories 加载配置类,配合 @ConditionalOnClass 等条件注解生效 |
| MyBatisPlus 和 MyBatis 区别? | MyBatisPlus 在 MyBatis 上扩展了单表 CRUD,逻辑删除、自动填充、分页插件,复杂查询仍需手写SQL |
| 登录安全怎么保证? | 密码 BCrypt 加密,JWT 签名过期,服务端拦截器鉴权,敏感接口校验角色 |
| 分页怎么实现? | MyBatisPlus 分页拦截器自动拼接 LIMIT,避免一次性加载全表 |
| 数据库表之间的关联关系? | 逻辑外键关联,应用层维护一致性,避免物理外键低性能和高耦合 |
| 如果用户量很大怎么办? | 可以从 Redis 缓存热点游戏数据、页面静态化、数据库读写分离和前端 CDN 方向回答,能说出思路即可 |
5.6 最后一个建议
这套项目真正做下来,你收获最大的不是那一行行代码,而是调试能力。我从带毕设的经验里说句实话:直接拿别人的源码交差,基本逃不过老师的提问;但只要你自己把项目跑起来,改过几个bug,重新造过几张表,哪怕代码风格一般,都说得清项目的前因后果。这也是为什么我特别强调“把坑踩一遍”的价值。
如果你接下来要扩展这个项目,优先级建议是:先加 Redis 缓存热门游戏列表和验证码,再加管理员数据统计图表,最后考虑用 Docker 打包发布。这三步做完,你再拿去面试 Java 开发岗,项目经验这一栏也就有的写了。