Spring Boot游戏分享网站实战:从数据库设计到部署全流程
最近把一个基于 Spring Boot 的游戏分享网站从零到一完整做完了包括前端页面、后端接口、MySQL 数据库脚本以及配套的设计文档。这个选题在课程设计和毕业设计里属于常年都在出现的经典题目功能不复杂但胜在业务闭环非常完整——用户注册登录、游戏资讯浏览、攻略文章发布、评论收藏、后台管理一趟走下来几乎把 Spring Boot 最基础也最常用的技术点全部覆盖了。这篇文章我打算把整个项目的完整脉络讲清楚从需求拆解、技术选型、数据库设计、核心代码实现到环境搭建、部署运行、常见问题排查再到源码、数据库脚本和万字文档怎么配合使用尽量做到每一步都能直接参考复刻。不管你现在是刚开始准备选题还是已经写了几千行代码卡在某个问题上这篇文章都能提供一些可落地的思路。1. 项目整体设计思路与功能拆解1.1 为什么说游戏分享网站是课程设计的“黄金选题”每次有学弟学妹问我课程设计选什么题好我都会先反问一句你想不想在答辩的时候被老师追着问“这个功能为什么要这么设计”。如果不想那游戏分享网站这个方向就是一个非常稳妥的选择。原因很直接。第一它的功能足够常规常规意味着参考资料多、实现路线清晰哪怕中间遇到问题也能快速找到解决方案。第二它的功能边界又足够撑起一篇完整的设计文档从需求分析、概要设计、数据库设计到系统测试每一个环节都有东西可以写。第三它天然具备“用户端 管理端”的双角色模型这在答辩时是一个明显的得分点因为权限控制、会话管理这些内容都属于 Spring Boot 项目的核心知识。技术栈方面整个项目没有炫技成分就是 Spring Boot MyBatis-Plus MySQL Thymeleaf/Vue 这种最常见组合。正因为常见才适合课程设计。你想想如果选题用了微服务、分布式、消息队列这些代码写起来吃力不说答辩时老师随便追问一个底层原理就可能答不上来。游戏分享网站这种“麻雀虽小五脏俱全”的规模恰恰是把基础知识点吃透的最佳载体。1.2 用户端与管理端的核心功能模块这个项目从功能上可以分成两大块前台用户使用、后台管理员维护。两块共用同一套数据库通过不同角色权限来区分访问范围。前台用户端包括功能模块具体说明注册登录用户名/邮箱注册BCrypt 加密存储登录后 Session 保存用户状态游戏资讯浏览首页展示游戏推荐、最新资讯列表支持按分类过滤游戏详情页展示游戏封面、简介、开发商、发布时间、热度等信息文章分享用户可以发布游戏攻略、评测文章支持富文本编辑评论互动对文章和游戏发表评论支持评论列表分页展示收藏功能用户可以收藏喜欢的游戏或文章方便后续查看个人中心修改个人资料、查看自己发布的内容、管理收藏夹后台管理端包括功能模块具体说明管理员登录独立登录入口只有管理员账号可以进入用户管理查看注册用户列表禁用/启用账号分类管理维护游戏分类比如动作、角色扮演、策略等游戏信息管理增删改查游戏数据上传封面图文章审核管理审核用户发布的文章支持通过/驳回评论管理删除违规评论轮播图管理编辑首页轮播图内容数据概览统计用户数量、游戏数量、文章数量等基础数据这个功能列表不是凭空想出来的而是根据大部分游戏分享类站点的通用模型提炼出来的。对于课程设计来说做到这个程度已经完全足够而且每个模块背后都能对应到 Spring Boot 的分层结构Controller 接收请求、Service 处理业务逻辑、Mapper 操作数据库。1.3 角色权限与页面流程项目采用单一入口方式登录后根据用户角色跳转不同界面。普通用户登录后进入前台首页管理员登录后进入后台管理页。页面流转大致是这样的游客访问首页 - 能浏览游戏和文章但点击“发布文章”“评论”“收藏”时会跳转到登录页登录成功后自动跳回之前的页面普通用户进入个人中心管理员访问固定的后台地址通过拦截器校验角色身份。权限控制这部分我没有选择引入 Spring Security因为这个项目的安全需求并没有那么重自己基于拦截器实现反而更简洁直观也更容易在答辩时讲清楚。实现思路是在 Spring MVC 中注册一个 HandlerInterceptor拦截所有/admin/**和/user/**请求检查 Session 中是否存在登录用户对于后台请求还要额外检查用户角色是否为管理员。代码量不大但能有效保护接口安全。2. 核心技术点拆解Spring Boot 项目里最容易拿分的地方2.1 版本选型JDK 8 Spring Boot 2.7 是课程设计的最稳组合项目在版本选择上走的是保守路线。看到很多同学在网上搜项目源码时经常遇到一个问题——下载下来的项目版本太高本地 JDK 版本跟不上一启动就报错。网上搜“springboot版本太高”居然有那么多人踩坑说明这个问题确实普遍。我这里用的是 Spring Boot 2.7.18 JDK 8。为什么不用 Spring Boot 3.x因为 Spring Boot 3 强制要求 JDK 17 及以上而且很多老版本的依赖不兼容。课程设计场景下大多数同学的开发环境还是 JDK 8学校机房提供的也往往是老版本 JDK。选择 Spring Boot 2.7 可以最大限度避免环境不匹配的问题。当然如果你本机已经安装了 JDK 17直接用 Spring Boot 3.x 也没问题。但要注意两个差异第一javax.servlet相关的依赖要改成jakarta.servlet包名会变第二MyBatis-Plus 需要引入支持 Spring Boot 3 的专门版本。这些细节在移植项目时非常容易踩坑所以我会更推荐先统一到 JDK 8 Spring Boot 2.7。另外还要注意 Spring Boot 2.7 版本中springfox这种 Swagger 依赖已经不兼容了如果你是做接口文档展示建议用springdoc-openapi替代但这部分在课程设计里不是必须的可以不做。2.2 持久层选型MyBatis-Plus 能把增删改查效率翻倍持久层框架我选的是 MyBatis-Plus。它本质上是对 MyBatis 的增强最大的优势是单表 CRUD 不需要手写 SQL直接继承BaseMapperT就能调用selectById、insert、updateById、deleteById这些现成方法。对于游戏分享网站这种以单表操作为主的业务模型能省下大量模板代码。举个例子用户表操作只需要这样public interface UserMapper extends BaseMapperUser { }业务层注入后直接就能用Autowired private UserMapper userMapper; public User findUserById(Long id) { return userMapper.selectById(id); }MyBatis-Plus 的分页插件也做了封装配置一个拦截器就能使用Page分页查询Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }使用分页查询文章列表时只需要PageArticle page new Page(current, size); LambdaQueryWrapperArticle wrapper new LambdaQueryWrapper(); wrapper.eq(Article::getStatus, 1).orderByDesc(Article::getCreateTime); articleMapper.selectPage(page, wrapper);这段代码底层会自动拼接LIMIT不用自己担心 SQL 语法问题。在课程设计中如果能熟练说出LambdaQueryWrapper的条件构造原理这在答辩时是很加分的。2.3 登录认证与权限控制不用 Spring Security 也能做得很完整很多课程设计项目一上来就引入 Spring Security结果配置一堆过滤器链最后自己都没完全搞懂。游戏分享网站这个体量基于 Session 拦截器完全够用。密码存储用的是 BCrypt 加密。为什么不用 MD5因为 MD5 是摘要算法虽然不可逆但存在彩虹表风险相同密码加密结果永远相同。BCrypt 每次加密都会生成随机盐相同密码两次加密结果都不一样安全性高一个量级。引入 Spring Security 的 crypto 模块就能使用这个加密或者直接用hutool工具类也可以。登录核心逻辑public User login(String username, String password) { User user userMapper.selectOne( new LambdaQueryWrapperUser() .eq(User::getUsername, username) .eq(User::getStatus, 1) ); if (user null) { throw new RuntimeException(用户不存在或已被禁用); } if (!BCrypt.checkpw(password, user.getPassword())) { throw new RuntimeException(密码错误); } return user; }登录成功后在 Controller 中把用户对象放入 Sessionsession.setAttribute(Constants.LOGIN_USER_KEY, user);定义拦截器校验登录状态public class LoginInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session request.getSession(); Object user session.getAttribute(Constants.LOGIN_USER_KEY); if (user null) { response.sendRedirect(/login); return false; } return true; } }对于后台管理接口再加一个管理员拦截器检查 Session 中用户对象的role字段是否为管理员。整套逻辑不依赖第三方安全框架原理更容易讲透。2.4 文件上传与富文本处理游戏封面、文章配图都需要文件上传功能。项目里我用的是本地磁盘存储上传的图片保存到服务器的指定目录然后通过一个配置好的虚拟路径映射到静态资源。在application.yml中配置上传文件大小限制spring: servlet: multipart: max-file-size: 10MB max-request-size: 20MB静态资源映射配置spring: web: resources: static-locations: classpath:/static/, file:${upload.path}其中upload.path是指向本地图片存储目录的路径使用file:前缀是因为要读取磁盘上的真实文件。文件上传 Controller 核心方法PostMapping(/upload) public Result upload(RequestParam(file) MultipartFile file) { if (file.isEmpty()) { return Result.error(请选择文件); } String originalFilename file.getOriginalFilename(); String suffix originalFilename.substring(originalFilename.lastIndexOf(.)); String fileName UUID.randomUUID() suffix; File dir new File(uploadPath); if (!dir.exists()) { dir.mkdirs(); } file.transferTo(new File(uploadPath fileName)); return Result.success(/files/ fileName); }富文本编辑器方面前端可以选 wangEditor 或者 quill后台控件只需把上传接口返回的 URL 插入到编辑器的内容中。课程设计里能实现图片上传到服务器并在富文本中展示已经是功能上的一个小亮点。3. 数据库表设计与关键字段说明3.1 核心表设计与关联关系数据库设计是整个系统的基础表结构设计得合理后面写业务代码会非常顺畅。项目一共设计了七张核心表覆盖用户、内容、互动三个维度表名中文说明关键字段tb_user用户表id, username, password, nickname, avatar, email, role, status, create_timetb_category游戏分类表id, name, sort, statustb_game游戏资料表id, category_id, name, cover, intro, developer, publisher, publish_date, hot, statustb_article文章表id, user_id, game_id, title, cover, content, view_count, like_count, status, create_timetb_comment评论表id, user_id, article_id, content, parent_id, create_timetb_favorite收藏表id, user_id, target_type, target_id, create_timetb_banner轮播图表id, image, title, url, sort, statustb_article中的game_id外键关联tb_game用来标识这篇文章是围绕哪款游戏写的。tb_favorite通过target_type字段区分收藏对象是游戏还是文章这样一张表就能承载两种收藏场景避免建两张收藏表。tb_comment中的parent_id支持回复功能parent_id为 0 表示顶级评论不为 0 则指向某条评论的 ID。用户表和管理员共用一张表通过role字段区分普通用户为0管理员为1。这样设计减少了表数量管理员的账号管理也直接复用用户模块的逻辑。3.2 关键 SQL 与索引设计虽然 MyBatis-Plus 能减少手写 SQL 的频率但项目中确实有一些场景适合自己写 SQL比如多表联查和统计类查询。查询文章信息并展示发布者昵称SELECT a.id, a.title, a.cover, a.content, a.view_count, a.create_time, u.nickname AS author_name, g.name AS game_name FROM tb_article a LEFT JOIN tb_user u ON a.user_id u.id LEFT JOIN tb_game g ON a.game_id g.id WHERE a.status 1 ORDER BY a.create_time DESC这种查询在首页文章列表和文章详情页都会用到。索引方面建议在tb_article的status和create_time上建立索引因为文章列表页经常按这两个字段过滤和排序。tb_favorite上对user_id建索引因为个人中心查询“我的收藏”是高频操作。还有几个常用的统计 SQL-- 统计各分类下的游戏数量 SELECT c.name, COUNT(g.id) AS total FROM tb_category c LEFT JOIN tb_game g ON c.id g.category_id GROUP BY c.id ORDER BY total DESC这个 SQL 用来做后台数据概览中的分类统计。3.3 初始化数据与演示账号课程设计要面临一个非常现实的问题老师打开系统的时候页面上必须有内容可以看。一个空数据库会给演示带来很大的尴尬所以数据库脚本里必须预置合理的演示数据。项目 SQL 脚本中包含一个默认管理员账号admin密码是admin123。注意这里不是明文存储而是 BCrypt 加密过的一串哈希值。同时还有若干个普通用户账号方便演示注册登录以外的用户操作。游戏分类预置了五个常见分类动作游戏、角色扮演、射击游戏、策略游戏、休闲益智。每个分类下放 2-3 条游戏数据游戏封面使用本地静态图片路径。文章区域预置了几篇图文并茂的攻略和评测内容评论和收藏数据也适当填充了一些。实测下来演示时数据充分的话老师更容易把关注点放在系统功能上而不是反复问“为什么这里没有内容”。4. 环境搭建与从零初始化运行4.1 本地环境清单别在版本上翻车开篇提到过一个高频热搜词“springboot版本太高”要避免这个问题环境版本必须提前统一。这里整理了一份我实际跑通的环境清单软件版本建议说明JDK1.8课程设计最稳妥的版本Maven3.6.3 及以上用来管理依赖和打包MySQL5.7 或 8.0两种版本都可以注意驱动配置略有区别IDEA2021.2 及以上社区版也能跑但旗舰版更方便Spring Boot2.7.18项目核心依赖版本MyBatis-Plus3.5.3.1兼容 Spring Boot 2.x如果你用的是 MySQL 8.0application.yml中的驱动类需要写成com.mysql.cj.jdbc.Driver并且数据源 URL 中要加上时区参数spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/game_share?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456这里不写serverTimezone参数的话高版本 MySQL 会报时区错误这是新手最容易遇到的问题。4.2 创建项目与核心依赖配置项目创建可以直接在 IDEA 中通过 Spring Initializr 完成选择 Java 8 版本然后引入 Web、MySQL、Lombok 等基础依赖。如果初始化时网络下载依赖慢建议将 Maven 仓库切换到国内镜像源。pom.xml中的核心依赖如下dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.1/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-security/artifactId /dependency最后这个spring-boot-starter-security仅用于使用其中的 BCrypt 加密工具类不需要配置 Spring Security 的过滤链。如果不想引入这个依赖也可以把工具类单独提取出来用其他加密工具替换。4.3 application.yml 配置与数据库导入完整的application.yml还包含 MyBatis-Plus 的配置和文件上传路径mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl map-underscore-to-camel-case: true global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0map-underscore-to-camel-case非常重要它能让数据库的create_time字段自动映射到 Java 实体的createTime属性避免大量手写 resultMap。数据库导入时先用 Navicat 或命令行创建名为game_share的数据库然后将项目中的sql/game_share.sql文件直接执行。脚本里包含建表语句和预置数据执行后项目就能直接连接使用。4.4 启动项目与第一次登录以上配置完成后找到主启动类运行main方法控制台出现 Spring Boot 的启动日志后访问http://localhost:8080就能看到首页。第一次登录建议用管理员账号在页面右上角找到后台入口输入admin / admin123进入后台管理界面。正常登录后可以在后台看到用户列表、游戏分类、文章审核等菜单。如果启动时报端口被占用在application.yml中修改server.port或者找到占用进程关闭即可# Linux/Mac lsof -i:8080 kill -9 PID5. 部署打包与运行环境排查5.1 Maven 打包并发布到服务器项目在本地跑通之后需要打成可执行 JAR 包部署到服务器。在 IDEA 的 Terminal 中执行mvn clean package -DskipTests打包完成后target目录下会生成game-share-0.0.1-SNAPSHOT.jar。上传到服务器后用以下命令启动nohup java -jar game-share-0.0.1-SNAPSHOT.jar app.log 21 这里做几点说明。-DskipTests是为了跳过测试用例加快打包nohup是为了让进程在退出终端后继续运行app.log保存运行日志排查问题时会用到。如果使用云服务器需要确认安全组和防火墙放行 8080 端口。部署后通过http://服务器IP:8080访问。5.2 本地能跑服务器上崩了环境差异怎么排查很多项目本地运行完全正常一到服务器就各种报错这种情况绝大部分是环境差异导致的。第一数据库地址问题。服务器上连接数据库不能再用localhost要改成 MySQL 所在机器的 IP并且保证数据库用户的host配置允许远程连接。用root账号远程连接时经常报“Host is not allowed to connect”需要执行授权 SQL。第二文件路径问题。项目里如果用绝对路径存储上传文件例如D:/upload在 Linux 服务器上肯定找不到这个目录。建议上传路径做成可配置在application.yml中配置绝对路径部署时再根据服务器环境修改。第三时区和日志问题。Java 进程默认时区可能和服务器时区不一致建议启动时加上-Duser.timezoneAsia/Shanghai参数。5.3 课程设计演示时的注意事项课程设计答辩现场本身就是一种“部署环境”如果临时打开项目加载数据很可能因为启动太慢或者数据库配置问题卡住。我个人的建议是提前一天在演示用的电脑上完整跑一遍浏览器打开页面所有功能点都点一遍确认没有报错再关闭。另外页面上的演示数据一定要提前准备充分。比如在轮播图位置放几张好看的推荐图在游戏详情页保证封面加载正常在评论区预置几条正常评论。这些东西会让答辩展示的观感好很多。6. 常见问题与排查技巧实录6.1 启动失败先看报错的前三行Spring Boot 启动失败时控制台会刷出来一大段错误日志。不要从头到尾看重点看最前面的几行异常信息。最常见的启动报错不外乎三种端口被占用、数据库连接失败、依赖下载不完整。数据库连接失败的典型报错是Cannot create PoolableConnectionFactory (Access denied for user rootlocalhost)这时候先检查application.yml中的用户名密码是否正确再确认 MySQL 服务有没有启动。如果报的是Access denied for user rootlocalhost (using password: YES)说明密码错误需要修改配置文件或重置数据库密码。6.2 中文乱码与时区问题数据库里中文乱码通常是字符集设置问题。创建数据库时指定 UTF-8 编码CREATE DATABASE game_share DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;同时连接 URL 中也要加上characterEncodingutf8参数。只要这两个地方统一为 UTF-8中文基本不会乱码。6.3 文件上传失败与静态资源404文件上传失败先检查max-file-size配置默认只有 1MB大图片会超过限制。检查上传目录是否存在程序里如果目录不存在会抛IOException。图片上传后访问出现 404十有八九是静态资源映射配置没生效。检查static-locations配置是否包含file:前缀注意路径末尾的斜杠。6.4 项目常见问题速查表问题现象可能原因解决办法启动后访问空白端口被占用或静态资源未加载修改端口清理项目缓存登录提示密码错误数据库中密码明文存贮改用 BCrypt 加密存储页面中文乱码数据库字符集不是 UTF-8重建数据库并指定 utf8mb4上传图片 404静态资源映射路径不对检查 yml 中 static-locations 配置评论出现 SQL 错误表字段名与实体属性不一致开启驼峰映射或加 resultMap后台功能访问无权限Session 校验失败检查拦截器放行路径配置7. 源码、数据库与万字文档项目交付物怎么用7.1 源码目录结构与关键文件定位完整项目源码按照 Spring Boot 标准结构组织拿到手之后不要急着跑先看目录结构知道每个文件是干什么用的。controller包里存放所有接口按业务模块拆分成 UserController、ArticleController、GameController、CommentController、AdminController 等service包存放业务逻辑接口和实现分离mapper包存放 MyBatis-Plus 的 Mapper 接口entity包存放数据库实体类config包存放拦截器、MyBatis-Plus 分页配置interceptor包存放权限校验拦截器common包存放统一返回结果类、常量类、异常处理类。看懂这个结构以后改功能就有方向了。比如想改注册逻辑去 UserController 里找注册接口然后调 UserService 里的对应方法。7.2 数据库脚本与演示数据怎么导入项目附带的数据库脚本位于sql/game_share.sql包含完整的建库、建表、预置数据语句。导入步骤非常固定打开 Navicat 或 MySQL 命令行新建数据库game_share字符集选utf8mb4右键选择“运行 SQL 文件”选择game_share.sql执行完成后刷新表列表应该能看到 7 张表以及每张表的演示数据强烈建议不要修改数据库名称因为配置文件里已经写死了数据库连接地址如果你改了库名同步要修改application.yml中的数据源配置。7.3 万字文档怎么写不显得“灌水”课程设计文档写到一万字并不难难的是写满一万字还能让老师觉得有内容。这里分享我组织文档章节的一个实际结构这套结构可以直接套用第一章绪论包括背景意义、国内外研究现状、研究内容。第二章需求分析包括可行性分析、功能需求分析、非功能需求分析、用例图。第三章系统设计包括总体架构设计、功能模块设计、数据库设计数据库设计部分附上 E-R 图和每张表的字段说明。第四章系统实现按模块逐个描述实现方式每个模块先放核心代码片段再解释代码逻辑。第五章系统测试整理测试用例表格包含测试项、测试步骤、预期结果、实际结果。最后是总结与展望。写文档的核心技巧是代码贴关键片段而不是全部粘贴每个模块的文字描述要和代码对得上测试部分最好真实跑一遍系统把界面截图放上去这些都是实打实的内容不容易被判定为拿来主义。最后说一个我自己的感受做课程设计最忌讳的是把文档和代码分开写很多同学代码跑完才回头编文档最后文档和代码完全对不上答辩时一问就露馅。我习惯在做每个功能的时候顺手把这块的设计思路、表结构变化、测试结果记在文档草稿里这样做完项目文档也基本成型了。另外功能可以适当加一两个小亮点比如图片上传支持拖拽、评论支持二级回复这些改动不大但在答辩时很容易让老师觉得你确实深入思考过。
