2026/10/17 15:17:16

SpringBoot+Vue+MyBatis+MySQL实现网游推荐网站系统实战

SpringBoot+Vue+MyBatis+MySQL实现网游推荐网站系统实战 做网游推荐站这事我前后搭过三版才理顺。最早是纯后端模板渲染改个页面得重启服务运营同学要调个推荐位得排队等开发后来切到前后端分离才解脱。这篇就聊这套基于SpringBootVueMyBatisMySQL的网游推荐网站系统从设计思路、表结构、核心代码到部署排坑完整过一遍想拿来练手或者直接改造成生产项目的都可以参考。1. 项目定位与整体设计1.1 这个系统解决了什么问题网游推荐网站听着简单但实际要承载的东西不少。用户要能按类型、热度、评分筛游戏要能看到游戏详情、截图、玩法介绍最好还有评论区可以交流。后台则需要一个管理界面让运营人员能上架新游戏、调整推荐位、审核评论。如果做成传统单体应用前端页面和后端逻辑强耦合改版成本高多人协作也容易冲突。前后端分离之后前端只管页面渲染和用户交互后端专注提供数据和业务规则两边通过JSON格式的接口通信联调效率高后续扩展移动端或者小程序也能直接复用同一套后端API。这套系统解决了几个痛点游戏信息集中管理、推荐位动态配置、用户评价体系落地、前后端独立部署互不干扰。1.2 技术选型背后的考量SpringBoot作为后端基础框架胜在配置简化、生态成熟内嵌Tomcat让打包部署变得很轻量。Vue负责前端SPA应用组件化开发让页面复用性大幅提升配合Vue Router实现单页路由切换用户体验接近原生应用。MyBatis负责数据库访问层相比JPA更灵活SQL由开发者掌控优化空间更大。MySQL则是最稳妥的关系型数据库选择对于这种结构化数据场景成熟稳定且运维成本低。这套组合是当前中小型项目最常见的标准配置不是最炫技的但是最容易上手、社区资料最多的。我之前也试过用其他方案组合最后又切回来了原因很简单招人容易、出问题能搜到答案、部署资料齐全。1.3 系统模块划分整个系统分为前台门户和后台管理两部分前台面向普通用户后台面向运营人员。前台核心模块包括首页推荐轮播图展示热门推荐位下面按热度、评分维度展示游戏列表游戏分类按端游、手游、单机等维度分类浏览游戏详情展示游戏名称、开发商、发布时间、配置要求、玩法介绍、截图轮播搜索功能支持按游戏名称关键词模糊搜索评论系统用户登录后可发表评论支持评分后台管理模块包括游戏管理游戏信息的增删改查图片上传上下架操作分类管理游戏分类的维护推荐位管理配置首页推荐顺序和展示内容评论审核审核用户评论内容过滤不当言论用户管理查看用户列表禁用违规账号这样的模块划分让整个系统的功能边界清晰开发时可以按模块分配给不同的人并行推进。2. 数据库设计与核心表结构2.1 表结构设计数据库是这套系统的地基表结构设计得好不好直接决定后面开发是顺利还是磨人。我拆了六张核心表用户表、游戏表、分类表、游戏截图表、评论表、推荐位表。用户表字段包括用户ID、用户名、密码存的是BCrypt加密后的密文、邮箱、头像URL、角色区分普通用户和管理员、注册时间、账号状态。管理员账号也在这张表里只是角色字段不同。游戏表是最核心的一张表字段包括游戏ID、游戏名称、所属分类ID、封面图URL、游戏简介、详细介绍、开发商、发行商、发布时间、支持平台PC、手机等、最低配置、推荐配置、评分由用户评论的平均分计算得出、热度值点击量加权重、上架状态、创建时间、更新时间。分类表就简单了分类ID、分类名称、分类描述、排序值。游戏截图表存储游戏的多张展示图ID、游戏ID、图片URL、排序值。评论表字段评论ID、游戏ID、用户ID、评分1到5分、评论内容、点赞数、审核状态、评论时间。推荐位表设计成ID、游戏ID、推荐位置编号、排序值、开始时间、结束时间。这样可以灵活控制某个游戏在某个位置展示多久时间到了自动过期。2.2 设计要点和细节说明游戏表的评分字段特别注意我采用的是评论表中所有用户评分的平均值而不是单独维护一个字段这样数据来源更真实。平均值计算放在后端接口里每次请求详情时实时聚合游戏列表页则从游戏表的评分字段读取这个字段在每次新评论生成时同步更新。列表页的评分展示要快详情页的评分要准用双写策略兼顾性能和数据一致性。还有一个容易忽略的细节推荐位表为什么不直接在游戏表加一个is_recommended字段。因为推荐位往往有时效性直接用布尔字段的话不好控制过期时间也表达不了多个推荐位的优先级。独立一张表之后运营可以自由设置推荐周期和顺序清理过期数据也更方便。2.3 建表语句参考CREATE TABLE user ( id int(11) NOT NULL AUTO_INCREMENT, username varchar(50) NOT NULL, password varchar(100) NOT NULL, email varchar(100) DEFAULT NULL, avatar varchar(255) DEFAULT NULL, role tinyint(4) DEFAULT 0, status tinyint(4) DEFAULT 1, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY idx_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE game ( id int(11) NOT NULL AUTO_INCREMENT, name varchar(100) NOT NULL, category_id int(11) NOT NULL, cover_url varchar(255) DEFAULT NULL, intro varchar(500) DEFAULT NULL, detail text, developer varchar(100) DEFAULT NULL, publisher varchar(100) DEFAULT NULL, publish_date date DEFAULT NULL, platform varchar(50) DEFAULT NULL, min_config varchar(500) DEFAULT NULL, recommended_config varchar(500) DEFAULT NULL, rating decimal(2,1) DEFAULT 0.0, hot_value int(11) DEFAULT 0, status tinyint(4) DEFAULT 1, create_time datetime DEFAULT CURRENT_TIMESTAMP, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_category (category_id), KEY idx_hot (hot_value) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;建表时统一用utf8mb4字符集不要用utf8因为utf8mb4才能完整支持四字节的emoji字符评论内容里有些用户就爱用表情符号用utf8会报错或者乱码。3. 后端SpringBoot核心模块实现3.1 项目初始化与分层架构SpringBoot项目我用的是2.7.x版本Java版本用1.8稳定可靠MyBatis用的是mybatis-spring-boot-starter 2.2.x。项目结构按照标准的分层架构组织controller层负责接收请求和参数校验service层负责业务逻辑mapper层DAO层负责数据库操作。分层的好处是职责单一切换成本低controller只考虑HTTP相关的事情service攒业务规则mapper只写SQL。一个请求的流程是这样的前端发起HTTP请求到达controllercontroller把请求参数绑定到DTO对象上简单校验后传给serviceservice里做业务校验和逻辑处理然后调用mapper接口执行数据库操作结果返回给serviceservice封装成VO对象返回给controller最后controller返回JSON响应。3.2 推荐接口的实现逻辑推荐位接口是网站的核心接口。实现思路是先从推荐位表查询当前时间段的推荐记录按排序值升序排列再关联查询游戏表获取游戏完整信息最后把推荐理由拼接进去返回。为保证首页响应速度这个接口加了本地缓存推荐数据五分钟内不会重复查数据库。Service public class RecommendService { Autowired private RecommendMapper recommendMapper; Autowired private GameMapper gameMapper; Cacheable(value recommendList, key home) public ListGameVO getHomeRecommends() { ListRecommend recommends recommendMapper.selectActive(); ListGameVO result new ArrayList(); for (Recommend r : recommends) { Game game gameMapper.selectById(r.getGameId()); if (game ! null game.getStatus() 1) { GameVO vo new GameVO(); BeanUtils.copyProperties(game, vo); result.add(vo); } } return result; } }缓存注解这块要注意一个坑当后台修改了推荐配置五分钟内前台不会生效。解决方法是加一个CacheEvict操作在推荐配置变更接口里主动清除缓存这样既能享受缓存的速度又能保证数据更新的及时性。3.3 用户评论与评分聚合评论模块的业务逻辑用户提交评论时传入游戏ID、评分、内容等参数。后端先校验用户是否登录再校验该用户是否已经评论过这个游戏如果没有评论过则插入评论记录同时更新游戏表的评分字段把最新评论的评分纳入平均值计算。为了防止同一个人刷分我在评论表加了用户ID和游戏ID的唯一索引这是最底层的一层保障代码里也要校验双重保险。Transactional(rollbackFor Exception.class) public void addComment(CommentDTO dto, Long userId) { // 1. 校验游戏是否存在且上架 Game game gameMapper.selectById(dto.getGameId()); if (game null || game.getStatus() ! 1) { throw new BusinessException(游戏不存在或已下架); } // 2. 校验是否重复评论 int count commentMapper.countByUserAndGame(userId, dto.getGameId()); if (count 0) { throw new BusinessException(您已经评论过该游戏); } // 3. 插入评论 Comment comment new Comment(); comment.setGameId(dto.getGameId()); comment.setUserId(userId); comment.setScore(dto.getScore()); comment.setContent(dto.getContent()); commentMapper.insert(comment); // 4. 更新游戏平均评分 BigDecimal avgScore commentMapper.selectAvgScoreByGameId(dto.getGameId()); gameMapper.updateRating(dto.getGameId(), avgScore); }这里加Transactional很有必要。插入评论和更新评分两步操作必须是一个原子操作如果中途出现异常评论插进去了评分没更新数据就不一致了。我一开始没加事务注解测试时用并发模拟器压了一轮出现了一次诡异数据加上事务后问题消失。3.4 接口设计与响应格式统一前后端分离项目里接口响应格式的统一是一件值得早做的事情。我定义了一个统一响应体Result对象包含三个字段code、message、data。成功时code为200业务异常时code为400未登录时code为401服务器异常时code为500。前端拿到响应后根据code做统一拦截处理比如401就跳转登录页。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; } }所有controller返回类型都使用Result这个包装类前端对接时只用处理一种数据格式。一开始可能有同事觉得麻烦但项目大了之后统一格式的价值就体现出来了前端axios拦截器里只需要写一份响应处理逻辑不用每个接口单独写错误分支。3.5 登录鉴权方案登录这块我用了JWT来做无状态认证。用户登录成功后后端签发一个包含用户ID和角色的token返回给前端前端把token存在localStorage里每次请求时在请求头加上Authorization字段携带token。后端通过拦截器统一解析token把用户信息放入ThreadLocal业务代码里随时可以获取当前登录用户。密码存储绝对不能明文。我用的BCrypt加密算法同一个密码每次加密结果都不同即使数据库泄露也无法直接反推出原始密码。初始化管理员账号时密码在第二天就被人撞库过这算是那段时间最惊险的一次。4. 前端Vue页面与交互设计4.1 前端工程结构Vue这块用的Vue2 Vue Router Vuex ElementUI的组合。ElementUI虽然是老牌组件库但胜在组件丰富、文档齐全、稳定可靠。工程结构按模块划分views目录放页面组件components目录放公共组件router目录配置路由store目录管理全局状态api目录统一封装接口请求。4.2 首页推荐页实现首页包括轮播图区域和推荐游戏列表。轮播图用ElementUI的Carousel组件封装数据来自推荐接口。推荐列表用Card组件展示游戏封面、名称、评分和简介点击卡片跳转到详情页。首页组件的核心逻辑就是页面挂载时调用推荐接口获取数据渲染到模板上。为提高加载速度封面图做了懒加载处理图片进入视口才开始加载。这个优化很重要因为推荐位图片通常分辨率高如果不做懒加载首页首屏渲染会拖慢好几秒。4.3 游戏详情页与评论区游戏详情页展示游戏的完整信息包括详情介绍、配置要求、截图相册、用户评论区。我在详情页做了一个评分展示组件用星星图标直观展示平均得分。评论区支持分页加载每页十条评论用户登录后可以在底部发表评论和评分。发表评论的表单做了前端本地校验评分不能为空内容长度在1到500字之间。校验通过后调用后端评论接口成功后刷新评论列表评分展示同步更新。这种交互反馈要做得即时提交后给一个loading状态防止用户重复点击产生重复评论。实现时踩过一个滚动的坑评论列表更新后页面最好平滑滚动到评论区顶部不然用户在长页面底部发表完评论新列表加载后视口位置不对会感觉页面乱跳。4.4 后台管理页面实现后台管理页面用独立路由挂载在/admin路径下通过路由守卫校验用户角色非管理员无法访问。布局用的是经典的侧边栏顶部栏结构侧边栏是菜单导航顶部栏显示当前管理员信息。游戏管理页面是后台最复杂的页面表格展示游戏列表支持按名称搜索、按分类筛选、按状态筛选点击新增或编辑弹出一个表单弹窗表单里包含游戏所有字段设置其中详情介绍用富文本编辑器方便运营排版。图片上传用的是ElementUI的Upload组件后端提供一个文件上传接口图片统一存到服务器指定目录访问时通过static映射路径读取。4.5 前端路由与状态管理路由配置中前台和后台做了区分。前台路由包括首页、游戏列表、游戏详情、登录注册、个人中心后台路由包括游戏管理、分类管理、评论审核等。所有后台路由包在同一个父路由下父路由的beforeEnter守卫统一做管理员校验。Vuex存储的是当前用户信息和登录状态。用户刷新页面时Vuex中状态会丢失所以需要在App.vue的created生命周期里从localStorage恢复用户信息或者调用后端接口根据token重新获取用户信息。我采用的是后者更安全因为token可能已经过期前端无法自己判断。5. 前后端联调与部署实操5.1 联调准备与接口调试前后端联调是项目从开发走向可用的必经阶段。开发环境我用Vue CLI启动前端开发服务器默认端口8080后端SpringBoot端口8081跨域问题通过后端配置CORS解决。后端配置一个CORS过滤器允许指定前端域名跨域访问携带token的请求也允许通过。联调时最常用的工具是Postman先把每个接口按接口文档验证一遍确认请求参数和返回值无误后再配合前端联调。建议后端同学在写完每个接口时做好自测别把未验证的接口直接丢给前端浪费时间也影响协作信任。跨域问题要重点说一嘴前端口号和后端口号不同浏览器默认会拦截跨域请求。后端需要配置CORS允许来自前端开发服务器的请求。上线后如果前后端部署在不同的域名或者端口下同样需要CORS配置否则前端请求会被浏览器拦掉。5.2 生产环境构建与Nginx配置前端打包是核心部署环节。在Vue项目根目录执行npm run build命令生成dist目录里面是编译压缩后的静态文件。打开dist目录检查index.html里面的js、css资源路径如果是绝对路径如/assets/xxx.js部署在子目录时会404需要在vue.config.js中设置publicPath为相对路径或者明确的域名前缀。后端打包更简单在项目根目录执行mvn clean package生成一个可执行的jar包通过java -jar命令即可运行。生产环境我建议把MySQL和jar包分离部署MySQL单独一台机器或者使用云数据库应用服务器只跑jar包这样不同实例之间互不影响。Nginx配置是上线最关键的环节需要把前端静态文件的请求指向dist目录把后端的API请求反向代理到后端服务端口。以一台应用服务器的配置为例前端静态文件和后端服务在同一台机器Nginx监听80端口静态请求指向/opt/www/dist目录API请求转发到本机的8081端口。server { listen 80; server_name your-domain.com; # 前端静态文件 location / { root /opt/www/dist; index index.html; try_files $uri $uri/ /index.html; } # 后端API代理 location /api/ { proxy_pass http://127.0.0.1:8081; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }注意location /里的try_files配置跳过了对服务端路由的物理文件查找直接把SPA应用的逻辑路由对应的页面请求交给前端路由处理。没有这个配置用户在首页点击到某个子路由页面后直接刷新会出现404错误。5.3 数据库初始化和数据迁移数据库初始化有两种方式方案一是执行sql脚本从头建表方案二是使用Flyway管理数据库版本变更。小项目用方案一简单省事项目要做迭代开发的话建议用Flyway。我这套项目提供了完整sql脚本包含建表语句和测试数据导入后系统即可运行。测试数据尽量准备得丰富一些十款左右的游戏分布在三四个分类里每款游戏配两三条评论推荐位配置三个。这样开发或者学习时打开页面就有直观的展示效果不用自己手动造数据。连接MySQL时有个细节要提醒在云服务器上安装MySQL 8.0后默认的认证插件是caching_sha2_password某些版本的连接驱动可能不兼容需要在连接URL中加上allowPublicKeyRetrievaltrue参数或者创建用户时指定mysql_native_password认证插件否则会报连接认证失败。5.4 部署步骤完整清单梳理一套标准的部署步骤照着走基本不会出错。第一步准备一台服务器安装JDK 1.8、MySQL 5.7或8.0、Nginx。第二步创建数据库和账号导入初始化SQL脚本。第三步打包后端项目本地生成jar包上传到服务器指定目录用java -jar命令启动并验证接口。第四步前端项目执行npm run build打包把dist目录上传到服务器配置Nginx站点把前端和API代理配置好。第五步修改后端配置文件的数据库连接信息重新打包并启动。确认Nginx配置无误后重新加载配置。第六步访问服务器IP或者域名验证首页是否能正常打开游戏列表、详情、评论、后台管理等模块是否功能正常。第七步配置SSL证书开启HTTPS访问。现在浏览器对非HTTPS接口的限制越来越多直接上HTTPS是标准操作。6. 常见问题与排查技巧实录6.1 前端页面白屏问题页面白屏是最常遇到的问题之一原因多半是JS报错导致应用没挂载成功。排查思路打开浏览器开发者工具看Console面板有没有红色报错常见的有语法错误、引入的模块路径不对、接口返回的数据结构不符合预期导致渲染报错。另一个常见原因是路由配置问题首次打开页面是根路径没问题刷新子路由页面就白屏这是Nginx没有配置try_files导致的。按照上文Nginx的配置方式即可解决。还有一种隐蔽情况如果用的是Vue2项目某个第三方组件库版本不兼容会导致构建时正常、运行时报错。解决办法是查看打包时的警告信息把组件库版本锁定到稳定版本。6.2 接口请求404或跨域报错前端请求接口报404先确认请求的URL路径是否正确再确认后端服务是否启动成功。如果路径没问题代码也没变可能是后端接口映射的路径改了没有同步前端。跨域报错比较好辨认浏览器Console里会提示CORS policy相关错误解决方式是后端配置CORS或者部署时让前端跟后端同域。生产环境Nginx反代方式是最干净的解决方案既解决了跨域问题又隐藏了后端端口减少暴露面。6.3 评论保存失败或评分不更新评论保存失败先看是不是重复评论导致的同一用户对同一游戏只能评论一次。后端返回的异常消息会直接展示给前端实际开发时要注意错误信息的友好性别把数据库底层的异常信息直接透出给用户。评分不更新的原因通常是事务问题评论插入成功了但更新评分失败导致回滚。排查方式后端日志里有没有抛异常数据库事务是否生效MyBatis的update语句是否匹配到记录。6.4 部署后图片不显示图片不显示先确认图片存储路径是否有访问权限Linux服务器上文件权限不对会导致Nginx读不到。同时检查后端配置的图片访问路径是否和实际路径一致。如果是部署后图片才不原路显示大概率是配置文件里的图片路径与生产环境不一致。开发环境用的本地绝对路径部署时就变成服务器路径了改配置后重启服务生效。6.5 性能优化心得项目上线后性能优化是个持续过程。我这边做的几个见效明显的优化推荐接口加Redis缓存从首次请求的200多ms降到20ms以内游戏列表页的分页SQL加索引降低慢查询数量前端图片做懒加载和CDN加速首屏加载时间减少一半以上。但这些优化要按需做不要一开始就全部铺开。先上线通过监控看出瓶颈再针对性优化比盲目操作效率高得多。7. 个人经验与扩展方向做了这套系统之后我对前后端分离项目的理解深了一层。最难的不是某个单独的技术点而是把业务需求合理拆分到前端和后端、设计清晰的数据模型、约定统一的接口规范。这些前期工作虽然费时但对项目的长期维护作用特别明显。现在回头看最值得改善的地方是把推荐逻辑从简单SQL查询换成一个独立的推荐服务模块支持按热度、评分、时间衰减等多个维度组合推荐根据用户行为数据做个性化排序。这套系统里我用的是相对简单的算法但如果要用在真实场景推荐算法和用户画像的深度会是核心竞争力。扩展方向上把评分体系完善一下增加评论点赞举报功能加入社交分享。另外移动端适配需要重点考虑目前只做了PC端页面后续要适配手机访问前端可以引入响应式布局或者做一套单独的移动端H5。做这种练手项目最划得来的点在于麻雀虽小五脏俱全单体应用、前后端分离、数据库设计、权限控制、缓存优化、部署上线全流程都会过一遍。把这套流程完整走通再去看真实商业项目的代码就不会有陌生感。