商品分类 — 技术方案(C 端)
依据: 《商品分类功能需求.md》v1.0.1
关联: 平台《商品分类技术方案.md》v1.2、《商品管理技术方案.md》v1.3、《店铺管理技术方案.md》v1.2.6、《商城首页技术方案.md》v1.1、《关联需求分析.md》v1.6
范围: C 端 /api/category/** 只读(全部分类树、一级下二级 Tab、二级下商品分页列表);无 平台/店铺分类 CRUD、无 搜索执行、无 新建业务主表。
原则: 无新建表;复用 biz_goods_category、biz_goods、biz_shop;全部 @Anonymous;搜索栏 无接口(GC-S1)。
1. 技术架构
| 项 |
选型 |
| 基础框架 |
RuoYi v3.9.2(springboot2 分支) |
| 数据库 |
MySQL 5.7.39 |
| ORM / 响应 |
MyBatis;分类树 AjaxResult;商品列表 TableDataInfo(分页) |
| 鉴权 |
C 端 @Anonymous(访客/会员均可读) |
| 分页 |
RuoYi PageHelper + startPage()(/goods) |
| 缓存 |
本期不做 Redis;读库即时生效 |
1.1 模块落位
baqing-shop/src/main/java/com/ruoyi/web/modules/home/
├── controller/CategoryAppController.java # /api/category/**
├── service/ICategoryAppService.java
├── service/impl/CategoryAppServiceImpl.java
├── mapper/CategoryAppMapper.java # 二级 Tab、分类商品 SQL
├── dto/CategoryGoodsQuery.java
├── constant/CategoryAppConstants.java # sortBy 枚举值
└── vo/HomeHotGoodsVO.java # 商品卡片(与首页热销共用)
已有(category 模块 · Facade):
└── com.ruoyi.web.modules.category.facade.ICategoryFacade
listVisibleByShopId(null) # 平台可见分类树(A 页 / tree)
isCategoryVisible(categoryId) # 二级校验(/goods)
已有(home 模块 · 首页一级导航,勿混用):
└── HomeAppController GET /api/home/categories
仅一级扁平列表,供首页横向导航;**不含** children
resources/mapper/home/
└── CategoryAppMapper.xml
说明: C 端分类与 C 端首页 同属 home 包、不同基路径(/api/category vs /api/home)。平台分类 CRUD 仍在 /agri/category(PlatformCategoryController)。
1.2 协作链
biz_goods_category(shop_id IS NULL)
├── GET /api/category/tree → A 页 · 一级+二级树
├── GET /api/category/{level1Id}/level2-tabs → B 页 · 二级 Tab
└── (校验)isCategoryVisible
biz_goods + biz_shop
└── GET /api/category/goods?categoryId=&sortBy=&pageNum=&pageSize=
→ B 内嵌列表 / C 独立列表(共用)
【页面与接口】
首页 HM7 ──一级──► B:level2-tabs + goods(默认首 Tab)
首页「更多」──► A:tree ──点二级──► C:goods(同 goods 接口)
搜索栏:纯前端 GC-S1(无接口)
| 关联模块 |
协作 |
| 平台 · 商品分类 |
维护 biz_goods_category;C 端只读 show_flag / 排序 |
| 商品分类 Facade |
listVisibleByShopId(null) 过滤空壳一级、父隐子隐(GC6) |
| 商城首页 |
/api/home/categories 一级快捷导航;点击进入本模块 B 页 |
| 商品 / 审核 |
列表 goods_status=2(出售中) |
| 店铺管理 |
JOIN shop_name 实时;不过滤 停业/库存(GC13) |
| 会员管理 |
不校验 Token |
| 商品详情 |
列表点击跳转;可购四条件在详情/Facade 校验(GC12) |
1.3 跨模块 Facade
| 接口 |
本模块用法 |
ICategoryFacade.listVisibleByShopId(null) |
/tree 平台全量可见树(含 children) |
ICategoryFacade.isCategoryVisible |
/goods 校验二级 categoryId |
IPlatformCategoryService |
不直接 暴露 C 端 HTTP |
IGoodsPurchaseFacade / 详情 |
本模块 不调用;下单层校验 |
2. 数据库设计
2.1 原则
无新建表。 只读下列已有表;DDL 见 sql/。
| 表 |
本模块用途 |
权威 DDL |
biz_goods_category |
平台一/二级导航 |
sql/biz_goods_category.sql |
biz_goods |
二级下商品列表 |
sql/biz_goods.sql |
biz_shop |
商品卡片店铺名 |
sql/biz_shop.sql |
2.2 本模块读字段与条件
biz_goods_category — 平台分类(shop_id IS NULL)
| 场景 |
条件 |
输出字段 |
| tree(Facade 内存组装) |
一级 show=1 且下有可见二级;二级 isCategoryVisible |
categoryId, categoryName, categoryPic, sortNo, hotFlag + children[] |
| level2-tabs |
level=2, parent_id=#{level1Id}, show=1, del=0;且一级可见 |
同上(无 children) |
biz_goods + biz_shop — 分类商品列表
| 字段 |
条件 / 说明 |
| g.category_id |
= 所选二级 ID |
| g.goods_status |
2 出售中(GC8) |
| g.del_flag |
0 |
| s.del_flag |
0(JOIN) |
| g.sales_count, g.sale_price, g.goods_sn |
排序键(GC9) |
| g.goods_id, g.goods_sn, g.goods_name, g.main_pic, g.sale_price |
输出 |
| s.shop_id, s.shop_name |
JOIN;实时(GC10) |
浏览层: SQL 不过滤 shop_status、不过滤 stock(GC13)。
2.3 与首页 /api/home/categories 差异
| 项 |
/api/home/categories |
/api/category/tree |
| 层级 |
仅 一级 扁平 |
一级 + 二级 树 |
| 空壳一级 |
SQL 仅 show=1(首页导航宜与 GC6 对齐:无可见二级的不展示) |
Facade 排除 无可见二级的一级 |
| 用途 |
首页横向导航 +「更多」 |
A 全部分类页 |
2.4 建议索引(可选)
-- 可选:与首页热销共用
-- idx_category_id on biz_goods(category_id)
-- idx_shop_status 等现有索引一般够用
3. C 端接口设计
基路径: /api/category
鉴权: 全部 @Anonymous
3.1 接口一览
| 方法 |
路径 |
页面 |
说明 |
| GET |
/tree |
A 全部分类 |
平台可见分类树 |
| GET |
/{level1Id}/level2-tabs |
B Tab 区 |
指定一级下二级列表 |
| GET |
/goods |
B/C 商品列表 |
二级下出售中商品 分页 |
本期不提供: 搜索 API、聚合 /api/category/index、店铺分类读接口。
3.2 可见分类树 GET /api/category/tree
| 项 |
说明 |
| Query |
无 |
| 实现 |
ICategoryFacade.listVisibleByShopId(null) |
data: CategoryVisibleVO[](category 模块已有 VO)
| 字段 |
说明 |
| categoryId |
一级 ID |
| categoryName |
名称 |
| categoryPic |
图片 |
| sortNo |
排序 |
| hotFlag |
是否热门 |
| children |
CategoryVisibleChildVO[](二级) |
children 元素: categoryId, categoryName, categoryPic, sortNo, hotFlag
前端(A 页): 左列 = data;右列 = 当前选中一级的 children;点 child → 路由 C 页并带 categoryId。
3.3 一级下二级 Tab GET /api/category/{level1Id}/level2-tabs
| 项 |
说明 |
| Path |
level1Id — 平台一级 ID |
| 校验 |
一级存在、shop_id IS NULL、level=1、show=1;否则 ServiceException |
data: CategoryVisibleChildVO[](按 sort_no, create_time 升序)
SQL 片段:
SELECT category_id, category_name, category_pic, hot_flag, sort_no
FROM biz_goods_category
WHERE shop_id IS NULL
AND category_level = '2'
AND parent_id = #{level1Id}
AND show_flag = '1'
AND del_flag = '0'
ORDER BY sort_no ASC, create_time ASC
前端(B 页): 首页带入 level1Id → 本接口渲染 Tab → 默认首 Tab 调 /goods;切换 Tab(C1)仅改 categoryId 重新请求 /goods。
3.4 分类商品列表 GET /api/category/goods
| 项 |
说明 |
| Query |
见下表 |
| 分页 |
pageNum、pageSize(RuoYi 默认) |
| 响应 |
TableDataInfo:{ code, msg, rows, total } |
Query:
| 参数 |
必填 |
说明 |
| categoryId |
是 |
平台二级 分类 ID |
| sortBy |
否 |
默认 sales_desc(CategoryAppConstants.DEFAULT_SORT) |
| pageNum |
否 |
页码 |
| pageSize |
否 |
每页条数 |
sortBy 合法值:
| 值 |
排序 |
sales_desc |
销量降序 → goods_sn 升序 |
sales_asc |
销量升序 → goods_sn 升序 |
price_desc |
售价降序 → goods_sn 升序 |
price_asc |
售价升序 → goods_sn 升序 |
校验:
categoryId 非空
categoryFacade.isCategoryVisible(categoryId) 为 true,否则「分类不存在或不可见」
sortBy 非法 →「排序参数无效」
rows 元素: HomeHotGoodsVO(与 /api/home/hot-goods 同结构)
| 字段 |
类型 |
说明 |
| goodsId |
long |
|
| goodsSn |
string |
|
| goodsName |
string |
|
| mainPic |
string |
|
| salePrice |
decimal |
|
| shopId |
long |
|
| shopName |
string |
实时 |
SQL 片段:
SELECT g.goods_id, g.goods_sn, g.goods_name, g.main_pic, g.sale_price,
s.shop_id, s.shop_name
FROM biz_goods g
INNER JOIN biz_shop s ON g.shop_id = s.shop_id AND s.del_flag = '0'
WHERE g.goods_status = '2'
AND g.del_flag = '0'
AND g.category_id = #{categoryId}
ORDER BY
-- 动态 sortBy,同键 goods_sn ASC
3.5 搜索栏
| 项 |
说明 |
| 占位 |
前端写死「搜索兽药、饲料、店铺」(GC3) |
| 接口 |
无 |
4. Service 分层
CategoryAppController
→ ICategoryAppService.listCategoryTree()
→ ICategoryAppService.listLevel2Tabs(level1Id)
→ ICategoryAppService.listCategoryGoods(query) # 分页由 Controller startPage
CategoryAppServiceImpl
→ ICategoryFacade.listVisibleByShopId(null)
→ ICategoryFacade.isCategoryVisible(categoryId)
→ BizGoodsCategoryMapper.selectById(level1Id, null) # 一级校验
→ CategoryAppMapper.selectPlatformLevel2Tabs(level1Id)
→ CategoryAppMapper.selectGoodsByCategory(categoryId, sortBy)
| 方法 |
说明 |
listCategoryTree() |
透传 Facade;shopId=null → 平台树 |
listLevel2Tabs() |
校验一级可见 → Mapper 查二级 |
listCategoryGoods() |
校验二级可见 + sortBy → Mapper;不 校验可购四条件 |
5. 与平台后台对照
| 平台操作 |
影响的 C 端接口 |
| 平台分类改 show/排序/名称/图 |
/tree、/level2-tabs |
| 平台分类改 show=0 |
树/Tab 即时隐藏;/goods 校验失败 |
| 商品上下架 |
/goods 增删行 |
| 店铺改名 |
/goods 的 shopName |
| 店铺停业 |
仍出现在 /goods;下单在详情拦截 |
| 会员禁用 |
不影响 三接口 |
6. 业务规则映射
| 规则 |
实现 |
| GC1 |
仅 shop_id IS NULL / Facade 平台树 |
| GC2 |
@Anonymous |
| GC3~GC-S2 |
无搜索 API |
| GC4 |
/tree + 前端 A→C 路由 |
| GC5 |
/level2-tabs + /goods;Tab 切换前端 C1 |
| GC5a |
/goods + 前端面包屑(路径非接口字段) |
| GC6 |
Facade listVisibleByShopId + isCategoryVisible |
| GC7 |
SQL / Facade 排序 |
| GC8~GC10 |
/goods SQL + HomeHotGoodsVO |
| GC9 |
sortBy 四档 + 默认 sales_desc |
| GC12 |
Service 不 调可购 Facade |
| GC13 |
SQL 不过滤店态/库存 |
| GC14 |
三接口 独立;前端模块级空态 |
| GC15 |
无写接口 |
7. 前端接口调用建议
| 页面 |
调用顺序 |
| A 全部分类 |
GET /tree → 点二级 → GET /goods?categoryId= |
| B 一级分类 |
GET /{level1Id}/level2-tabs → GET /goods?categoryId=首Tab → 切换 Tab 仅重调 /goods |
| C 独立列表 |
GET /goods?categoryId=(level1Id 由路由/状态展示面包屑) |
C1: Tab 切换时前端 列表回顶 后再请求 /goods(产品层,非后端字段)。
8. 实现状态
| 项 |
状态 |
GET /api/category/tree |
待实现 |
GET /api/category/{level1Id}/level2-tabs |
待实现 |
GET /api/category/goods |
待实现 |
CategoryAppController / CategoryAppServiceImpl |
待创建 |
CategoryAppMapper.xml |
待创建 |
| C 端分类前端 |
已实现(见《商品分类前端技术方案.md》v1.0) |
9. 非本期
| 项 |
说明 |
GET /api/category/index 聚合 |
前端分调三接口即可 |
| Redis 缓存 |
— |
/api/search/** |
搜索模块 |
| 店铺商品分类 C 端读 |
GC1 排除 |
| 列表返回销量/库存字段 |
GC10 卡片不展示 |
| 商品详情 API |
商品详情模块 |
10. 修订记录
| 版本 |
说明 |
| v1.0 |
首版;无新建表;/api/category 三读接口;关联平台分类 Facade、商城首页 v1.1 |
文档版本:v1.0 · MySQL 5.7.39 · RuoYi v3.9.2-springboot2 · 关联《商品分类功能需求.md》v1.0.1、《商品分类技术方案.md》v1.2(平台)、《商城首页技术方案.md》v1.1