首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【苍穹外卖】深度解析:商品浏览四大核心接口设计(附完整数据流转图)

【苍穹外卖】深度解析:商品浏览四大核心接口设计(附完整数据流转图)

作者头像
北极的代码
发布2026-04-22 16:51:20
发布2026-04-22 16:51:20
1320
举报
前言:我们前面完成了小程序的开发,接下来我们完善小程序的页面展示,分页查询,查询分类,菜品,套餐等接口..........

四个核心接口的完整设计详解

让我用数据流转图的方式,详细解释每个接口的设计和ID的来源:

一、接口概览

java

代码语言:javascript
复制
1. 查询分类接口    →  /user/category/list
2. 根据ID查菜品    →  /user/dish/{id}
3. 根据ID查套餐    →  /user/setmeal/{id}
4. 查套餐下的菜品  →  /user/setmeal/dish/list/{setmealId}
二、详细设计(含ID来源)
接口1:查询分类接口
代码语言:javascript
复制
java

/**
 * 查询所有分类
 * 场景:用户打开APP首页,需要显示菜品分类和套餐分类
 * ID来源:这个接口不传ID,而是获取所有分类的ID
 */
@GetMapping("/user/category/list")
public Result<List<Category>> list(@RequestParam(required = false) Integer type) {
    // type=1查菜品分类,type=2查套餐分类,不传就查所有
    List<Category> list = categoryService.list(type);
    return Result.success(list);
}

// 返回数据示例
[
    {
        "id": 101,        // ← 这是分类ID,会在接口2、3中使用
        "name": "凉菜",
        "type": 1,        // 菜品分类
        "sort": 1,
        "image": "xxx.jpg"
    },
    {
        "id": 102,        
        "name": "热菜",   
        "type": 1
    },
    {
        "id": 201,        // ← 套餐分类ID
        "name": "超值套餐",
        "type": 2         // 套餐分类
    }
]
接口2:根据ID查询菜品
代码语言:javascript
复制
java

/**
 * 根据ID查询菜品详情
 * 场景:用户点击某个菜品,查看详细信息
 * ID来源:从接口1返回的菜品分类ID,或者从菜品列表中点击
 */
@GetMapping("/user/dish/{id}")
public Result<DishVO> getById(@PathVariable Long id) {
    // id 是从哪里来的?
    // 来源1:用户点击菜品分类后,从菜品列表中选择一个菜品
    // 来源2:用户直接搜索菜品ID
    // 来源3:从套餐详情中点击某个菜品
    DishVO dishVO = dishService.getWithFlavor(id);
    return Result.success(dishVO);
}

// 调用示例
GET /user/dish/501  // 501是菜品ID

// 返回数据
{
    "id": 501,              // ← 菜品ID
    "name": "香辣鸡腿堡",
    "categoryId": 101,      // 所属分类ID
    "price": 18.00,
    "image": "burger.jpg",
    "description": "香辣可口",
    "flavors": [            // 口味选项
        {"name": "辣度", "options": ["微辣", "中辣", "特辣"]},
        {"name": "酱料", "options": ["番茄酱", "沙拉酱", "不要酱"]}
    ]
}
接口3:根据ID查询套餐
代码语言:javascript
复制
java

/**
 * 根据ID查询套餐基本信息
 * 场景:用户点击某个套餐,查看套餐概览
 * ID来源:从接口1返回的套餐分类ID,然后点击具体套餐
 */
@GetMapping("/user/setmeal/{id}")
public Result<Setmeal> getById(@PathVariable Long id) {
    // id 是从哪里来的?
    // 来源1:用户点击套餐分类后,从套餐列表中选择一个套餐
    // 来源2:用户直接搜索套餐ID
    Setmeal setmeal = setmealService.getById(id);
    return Result.success(setmeal);
}

// 调用示例
GET /user/setmeal/1001  // 1001是套餐ID

// 返回数据
{
    "id": 1001,            // ← 套餐ID
    "name": "经典双人餐",
    "categoryId": 201,     // 所属套餐分类ID
    "price": 68.00,
    "image": "setmeal.jpg",
    "description": "超值优惠套餐",
    "status": 1            // 启售状态
}
接口4:查询套餐下的菜品
代码语言:javascript
复制
java

/**
 * 查询套餐包含的所有菜品
 * 场景:用户查看套餐详情时,需要知道套餐里具体有哪些菜
 * ID来源:从接口3返回的套餐ID
 */
@GetMapping("/user/setmeal/dish/list/{setmealId}")
public Result<List<DishVO>> getDishBySetmealId(@PathVariable Long setmealId) {
    // setmealId 是从哪里来的?
    // 来源:接口3返回的套餐ID(如1001)
    List<DishVO> list = setmealDishService.getDishBySetmealId(setmealId);
    return Result.success(list);
}

// 调用示例
GET /user/setmeal/dish/list/1001  // 1001是套餐ID

// 返回数据
[
    {
        "id": 501,           // ← 菜品ID
        "name": "香辣鸡腿堡",
        "price": 18.00,
        "copies": 2,         // 套餐中包含2份
        "image": "burger.jpg",
        "flavors": [...]      // 口味选项
    },
    {
        "id": 502,
        "name": "中份薯条",
        "price": 12.00,
        "copies": 1,
        "image": "fries.jpg"
    },
    {
        "id": 503,
        "name": "可乐",
        "price": 8.00,
        "copies": 2,
        "image": "cola.jpg"
    }
]
三、完整的数据流转图
四、后端实现代码
代码语言:javascript
复制
java

@RestController
@RequestMapping("/user")
public class UserBrowseController {

    @Autowired
    private CategoryService categoryService;
    @Autowired
    private DishService dishService;
    @Autowired
    private SetmealService setmealService;
    @Autowired
    private SetmealDishService setmealDishService;

    // 1. 查询分类接口
    @GetMapping("/category/list")
    public Result<List<Category>> list(Integer type) {
        // SQL: SELECT * FROM category 
        // WHERE (type = ? OR ? IS NULL) 
        // ORDER BY sort DESC
        List<Category> list = categoryService.lambdaQuery()
                .eq(type != null, Category::getType, type)
                .orderByDesc(Category::getSort)
                .list();
        return Result.success(list);
    }

    // 2. 根据ID查询菜品
    @GetMapping("/dish/{id}")
    public Result<DishVO> getDishById(@PathVariable Long id) {
        // 1. 查询菜品基本信息
        // SQL: SELECT * FROM dish WHERE id = #{id}
        Dish dish = dishService.getById(id);
        
        // 2. 查询菜品口味
        // SQL: SELECT * FROM dish_flavor WHERE dish_id = #{id}
        List<DishFlavor> flavors = dishFlavorService.lambdaQuery()
                .eq(DishFlavor::getDishId, id)
                .list();
        
        // 3. 组装VO
        DishVO dishVO = new DishVO();
        BeanUtils.copyProperties(dish, dishVO);
        dishVO.setFlavors(flavors);
        
        return Result.success(dishVO);
    }

    // 3. 根据ID查询套餐
    @GetMapping("/setmeal/{id}")
    public Result<Setmeal> getSetmealById(@PathVariable Long id) {
        // SQL: SELECT * FROM setmeal WHERE id = #{id} AND status = 1
        Setmeal setmeal = setmealService.lambdaQuery()
                .eq(Setmeal::getId, id)
                .eq(Setmeal::getStatus, 1)  // 只查启售的
                .one();
        return Result.success(setmeal);
    }

    // 4. 查询套餐下的菜品
    @GetMapping("/setmeal/dish/list/{setmealId}")
    public Result<List<DishVO>> getDishBySetmealId(@PathVariable Long setmealId) {
        // SQL: SELECT d.*, sd.copies 
        // FROM setmeal_dish sd
        // LEFT JOIN dish d ON sd.dish_id = d.id
        // WHERE sd.setmeal_id = #{setmealId}
        // ORDER BY sd.sort
        List<DishVO> list = setmealDishService.getBaseMapper().selectDishBySetmealId(setmealId);
        return Result.success(list);
    }
}
五、ID来源汇总表

接口

ID参数

ID来源

示例

查询分类

-

-

根据ID查菜品

dishId

1. 从菜品列表点击 2. 从套餐详情点击菜品

501

根据ID查套餐

setmealId

从套餐列表点击

1001

查套餐下的菜品

setmealId

从接口3获取的套餐ID

1001

六、调用时序图

text

代码语言:javascript
复制
时间线    用户操作                前端请求                   后端处理
   │         │                      │                         │
   │   打开APP                     │                         │
   │         │─── /category/list ─→│                         │
   │         │                     │─── 查询category表 ─────→│
   │         │                     │←── 返回分类列表 ────────│
   │         │←── 显示分类列表 ────│                         │
   │         │                      │                         │
   │   点击"超值套餐"               │                         │
   │         │─── /setmeal/list?    │                         │
   │         │    categoryId=201 ─→│                         │
   │         │                     │─── 查询setmeal表 ─────→│
   │         │                     │←── 返回套餐列表 ────────│
   │         │←── 显示套餐列表 ────│                         │
   │         │                      │                         │
   │   点击"经典双人餐"             │                         │
   │         │─── /setmeal/1001 ──→│                         │
   │         │                     │─── 查询setmeal表 ─────→│
   │         │                     │←── 返回套餐信息 ────────│
   │         │                      │                         │
   │         │─── /setmeal/dish/    │                         │
   │         │    list/1001 ──────→│                         │
   │         │                     │─── 查询setmeal_dish表 ─→│
   │         │                     │─── 关联查询dish表 ─────→│
   │         │                     │←── 返回菜品列表 ────────│
   │         │←── 显示套餐详情 ────│                         │
   │         │(汉堡×2,薯条×1,可乐×2)│                         │
   ▼         │                      │                         │
七、关键点总结
  1. ID的传递链: text 分类ID:数据库生成 → 接口1返回 → 前端存储 → 用于查菜品/套餐列表 菜品ID:数据库生成 → 接口2返回 → 前端存储 → 用于查菜品详情 套餐ID:数据库生成 → 接口3返回 → 前端存储 → 用于查套餐详情和套餐内菜品
  2. 接口设计原则
    • 每个接口职责单一(一个接口只做一件事)
    • ID作为资源标识符(RESTful风格)
    • 通过路径传参(@PathVariable)
  3. 数据流向
    • 前端只负责传递用户选择的ID
    • 后端根据ID查询对应的数据
    • 数据库通过主键ID快速定位记录

这样设计既清晰又高效,符合RESTful API的设计规范!

让我用一个餐厅点餐的场景,来理解这个功能的实现原理。

一、需求分析(为什么要做?)

想象你走进一家餐厅,服务员递给你一本菜单,你需要:

  1. 看到所有菜品分类(热菜、凉菜、主食等)
  2. 查看某个分类下的菜品(比如只看凉菜)
  3. 看到菜品详情(价格、口味、图片等)
  4. 能快速搜索想吃的菜

这就是商品浏览功能要解决的核心需求

二、接口设计(前后端如何沟通?)

就像餐厅有服务员帮你传话,接口就是前后端沟通的桥梁:

text

代码语言:javascript
复制
1. 查询分类接口
   GET /user/category/list
   作用:像翻开菜单的第一页,看到所有菜品分类

2. 根据分类查询菜品接口  
   GET /user/dish/list?categoryId=xxx
   作用:点击某个分类(如"凉菜"),展示该分类下的所有菜品

3. 菜品详情接口
   GET /user/dish/detail/{id}
   作用:点击某个菜品,查看它的详细信息
三、实现原理(怎么做到的?)
形象比喻:像整理一本"智能菜单"

第一步:数据存储(菜单怎么写好的?)

  • 厨师(管理员)提前把菜品信息录入系统
  • 存在数据库里,就像把菜名、价格、图片写在菜单上
  • 数据结构: sql -- 分类表:好比菜单的章节 category表:id、名称、类型、排序 -- 菜品表:好比每道菜的介绍 dish表:id、名称、分类id、价格、图片、描述

第二步:数据查询(怎么快速找到菜?)

  • 顾客(用户)点击"凉菜"分类
  • 系统自动执行SQL查询: sql SELECT * FROM dish WHERE category_id = 凉菜的id AND status = 1 -- 只查询启售的菜品 ORDER BY sort -- 按排序字段展示
  • 就像服务员快速翻到凉菜那几页

第三步:数据组装(怎么让菜品更诱人?)

  • 查询到基础菜品信息后,还需要:
    • 组装上图片的完整访问路径(http://.../dish/xxx.jpg
    • 如果有口味选项(辣度、规格),也要一起返回
    • 就像给每道菜配上精美的图片和标注

第四步:缓存优化(怎么让翻菜单更快?)

  • 使用Redis缓存热门菜品数据
  • 第一次查询:"这个凉菜分类有哪些菜?" → 查数据库
  • 第二次查询:直接从Redis拿,不用再查数据库
  • 就像服务员把常点的菜品记在脑子里,不用每次都翻菜单
四、代码实现示例
代码语言:javascript
复制
java

// 1. 分类查询接口
@GetMapping("/user/category/list")
public Result<List<Category>> list(String type) {
    List<Category> list = categoryService.list(type);
    return Result.success(list);
}

// 2. 根据分类查菜品
@GetMapping("/user/dish/list")
public Result<List<DishVO>> list(Long categoryId) {
    // 1. 先查Redis缓存
    String key = "dish_" + categoryId;
    List<DishVO> list = (List<DishVO>) redisTemplate.opsForValue().get(key);
    
    if (list == null) {
        // 2. 缓存没有,查数据库
        list = dishService.listWithFlavor(categoryId);
        // 3. 放入缓存
        redisTemplate.opsForValue().set(key, list);
    }
    
    return Result.success(list);
}
五、核心流程总结
  1. 用户请求:点击某个菜品分类
  2. 后端处理
    • 查询该分类下的所有启售菜品
    • 组装菜品图片和口味信息
    • 返回给前端
  3. 前端展示:以网格或列表形式展示菜品

这就是商品浏览功能的实现原理,像一本智能菜单,让顾客能快速浏览、查找想点的菜品

结语:如果这篇文章对你有帮助,请点赞,关注,收藏,你的支持就是我更新的动力!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2026-03-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 四个核心接口的完整设计详解
    • 一、接口概览
    • 二、详细设计(含ID来源)
      • 接口1:查询分类接口
      • 接口2:根据ID查询菜品
      • 接口3:根据ID查询套餐
      • 接口4:查询套餐下的菜品
    • 三、完整的数据流转图
    • 四、后端实现代码
    • 五、ID来源汇总表
    • 六、调用时序图
    • 七、关键点总结
    • 一、需求分析(为什么要做?)
    • 二、接口设计(前后端如何沟通?)
    • 三、实现原理(怎么做到的?)
      • 形象比喻:像整理一本"智能菜单"
    • 四、代码实现示例
    • 五、核心流程总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档