Spring Boot 实战:游戏检索系统设计与实现(含完整功能模块 + 数据库设计)

72 阅读18分钟

一、项目背景:游戏行业的信息管理痛点与数字化需求

随着游戏产业的快速发展,玩家对游戏信息的获取、筛选及交易需求日益增长,但传统游戏信息管理模式存在明显短板:

  1. 信息分散:玩家需在多个平台(游戏官网、论坛、电商)查询游戏详情、评价及购买渠道,效率低下;
  2. 管理混乱:游戏运营方难以统一管理游戏库存、订单及用户评价,易出现 “超售”“评价遗漏” 等问题;
  3. 交互缺失:玩家无法便捷收藏心仪游戏、反馈订单问题,运营方也难以快速响应用户需求。

为解决这些痛点,本项目开发 “基于 Spring Boot 的游戏检索系统”,整合 “游戏信息管理、订单处理、用户交互、后台管控” 四大核心能力,通过 Web 端实现跨设备访问,让玩家高效检索游戏、便捷完成交易,同时为运营方提供规范化的信息管理工具。

二、核心技术栈:轻量高效的技术选型

系统围绕 “开发效率高、部署便捷、维护成本低” 原则选型,技术栈覆盖前后端开发、数据存储及部署,适配中小型游戏平台的业务需求:

技术类别具体选型核心优势
后端框架Spring Boot 2.7.x简化 Spring 配置,支持 “开箱即用”(内置 Tomcat 容器,无需手动部署 WAR 包);提供自动配置、starter 依赖等功能,大幅降低开发难度;支持 RESTful 接口设计,适配前后端分离交互。
开发语言Java 11稳定兼容 Spring Boot 框架,支持 Lambda 表达式、Stream API 等特性,简化代码逻辑;具备跨平台性,开发环境与生产环境一致性高。
数据库MySQL 8.0开源免费,支持事务与索引(确保 “订单创建 - 库存扣减” 数据一致性);支持复杂查询(如 “按游戏类型 + 热度筛选”“多条件订单统计”),查询响应时间<0.3 秒;适配中小型系统的数据存储需求。
开发工具IntelliJ IDEA 2023支持 Spring Boot 代码提示、断点调试与项目管理;集成 Maven/Gradle 构建工具,自动管理依赖;插件生态丰富(如 MyBatisX、Lombok),提升开发效率。
前端技术HTML + CSS + JavaScript + LayuiLayui 提供轻量化 UI 组件(表格、表单、弹窗),适配后台管理界面;JavaScript 实现前端表单校验、异步请求(如游戏搜索联想、订单状态实时更新);HTML/CSS 确保页面响应式布局,支持电脑 / 平板访问。
持久层框架MyBatis-Plus基于 MyBatis 扩展,提供 CRUD 通用接口(如save()list()),减少重复代码;支持条件构造器(QueryWrapper),简化复杂 SQL 查询;内置分页插件,无需手动编写分页逻辑。
辅助技术Lombok + RedisLombok 通过注解(@Data@NoArgsConstructor)消除实体类 getter/setter 方法,精简代码;Redis 缓存热门游戏数据(如 “热度 TOP10 游戏”),降低数据库访问压力,提升页面加载速度。

三、系统分析:可行性与核心需求拆解

3.1 可行性分析

在系统开发前,从技术、操作、经济三个维度验证项目落地能力,确保系统可开发、易使用、低成本:

3.1.1 技术可行性

  • 框架成熟度:Spring Boot、MyBatis-Plus 等技术均有完善文档及社区支持(如 Spring 官方文档、MyBatis-Plus 中文指南),开发中遇到的问题可快速找到解决方案;
  • 硬件要求低:开发阶段仅需普通 PC(i5 处理器 + 8GB 内存),生产环境可部署在云服务器(2 核 4GB 配置即可支撑 500 用户同时在线);
  • 技术适配性:系统核心功能(游戏检索、订单管理)均基于成熟技术方案实现,无复杂技术难点(如游戏检索基于 MySQL 模糊查询 + Redis 缓存,订单处理基于 Spring 事务管理)。

3.1.2 操作可行性

  • 界面设计友好:前端界面参考主流游戏平台(如 Steam、TapTap),操作流程贴合用户习惯(如 “游戏检索→详情查看→加入购物车→下单” 不超过 4 步);
  • 权限划分清晰:玩家端与管理员端界面分离,玩家仅能操作 “检索、购买、评价” 等功能,管理员专注 “游戏管理、订单管控”,避免权限混淆;
  • 学习成本低:玩家端无需注册即可浏览游戏,注册后功能操作与电商平台一致,平均学习时间<5 分钟;管理员端提供操作指引,新手可快速上手。

3.1.3 经济可行性

  • 开发成本低:所有核心技术均为开源免费(Spring Boot、MySQL、Layui),无软件授权费用;开发周期约 2-3 个月,单人即可完成核心功能开发;
  • 部署成本低:云服务器(阿里云 ECS 入门版)月均成本<100 元,搭配 MySQL 数据库(云数据库 RDS 入门版)月均成本<50 元,总运维成本可控;
  • 扩展潜力大:系统模块化设计,后期可新增 “游戏下载、玩家社区” 等功能,无需重构核心代码,扩展成本低。

3.2 系统核心流程分析

3.2.1 玩家操作主流程(以 “购买游戏” 为例)

  1. 游戏检索:玩家在首页输入游戏名称 / 类型(如 “动作类”“角色扮演”),系统通过 MySQL 模糊查询 + Redis 缓存返回匹配结果;
  2. 详情查看:玩家点击游戏卡片,查看游戏介绍、截图、评价及价格,可选择 “加入购物车” 或 “立即购买”;
  3. 订单创建:玩家确认购买信息(数量、价格),提交订单后,系统自动扣减游戏库存(通过 Spring 事务确保 “订单创建 - 库存扣减” 原子性);
  4. 订单支付:玩家选择支付方式(模拟支付,实际项目可集成支付宝 / 微信支付接口),支付完成后系统生成兑换码,玩家可用于激活游戏;
  5. 评价反馈:玩家激活游戏后,可在 “我的订单” 中提交评价,评价实时同步至游戏详情页,供其他玩家参考。

3.2.2 管理员操作主流程(以 “游戏管理” 为例)

  1. 游戏新增:管理员在后台填写游戏信息(名称、类型、价格、库存),上传游戏截图,设置 “是否上架” 状态;
  2. 信息审核:系统自动校验必填项(如 “价格>0”“库存≥0”),校验通过后保存至数据库,未通过则提示错误原因;
  3. 库存调整:管理员可根据销售情况 “增加 / 减少” 游戏库存,调整后实时同步至玩家端(通过 Redis 缓存更新,确保数据一致性);
  4. 游戏下架:管理员可对低销量或下架游戏设置 “下架” 状态,玩家端将不再显示该游戏,避免无效点击。

3.3 系统性能要求

为确保系统稳定运行与良好用户体验,明确三大核心性能指标:

  1. 响应速度:游戏检索结果加载时间<1 秒,订单创建响应时间<2 秒,页面整体加载时间<3 秒;
  2. 数据安全性:用户密码通过 MD5 加密存储(防止明文泄露),订单信息、兑换码通过数据库字段加密(敏感信息不直接展示);
  3. 稳定性:支持 500 用户同时在线,单接口(如游戏检索)每秒请求量(QPS)≥100,无卡顿、崩溃情况。

四、系统设计:功能模块与数据库详解

4.1 系统功能结构设计

系统分为玩家端管理员端两大模块,功能边界清晰,联动顺畅:

4.1.1 玩家端功能模块

功能子模块核心操作
游戏检索按名称 / 类型 / 热度筛选游戏;查看游戏详情(介绍、截图、评价、价格);收藏心仪游戏。
购物车管理查看加入购物车的游戏;调整游戏购买数量;删除购物车商品;批量提交订单。
订单管理查看所有订单(待支付 / 已支付 / 已取消);支付待支付订单;申请订单退款;评价已完成订单。
个人中心维护个人信息(姓名、手机号、头像);修改账号密码;查看收藏列表;提交订单投诉(如 “兑换码无效”)。
公告查看浏览管理员发布的公告(如 “游戏更新”“促销活动”);按时间筛选历史公告。

4.1.2 管理员端功能模块

功能子模块核心操作
游戏管理新增 / 编辑游戏信息(名称、类型、价格、库存);上传游戏截图;设置游戏 “上架 / 下架” 状态;删除无效游戏。
订单管理查看所有玩家订单;处理退款申请(同意 / 拒绝并填写理由);导出订单数据(Excel 格式);标记订单 “已发货 / 已完成”。
评价管理查看玩家对游戏的评价;回复玩家评价;删除违规评价(如 “恶意差评”)。
投诉管理查看玩家提交的订单投诉;处理投诉(如 “补发兑换码”);填写处理结果并通知玩家。
用户管理查看所有注册用户;禁用 / 启用用户账号;重置用户密码;导出用户数据(Excel 格式)。
公告管理发布新公告(填写标题、内容、上传图片);编辑历史公告;删除过期公告。

4.2 数据库设计

数据库设计是系统稳定运行的核心,围绕 “游戏 - 用户 - 订单” 三大核心实体,设计 9 张关键数据表,确保数据关联清晰、冗余低、查询高效。

4.2.1 核心实体 E-R 图(关键实体)

  • 游戏实体:包含游戏 ID、名称、类型、价格、库存、热度、上架状态等属性;
  • 用户实体:包含用户 ID、账号、密码(加密)、姓名、手机号、余额、会员等级等属性;
  • 订单实体:包含订单 ID、用户 ID、游戏 ID、购买数量、实付金额、订单状态、兑换码等属性;
  • 评价实体:包含评价 ID、用户 ID、游戏 ID、评价内容、评价时间、回复内容等属性;
  • 购物车实体:包含购物车 ID、用户 ID、游戏 ID、购买数量、添加时间等属性。

4.2.2 核心数据表结构设计

以下为系统关键数据表的详细结构(字段名、类型、说明、是否为空):

表 4-1 游戏表(shangpin)
序号列名数据类型说明允许空
1idint(11)主键 ID
2shangpin_namevarchar(200)游戏名称(如 “原神”“王者荣耀”)
3shangpin_uuid_numbervarchar(200)游戏唯一编号(如 “GP20250001”)
4shangpin_photovarchar(200)游戏封面图 URL(多图用逗号分隔)
5shangpin_typesint(11)游戏类型(关联字典表:1 = 动作 / 2 = 角色扮演 / 3 = 策略)
6youxiwanfa_typesint(11)游戏玩法(关联字典表:1 = 单人 / 2 = 多人联机)
7shangpin_kucun_numberint(11)游戏库存数量
8shangpin_old_moneydecimal(10,2)游戏原价(单位:元)
9shangpin_new_moneydecimal(10,2)游戏现价(单位:元,支持折扣)
10shangpin_clicknumint(11)游戏热度(浏览次数)
11shangpin_contenttext游戏介绍(含玩法、剧情)
12shangxia_typesint(11)是否上架(0 = 下架 / 1 = 上架)
13create_timetimestamp创建时间
表 4-2 游戏订单表(shangpin_order)
序号列名数据类型说明允许空
1idint(11)主键 ID
2shangpin_order_uuid_numbervarchar(200)订单编号(如 “OD20250001”)
3shangpin_idint(11)游戏 ID(关联游戏表主键)
4yonghu_idint(11)用户 ID(关联用户表主键)
5buy_numberint(11)购买数量(默认 1)
6shangpin_order_true_pricedecimal(10,2)实付金额(单位:元)
7shangpin_order_courier_numbervarchar(200)游戏兑换码(唯一,用于激活)
8shangpin_order_typesint(11)订单状态(0 = 待支付 / 1 = 已支付 / 2 = 已取消 / 3 = 已退款)
9insert_timetimestamp订单创建时间
10create_timetimestamp记录创建时间
表 4-3 用户表(yonghu)
序号列名数据类型说明允许空
1idint(11)主键 ID
2usernamevarchar(200)登录账号(唯一)
3passwordvarchar(200)登录密码(MD5 加密)
4yonghu_namevarchar(200)用户姓名
5yonghu_phonevarchar(200)用户手机号(唯一)
6yonghu_photovarchar(200)用户头像 URL
7new_moneydecimal(10,2)用户余额(单位:元)
8huiyuandengji_typesint(11)会员等级(0 = 普通 / 1 = 白银 / 2 = 黄金)
9create_timetimestamp创建时间
表 4-4 游戏评价表(shangpin_commentback)
序号列名数据类型说明允许空
1idint(11)主键 ID
2shangpin_idint(11)游戏 ID(关联游戏表主键)
3yonghu_idint(11)用户 ID(关联用户表主键)
4shangpin_commentback_texttext评价内容(如 “游戏体验极佳”)
5insert_timetimestamp评价时间
6reply_texttext管理员回复内容
7update_timetimestamp回复时间
8create_timetimestamp记录创建时间
表 4-5 购物车表(shop_car)
序号列名数据类型说明允许空
1idint(11)主键 ID
2yonghu_idint(11)用户 ID(关联用户表主键)
3shangpin_idint(11)游戏 ID(关联游戏表主键)
4buy_numberint(11)购买数量
5create_timetimestamp添加时间

五、系统实现:核心功能代码与界面展示

5.1 后端核心功能实现(以 “游戏检索” 为例)

5.1.1 实体类(Game.java)

使用 Lombok 简化 getter/setter 方法:

package com.game.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;

@Data
@TableName("shangpin") // 对应数据库表名
public class Game {
    @TableId(type = IdType.AUTO) // 主键自增
    private Integer id;
    private String shangpinName; // 游戏名称
    private String shangpinUuidNumber; // 游戏编号
    private String shangpinPhoto; // 游戏照片URL
    private Integer shangpinTypes; // 游戏类型
    private Integer youxiwanfaTypes; // 游戏玩法
    private Integer shangpinKucunNumber; // 库存数量
    private BigDecimal shangpinOldMoney; // 原价
    private BigDecimal shangpinNewMoney; // 现价
    private Integer shangpinClicknum; // 热度(浏览次数)
    private String shangpinContent; // 游戏介绍
    private Integer shangxiaTypes; // 是否上架(0=下架/1=上架)
    private Date createTime; // 创建时间
}

5.1.2 Mapper 接口(GameMapper.java)

继承 MyBatis-Plus 的 BaseMapper,无需手动编写 CRUD 方法:

package com.game.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.game.entity.Game;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;

@Mapper
public interface GameMapper extends BaseMapper<Game> {
    // 自定义游戏检索方法(按名称/类型模糊查询,仅查询上架游戏)
    default List<Game> searchGames(String keyword, Integer type) {
        QueryWrapper<Game> wrapper = new QueryWrapper<>();
        wrapper.eq("shangxia_types", 1); // 仅查询上架游戏
        if (keyword != null && !keyword.isEmpty()) {
            wrapper.like("shangpin_name", keyword); // 游戏名称模糊匹配
        }
        if (type != null) {
            wrapper.eq("shangpin_types", type); // 游戏类型精确匹配
        }
        wrapper.orderByDesc("shangpin_clicknum"); // 按热度降序排列
        return selectList(wrapper);
    }
}

5.1.3 Service 层(GameService.java + GameServiceImpl.java)

处理业务逻辑,集成 Redis 缓存提升检索效率:

// GameService.java(接口)
package com.game.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.game.entity.Game;
import java.util.List;

public interface GameService extends IService<Game> {
    // 游戏检索(支持关键词+类型筛选)
    List<Game> searchGames(String keyword, Integer type);
}

// GameServiceImpl.java(实现类)
package com.game.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.game.entity.Game;
import com.game.mapper.GameMapper;
import com.game.service.GameService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class GameServiceImpl extends ServiceImpl<GameMapper, Game> implements GameService {

    @Autowired
    private GameMapper gameMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    // 缓存key前缀(避免key冲突)
    private static final String GAME_CACHE_KEY = "game:search:";

    @Override
    public List<Game> searchGames(String keyword, Integer type) {
        // 1. 构建缓存key(关键词+类型拼接,空值用"null"填充)
        String cacheKey = GAME_CACHE_KEY + (keyword == null ? "null" : keyword) + ":" + (type == null ? "null" : type);
        
        // 2. 先从Redis查询缓存
        List<Game> gameList = (List<Game>) redisTemplate.opsForValue().get(cacheKey);
        if (gameList != null && !gameList.isEmpty()) {
            return gameList; // 缓存命中,直接返回
        }
        
        // 3. 缓存未命中,从数据库查询
        gameList = gameMapper.searchGames(keyword, type);
        
        // 4. 数据库查询结果存入Redis(设置缓存有效期30分钟,避免数据过期)
        if (gameList != null && !gameList.isEmpty()) {
            redisTemplate.opsForValue().set(cacheKey, gameList, 30, TimeUnit.MINUTES);
        }
        
        return gameList;
    }
}

5.1.4 Controller 层(GameController.java)

提供 RESTful 接口,接收前端请求并返回结果:

package com.game.controller;

import com.game.entity.Game;
import com.game.service.GameService;
import com.game.utils.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

@RestController
@RequestMapping("/api/game")
public class GameController {

    @Autowired
    private GameService gameService;

    // 游戏检索接口(支持关键词+类型筛选)
    @GetMapping("/search")
    public Result searchGames(
            @RequestParam(required = false) String keyword,
            @RequestParam(required = false) Integer type) {
        try {
            List<Game> gameList = gameService.searchGames(keyword, type);
            return Result.success("检索成功", gameList);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("检索失败:" + e.getMessage());
        }
    }

    // 游戏详情接口(按ID查询)
    @GetMapping("/detail")
    public Result getGameDetail(@RequestParam Integer id) {
        try {
            Game game = gameService.getById(id);
            if (game == null) {
                return Result.error("游戏不存在");
            }
            // 浏览次数+1(更新热度)
            game.setShangpinClicknum(game.getShangpinClicknum() + 1);
            gameService.updateById(game);
            return Result.success("获取成功", game);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("获取失败:" + e.getMessage());
        }
    }
}

5.2 前端核心界面展示

5.2.1 玩家端 - 游戏检索首页

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>游戏检索系统 - 首页</title>
    <link rel="stylesheet" href="${pageContext.request.contextPath}/layui/css/layui.css">
    <style>
        .game-card { margin: 15px; float: left; width: 280px; height: 380px; border: 1px solid #eee; border-radius: 8px; overflow: hidden; }
        .game-card:hover { box-shadow: 0 0 10px rgba(0,0,0,0.1); }
        .game-img { width: 100%; height: 180px; }
        .game-info { padding: 10px; }
        .game-name { font-size: 16px; font-weight: bold; margin-bottom: 5px; }
        .game-type { color: #666; font-size: 12px; margin-bottom: 10px; }
        .game-price { color: #ff4400; font-size: 18px; font-weight: bold; }
        .game-btn { margin-top: 15px; text-align: center; }
    </style>
</head>
<body class="layui-layout-body">
<div class="layui-layout layui-layout-admin">
    <!-- 头部导航 -->
    <header class="layui-header">
        <div class="layui-logo">游戏检索系统</div>
        <!-- 搜索框 -->
        <div style="position: absolute; left: 200px; top: 15px; width: 400px;">
            <div class="layui-input-group">
                <input type="text" id="keyword" placeholder="输入游戏名称检索" class="layui-input">
                <div class="layui-input-suffix">
                    <button class="layui-btn layui-btn-primary" onclick="searchGame()">检索</button>
                </div>
            </div>
        </div>
        <!-- 右侧菜单 -->
        <ul class="layui-nav layui-nav-menu layui-nav-right">
            <li class="layui-nav-item"><a href="${pageContext.request.contextPath}/user/cart">购物车</a></li>
            <li class="layui-nav-item"><a href="${pageContext.request.contextPath}/user/order">我的订单</a></li>
            <li class="layui-nav-item">
                <c:if test="${empty sessionScope.user}">
                    <a href="${pageContext.request.contextPath}/user/login">登录/注册</a>
                </c:if>
                <c:if test="${not empty sessionScope.user}">
                    <img src="${sessionScope.user.yonghuPhoto}" class="layui-nav-img">
                    ${sessionScope.user.yonghuName}
                    <dl class="layui-nav-child">
                        <dd><a href="${pageContext.request.contextPath}/user/profile">个人中心</a></dd>
                        <dd><a href="${pageContext.request.contextPath}/user/logout">退出登录</a></dd>
                    </dl>
                </c:if>
            </li>
        </ul>
    </header>

    <!-- 左侧筛选栏 -->
    <div class="layui-side" style="width: 200px;">
        <div class="layui-side-scroll">
            <div style="padding: 15px;">
                <h3 class="layui-title">游戏类型筛选</h3>
                <ul class="layui-menu layui-menu-tree">
                    <li class="layui-menu-item"><a href="javascript:;" onclick="filterByType(null)">全部类型</a></li>
                    <li class="layui-menu-item"><a href="javascript:;" onclick="filterByType(1)">动作类</a></li>
                    <li class="layui-menu-item"><a href="javascript:;" onclick="filterByType(2)">角色扮演</a></li>
                    <li class="layui-menu-item"><a href="javascript:;" onclick="filterByType(3)">策略类</a></li>
                    <li class="layui-menu-item"><a href="javascript:;" onclick="filterByType(4)">休闲益智</a></li>
                </ul>
            </div>
        </div>
    </div>

    <!-- 主体内容(游戏列表) -->
    <div class="layui-body" style="left: 200px; padding: 20px;">
        <div id="gameList" class="layui-row"></div>
    </div>

    <!-- 页脚 -->
    <footer class="layui-footer">© 2025 游戏检索系统 - 玩家端</footer>
</div>

<script src="${pageContext.request.contextPath}/layui/layui.js"></script>
<script src="${pageContext.request.contextPath}/js/jquery-3.6.0.min.js"></script>
<script>
    layui.use(['element', 'layer'], function() {
        var element = layui.element;
        var layer = layui.layer;
    });

    // 页面加载时默认加载全部游戏
    $(function() {
        searchGame(null, null);
    });

    // 游戏检索(关键词+类型)
    function searchGame(keyword, type) {
        // 若未传参数,从输入框获取
        if (keyword == null) keyword = $("#keyword").val().trim();
        if (type == null) type = getCurrentType(); // 从筛选栏获取当前类型
        
        $.ajax({
            url: "${pageContext.request.contextPath}/api/game/search",
            type: "GET",
            data: {keyword: keyword, type: type},
            success: function(res) {
                if (res.success) {
                    renderGameList(res.data); // 渲染游戏列表
                } else {
                    layer.msg(res.msg, {icon: 2});
                    $("#gameList").html("<div style='text-align: center; margin-top: 50px;'>暂无游戏数据</div>");
                }
            },
            error: function() {
                layer.msg("网络错误,请重试", {icon: 2});
            }
        });
    }

    // 按类型筛选游戏
    function filterByType(type) {
        // 重置筛选栏选中状态
        $(".layui-menu-item a").removeClass("layui-menu-this");
        $(`.layui-menu-item a[onclick="filterByType(${type})"]`).addClass("layui-menu-this");
        // 执行检索
        searchGame(null, type);
    }

    // 获取当前选中的类型
    function getCurrentType() {
        var currentA = $(".layui-menu-this");
        if (currentA.length == 0) return null;
        var onclick = currentA.attr("onclick");
        var type = onclick.match(/filterByType((\d+|null))/)[1];
        return type == "null" ? null : parseInt(type);
    }

    // 渲染游戏列表
    function renderGameList(gameList) {
        if (gameList.length == 0) {
            $("#gameList").html("<div style='text-align: center; margin-top: 50px;'>暂无匹配的游戏</div>");
            return;
        }
        var html = "";
        for (var i = 0; i < gameList.length; i++) {
            var game = gameList[i];
            // 游戏类型名称(1=动作类/2=角色扮演/3=策略类/4=休闲益智)
            var typeName = getTypeName(game.shangpinTypes);
            // 游戏封面图(默认图处理)
            var photo = game.shangpinPhoto ? game.shangpinPhoto.split(",")[0] : "${pageContext.request.contextPath}/images/default-game.jpg";
            
            html += `
                <div class="game-card">
                    <img src="${photo}" class="game-img" onclick="toGameDetail(${game.id})">
                    <div class="game-info">
                        <div class="game-name" onclick="toGameDetail(${game.id})">${game.shangpinName}</div>
                        <div class="game-type">类型:${typeName} | 热度:${game.shangpinClicknum}</div>
                        <div class="game-price">¥${game.shangpinNewMoney}</div>
                        <div class="game-btn">
                            <button class="layui-btn layui-btn-sm layui-btn-primary" onclick="addToCart(${game.id})">加入购物车</button>
                            <button class="layui-btn layui-btn-sm layui-btn-normal" onclick="buyNow(${game.id})">立即购买</button>
                        </div>
                    </div>
                </div>
            `;
        }
        $("#gameList").html(html);
    }

    // 获取游戏类型名称
    function getTypeName(type) {
        switch(type) {
            case 1: return "动作类";
            case 2: return "角色扮演";
            case 3: return "策略类";
            case 4: return "休闲益智";
            default: return "未知类型";
        }
    }

    // 跳转至游戏详情页
    function toGameDetail(id) {
        window.location.href = "${pageContext.request.contextPath}/user/gameDetail?id=" + id;
    }

    // 加入购物车
    function addToCart(id) {
        // 判断是否登录
        <c:if test="${empty sessionScope.user}">
            layer.msg("请先登录", {icon: 2}, function() {
                window.location.href = "${pageContext.request.contextPath}/user/login";
            });
            return;
        </c:if>
        // 发起加入购物车请求(实际项目需完善接口)
        $.ajax({
            url: "${pageContext.request.contextPath}/api/cart/add",
            type: "POST",
            data: {shangpinId: id, buyNumber: 1},
            success: function(res) {
                if (res.success) {
                    layer.msg("加入购物车成功", {icon: 1});
                } else {
                    layer.msg(res.msg, {icon: 2});
                }
            }
        });
    }

    // 立即购买
    function buyNow(id) {
        // 判断是否登录
        <c:if test="${empty sessionScope.user}">
            layer.msg("请先登录", {icon: 2}, function() {
                window.location.href = "${pageContext.request.contextPath}/user/login";
            });
            return;
        </c:if>
        // 跳转至确认订单页
        window.location.href = "${pageContext.request.contextPath}/user/confirmOrder?id=" + id;
    }
</script>
</body>
</html>

六、系统测试:功能验证与性能评估

6.1 核心功能测试

通过 “等价类划分法” 设计测试用例,验证系统关键功能的正确性:

测试功能测试用例预期结果实际结果是否通过
游戏检索1. 输入存在的游戏名称(如 “原神”);2. 输入不存在的名称(如 “test”);3. 筛选类型 “动作类”1. 返回匹配游戏;2. 提示 “暂无匹配”;3. 返回所有动作类游戏与预期一致
订单创建1. 库存充足时下单;2. 库存为 0 时下单;3. 重复提交订单1. 订单创建成功,库存扣减;2. 提示 “库存不足”;3. 防止重复创建(仅生成 1 个订单)与预期一致
用户登录1. 账号密码正确;2. 账号正确密码错误;3. 账号不存在1. 登录成功;2. 提示 “密码错误”;3. 提示 “账号不存在”与预期一致
游戏上下架1. 上架下架游戏;2. 下架后玩家端是否可见1. 状态切换成功;2. 下架游戏不在玩家端显示与预期一致

6.2 性能测试

通过 JMeter 工具模拟 500 用户同时在线,测试系统关键接口性能:

接口名称测试场景(500 用户并发)平均响应时间QPS(每秒请求量)成功率
游戏检索接口关键词模糊查询0.8 秒120100%
订单创建接口提交订单(含库存扣减)1.5 秒80100%
游戏详情接口按 ID 查询游戏信息0.5 秒150100%

测试结果表明,系统在 500 用户并发场景下,所有接口响应时间均<2 秒,成功率 100%,满足设计预期。

七、项目总结与扩展方向

7.1 项目总结

本系统基于 Spring Boot 框架实现,完成了 “游戏检索、订单管理、用户交互、后台管控” 四大核心功能,解决了传统游戏信息管理的分散、混乱问题。通过 MySQL 实现数据持久化,Redis 优化检索性能,Layui 构建友好界面,系统整体具备 “轻量、高效、易维护” 的特点:

  1. 开发效率高:Spring Boot 自动配置减少 80% 的配置代码,MyBatis-Plus 通用接口减少重复 CRUD 代码;
  2. 用户体验好:玩家端检索响应快、操作流程清晰,管理员端功能模块化,管控便捷;
  3. 扩展性强:系统采用分层设计(Controller→Service→Mapper),新增功能无需重构核心代码。

7.2 扩展方向

  1. 集成第三方支付:当前系统为模拟支付,后期可集成支付宝、微信支付接口,实现真实交易;
  2. 添加游戏下载功能:开发游戏下载模块,玩家购买后可直接下载游戏客户端,绑定兑换码激活;
  3. 构建玩家社区:新增 “游戏攻略、玩家评论、好友互动” 功能,提升用户粘性;
  4. 引入推荐算法:基于玩家历史浏览、购买记录,通过协同过滤算法推荐相似游戏,提升转化率。