跳到主要内容

商品分类架构

概述

  1. 商品分类是商品重要组成部分,商品参数和品牌信息都是通过分类与商品进行关联的
  2. Javashop电商系统只支持三级分类
  3. 分类由平台统一进行维护,商家在入驻时需要选择对应的经营类目
  4. 在新增商品时,必须要先选择分类

数据库设计

分类表

表名:es_category

字段名类型与长度备注
category_idbigint(20)主键ID
namevarchar(100)分类名称
parent_idbigint(20)父分类ID(一级分类该字段值为0)
category_pathvarchar(255)上下级分类ID关系结构(如:0|1|2|3|
goods_countint(10)分类下的商品数量(预留字段,当前版本暂时未用到)
category_orderint(10)分类排序值(数值越小,排序越靠前)
imagevarchar(255)分类图片
is_showvarchar(20)是否在客户端显示 YES:是,NO:否
adv_imagevarchar(255)分类广告图片
adv_image_linkvarchar(255)分类广告图片跳转链接
custom_snvarchar(50)自定义编码(需唯一)

结构图

image-20230811165806918

API说明

核心API

实体类参数可参考下方的类图展示

管理端

请求方式API地址参数说明作用
GEThttps://{admin-api-domain}/admin/goods/categories/{parent_id}/childrenLong parentId:父分类主键ID(如果获取一级分类,此值传0)查询某分类下的子分类数据集合
POSThttps://{admin-api-domain}/admin/goods/categoriesCategoryDO category:分类信息新增分类信息
PUThttps://{admin-api-domain}/admin/goods/categories/{id}CategoryDO category:分类信息,Long id:分类主键ID修改分类信息
GEThttps://{admin-api-domain}/admin/goods/categories/{id}Long id:分类主键ID根据主键ID获取分类信息
DELETEhttps://{admin-api-domain}/admin/goods/categories/{id}Long id:分类主键ID删除分类信息

商家端

请求方式API地址参数说明作用
GEThttps://{seller-api-domain}/seller/goods/category/{category_id}/childrenLong categoryId:分类主键ID商品发布时,获取当前店铺选择的经营类目信息
GEThttps://{seller-api-domain}/seller/goods/category/{parent_id}/all-childrenLong parentId:父分类主键ID(如果获取一级分类,此值传0)查询某分类下的子分类数据集合
GEThttps://{seller-api-domain}/seller/goods/category/seller/children获取商家所有经营类目数据
GEThttps://{seller-api-domain}/seller/goods/export/categories导出店铺经营类目信息

用户端

请求方式API地址参数说明作用
GEThttps://{buyer-api-domain}/buyer/goods/categories/{parent_id}/childrenLong parentId:父分类主键ID(如果获取一级分类,此值传0)查询某分类下的子分类数据集合

类图展示

API类图

image-20230811181102815

实体类

image-20230811181433412

缓存设计

由于商品分类数据较多,而且会频繁读取,不适合直接读库,因此我们把分类信息放入redis缓存中进行存储

缓存数据结构

缓存key值:{GOODS_CAT}_ALL

缓存value值:List<CategoryVO>,格式如下:

只展示主要数据

[
{
"category_id":"1",
"name":"服装鞋靴",
"parent_id":"0",
"category_path":"0|1|",
"children":[
{
"category_id":"10",
"name":"男装",
"parent_id":"1",
"category_path":"0|1|10|",
"children":[
{
"category_id":"20",
"name":"衬衫",
"parent_id":"10",
"category_path":"0|1|10|20|",
"children":null
},
{
"category_id":"21",
"name":"西服",
"parent_id":"10",
"category_path":"0|1|11|21|",
"children":null
}
]
},
{
"category_id":"11",
"name":"女装",
"parent_id":"1",
"category_path":"0|1|11|",
"children":[
{
"category_id":"22",
"name":"连衣裙",
"parent_id":"11",
"category_path":"0|1|11|22|",
"children":null
},
{
"category_id":"23",
"name":"短裙",
"parent_id":"11",
"category_path":"0|1|11|23|",
"children":null
}
]
}
]
}
]

代码展示

com.enation.app.javashop.service.goods.impl.CategoryManagerImpl#getByParentId

@Override
public List<CategoryVO> getByParentId(Long parentId, Boolean showHidden) {
//如果不显示隐藏的分类,应为会员端调用 介于使用频率较高 则首先从缓存中取值 去不到的话再从数据库中取值
//显示隐藏的分类,应为后台管理端调用 则从数据库中取值
if (!showHidden) {
List<CategoryDO> categoryList = this.lambdaQuery().orderByAsc(CategoryDO::getCategoryOrder).list();
//获取分类树
return this.getMenuTree(categoryList, parentId);
}
//从缓存中取值
List<CategoryVO> categoryVOList = (List<CategoryVO>) this.cache.get(this.getCacheKey());

//如果缓存中为空则从数据库中取值
if (CollUtil.isEmpty(categoryVOList)) {
List<CategoryDO> categoryList = this.lambdaQuery()
.eq(CategoryDO::getIsShow, CommonStatusEnum.YES)
.orderByAsc(CategoryDO::getCategoryOrder)
.list();
categoryVOList = this.getMenuTree(categoryList, parentId);
//将分类信息放入缓存
this.cache.put(this.getCacheKey(), categoryVOList);

}
//获取分类树
return categoryVOList;
}

/**
* 获取分类缓存key
*
* @return String
*/
private String getCacheKey() {
return CachePrefix.GOODS_CAT.getPrefix() + "ALL";
}