写点什么

商品中心—商品属性与状态流转的技术文档

  • 2025-06-13
    福建
  • 本文字数:24010 字

    阅读完需:约 79 分钟

1.商品属性库系统简介


(1)属性分类


为了⽅便管理商品,可以将属性分为三类:

 

一.基础属性

商品的通⽤属性,例如名称、品牌、品类等。

 

二.销售属性

商品的销售价格属性,不同销售属性的商品,其销售价会有所不同,例如⼿机的颜⾊、内存等。

 

三.搜索属性

商品搜索的属性,例如名称、品牌、品类等。

 

(2)属性模版


为了提⾼效率,合理化运营,会将商品的属性与品类绑定到⼀起。品类是以树形结构来管理的。既然属性与品类绑定在⼀起,为避免重复添加属性,会将每级品类的公共属性抽取出来作为⼀个属性模板。后期关联商品查询时,可以将属性最终展示在商品下⾯。



(3)属性组


由于商品的属性很多,为了⽅便⽤户浏览和数据⽐对,需要对属性进⾏分组管理。

 

一.电子产品属性组



二.汽车属性组



(4)属性库运行流程


一.创建属性库数据



二.查询属性库数据



三.商品对接属性库


 

2.商品属性库系统数据库设计


(1)属性相关表的关系


属性表管理:attribute management,简称 atm。



一个品类会关联一个属性模版,一个属性模版里会有多个属性组或多个属性,一个属性组里会有多个属性,一个属性里会有多个属性值。

 

(2)属性相关表的详情


一.属性表


create table if not exists atm_attribute_info (     id int(10) auto_increment comment '主键' primary key,    category_id int(10) default null comment '品类id',    attribute_name varchar(128) not null comment '属性名称',    attribute_code varchar(128) null comment '属性编码',    attribute_type varchar(128) not null comment '属性类型,格式为json数组(1-基础属性,2-销售属性,3-搜索属性,null-其他属性)',    attribute_input_type int not null comment '属性值的输⼊⽅式(1-⽤户⾃⼰输⼊,2-单选下拉框,3-多选下拉框,4-⽇期)',    attribute_comment varchar(128) default null comment '属性说明',    del_flag tinyint(1) default 0 not null comment '删除标记(1-有效,0-删除)',    create_user int not null comment '创建⼈',    create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',    update_user int not null comment '更新⼈',    update_time datetime default CURRENT_TIMESTAMP not null comment '修改时间') comment '属性表';
复制代码


例如添加三个属性:品牌、颜色、版本。



二.属性可选值表


create table if not exists atm_attribute_value (    id int(10) auto_increment comment '主键' primary key,    attribute_id int(10) not null comment '属性id',    attribute_value varchar(128) not null comment '属性值',    sort int not null comment '排序序号',    del_flag tinyint(1) default 0 not null comment '删除标记(1-有效,0-删除)',    create_user int not null comment '创建⼈',    create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',    update_user int not null comment '更新⼈',    update_time datetime default CURRENT_TIMESTAMP not null comment '修改时间') comment '属性值表';
复制代码


例如给颜色属性添加了 3 个可选值:红色、黄色、蓝色。例如给版本属性添加了 3 个可选值:公开版、无线耳机套装、智能手表套装。



三.属性组表


create table if not exists atm_attribute_group (    id int(10) auto_increment comment '主键' primary key,    category_id int(10) default null comment '品类id',    group_name varchar(128) not null comment '属性组名称',    del_flag tinyint(1) default 0 not null comment '删除标记(1-有效,0-删除)',    create_user int not null comment '创建⼈',    create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',    update_user int not null comment '更新⼈',    update_time datetime default CURRENT_TIMESTAMP not null comment '修改时间') comment '属性组表';
复制代码


例如添加一个属性组:基本属性组。



四.属性模板表


create table atm_attribute_template (    id int auto_increment comment '主键' primary key,    template_name varchar(128) not null comment '属性模板名称',    category_id int not null comment '品类id',    del_flag tinyint(1) default 0 not null comment '删除标记(1-有效,0-删除)',    create_user int not null comment '创建⼈',    create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',    update_user int not null comment '更新⼈',    update_time datetime default CURRENT_TIMESTAMP not null comment '修改时间') comment '属性模板表';
复制代码


例如添加一个属性模版:智能手机模版;



五.属性模板内容表


create table atm_attribute_template_content (    id int auto_increment comment '主键' primary key,    template_id int not null comment '属性模板id',    group_id int null comment '属性组id',    attribute_id int not null comment '属性id',    participant_type int not null comment '参与类型(1-表示该属性是放到item上的,2-表示该属性是放到sku上的)',    sort int null comment '排序序号',    del_flag tinyint(1) default 0 not null comment '删除标记(1-有效,0-删除)',    create_user int not null comment '创建⼈',    create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',    update_user int not null comment '更新⼈',    update_time datetime default CURRENT_TIMESTAMP not null comment '修改时间') comment '模板内容表';
复制代码


例如给智能⼿机模板配置三个属性,同时指定每个属性所属的属性组,分别为品牌属性(⽆属性组)、颜⾊属性和版本属性(属于基本属性组)。另外配置品牌属性放到 item 上,颜⾊和版本属性放到 sku 上,而且属性组的顺序分别是品牌、颜⾊、版本。



六.标品商品属性值表


create table atm_item_sku_attribute_value (    id int auto_increment comment '主键' primary key,    participant_id varchar(64) not null comment '标品id或商品id',    participant_type int not null comment '参与类型(1-表示该属性是放到item上的,2-表示该属性是放到sku上的)',    template_id int not null comment '模板id',    group_id int null comment '属性组id',    attribute_id int not null comment '属性id',    attribute_value varchar(128) not null comment '属性值',    sort int not null comment '排序序号',    del_flag tinyint(1) default 0 not null comment '删除标记(1-有效,0-删除)',    create_user int not null comment '创建⼈',    create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',    update_user int not null comment '更新⼈',    update_time datetime default CURRENT_TIMESTAMP not null comment '修改时间') comment '标品商品属性值表';
复制代码


例如 item 为 111 的标品,关联了品牌属性,值为华为。sku 为 222 的商品关联了颜⾊属性(红色),版本属性(公开版)。sku 为 333 的商品关联了颜⾊属性(黄色),版本属性(⽆线⽿机套装)。sku 为 444 的商品关联了颜⾊属性(蓝色),版本属性(智能⼿表套装)。


 

3.商品属性库系统对品类添加属性


//属性管理相关操作API@DubboService(version = "1.0.0", interfaceClass = AttributeApi.class, retries = 0)public class AttributeApiImpl implements AttributeApi {    @Autowired    private AttributeService attributeService;        //添加属性接口    @Override    public JsonResult<AttributeInfoResultDTO> saveAttribute(AttributeInfoRequest request) {        AttributeInfoResultDTO attributeResultV2DTO = attributeService.saveAttributeInfo(request);        return JsonResult.buildSuccess(attributeResultV2DTO);    }    ...}
//新增/编辑属性请求入参@Datapublic class AttributeInfoRequest implements Serializable { //品类id private Long categoryId; //属性名称 private String attributeName; //属性编码 private String attributeCode; //属性类型 private String attributeType; //属性值的输入方式 private Integer attributeInputType; //属性说明 private String attributeComment; //操作人 @NotNull(message = "操作人[operateUser]不能为空") private Integer operateUser;}
//属性管理相关操作API@Servicepublic class AttributeServiceImpl implements AttributeService { @Autowired private AttributeRepository attributeRepository; //添加属性 @Override public AttributeInfoResultDTO saveAttributeInfo(AttributeInfoRequest request) { //入参检查 checkAttributeInfoRequest(request); //保存属性 Long attributeId = attributeRepository.saveAttributeInfo(request); return new AttributeInfoResultDTO(attributeId, true); } ...}
@Repositorypublic class AttributeRepository { @Resource private AttributeInfoMapper attributeInfoMapper; ... //保存属性信息 public Long saveAttributeInfo(AttributeInfoRequest request) { AttributeInfoDO attributeInfoDO = attributeConverter.convertAttributeInfoDO(request); attributeInfoDO.initCommon(); attributeInfoMapper.insert(attributeInfoDO); return attributeInfoDO.getId(); } ...}
复制代码


4.商品属性库系统添加属性值与属性组


(1)添加可选的属性值


//属性管理相关操作API@DubboService(version = "1.0.0", interfaceClass = AttributeApi.class, retries = 0)public class AttributeApiImpl implements AttributeApi {    ...    @Autowired    private AttributeService attributeService;        //给属性添加可选的属性值接口    @Override    public JsonResult<AttributeValueResultDTO> saveAttributeValue(List<AttributeValueRequest> list) {        AttributeValueResultDTO attributeValueResultDTO = attributeService.saveAttributeValues(list);        return JsonResult.buildSuccess(attributeValueResultDTO);    }    ...}
//属性管理相关操作API@Servicepublic class AttributeServiceImpl implements AttributeService { @Autowired private AttributeRepository attributeRepository; ... //批量给属性添加可选的属性值 @Override public AttributeValueResultDTO saveAttributeValues(List<AttributeValueRequest> list) { attributeRepository.saveAttributeValues(list); return new AttributeValueResultDTO(true); } ...}
//属性库@Repositorypublic class AttributeRepository { @Resource private AttributeValueMapper attributeValueV2Mapper; ... //批量保存属性值 public void saveAttributeValues(List<AttributeValueRequest> list) { //先删 LambdaQueryWrapper<AttributeValueDO> queryWrapper = Wrappers.lambdaQuery(); queryWrapper.eq(AttributeValueDO::getAttributeId, list.get(0).getAttributeId()); attributeValueV2Mapper.delete(queryWrapper); //后保存 List<AttributeValueDO> attributeValueDOS = attributeConverter.convertAttributeValueV2DOList(list); attributeValueDOS.forEach(e -> { e.setUpdateUser(list.get(0).getOperateUser()); e.initCommon(); }); Integer count = attributeValueV2Mapper.insertBatch(attributeValueDOS); if (count <= 0) { throw new ProductBizException(CommonErrorCodeEnum.SQL_ERROR); } } ...}
复制代码


(2)添加属性组


//属性管理相关操作API@DubboService(version = "1.0.0", interfaceClass = AttributeApi.class, retries = 0)public class AttributeApiImpl implements AttributeApi {    ...    @Autowired    private AttributeService attributeService;        //添加属性组接口    @Override    public JsonResult<AttributeGroupResultDTO> saveAttributeGroup(AttributeGroupRequest request) {        AttributeGroupResultDTO attributeGroupResultDTO = attributeService.saveAttributeGroup(request);        return JsonResult.buildSuccess(attributeGroupResultDTO);    }    ...}
//属性管理相关操作API@Servicepublic class AttributeServiceImpl implements AttributeService { @Autowired private AttributeRepository attributeRepository; ... //添加属性组接口 @Override public AttributeGroupResultDTO saveAttributeGroup(AttributeGroupRequest request) { //入参检查 checkAttributeGroupRequest(request); Long groupId = attributeRepository.saveAttributeGroup(request); return new AttributeGroupResultDTO(groupId, true); } ...}
//属性库@Repositorypublic class AttributeRepository { @Resource private AttributeGroupMapper attributeGroupMapper; ... //保存属性组 public Long saveAttributeGroup(AttributeGroupRequest request) { AttributeGroupDO attributeGroupDO = attributeConverter.convertAttributeGroupDO(request); attributeGroupDO.initCommon(); attributeGroupMapper.insert(attributeGroupDO); return attributeGroupDO.getId(); } ...}
复制代码


5.商品属性库系统添加属性模版及模版内容


一个品类会关联一个属性模版,一个属性模版里会有多个属性组或多个属性,一个属性组里会有多个属性,一个属性里会有多个属性值。


//属性管理相关操作API@DubboService(version = "1.0.0", interfaceClass = AttributeApi.class, retries = 0)public class AttributeApiImpl implements AttributeApi {    ...    @Autowired    private AttributeService attributeService;        //添加属性模板接口    @Override    public JsonResult<AttributeTemplateResultDTO> saveAttributeTemplate(AttributeTemplateRequest request) {        AttributeTemplateResultDTO attributeTemplateResultDTO = attributeService.saveAttributeTemplate(request);        return JsonResult.buildSuccess(attributeTemplateResultDTO);    }        //给模板添加模板内容接口    @Override    public JsonResult<AttributeTemplateContentResultDTO> saveAttributeTemplateContents(List<AttributeTemplateContentRequest> list) {        AttributeTemplateContentResultDTO attributeTemplateContentResultDTO = attributeService.saveAttributeTemplateContents(list);        return JsonResult.buildSuccess(attributeTemplateContentResultDTO);    }    ...}
//属性管理相关操作API@Servicepublic class AttributeServiceImpl implements AttributeService { @Autowired private AttributeRepository attributeRepository; ... //添加属性模板接口 @Override public AttributeTemplateResultDTO saveAttributeTemplate(AttributeTemplateRequest request) { //入参检查 checkAttributeTemplateRequest(request); Long templteId = attributeRepository.saveAttributeTemplate(request); return new AttributeTemplateResultDTO(templteId, true); } //添加属性模板内容接口 @Override public AttributeTemplateContentResultDTO saveAttributeTemplateContents(List<AttributeTemplateContentRequest> list) { //入参检查 checkAttributeTemplateContentRequest(list); attributeRepository.saveAttributeTemplateContents(list); return new AttributeTemplateContentResultDTO(true); } ...}
//属性库@Repositorypublic class AttributeRepository { @Resource private AttributeTemplateMapper attributeTemplateMapper; @Resource private AttributeTemplateContentMapper attributeTemplateContentMapper; ... //保存属性模板 public Long saveAttributeTemplate(AttributeTemplateRequest request) { AttributeTemplateDO attributeTemplateDO = attributeConverter.convertAttributeTemplateDO(request); attributeTemplateDO.initCommon(); attributeTemplateMapper.insert(attributeTemplateDO); return attributeTemplateDO.getId(); } //保存属性模板内容 public void saveAttributeTemplateContents(List<AttributeTemplateContentRequest> list) { //先删 LambdaQueryWrapper<AttributeTemplateContentDO> queryWrapper = Wrappers.lambdaQuery(); queryWrapper.eq(AttributeTemplateContentDO::getTemplateId, list.get(0).getTemplateId()); attributeTemplateContentMapper.delete(queryWrapper); //后保存 List<AttributeTemplateContentDO> attributeTemplateContentDOS = attributeConverter.convertAttributeTemplateContentDOList(list); attributeTemplateContentDOS.forEach(e -> { e.setUpdateUser(list.get(0).getOperateUser()); e.initCommon(); }); Integer count = attributeTemplateContentMapper.insertBatch(attributeTemplateContentDOS); if (count <= 0) { throw new ProductBizException(CommonErrorCodeEnum.SQL_ERROR); } } ...}
复制代码


6.查询属性库系统数据相关接口


//属性管理相关操作API@DubboService(version = "1.0.0", interfaceClass = AttributeApi.class, retries = 0)public class AttributeApiImpl implements AttributeApi {    ...    @Autowired    private AttributeService attributeService;        //属性分页查询接口    @Override    public JsonResult<PageResult<AttributeInfoDTO>> pageAttributeInfo(QueryAttributeInfoRequest request) {        PageResult<AttributeInfoDTO> pageResult = attributeService.pageAttributeInfo(request);        return JsonResult.buildSuccess(pageResult);    }        //根据属性id查询属性及可选的属性值    @Override    public JsonResult<List<AttributeValueDTO>> queryAttributeValueByAttributeId(Long attributeId) {        List<AttributeValueDTO> attributeValueDTOS = attributeService.queryAttributeValueByAttributeId(attributeId);        return JsonResult.buildSuccess(attributeValueDTOS);    }        //属性组分页查询接口    @Override    public JsonResult<PageResult<AttributeGroupDTO>> pageAttributeGroup(QueryAttributeGroupRequest request) {        PageResult<AttributeGroupDTO> pageResult = attributeService.pageAttributeGroup(request);        return JsonResult.buildSuccess(pageResult);    }        //属性模板分页查询接口    @Override    public JsonResult<PageResult<AttributeTemplateDTO>> pageAttributeTemplate(QueryAttributeTemplateRequest request) {        PageResult<AttributeTemplateDTO> pageResult = attributeService.pageAttributeTemplate(request);        return JsonResult.buildSuccess(pageResult);    }        //根据模板id查询模板内容接口    @Override    public JsonResult<List<AttributeTemplateContentDTO>> queryAttributeTemplateContentByTemplateId(Long templateId) {        List<AttributeTemplateContentDTO> attributeTemplateContentDTOS = attributeService.queryAttributeTemplateContentByTemplateId(templateId);        return JsonResult.buildSuccess(attributeTemplateContentDTOS);    }    ...}
//属性管理相关操作API@Servicepublic class AttributeServiceImpl implements AttributeService { @Autowired private AttributeRepository attributeRepository; //分页查询属性 @Override public PageResult<AttributeInfoDTO> pageAttributeInfo(QueryAttributeInfoRequest request) { return attributeRepository.pageAttributeInfo(request); } //根据属性id查询属性及可选的属性值 @Override public List<AttributeValueDTO> queryAttributeValueByAttributeId(Long attributeId) { if (attributeId == null || attributeId < 0) { return null; } return attributeRepository.queryAttributeValueByAttributeId(attributeId); } //分页查询属性组 @Override public PageResult<AttributeGroupDTO> pageAttributeGroup(QueryAttributeGroupRequest request) { return attributeRepository.pageAttributeGroup(request); } //分页查询属性模板 @Override public PageResult<AttributeTemplateDTO> pageAttributeTemplate(QueryAttributeTemplateRequest request) { return attributeRepository.pageAttributeTemplate(request); } //根据属性模板id查询属性模板的内容 @Override public List<AttributeTemplateContentDTO> queryAttributeTemplateContentByTemplateId(Long templateId) { if (templateId == null || templateId < 0) { return null; } return attributeRepository.queryAttributeTemplateContentByTemplateId(templateId); } ...}
//属性库@Repositorypublic class AttributeRepository { @Resource private AttributeGroupMapper attributeGroupMapper; //分页查询属性 public PageResult<AttributeInfoDTO> pageAttributeInfo(QueryAttributeInfoRequest request) { LambdaQueryWrapper<AttributeInfoDO> queryWrapper = Wrappers.lambdaQuery(); if (request.getCategoryId() != null && request.getCategoryId() > 0) { queryWrapper.eq(AttributeInfoDO::getCategoryId, request.getCategoryId()); } if (StringUtils.isNotBlank(request.getAttributeName())) { queryWrapper.like(AttributeInfoDO::getAttributeName, request.getAttributeName()); } if (StringUtils.isNotBlank(request.getAttributeCode())) { queryWrapper.like(AttributeInfoDO::getAttributeCode, request.getAttributeCode()); } if (request.getAttributeType() != null) { queryWrapper.eq(AttributeInfoDO::getAttributeType, request.getAttributeType()); } if (request.getAttributeInputType() != null) { queryWrapper.eq(AttributeInfoDO::getAttributeInputType, request.getAttributeInputType()); } Page<AttributeInfoDO> page = new Page<>(request.getPageNum(), request.getPageSize()); Page<AttributeInfoDO> pageResult = attributeInfoMapper.selectPage(page, queryWrapper); return attributeConverter.convertAttributeInfoDTOPageResult(pageResult); } //根据属性id查询属性值 public List<AttributeValueDTO> queryAttributeValueByAttributeId(Long attributeId) { LambdaQueryWrapper<AttributeValueDO> queryWrapper = Wrappers.lambdaQuery(); queryWrapper.eq(AttributeValueDO::getAttributeId, attributeId); List<AttributeValueDO> attributeValueDOS = attributeValueV2Mapper.selectList(queryWrapper); return attributeConverter.convertAttributeValueV2DTOList(attributeValueDOS); } //分页查询属性组 public PageResult<AttributeGroupDTO> pageAttributeGroup(QueryAttributeGroupRequest request) { LambdaQueryWrapper<AttributeGroupDO> queryWrapper = Wrappers.lambdaQuery(); if (request.getCategoryId() != null && request.getCategoryId() > 0) { queryWrapper.eq(AttributeGroupDO::getCategoryId, request.getCategoryId()); } if (StringUtils.isNotBlank(request.getGroupName())) { queryWrapper.like(AttributeGroupDO::getGroupName, request.getGroupName()); } Page<AttributeGroupDO> page = new Page<>(request.getPageNum(), request.getPageSize()); Page<AttributeGroupDO> pageResult = attributeGroupMapper.selectPage(page, queryWrapper); return attributeConverter.convertAttributeGroupDTOPageResult(pageResult); } //分页查询属性模板 public PageResult<AttributeTemplateDTO> pageAttributeTemplate(QueryAttributeTemplateRequest request) { LambdaQueryWrapper<AttributeTemplateDO> queryWrapper = Wrappers.lambdaQuery(); if (request.getCategoryId() != null && request.getCategoryId() > 0) { queryWrapper.eq(AttributeTemplateDO::getCategoryId, request.getCategoryId()); } if (StringUtils.isNotBlank(request.getTemplateName())) { queryWrapper.like(AttributeTemplateDO::getTemplateName, request.getTemplateName()); } Page<AttributeTemplateDO> page = new Page<>(request.getPageNum(), request.getPageSize()); Page<AttributeTemplateDO> pageResult = attributeTemplateMapper.selectPage(page, queryWrapper); return attributeConverter.convertAttributeTemplateDTOPageResult(pageResult); } //根据属性模板id查询属性模板内容 public List<AttributeTemplateContentDTO> queryAttributeTemplateContentByTemplateId(Long templateId) { LambdaQueryWrapper<AttributeTemplateContentDO> queryWrapper = Wrappers.lambdaQuery(); queryWrapper.eq(AttributeTemplateContentDO::getTemplateId, templateId); List<AttributeTemplateContentDO> attributeTemplateContentDOS = attributeTemplateContentMapper.selectList(queryWrapper); return attributeConverter.convertAttributeTemplateContentDTOList(attributeTemplateContentDOS); } ...}
复制代码


7.商品属性库系统与商品 M 端系统对接


//商品属性相关操作API@DubboService(version = "1.0.0", interfaceClass = ItemSkuAttributeApi.class, retries = 0)public class ItemSkuAttributeApiImpl implements ItemSkuAttributeApi {    @Autowired    private ItemSkuAttributeService itemSkuAttributeService;        //保存标品和商品属性接口    @Override    public JsonResult<ItemSkuAttributeValueResultDTO> saveItemSkuAttributeValue(List<ItemSkuAttributeValueRequest> list) {        ItemSkuAttributeValueResultDTO itemSkuAttributeValueResultDTO = itemSkuAttributeService.saveItemSkuAttributeValue(list);        return JsonResult.buildSuccess(itemSkuAttributeValueResultDTO);    }        //根据商品id品类id查询聚合商品属性值接口    @Override    public JsonResult<List<SkuAttributeValueDTO>> queryItemSkuAttributeValueList(QueryItemSkuAttributeValueRequest request) {        List<SkuAttributeValueDTO> skuAttributeValueDTOS = itemSkuAttributeService.queryItemSkuAttributeValueList(request);        return JsonResult.buildSuccess(skuAttributeValueDTOS);    }        //根据属性查询条件搜索商品接口    @Override    public JsonResult<List<String>> querySkuIdsByAttribute(QuerySkuIdsByAttributeRequest request) {        List<String> skuIds = itemSkuAttributeService.querySkuIdsByAttributes(request);        return JsonResult.buildSuccess(skuIds);    }}
//商品属性相关操作API@Servicepublic class ItemSkuAttributeServiceImpl implements ItemSkuAttributeService { @Autowired private AttributeRepository attributeRepository; //保存标品和商品属性 @Override public ItemSkuAttributeValueResultDTO saveItemSkuAttributeValue(List<ItemSkuAttributeValueRequest> list) { //入参检查 checkItemSkuAttributeValueRequest(list); attributeRepository.saveItemSkuAttributeValue(list); return new ItemSkuAttributeValueResultDTO(true); } //根据商品id类目id查询聚合商品属性值接口 @Override public List<SkuAttributeValueDTO> queryItemSkuAttributeValueList(QueryItemSkuAttributeValueRequest request) { //1.根据skuId和itemId查询出商品所有的属性 List<ItemSkuAttributeValueDTO> itemSkuAttributeValueDTOS = attributeRepository.queryItemSkuAttributeValueList(request); //2.找出使用这个sku使用的是哪个模板 Long templateId = itemSkuAttributeValueDTOS.get(0).getTemplateId(); //3.查询出模板内容 List<AttributeTemplateContentDTO> attributeTemplateContentDTOS = attributeRepository.queryAttributeTemplateContentByTemplateId(templateId); //4.查询出相关的属性组 List<Long> groupIds = attributeTemplateContentDTOS.stream() .map(AttributeTemplateContentDTO::getGroupId) .filter(Objects::nonNull) .collect(Collectors.toList()); List<AttributeGroupDTO> groupDTOS = attributeRepository.queryGroups(groupIds); Map<Long, String> groupIdAndNameMap = groupDTOS.stream().collect(Collectors.toMap(AttributeGroupDTO::getId, AttributeGroupDTO::getGroupName)); //5.查询出相关的属性 List<Long> attributeIds = attributeTemplateContentDTOS.stream() .map(AttributeTemplateContentDTO::getAttributeId) .collect(Collectors.toList()); List<AttributeInfoDTO> attributeInfoDTOS = attributeRepository.queryAttributeInfos(attributeIds); Map<Long, String> attributeIdAndNameMap = attributeInfoDTOS.stream().collect(Collectors.toMap(AttributeInfoDTO::getId, AttributeInfoDTO::getAttributeName)); //6.拼装结果 return buildSkuAttributeValueDTOS(itemSkuAttributeValueDTOS, groupIdAndNameMap, attributeIdAndNameMap); } //根据属性查询条件搜索商品接口 @Override public List<String> querySkuIdsByAttributes(QuerySkuIdsByAttributeRequest request) { return attributeRepository.querySkuIdsByAttribute(request); } ...}
//属性库@Repositorypublic class AttributeRepository { ... //保存标品和商品属性 public void saveItemSkuAttributeValue(List<ItemSkuAttributeValueRequest> list) { //先删 LambdaQueryWrapper<ItemSkuAttributeValueDO> queryWrapper = Wrappers.lambdaQuery(); queryWrapper.eq(ItemSkuAttributeValueDO::getParticipantId, list.get(0).getParticipantId()); itemSkuAttributeValueMapper.delete(queryWrapper); //后保存 List<ItemSkuAttributeValueDO> itemSkuAttributeValueDOS = attributeConverter.convertItemSkuAttributeValueDOList(list); itemSkuAttributeValueDOS.forEach(e -> { e.setUpdateUser(list.get(0).getOperateUser()); e.initCommon(); }); Integer count = itemSkuAttributeValueMapper.insertBatch(itemSkuAttributeValueDOS); if (count <= 0) { throw new ProductBizException(CommonErrorCodeEnum.SQL_ERROR); } } //根据商品id类目id查询聚合商品属性值接口 public List<ItemSkuAttributeValueDTO> queryItemSkuAttributeValueList(QueryItemSkuAttributeValueRequest request) { LambdaQueryWrapper<ItemSkuAttributeValueDO> queryWrapper = Wrappers.lambdaQuery(); List<String> participantIds = new ArrayList<>(); if (StringUtils.isNotBlank(request.getItemId())) { participantIds.add(request.getItemId()); } if (StringUtils.isNotBlank(request.getSkuId())) { participantIds.add(request.getSkuId()); } queryWrapper.in(ItemSkuAttributeValueDO::getParticipantId, participantIds.stream().distinct().collect(Collectors.toList())); List<ItemSkuAttributeValueDO> itemSkuAttributeValueDOS = itemSkuAttributeValueMapper.selectList(queryWrapper); return attributeConverter.convertItemSkuAttributeValueDTO(itemSkuAttributeValueDOS); } //根据属性模板id查询属性模板内容 public List<AttributeTemplateContentDTO> queryAttributeTemplateContentByTemplateId(Long templateId) { LambdaQueryWrapper<AttributeTemplateContentDO> queryWrapper = Wrappers.lambdaQuery(); queryWrapper.eq(AttributeTemplateContentDO::getTemplateId, templateId); List<AttributeTemplateContentDO> attributeTemplateContentDOS = attributeTemplateContentMapper .selectList(queryWrapper); return attributeConverter.convertAttributeTemplateContentDTOList(attributeTemplateContentDOS); } //根据id批量查询属性组 public List<AttributeGroupDTO> queryGroups(List<Long> groupIds) { List<AttributeGroupDO> attributeGroupDOS = attributeGroupMapper.selectBatchIds(groupIds); return attributeConverter.convertAttributeGroupDTOList(attributeGroupDOS); } //根据id批量查询属性 public List<AttributeInfoDTO> queryAttributeInfos(List<Long> attributeIds) { List<AttributeInfoDO> attributeInfoDOS = attributeInfoMapper.selectBatchIds(attributeIds); return attributeConverter.convertAttributeInfoDTOList(attributeInfoDOS); } //根据属性查询条件搜索商品接口 public List<String> querySkuIdsByAttribute(QuerySkuIdsByAttributeRequest request) { LambdaQueryWrapper<ItemSkuAttributeValueDO> queryWrapper = Wrappers.lambdaQuery(); for (QuerySkuIdsByAttributeRequest.AttributeCriteria attributeCriteria : request.getAttributeCriterias()) { queryWrapper.or(wrapper -> wrapper .eq(ItemSkuAttributeValueDO::getAttributeId, attributeCriteria.getAttributeId()) .like(ItemSkuAttributeValueDO::getAttributeValue, attributeCriteria.getAttributeValue()) ); } List<ItemSkuAttributeValueDO> itemSkuAttributeValueDOS = itemSkuAttributeValueMapper.selectList(queryWrapper); return itemSkuAttributeValueDOS.stream().map(ItemSkuAttributeValueDO::getParticipantId).collect(Collectors.toList()); } ...}
复制代码


8.商品状态变更流转架构设计


(1)状态流转策略表


CREATE TABLE `product_status_strategy` (    `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',    `start_status` int(10)  NOT NULL DEFAULT '0' COMMENT '起始状态',    `end_status` int(10)  NOT NULL DEFAULT '0' COMMENT '截⽌状态',    `strategy_code` varchar(64) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '策略映射码',    `business_code` varchar(64) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '业务编码',    `version_id` int(10) NOT NULL DEFAULT '0' COMMENT '版本号',    `del_flag` tinyint(1) NOT NULL DEFAULT '0' COMMENT '删除标记(1-有效,0-删除)',    `create_user` int(10) NOT NULL DEFAULT '0' COMMENT '创建⼈',    `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',    `update_user` int(10) NOT NULL DEFAULT '0' COMMENT '更新⼈',    `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',    PRIMARY KEY (`ID`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='状态流转策略表';
复制代码


(2)商品状态变更流向图


说明:严格按照箭头方向执行,除了可重新上架,其他状态变更均不可逆。


(3)接口实现流程图


 

9.商品状态变更流转的策略模式实现


具体实现在商品 M 端系统:

一.验证⼊参必填(商品 ID 和变更状态)

二.验证商品是否存在,停售状态禁⽌变更状态

三.获取状态流转策略表,根据商品的当前状态和变更状态获取配置的映射策略类的实例名称

四.实现关于每个状态变更的具体逻辑


//商品状态变更请求入参@Datapublic class ProductStatusRequest implements Serializable {    //商品ID    private String itemId;        //商品变更状态(1-准备上架、2-试销上架、3-上架、4-预下架、5-下架、6-停售)    private Integer itemStatus;}
@Servicepublic class ProductServiceImpl implements ProductService { ... //修改商品状态 @Override public void updateProductStatus(ProductStatusRequest productStatusRequest) { //1.验证入参 checkUpdateProductStatusParam(productStatusRequest); //2.获取商品对应的信息 ItemInfoDO itemInfoDO = productInfoRepository.getItemByItemId(productStatusRequest.getItemId()); //停售状态不允许操作 if (itemInfoDO.getItemStatus().equals(ProductStatusEnum.STOP_SALE.getCode())) { throw new BaseBizException(ProductExceptionCode.PRODUCT_STATUS_ERROR); } //3.获取商品状态变更配置策略 String productStatusStrategy = productInfoRepository.getProductStatusStrategy(itemInfoDO.getItemStatus(), productStatusRequest.getItemStatus(), ProductConstants.PRODUCT_UPDATE_STATUS); //4.策略调用具体变更实现类 updateProductStatus(productStatusRequest, productStatusStrategy); } //通过策略模式更新商品状态 private void updateProductStatus(ProductStatusRequest productStatusRequest, String productStatusStrategy) { AbstractStatusStrategy strategy = productStatusStrategyFactory.getStrategy(productStatusStrategy); if (null == strategy) { throw new BaseBizException(ProductExceptionCode.PRODUCT_STRATEGY_ERROR); } //通过策略模式,调用底层对应的状态变更方法 strategy.updateProductStatus(productStatusRequest); } ...}
@Repositorypublic class ProductInfoRepository { ... //根据itemId查询item信息 public ItemInfoDO getItemByItemId(String itemId) { ItemInfoDO itemInfoDO = itemInfoMapper.selectByItemId(itemId); if (Objects.isNull(itemInfoDO)) { throw new BaseBizException(ProductExceptionCode.PRODUCT_DETAIL_NULL); } return itemInfoDO; } //获取对应的修改状态流程策略映射码 public String getProductStatusStrategy(Integer startStatus, Integer endStatus, String businessCode) { LambdaQueryWrapper<ProductStatusStrategyDO> queryWrapper = Wrappers.lambdaQuery(); queryWrapper.eq(ProductStatusStrategyDO::getStartStatus, startStatus); queryWrapper.eq(ProductStatusStrategyDO::getEndStatus, endStatus); queryWrapper.eq(ProductStatusStrategyDO::getBusinessCode, businessCode); ProductStatusStrategyDO productStatusStrategy = productStatusStrategyMapper.selectOne(queryWrapper); if (Objects.isNull(productStatusStrategy)) { throw new BaseBizException(ProductExceptionCode.PRODUCT_STRATEGY_NULL); } return productStatusStrategy.getStrategyCode(); } ...}
//商品状态变更策略工厂@Componentpublic class ProductStatusStrategyFactory { //@Autowired会把所有继承了AbstractStatusStrategy抽象类的Bean实例,加载到productStatusMap中 @Autowired private Map<String, AbstractStatusStrategy> productStatusMap = new ConcurrentHashMap<>(16); //获取 商品状态变更 策略实例 public AbstractStatusStrategy getStrategy(String productStatusStrategy) { return productStatusMap.get(productStatusStrategy); }}
//商品状态变更抽象策略public abstract class AbstractStatusStrategy { //商品状态流转 public abstract void updateProductStatus(ProductStatusRequest productStatusRequest);}
复制代码


10.商品状态变更流转的具体策略实现


(1)商品试销上架的实现


一.商品试销上架时对前端销售数据校验

//试销上架状态变更@Service("trialSaleStatus")public class TrialSaleStatusService extends AbstractStatusStrategy {    @Autowired    private ProductConverter productConverter;        @Autowired    private ProductStatusRepository productStatusRepository;        @Value("${trial.date-num}")    private Integer dateNum;
//准备上架状态 流转到试销上架 @Transactional(rollbackFor = BaseBizException.class) @Override public void updateProductStatus(ProductStatusRequest productStatusRequest) { //1.验证商品和前台类目绑定关系,绑定关系有效 checkFrontCategoryList(productStatusRequest.getItemId()); //2.验证商品数据是否完整 ProductDetailDO productDetailDO = checkProductInfo(productStatusRequest.getItemId()); //3.填入补充试销商品的扩展字段(试销期截止时间) buildAttributeContent(productDetailDO); //4.变更商品信息 updateProduct(productDetailDO, productStatusRequest); //5.发送商品消息变更通知对象(已做MySQL + Canal监听) } //检查商品是否和前台类目存在绑定关系 private void checkFrontCategoryList(String itemId) { //获取类目绑定关系 List<FrontCategoryRelationDO> frontCategoryRelationList = productStatusRepository.queryFrontCategoryList(itemId); //过滤状态,只保留有效的 List<FrontCategoryRelationDO> categoryRelationDOList = frontCategoryRelationList.stream().filter(frontCategoryRelationDO -> { if (frontCategoryRelationDO.getDelFlag().equals(DelFlagEnum.EFFECTIVE.getCode())) { return true; } return false; }).collect(Collectors.toList()); //商品不存在有效的绑定关系,提示错误 if (CollectionUtils.isEmpty(categoryRelationDOList)) { throw new BaseBizException(ProductExceptionCode.PRODUCT_CATEGORY_RELATION_NULL); } } //检查商品的数据完整性 private ProductDetailDO checkProductInfo(String itemId) { //查询商品的详情信息 ProductDetailDO productDetailDO = productStatusRepository.queryProductDetail(itemId); //验证商品完整性 productStatusRepository.checkProductComplete(productDetailDO); return productDetailDO; } ...}
@Repositorypublic class ProductStatusRepository { ... //查询商品的详情信息 public ProductDetailDO queryProductDetail(String itemId) { List<ProductDetailDO> productDetailDOList = itemInfoMapper.queryProductInfoList(itemId); if (CollectionUtils.isEmpty(productDetailDOList)) { throw new BaseBizException(ProductExceptionCode.PRODUCT_DETAIL_NULL); } return productDetailDOList.get(0); } //检查商品得完整性 public void checkProductComplete(ProductDetailDO productDetailDO) { //1.验证商品的存储信息是否完整 if (Objects.isNull(productDetailDO.getStoreConditionType()) || Objects.isNull(StoreLabelEnum.getByCode(productDetailDO.getStoreConditionType()))) { throw new BaseBizException(ProductExceptionCode.PRODUCT_DETAIL_NULL); } //2.是否有推广信息 if (StringUtils.isBlank(productDetailDO.getRecommend())) { throw new BaseBizException(ProductExceptionCode.PRODUCT_DETAIL_NULL); } //3.是否有销售信息 if (Objects.isNull(productDetailDO.getBasePrice()) || Objects.isNull(productDetailDO.getVipPrice())) { throw new BaseBizException(ProductExceptionCode.PRODUCT_DETAIL_NULL); } //4.验证商品是否品控信息完整 List<QualityControlDO> qualityControlList = getQualityControlList(productDetailDO.getItemId()); if (CollectionUtils.isEmpty(qualityControlList)) { throw new BaseBizException(ProductExceptionCode.PRODUCT_DETAIL_NULL); } //5.是否有图文信息(必须包含1-主图,2-轮播图、3-详情图) List<ItemVideoImgDO> itemVideoImgList = getItemVideoImgList(productDetailDO.getItemId()); //先过滤掉不需要的图文信息 List<ItemVideoImgDO> videoImgDOList = itemVideoImgList.stream().filter(itemVideoImgDO -> { if (ProductConstants.PRODUCT_IMG_TYPE_LIST.contains(itemVideoImgDO.getContentType())) { return true; } return false; }).collect(Collectors.toList()); //空验证 if (CollectionUtils.isEmpty(itemVideoImgList)) { throw new BaseBizException(ProductExceptionCode.PRODUCT_DETAIL_NULL); } //获取图文集合类型 Set<Integer> contentTypeList = videoImgDOList.stream().map(ItemVideoImgDO::getContentType).collect(Collectors.toSet()); //过滤掉不符合的图片类型后,去重后,剩余的图片类型要和存储的一样多 if (contentTypeList.size() != ProductConstants.PRODUCT_IMG_TYPE_LIST.size()) { throw new BaseBizException(ProductExceptionCode.PRODUCT_DETAIL_NULL); } } ...}
复制代码


二.商品试销上架时补充扩展属性和变更商品状态

//试销上架状态变更@Service("trialSaleStatus")public class TrialSaleStatusService extends AbstractStatusStrategy {    ...    //填充 试销商品的扩展字段(试销期截止时间)    private void buildAttributeContent(ProductDetailDO productDetailDO) {        //1.只有普通商品或者组套商品才处理扩展信息的变化        if (checkItemType(productDetailDO)) {            //获取试销期截止时间            String trialSaleTime = DateFormatUtil.getDate(dateNum);            //先获取到试销商品的原有扩展字段            AttributeExtendDO attributeExtend = productStatusRepository.getAttributeExtend(productDetailDO.getItemId());            AttributeExtendBO attributeExtendBO = null;            //没有已经存在的扩展信息            if (!Objects.isNull(attributeExtend) || StringUtils.isBlank(attributeExtend.getAttributeContent())) {                attributeExtendBO = new AttributeExtendBO();            } else {                attributeExtendBO = JsonUtil.json2Object(attributeExtend.getAttributeContent(), AttributeExtendBO.class);            }            attributeExtendBO.setTrialSaleTime(trialSaleTime);            //字段存储起来            productDetailDO.setAttributeContent(JSONObject.toJSONString(attributeExtendBO));        }    }        //变更商品的状态    private void updateProduct(ProductDetailDO productDetailDO, ProductStatusRequest productStatusRequest) {        ItemInfoDO itemInfoDO = productConverter.converterDO(productDetailDO);        //更新商品状态        productStatusRepository.updateProductStatus(itemInfoDO, productStatusRequest.getItemStatus());        if (checkItemType(productDetailDO)) {            //更新商品扩展信息            productStatusRepository.updateAttributeExtend(productDetailDO);        }    }    ...}
@Repositorypublic class ProductStatusRepository { ... //更新商品状态 public void updateProductStatus(ItemInfoDO itemInfoDO, Integer updateItemStatus) { LambdaUpdateWrapper<ItemInfoDO> updateWrapper = Wrappers.lambdaUpdate(); updateWrapper.eq(ItemInfoDO::getItemId, itemInfoDO.getItemId()); updateWrapper.eq(ItemInfoDO::getItemStatus, itemInfoDO.getItemStatus()); updateWrapper.set(ItemInfoDO::getItemStatus, updateItemStatus); int count = itemInfoMapper.update(updateWrapper.getEntity(), updateWrapper); if (count <= 0) { throw new BaseBizException(ProductExceptionCode.PRODUCT_SQL); } } //更新商品的扩展信息 public void updateAttributeExtend(ProductDetailDO productDetailDO) { LambdaUpdateWrapper<AttributeExtendDO> updateWrapper = Wrappers.lambdaUpdate(); updateWrapper.eq(AttributeExtendDO::getParticipateId, productDetailDO.getItemId()); updateWrapper.eq(AttributeExtendDO::getParticipateType, ProductTypeEnum.ITEM.getCode()); updateWrapper.set(AttributeExtendDO::getAttributeContent, productDetailDO.getAttributeContent()); int count = attributeExtendMapper.update(updateWrapper.getEntity(), updateWrapper); if (count <= 0) { throw new BaseBizException(ProductExceptionCode.PRODUCT_SQL); } } ...}
复制代码


(2)商品上架与预下架状态流转实现


//预下架状态变更@Service("advanceShelvesStatus")public class AdvanceShelvesStatusService extends AbstractStatusStrategy {    @Autowired    private ProductStatusRepository productStatusRepository;        @Autowired    private ProductConverter productConverter;
//上架状态变更到预下架 @Override public void updateProductStatus(ProductStatusRequest productStatusRequest) { //1.验证商品和前台类目绑定关系,绑定关系有效 checkFrontCategoryList(productStatusRequest.getItemId()); //2.验证商品数据是否完整 ProductDetailDO productDetailDO = checkProductInfo(productStatusRequest.getItemId()); //3.变更商品信息 updateProduct(productDetailDO, productStatusRequest); } //查询商品是否和前台类目存在绑定关系 private void checkFrontCategoryList(String itemId) { //获取类目绑定关系 List<FrontCategoryRelationDO> frontCategoryRelationList = productStatusRepository.queryFrontCategoryList(itemId); //过滤状态,只保留有效的 List<FrontCategoryRelationDO> categoryRelationDOList = frontCategoryRelationList.stream().filter(frontCategoryRelationDO -> { if (frontCategoryRelationDO.getDelFlag().equals(DelFlagEnum.EFFECTIVE.getCode())) { return true; } return false; }).collect(Collectors.toList()); //商品不存在有效的绑定关系,提示错误 if (CollectionUtils.isEmpty(categoryRelationDOList)) { throw new BaseBizException(ProductExceptionCode.PRODUCT_CATEGORY_RELATION_NULL); } } //验证商品的数据完整性 private ProductDetailDO checkProductInfo(String itemId) { //查询商品的详情信息 ProductDetailDO productDetailDO = productStatusRepository.queryProductDetail(itemId); //验证商品完整性 productStatusRepository.checkProductComplete(productDetailDO); return productDetailDO; } //变更商品的状态 private void updateProduct(ProductDetailDO productDetailDO, ProductStatusRequest productStatusRequest) { ItemInfoDO itemInfoDO = productConverter.converterDO(productDetailDO); productStatusRepository.updateProductStatus(itemInfoDO, productStatusRequest.getItemStatus()); } ...}
复制代码


(3)商品下架和停售状态流转实现


//下架状态变更@Service("offShelvesSaleStatus")public class OffShelvesStatusService extends AbstractStatusStrategy {    @Autowired    private ProductStatusRepository productStatusRepository;        @Autowired    private ProductInfoRepository productInfoRepository;        //上架状态 变更到下架状态    //预上架状态 变更到下架状态    @Override    public void updateProductStatus(ProductStatusRequest productStatusRequest) {        //1.查询商品信息        ItemInfoDO itemInfoDO = productInfoRepository.getItemByItemId(productStatusRequest.getItemId());        //2.商品状态变更        productStatusRepository.updateProductStatus(itemInfoDO, productStatusRequest.getItemStatus());    }}
//停售状态@Service("stopStatus")public class StopStatusService extends AbstractStatusStrategy { @Autowired private ProductStatusRepository productStatusRepository; @Autowired private ProductInfoRepository productInfoRepository; //下架状态 变更到停售 @Override public void updateProductStatus(ProductStatusRequest productStatusRequest) { //1.查询商品信息 ItemInfoDO itemInfoDO = productInfoRepository.getItemByItemId(productStatusRequest.getItemId()); //2.商品状态变更 productStatusRepository.updateProductStatus(itemInfoDO, productStatusRequest.getItemStatus()); }}
复制代码


(4)流转到上架的状态变更


//上架状态变更@Service("shelvesSaleStatus")public class ShelvesStatusService extends AbstractStatusStrategy {    @Autowired    private ProductConverter productConverter;        @Autowired    private ProductStatusRepository productStatusRepository;
//准备上架状态 流转到上架 //试销上架状态 流转到上架 @Override public void updateProductStatus(ProductStatusRequest productStatusRequest) { //1.验证商品和前台类目绑定关系,绑定关系有效 checkFrontCategoryList(productStatusRequest.getItemId()); //2.验证商品数据是否完整 ProductDetailDO productDetailDO = checkProductInfo(productStatusRequest.getItemId()); //3.变更商品信息 updateProduct(productDetailDO, productStatusRequest); } ...}
复制代码


文章转载自:东阳马生架构

原文链接:https://www.cnblogs.com/mjunz/p/18924919

体验地址:http://www.jnpfsoft.com/?from=001YH

用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
商品中心—商品属性与状态流转的技术文档_数据库_不在线第一只蜗牛_InfoQ写作社区