商品中心—1.B端建品和C端缓存的技术文档一

发布于:2025-06-13 ⋅ 阅读:(21) ⋅ 点赞:(0)

大纲

1.商品中心的专业术语

2.商品中心的基本业务系统

3.商品中心整体架构设计以及运行流程

4.商品B端—商品编码生成逻辑

5.商品B端—商品核心数据模型

6.商品B端—转换建品请求数据为商品模型数据

7.商品B端—商品建品时商品编号补全与审核配置

8.商品B端—商品审核前的草稿数据保存逻辑

9.商品B端—不需审核的建品流程持久化逻辑

10.商品B端—审核工单分页列表和商品草稿查询

11.商品B端—商品审核时的敏感字段diff计算逻辑

12.商品B端—对草稿中的商品进行审核的逻辑

13.商品B端—商品属性+买手+品类的数据维护

14.商品C端—通用缓存读写组件的实现逻辑

15.商品C端—接口代码实现逻辑

1.商品中心的专业术语

一.ITEM

商品售卖展示单位,仅⽤于销售时展示使⽤。

二.SKU

SKU是Stock Keeping Unit(库存单位),即库存进出计量的单位。可以是以件、盒、托盘等为单位,如:iPhoneX + ⿊⾊ + 256G。

三.SPU

SPU是Standard Product Unit标准化产品单元,是对某一类标准产品的共同特征属性的描述。SPU是商品信息聚合的最⼩单位,如:iPhoneX就是SPU。SPU的出现是为了满足在叶子类目下对商品进行进一步抽象的需求。比如手机就是叶子类目,虽然可以添加苹果手机或者华为手机这样的类目,但这样添加就比较麻烦了,可能会导致类目树就会变得非常庞大。所以SPU是一个介于叶子类目和商品之间的概念,是对类目的细化。因此SPU通常由"后台类目 + 关键属性"唯一确定。

四.CSPU

CSPU也就是子标准化产品单元,即SPU的细分,Child SPU。CSPU通常由"后台类目 + 关键属性 + 销售属性"唯一确定。比如手机类型下,品牌和型号这两个属性可以确定一个SPU,但还不能确定一个CSPU,需要额外的销售属性才能确定一个CSPU。以苹果手机为例,品牌是iPhone、型号是X、颜色为黑色、存储为256G,两个关键属性是品牌和型号,两个销售属性为颜色和存储。

五.运营品类

运营品类是⼀种抽象的概念,例如:运动裤、⼿机。每一个商品都会有所属的品类,比如iPhone X这个SPU会属于手机这个品类。不同的电商平台会对品类进行不同的划分,手机品类在有的平台是一级品类,在有的平台是电子产品品类的子品类。

六.前台类⽬

多级品类可以构成前台类⽬,例如:男T恤 + 男短裤可归属到男装类⽬。电商网站首页里,左侧都会有一颗类目树,这个类目树就是前台类目。

七.SKU规格

⽤来区分单品的主要指标。例如⼿机商品由颜⾊、内存两种规格区分单品,每个规格有多个可选值。从每个规格选出一个值,拼凑起来的组合就可以唯一确定一款商品SKU。颜色规格:白色、黑色、粉色、天蓝色;内存:128G、256G、512G。

八.原料商品

只采购不销售的商品,只有采购属性如包材或原材料,例如:吸管、开瓶器。

九.普通商品

⼜采购⼜销售的商品,有库存和销售属性。

十.组套商品

不采购只销售的商品,共享库存和销售属性,例如:原料商品 + 普通商品组合为⼀个商品。开瓶器是原料商品,红酒是普通商品,开瓶器 + 红酒就是一个组套商品。开瓶器不能单卖但需要采购,用户购买红酒时不用关注开瓶器,开瓶器会和红酒打包在一起进行展示和售卖。

十一.虚拟商品

不采购只销售,只有虚拟库存,只有销售属性,例如:会员卡、虚拟卡、购物卡、游戏点卡。这些虚拟商品没有必要去进行采购,用户支付后也不需要履约签收。用户完成对虚拟商品的支付后,商品直接可以展示在用户的会员中心里。

十二.售卖区

商品可以在哪⾥卖,售卖范围配置:按城市配置、按卖家组配置。有的商品只能在部分城市可以售卖,部分城市是没法售卖的。在某些区域里,商品的库存不好发货,可能会显示该区域无货。

仓库会分成两种:微仓和大仓,微仓就是微型的小仓库,大仓就是大型的大仓库。大仓可以辐射很大一片区域的发货,仓库容量很大,里面可以放很多商品。微仓也叫前置仓,在一个城市里,可以设置微仓。可以将该城市经常购买的,库存量消耗比较大的商品,放到多个微仓里。这样距离消费者就会更近一些,发货也可以更快一些。

十三.卖家类型

类型一:⾃营,类型二:POP。自营就是商品是由平台自己来采购、入仓、售卖,POP(Platform Open Plan)意思是平台开放计划,POP就是第三方卖家入驻平台开店售卖自己的商品。

十四.商品状态

可售:商品配置了售卖区并且状态为可售

可补:商品可售且微仓可补货状态

可采:商品可售且⼤仓可采货状态

准备上架:建品后为此状态,表示可采和可补

试销上架:上架状态,表示处于试销阶段

上架:正式上架售卖

预下架:售完不展示商品,表示不可采和可补

下架:不可采和不可补

停售:永久下架,已淘汰

十五.商品价格

商城价:⾮会员⽤户购买商品的价格

会员价:会员⽤户购买的价格

营销价:促销活动价

秒杀价:秒杀活动价格,⼀⼝价

2.商品中心的基本业务系统

(1)商品基础服务

(2)商品类型与采购销售之间的关系

(3)商品中心的业务系统

(1)商品基础服务

服务一:提供从建品到下架期间可采可补可售管理的商品全流程服务

服务二:对商品基本信息、品牌信息、运营品类、前台类⽬、仓配信息、标签信息、品控信息、销售信息、推⼴信息等进⾏精细化管理与运营

服务三:通过权限收敛,可以很好把控并记录⽤户操作⾏为,使流程更加规范

服务四:通过提效⼯具,业务⽅可以批量处理商品相关⼯作,降低⼈⼒成本

(2)商品类型与采购销售之间的关系

(3)商品中心的业务系统

商品中心的系统主要会分为两类:一个是面向B端,一个是面向C端。面向B端的系统,主要由公司运营来使用,对商品进行精细化管理。面向C端的系统,则会对C端用户提供各种商品浏览和查询的接口。

一.价格中心系统

商品价格管理,提供全流程价格管控和分析。⽀持功能:价格查询、价格设置、审核流程、历史价格查询与趋势分析等。

二.商品卖家系统

商品售卖⽅,这⾥将卖家定义为卖家树,⽤户可以定位到多个卖家。商品基于卖家售卖,⽤户在当前覆盖的区域内可浏览到相应卖家的商品。将多个卖家合并为⼀个⼤的卖家称为卖家组,也称为售卖区,售卖区之间的逻辑处理称为售卖区管理(可售区域)。

三.商品⽣命周期系统

商品的状态分为:准备上架、试销上架、上架、预下架、下架、停售。为了更好的管理商品,需要对商品进⾏⼀套⽣命周期管理。⽤于考核商品,降低滞销率、资⾦成本以及影响商品的可采可补逻辑。

四.商品库存系统

商品库存需要分卖家设置,卖家 + 商品 + 库存关系定位具体商品库存数量。

五.商品标签系统

需要打上特殊标签的商品,例如:爆款,后台进⾏标签 + 标签组 + 商品管理。

六.属性库系统

商品关联的属性,涉及四种属性:关键属性、销售属性、⾮关键属性、导购属性。

七.商品品控系统

把控商品质量,在商品⼊库前进⾏取样检测,给出质检报告。合格商品允许⼊库,不合格商品不允许⼊库。将可售卖商品关联上质检报告,展示给⽤户。

3.商品中心整体架构设计以及运行流程

(1)商品中心整体架构

(2)商品新建编辑流程

(1)商品中心整体架构

(2)商品新建编辑流程

//商品服务
@DubboService(version = "1.0.0", interfaceClass = ProductApi.class, retries = 0)
public class ProductApiImpl implements ProductApi {
    @Autowired
    private ProductService productService;

    //建品/编辑商品接口
    @Override
    public JsonResult<ProductDTO> product(ProductRequest request) {
        try {
            ProductDTO productDTO = productService.product(request);
            return JsonResult.buildSuccess(productDTO);
        } catch (ProductBizException e) {
            log.error("biz error: request={}", JSON.toJSONString(request), e);
            return JsonResult.buildError(e.getErrorCode(), e.getErrorMsg());
        } catch (Exception e) {
            log.error("system error: request={}", JSON.toJSONString(request), e);
            return JsonResult.buildError(e.getMessage());
        }
    }
    ...
}

4.商品B端—商品编码生成逻辑

//商品编码
@Service
public class ProductNoManagerImpl implements ProductNoManager {
    //6位序列号
    private static final int width = 6;

    @Autowired
    private ProductAutoNoMapper productAutoNoMapper;

    //生成商品编码
    @Override
    public String generateProductNo(Integer sourceType) {
        ProductTypeEnum productTypeEnum = ProductTypeEnum.getByCode(sourceType);
        if (productTypeEnum == null) {
            throw new ProductBizException(ProductErrorCodeEnum.PARAM_ERROR);
        }
        return getProductNo(productTypeEnum.getValue());
    }

    //获取组装后的商品编码,商品的prefixNo是100000
    private String getProductNo(String prefixNo) {
        //有一张ProductAutoNo表专门用于生成商品ID
        //分库分表也可以利用此来实现基于数据库的内存缓存分段的发号器
        ProductAutoNoDO productAutoNoDO = new ProductAutoNoDO();
        productAutoNoMapper.insert(productAutoNoDO);
        Long autoNo = productAutoNoDO.getId();//获取自增ID
        return prefixNo + IDUtils.genId(autoNo, width);//数字混淆算法
    }
}

5.商品B端—商品核心数据模型

//建品/编辑商品请求入参
@Data
public class ProductRequest implements Serializable {
    //商品基本信息
    private ItemBaseRequest itemBaseRequest;
    //存储信息
    private ItemStorageRequest itemStorageRequest;
    //品控信息
    private ShelfLifeRequest shelfLifeRequest;
    //图文信息
    private List<ItemVideoImgRequest> itemVideoImgRequestList;
    //销售信息
    private ItemSaleRequest itemSaleRequest;
    //推广信息
    private ItemPopularizeRequest itemPopularizeRequest;
    //操作人
    @NotNull(message = "操作人[operateUser]不能为空")
    private Integer operatorUser;

    //商品基本信息
    @Data
    public static class ItemBaseRequest implements Serializable {
        //商品ID
        private String itemId;
        //商品名称
        private String itemName;
        //渠道(1-每日生鲜、2-美团、3-饿了么、4-淘鲜达、5-招商银行)
        private Integer channel;
        //卖家类型(1-自营、2-POP)
        private Integer sellerType;
        //商品状态
        private Integer itemStatus;
        //商品类型
        private Integer itemType;
        //品牌ID
        private Integer brandId;
        //产地ID
        private Integer producingAreaId;
        //成本价(单位:分)
        private Integer basePrice;
        //末级品类ID
        private Integer lastCategoryId;
        //一级品类ID
        private Integer oneCategoryId;
        //二级品类ID
        private Integer twoCategoryId;
        //三级品类ID
        private Integer threeCategoryId;
    }

    //存储信息
    @Data
    public static class ItemStorageRequest implements Serializable {
        //存储条件
        private Integer storeConditionType;
        //ITEM维度规格值(多个规格集合):key=颜色,value=蓝色;key=颜色,value=红色;key=内存,value=128g;key=内存,value=256g
        private List<ProductSpcesValue> productSpcesValueList;
    }

    //规格信息
    @Data
    public static class ProductSpcesValue implements Serializable {
        //规格关键字
        private String key;
        //规格值
        private String value;
        //排序
        private Integer sort;
    }

    //品控信息
    @Data
    public static class ShelfLifeRequest implements Serializable {

    //保质期(单位:小时)
    private Integer shelfLife;
        //Map<key=保质期类型,value=保质期时间(单位:小时)>:acceptLife 允收期,shelfLife 货架期
        private Map<String, Integer> shelfLifeMap;
    }

    //图文信息
    @Data
    public static class ItemVideoImgRequest implements Serializable {
        //内容类型(1-主图,2-轮播图、3-详情图、4-视频)
        private Integer contentType;
        //链接地址
        private String contentUrl;
        //排序(正整数,数字越小越靠前)
        private Integer contentSort;
    }

    //销售信息
    @Data
    public static class ItemSaleRequest implements Serializable {
        //sku信息
        private List<SkuInfoRequest> skuInfoRequestList;
    }

    //sku信息
    @Data
    public static class SkuInfoRequest implements Serializable {
        //商品itemId
        private String itemId;
        //商品skuId
        private String skuId;
        //商品SKU名称
        private String skuName;
        //商城价
        private Integer basePrice;
        //会员价
        private Integer vipPrice;
        //商品分级(ABC标签,运营归类处理)
        private Integer skuGrade;
        //69码,条形码
        private String barCode;
        //SKU维度规格值(单个):key=颜色,value=蓝色;key=内存,value=128g
        private List<ProductSpcesValue> productSpcesValueList;
        //sku匹配的spu信息
        private Long cspuId;
    }

    //推广信息
    @Data
    public static class ItemPopularizeRequest implements Serializable {
        //推荐语
        private String recommend;
        //亮点
        private List<HighlightsRequest> highlightsRequestList;
        //卖点
        private List<SellingPointRequest> sellingPointRequestList;
        //质检报告
        private List<QualityControlRequest> qualityControlRequestList;
    }

    //亮点
    @Data
    public static class HighlightsRequest implements Serializable {
        //亮点文案
        private String highlights;
        //排序(正整数,数字越小越靠前)
        private Integer sort;
    }

    //卖点
    @Data
    public static class SellingPointRequest implements Serializable {
        //卖点文案
        private String sellingPoint;
        //排序(正整数,数字越小越靠前)
        private Integer sort;
    }

    //质检报告
    @Data
    public static class QualityControlRequest implements Serializable {
        //商品skuId
        private String skuId;
        //质检报告名称
        private String qcName;
        //材料图片链接
        private String qcImgUrl;
        //排序(正整数,数字越小越靠前)
        private Integer qcSort;
    }
}

6.商品B端—转换建品请求数据为商品模型数据

前端的建品请求数据比较复杂,需要和后端的商品模型数据匹配起来,所以需要进行数据转换。这种数据转换,通常会用Builder模式来实现。

@Service
public class ProductServiceImpl implements ProductService {
    ...
    //建品/编辑商品
    @Transactional(rollbackFor = Exception.class)
    @Override
    @ParamsValidate
    public ProductDTO product(ProductRequest productRequest) {
        //入参检查
        checkProductRequestParam(productRequest);
        //商品数据处理
        ProductDTO productDTO = handleProduct(productRequest);
        //返回商品信息
        return productDTO;
    }

    //建品/编辑商品入参检查
    private void checkProductRequestParam(ProductRequest productRequest) {
        ParamCheckUtil.checkObjectNonNull(productRequest);
        //商品基本信息
        ProductRequest.ItemBaseRequest itemBaseRequest = productRequest.getItemBaseRequest();
        ParamCheckUtil.checkObjectNonNull(itemBaseRequest);
        //存储信息
        ProductRequest.ItemStorageRequest itemStorageRequest = productRequest.getItemStorageRequest();
        ParamCheckUtil.checkObjectNonNull(itemStorageRequest);
        //品控信息
        ProductRequest.ShelfLifeRequest shelfLifeRequest = productRequest.getShelfLifeRequest();
        ParamCheckUtil.checkObjectNonNull(shelfLifeRequest);
        //图文信息
        List<ProductRequest.ItemVideoImgRequest> itemVideoImgRequestList = productRequest.getItemVideoImgRequestList();
        ParamCheckUtil.checkObjectNonNull(itemVideoImgRequestList);
        //销售信息
        ProductRequest.ItemSaleRequest itemSaleRequest = productRequest.getItemSaleRequest();
        ParamCheckUtil.checkObjectNonNull(itemSaleRequest);
        //推广信息
        ProductRequest.ItemPopularizeRequest itemPopularizeRequest = productRequest.getItemPopularizeRequest();
        ParamCheckUtil.checkObjectNonNull(itemPopularizeRequest);
    }

    //商品数据处理
    private ProductDTO handleProduct(ProductRequest productRequest) {
        //构建商品的全量信息
        FullProductData fullProductData = buildProduct(productRequest);
        //是否构建填充 itemId
        Boolean createFlag = whetherBuildProductItemId(fullProductData);
        //判断是否需要审核,根据配置的sku或者item或者品类信息,如果需要审核,只处理草稿表中的数据,正式表中的数据不动
        if (productAuditRepository.needAudit(fullProductData, createFlag)) {
            //需要审核,则正式表中的数据不变更,只新增草稿表记录
            FullDraftData fullDraftData = buildDraft(fullProductData, AuditTypeEnum.GOODS.getCode());
            //保存草稿信息
            productAuditRepository.saveDraft(fullDraftData);
            return new ProductDTO(null, null);
        }
        //如果不需要审核,则保存商品信息
        this.saveOrUpdateDBProduct(fullProductData, createFlag);
        //发送消息通知订阅方
        sendUpdateProductMessage(fullProductData);
        //返回商品返回结果
        return new ProductDTO(fullProductData.getItemInfoDO().getItemId(), buildProductSkuIds(fullProductData));
    }

    //前端建品请求数据到后端商品数据模型的转换
    private FullProductData buildProduct(ProductRequest productRequest) {
        ProductBuilder productBuilder = new ProductBuilder(productRequest);
        FullProductData fullProductData = productBuilder.buildItemInfo()
            .buildItemShelfLife()
            .buildItemVideoImgList()
            .buildSkuInfoList()
            .buildSkuBarCodeRelationList()
            .buildCspuSkuRelation()
            .buildAttributeExtend()
            .buildQualityControl()
            .build();
        return fullProductData;
    }
    ...
}

//全量商品数据
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FullProductData {
    //ITEM信息
    private ItemInfoDO itemInfoDO;
    //保质期信息
    private ItemShelfLifeDO itemShelfLifeDO;
    //视频图片信息
    private List<ItemVideoImgDO> itemVideoImgDOList;
    //SKU信息
    private List<SkuInfoDO> skuInfoDOList;
    //69码关系
    private List<SkuBarCodeRelationDO> skuBarCodeRelationDOList;
    //CSPU与SKU关系
    private List<CspuSkuRelationDO> cspuSkuRelationDOList;
    //ITEM或SKU扩展属性
    private AttributeExtendDO attributeExtendDO;
    //品控信息
    private List<QualityControlDO> qualityControlDOList;

    public FullProductData(ItemInfoDO itemInfoDO, List<SkuInfoDO> skuInfoDOList) {
        this.itemInfoDO = itemInfoDO;
        this.skuInfoDOList = skuInfoDOList;
    }
}

//全量商品数据
public class ProductBuilder {
    //商品入参
    private ProductRequest productRequest;
    //全量商品数据
    private FullProductData fullProductData;

    public ProductBuilder(ProductRequest productRequest) {
        this.productRequest = productRequest;
        this.fullProductData = new FullProductData();
    }

    public ProductBuilder buildItemInfo() {
        ItemInfoDO itemInfoDO = new ItemInfoDO();
        ProductRequest.ItemBaseRequest itemBaseRequest = productRequest.getItemBaseRequest();
        itemInfoDO.setItemId(itemBaseRequest.getItemId());
        itemInfoDO.setItemName(itemBaseRequest.getItemName());
        ...
        fullProductData.setItemInfoDO(itemInfoDO);
        return this;
    }

    public ProductBuilder buildItemShelfLife() {
        ItemShelfLifeDO itemShelfLifeDO = new ItemShelfLifeDO();
        ProductRequest.ItemBaseRequest itemBaseRequest = productRequest.getItemBaseRequest();
        ProductRequest.ShelfLifeRequest shelfLifeRequest = productRequest.getShelfLifeRequest();
        itemShelfLifeDO.setItemId(itemBaseRequest.getItemId());
        itemShelfLifeDO.setShelfLifeContent(JSON.toJSONString(shelfLifeRequest.getShelfLife()));
        itemShelfLifeDO.setDelFlag(DelFlagEnum.EFFECTIVE.getCode());
        ...
        fullProductData.setItemShelfLifeDO(itemShelfLifeDO);
        return this;
    }

    public ProductBuilder buildItemVideoImgList() {
        List<ItemVideoImgDO> itemVideoImgDOList = new ArrayList<>(16);
        ProductRequest.ItemBaseRequest itemBaseRequest = productRequest.getItemBaseRequest();
        List<ProductRequest.ItemVideoImgRequest> itemVideoImgRequestList = productRequest.getItemVideoImgRequestList();
        for (ProductRequest.ItemVideoImgRequest itemVideoImgRequest : itemVideoImgRequestList) {
            ItemVideoImgDO itemVideoImgDO = new ItemVideoImgDO();
            itemVideoImgDO.setItemId(itemBaseRequest.getItemId());
            ...
            itemVideoImgDOList.add(itemVideoImgDO);
        }
        fullProductData.setItemVideoImgDOList(itemVideoImgDOList);
        return this;
    }

    public ProductBuilder buildSkuInfoList() {
        List<SkuInfoDO> skuInfoDOList = new ArrayList<>(16);
        ProductRequest.ItemBaseRequest itemBaseRequest = productRequest.getItemBaseRequest();
        List<ProductRequest.SkuInfoRequest> skuInfoRequestList = productRequest.getItemSaleRequest().getSkuInfoRequestList();
        for (ProductRequest.SkuInfoRequest skuInfoRequest : skuInfoRequestList) {
            SkuInfoDO skuInfoDO = new SkuInfoDO();
            skuInfoDO.setItemId(skuInfoRequest.getItemId());
            skuInfoDO.setSkuId(skuInfoRequest.getSkuId());
            skuInfoDO.setSkuName(skuInfoRequest.getSkuName());
            ...
            skuInfoDOList.add(skuInfoDO);
        }
        fullProductData.setSkuInfoDOList(skuInfoDOList);
        return this;
    }

    public ProductBuilder buildSkuBarCodeRelationList() {
        List<SkuBarCodeRelationDO> skuBarCodeRelationDOList = new ArrayList<>(16);
        List<ProductRequest.SkuInfoRequest> skuInfoRequestList = productRequest.getItemSaleRequest().getSkuInfoRequestList();
        for (ProductRequest.SkuInfoRequest skuInfoRequest : skuInfoRequestList) {
            SkuBarCodeRelationDO skuBarCodeRelationDO = new SkuBarCodeRelationDO();
            skuBarCodeRelationDO.setSkuId(skuInfoRequest.getSkuId());
            skuBarCodeRelationDO.setBarCode(skuInfoRequest.getBarCode());
            ...
            skuBarCodeRelationDOList.add(skuBarCodeRelationDO);
        }
        fullProductData.setSkuBarCodeRelationDOList(skuBarCodeRelationDOList);
        return this;
    }

    public ProductBuilder buildCspuSkuRelation() {
        List<CspuSkuRelationDO> cspuSkuRelationDOList = new ArrayList<>(16);
        ProductRequest.ItemBaseRequest itemBaseRequest = productRequest.getItemBaseRequest();
        List<ProductRequest.SkuInfoRequest> skuInfoRequestList = productRequest.getItemSaleRequest().getSkuInfoRequestList();
        for (ProductRequest.SkuInfoRequest skuInfoRequest : skuInfoRequestList) {
            CspuSkuRelationDO cspuSkuRelationDO = new CspuSkuRelationDO();
            cspuSkuRelationDO.setSkuId(skuInfoRequest.getSkuId());
            cspuSkuRelationDO.setCspuId(skuInfoRequest.getCspuId());
            ...
            cspuSkuRelationDOList.add(cspuSkuRelationDO);
        }
        fullProductData.setCspuSkuRelationDOList(cspuSkuRelationDOList);
        return this;
    }

    public ProductBuilder buildAttributeExtend() {
        AttributeExtendDO attributeExtendDO = new AttributeExtendDO();
        ProductRequest.ItemBaseRequest itemBaseRequest = productRequest.getItemBaseRequest();
        ProductRequest.ItemPopularizeRequest itemPopularizeRequest = productRequest.getItemPopularizeRequest();
        attributeExtendDO.setParticipateId(itemBaseRequest.getItemId());
        ...
        fullProductData.setAttributeExtendDO(attributeExtendDO);
        return this;
    }

    public ProductBuilder buildQualityControl() {
        List<QualityControlDO> qualityControlDOList = new ArrayList<>(16);
        ProductRequest.ItemBaseRequest itemBaseRequest = productRequest.getItemBaseRequest();
        ProductRequest.ItemPopularizeRequest itemPopularizeRequest = productRequest.getItemPopularizeRequest();
        List<ProductRequest.QualityControlRequest> qualityControlRequestList = itemPopularizeRequest.getQualityControlRequestList();
        for (ProductRequest.QualityControlRequest qualityControlRequest : qualityControlRequestList) {
            QualityControlDO qualityControlDO = new QualityControlDO();
            qualityControlDO.setItemId(itemBaseRequest.getItemId());
            qualityControlDO.setSkuId(qualityControlRequest.getSkuId());
            ...
            qualityControlDOList.add(qualityControlDO);
        }
        fullProductData.setQualityControlDOList(qualityControlDOList);
        return this;
    }

    public FullProductData build() {
        return this.fullProductData;
    }
}

7.商品B端—商品建品时商品编号补全与审核配置

@Service
public class ProductServiceImpl implements ProductService {
    ...
    //建品/编辑商品
    @Transactional(rollbackFor = Exception.class)
    @Override
    @ParamsValidate
    public ProductDTO product(ProductRequest productRequest) {
        //入参检查
        checkProductRequestParam(productRequest);
        //商品数据处理
        ProductDTO productDTO = handleProduct(productRequest);
        //返回商品信息
        return productDTO;
    }
    ...

    //商品数据处理
    private ProductDTO handleProduct(ProductRequest productRequest) {
        //构建商品的全量信息
        FullProductData fullProductData = buildProduct(productRequest);
        //是否构建填充itemId
        Boolean createFlag = whetherBuildProductItemId(fullProductData);
        //判断是否需要审核,根据配置的sku或者item或者品类信息,如果需要审核,只处理草稿表中的数据,正式表中的数据不动
        if (productAuditRepository.needAudit(fullProductData, createFlag)) {
            //需要审核,则正式表中的数据不变更,只新增草稿表记录
            FullDraftData fullDraftData = buildDraft(fullProductData, AuditTypeEnum.GOODS.getCode());
            //保存草稿信息
            productAuditRepository.saveDraft(fullDraftData);
            return new ProductDTO(null, null);
        }
        //如果不需要审核,则保存商品信息
        this.saveOrUpdateDBProduct(fullProductData, createFlag);
        //发送消息通知订阅方
        sendUpdateProductMessage(fullProductData);
        //返回商品返回结果
        return new ProductDTO(fullProductData.getItemInfoDO().getItemId(), buildProductSkuIds(fullProductData));
    }

    //是否需要构建商品的ItemId
    private Boolean whetherBuildProductItemId(FullProductData fullProductData) {
        //ITEM信息
        ItemInfoDO itemInfoDO = fullProductData.getItemInfoDO();
        //新增
        if (StringUtils.isEmpty(itemInfoDO.getItemId())) {
            //保质期
            ItemShelfLifeDO itemShelfLifeDO = fullProductData.getItemShelfLifeDO();
            //生成Item的Id
            String itemId = createItemId();
            //赋值itemId
            itemInfoDO.setItemId(itemId);
            itemShelfLifeDO.setItemId(itemId);
            //SKU信息
            List<SkuInfoDO> skuInfoDOList = fullProductData.getSkuInfoDOList();
            for (SkuInfoDO skuInfoDO : skuInfoDOList) {
                //对每个SKU也生成ID
                String skuId = productNoManager.generateProductNo(ProductTypeEnum.SKU.getCode());
                skuInfoDO.setSkuId(skuId);
                skuInfoDO.setItemId(itemId);
            }
            //视频图片
            List<ItemVideoImgDO> itemVideoImgDOList = fullProductData.getItemVideoImgDOList();
            for (ItemVideoImgDO itemVideoImgDO : itemVideoImgDOList) {
                itemVideoImgDO.setItemId(itemId);
            }
            //属性扩展
            AttributeExtendDO attributeExtendDO = fullProductData.getAttributeExtendDO();
            attributeExtendDO.setParticipateId(itemInfoDO.getItemId());
            attributeExtendDO.setParticipateType(ProductTypeEnum.ITEM.getCode());
            return true;
        }
        return false;
    }

    //创建ItemId
    private String createItemId() {
        String itemId = productNoManager.generateProductNo(ProductTypeEnum.ITEM.getCode());
        return itemId;
    }
    ...
}

//商品审核 资源管理
@Repository
public class ProductAuditRepository {
    ...
    //验证是否需要审核
    public Boolean needAudit(FullProductData fullProductData, Boolean createFlag) {
        ItemInfoDO itemInfoDO = fullProductData.getItemInfoDO();
        Integer count = 0;
        if (!createFlag) {
            //1.首先判断 商品审核内容配置表 中是否有对应的skuId
            List<String> skuIds = fullProductData.getSkuInfoDOList().stream().map(SkuInfoDO::getSkuId).collect(Collectors.toList());
            count = countByCustomIds(skuIds, AuditCustomTypeEnum.SKU);
            if (count > 0) {
                return true;
            }
            //2.是否有对应的item
            count = countByCustomIds(Collections.singletonList(itemInfoDO.getItemId()), AuditCustomTypeEnum.ITEM);
            if (count > 0) {
                return true;
            }
        }
        //3.验证是否有对应的categoryId
        List<Integer> categoryIds = Arrays.asList(itemInfoDO.getFirstCategoryId(), itemInfoDO.getSecondCategoryId(), itemInfoDO.getThirdCategoryId());
        count = countByCustomIds(categoryIds, AuditCustomTypeEnum.CATEGORY);
        //当商品审核内容配置表中有相应的品类数据,则需要审核,否则不需要审核
        return count > 0;
    }
    ...
}

8.商品B端—商品审核前的草稿数据保存逻辑

@Service
public class ProductServiceImpl implements ProductService {
    ...
    //建品/编辑商品
    @Transactional(rollbackFor = Exception.class)
    @Override
    @ParamsValidate
    public ProductDTO product(ProductRequest productRequest) {
        //入参检查
        checkProductRequestParam(productRequest);
        //商品数据处理
        ProductDTO productDTO = handleProduct(productRequest);
        //返回商品信息
        return productDTO;
    }
    ...

    //商品数据处理
    private ProductDTO handleProduct(ProductRequest productRequest) {
        //构建商品的全量信息
        FullProductData fullProductData = buildProduct(productRequest);
        //是否构建填充itemId
        Boolean createFlag = whetherBuildProductItemId(fullProductData);
        //判断是否需要审核,根据配置的sku或者item或者品类信息,如果需要审核,只处理草稿表中的数据,正式表中的数据不动
        if (productAuditRepository.needAudit(fullProductData, createFlag)) {
            //需要审核,则正式表中的数据不变更,只新增草稿表记录
            FullDraftData fullDraftData = buildDraft(fullProductData, AuditTypeEnum.GOODS.getCode());
            //保存草稿信息
            productAuditRepository.saveDraft(fullDraftData);
            return new ProductDTO(null, null);
        }
        //如果不需要审核,则保存商品信息
        this.saveOrUpdateDBProduct(fullProductData, createFlag);
        //发送消息通知订阅方
        sendUpdateProductMessage(fullProductData);
        //返回商品返回结果
        return new ProductDTO(fullProductData.getItemInfoDO().getItemId(), buildProductSkuIds(fullProductData));
    }
    ...

    //根据商品数据构建商品草稿数据
    private FullDraftData buildDraft(FullProductData fullProductData, Integer auditType) {
        ProductDraftBuilder productDraftBuilder = new ProductDraftBuilder(fullProductData);
        FullDraftData fullDraftData = productDraftBuilder.buildDraftMain(auditType)
            .buildDraftImgList()
            .build();
        return fullDraftData;
    }
    ...
}

//商品审核 资源管理
@Repository
public class ProductAuditRepository {
    ...
    //保存草稿信息
    public void saveDraft(FullDraftData fullDraftData) {
        //1.保存工单信息
        AuditInfoDO auditInfoDO = saveAudit(fullDraftData);
        //2.保存工单审核历史信息
        saveAuditHistory(auditInfoDO);
        //3.保存草稿信息
        saveDraftMain(fullDraftData, auditInfoDO.getId());
        //4.保存草稿图片信息
        saveDraftImgBatch(fullDraftData);
    }

    //保存工单信息
    private AuditInfoDO saveAudit(FullDraftData fullDraftData) {
        AuditInfoDO auditInfoDO = auditConverter.converterDO(fullDraftData.getDraftMainDO());
        auditInfoDO.initCommon();
        int count = auditInfoMapper.insert(auditInfoDO);
        if (count <= 0) {
            throw new ProductBizException(AuditExceptionCode.AUDIT_SQL.getErrorCode(), "保存工单失败");
        }
        return auditInfoDO;
    }

    //保存工单审核历史信息
    private void saveAuditHistory(AuditInfoDO auditInfoDO) {
        AuditHistoryDO auditHistoryDO = auditConverter.converterHistoryDO(auditInfoDO);
        int count = this.auditHistoryMapper.insert(auditHistoryDO);
        if (count <= 0) {
            throw new ProductBizException(AuditExceptionCode.AUDIT_SQL.getErrorCode(), "保存工单审核历史信息失败");
        }
    }

    //保存草稿信息
    private void saveDraftMain(FullDraftData fullDraftData, Long auditId) {
        DraftMainDO draftMainDO = fullDraftData.getDraftMainDO();
        draftMainDO.setTicketId(auditId);
        int count = draftMainMapper.insert(draftMainDO);
        if (count <= 0) {
            throw new ProductBizException(AuditExceptionCode.AUDIT_SQL.getErrorCode(), "保存草稿审核信息失败");
        }
    }

    //保存草稿图片信息
    private void saveDraftImgBatch(FullDraftData fullDraftData) {
        List<DraftImgDO> draftImgDOS = fullDraftData.getDraftImgDOS();
        if (!CollectionUtils.isEmpty(draftImgDOS)) {
            for (DraftImgDO draftImgDO : draftImgDOS) {
                draftImgDO.setDraftId(fullDraftData.getDraftMainDO().getId());
            }
            draftImgMapper.saveBatch(draftImgDOS);
        }
    }
    ...
}

9.商品B端—不需审核的建品流程持久化逻辑

@Service
public class ProductServiceImpl implements ProductService {
    ...
    //商品数据处理
    private ProductDTO handleProduct(ProductRequest productRequest) {
        //构建商品的全量信息
        FullProductData fullProductData = buildProduct(productRequest);
        //是否构建填充itemId
        Boolean createFlag = whetherBuildProductItemId(fullProductData);
        //判断是否需要审核,根据配置的sku或者item或者品类信息,如果需要审核,只处理草稿表中的数据,正式表中的数据不动
        if (productAuditRepository.needAudit(fullProductData, createFlag)) {
            //需要审核,则正式表中的数据不变更,只新增草稿表记录
            FullDraftData fullDraftData = buildDraft(fullProductData, AuditTypeEnum.GOODS.getCode());
            //保存草稿信息
            productAuditRepository.saveDraft(fullDraftData);
            return new ProductDTO(null, null);
        }
        //如果不需要审核,则保存商品信息
        this.saveOrUpdateDBProduct(fullProductData, createFlag);
        //发送消息通知订阅方
        sendUpdateProductMessage(fullProductData);
        //返回商品返回结果
        return new ProductDTO(fullProductData.getItemInfoDO().getItemId(), buildProductSkuIds(fullProductData));
    }

    //新增或者修改商品相关信息
    @Override
    public void saveOrUpdateDBProduct(FullProductData fullProductData, Boolean createFlag) {
        if (createFlag) {
            //新增
            productInfoRepository.saveItemInfo(fullProductData);
        } else {
            //修改
            productInfoRepository.updateItemInfo(fullProductData);
        }
    }
    ...
}

//商品 资源管理
@Repository
public class ProductInfoRepository {
    ...
    //保存商品的明细信息
    public void saveItemInfo(FullProductData fullProductData) {
        //保存商品Item的信息
        saveItemInfo(fullProductData.getItemInfoDO());
        //保存商品保质期信息
        saveItemShelfLife(fullProductData.getItemShelfLifeDO());
        //批量保存商品图片视频信息
        saveBatchVideoImg(fullProductData.getItemVideoImgDOList());
        //批量保存商品sku信息
        saveBatchSkuInfo(fullProductData.getSkuInfoDOList());
        //批量保存69码信息
        saveBatchSkuBarCodeRelation(fullProductData.getSkuBarCodeRelationDOList());
        //批量保存CSPU与SKU关系
        saveBatchCspuSkuRelation(fullProductData.getCspuSkuRelationDOList());
        //批量保存品控信息
        saveBatchQualityControl(fullProductData.getQualityControlDOList());
        //保存ITEM或SKU扩展属性
        saveAttributeExtend(fullProductData.getAttributeExtendDO());
    }

    //修改商品的明细信息
    public void updateItemInfo(FullProductData fullProductData) {
        //更新商品item信息
        updateItemInfo(fullProductData.getItemInfoDO());
        //更新商品保质期信息
        updateItemShelfLife(fullProductData.getItemShelfLifeDO());
        //更新商品扩展信息
        updateAttributeExtend(fullProductData.getAttributeExtendDO());
        //更新商品的视频图片信息
        batchUpdateVideoImg(fullProductData.getItemVideoImgDOList());
        //批量更新商品sku信息
        batchUpdateSkuInfo(fullProductData.getSkuInfoDOList());
        //批量更新商品的69规格
        batchUpdateSkuBarCodeRelation(fullProductData.getSkuBarCodeRelationDOList());
        //批量更新 CSPU与SKU关系
        batchUpdateCspuSkuRelation(fullProductData.getCspuSkuRelationDOList());
        //批量更新品控信息
        batchUpdateQualityControl(fullProductData.getQualityControlDOList());
    }
    ...

    //保存商品Item的信息
    private void saveItemInfo(ItemInfoDO itemInfoDO) {
        int count = itemInfoMapper.insert(itemInfoDO);
        if (count <= 0) {
            throw new BaseBizException(ProductExceptionCode.PRODUCT_SQL);
        }
    }

    //保存商品保质期信息
    private void saveItemShelfLife(ItemShelfLifeDO itemShelfLifeDO) {
        int count = itemShelfLifeMapper.insert(itemShelfLifeDO);
        if (count <= 0) {
            throw new BaseBizException(ProductExceptionCode.PRODUCT_SQL);
        }
    }

    //批量保存商品图片视频信息
    private void saveBatchVideoImg(List<ItemVideoImgDO> itemVideoImgDOList) {
        int count = itemVideoImgMapper.saveBatch(itemVideoImgDOList);
        if (count <= 0) {
            throw new BaseBizException(ProductExceptionCode.PRODUCT_SQL);
        }
    }

    //批量保存商品sku信息
    private void saveBatchSkuInfo(List<SkuInfoDO> skuInfoDOList) {
        int count = skuInfoMapper.saveBatch(skuInfoDOList);
        if (count <= 0) {
            throw new BaseBizException(ProductExceptionCode.PRODUCT_SQL);
        }
    }

    //批量保存69码信息
    private void saveBatchSkuBarCodeRelation(List<SkuBarCodeRelationDO> skuBarCodeRelationDOList) {
        int count = skuBarCodeRelationMapper.saveBatch(skuBarCodeRelationDOList);
        if (count <= 0) {
            throw new BaseBizException(ProductExceptionCode.PRODUCT_SQL);
        }
    }

    //批量保存CSPU与SKU关系
    private void saveBatchCspuSkuRelation(List<CspuSkuRelationDO> cspuSkuRelationDOList) {
        int count = cspuSkuRelationMapper.saveBatch(cspuSkuRelationDOList);
        if (count <= 0) {
            throw new BaseBizException(ProductExceptionCode.PRODUCT_SQL);
        }
    }

    //批量保存品控信息
    private void saveBatchQualityControl(List<QualityControlDO> qualityControlDOList) {
        int count = qualityControlMapper.saveBatch(qualityControlDOList);
        if (count <= 0) {
            throw new BaseBizException(ProductExceptionCode.PRODUCT_SQL);
        }
    }

    //保存 ITEM或SKU扩展属性
    private void saveAttributeExtend(AttributeExtendDO attributeExtendDO) {
        int count = attributeExtendMapper.insert(attributeExtendDO);
        if (count <= 0) {
            throw new BaseBizException(ProductExceptionCode.PRODUCT_SQL);
        }
    }
    ...
}