商品中心—商品属性与状态流转的技术文档
- 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);
}
...
}
//新增/编辑属性请求入参
@Data
public 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
@Service
public 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);
}
...
}
@Repository
public 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
@Service
public class AttributeServiceImpl implements AttributeService {
@Autowired
private AttributeRepository attributeRepository;
...
//批量给属性添加可选的属性值
@Override
public AttributeValueResultDTO saveAttributeValues(List<AttributeValueRequest> list) {
attributeRepository.saveAttributeValues(list);
return new AttributeValueResultDTO(true);
}
...
}
//属性库
@Repository
public 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
@Service
public 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);
}
...
}
//属性库
@Repository
public 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
@Service
public 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);
}
...
}
//属性库
@Repository
public 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
@Service
public 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);
}
...
}
//属性库
@Repository
public 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
@Service
public 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);
}
...
}
//属性库
@Repository
public 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 和变更状态)
二.验证商品是否存在,停售状态禁⽌变更状态
三.获取状态流转策略表,根据商品的当前状态和变更状态获取配置的映射策略类的实例名称
四.实现关于每个状态变更的具体逻辑
//商品状态变更请求入参
@Data
public class ProductStatusRequest implements Serializable {
//商品ID
private String itemId;
//商品变更状态(1-准备上架、2-试销上架、3-上架、4-预下架、5-下架、6-停售)
private Integer itemStatus;
}
@Service
public 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);
}
...
}
@Repository
public 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();
}
...
}
//商品状态变更策略工厂
@Component
public 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;
}
...
}
@Repository
public 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);
}
}
...
}
@Repository
public 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);
}
...
}
文章转载自:东阳马生架构

不在线第一只蜗牛
还未添加个人签名 2023-06-19 加入
还未添加个人简介
评论