商品中心—9.商品卖家系统的技术文档

大纲

1.卖家和卖家组模型以及业务流程

2.卖家系统数据库表模型与缓存结构设计

3.卖家系统核心接口与代码实现

 

1.卖家和卖家组模型以及业务流程

(1)卖家模型

(2)卖家组模型

(3)业务流程详解

 

(1)卖家模型

卖家类型分为:⾃营卖家和POP卖家。

 

⾃营卖家:类似于京东⾃营卖家。其商品由平台采购,建⽴仓储系统存储,平台⾃⾏上架商品。其最⼩维度为⻔店,如北京市-东城区-⽣鲜⻔店。

 

POP卖家:第三⽅供货商接⼊平台作为⼀个卖家。其最⼩维度为区域,如北京市-东城区卖家。

 

卖家树模型可以看成是类目树模型。卖家节点也分为叶子节点和非叶子节点。非叶子节点的卖家节点可以看成是卖家所属的分类,叶子节点的卖家节点才是具体的某一个卖家。所以创建卖家节点之前,必须先根据全国地区编码初始化一次卖家树。初始化完之后,后续创建卖家节点就不需要再初始化卖家树了。

 

一.自营卖家树体系

商品中心—9.商品卖家系统的技术文档

二.POP卖家树体系

商品中心—9.商品卖家系统的技术文档

(2)卖家组模型

卖家组:⼀组具有相同供应属性的卖家组合。注意:POP类型的卖家和⾃营类型的卖家不能同属⼀个卖家组。在⼀个卖家组中,要么全都是⾃营卖家,要么全都是POP卖家。

商品中心—9.商品卖家系统的技术文档

(3)业务流程详解

一.建立卖家体系

⾃营卖家:根据国家的地区编码建⽴卖家树。其⾮叶⼦节点为虚拟卖家,叶⼦节点为实体卖家,例如东城区⻔店1。

 

POP卖家:根据国家的地区编码建⽴卖家树。其⾮叶⼦节点为虚拟卖家,叶⼦节点为实体卖家,例如东城区卖家。

 

二.建立卖家组

⾃营:例如根据地域关系划分,东城区卖家组,⻄城区卖家组。

 

POP:例如根据地域关系划分,上海卖家组,北京卖家组。

 

三.绑定卖家与卖家组关系

运营将⼀组卖家与卖家组绑定。注意:绑定时卖家与卖家组类型必须⼀致才可以绑定,否则不能绑定。而且卖家组与卖家是多对多关系,即⼀个卖家组能同时添加多个同⼀⾃营类型卖家或者POP类型卖家,⼀个卖家也可以被添加到多个同⼀类型的卖家组中。

 

卖家组与卖家建⽴绑定关系后,即可对外提供卖家能⼒。只有当卖家与卖家组绑定关系后,才可以对外提供售卖商品的能⼒。商品需要划分到卖家,⽽卖家也必须⾄少在⼀个卖家组中。

商品中心—9.商品卖家系统的技术文档

 

2.卖家系统数据库表模型与缓存结构设计

(1)卖家信息表

(2)卖家组表

(3)卖家与卖家组关系表

(4)卖家账户表

(5)卖家系统ID表

(6)国家⾏政编号信息表

(7)缓存结构设计

 

(1)卖家信息表

CREATE TABLE `seller_info` (     `id` bigint(40) NOT NULL AUTO_INCREMENT COMMENT '主键',     `seller_id` int(10) NOT NULL COMMENT '卖家ID:20开头 + 6位随机数',     `seller_code` varchar(64) NOT NULL COMMENT '卖家编码:⾃营指微仓编码(WJ-1001),POP指区域编码(国标编码)',     `seller_name` varchar(128) NOT NULL COMMENT '卖家名称',     `seller_desc` varchar(512) DEFAULT NULL COMMENT '卖家描述',     `seller_type` tinyint(3) NOT NULL COMMENT '卖家类型:1-⾃营,2-POP ',     `seller_position` SMALLINT(3) NOT NULL COMMENT '卖家位置:100-全国,200-⼤区,300-省/直辖市,400-城市,500-地区,600-微仓',     `seller_status` tinyint(3) NOT NULL COMMENT '卖家状态:1-开店,2-闭店,3-删除',     `store_label_list` varchar(10) comment '存储标签(1-常温,2-冷藏,3-冷冻,4-⽔产)',     `trial_sale_label` tinyint(1) comment '是否有试销标签(1-试销,0-⾮试销)',     `parent_id` bigint(40) DEFAULT '0' COMMENT '⽗卖家ID',     `last_node` tinyint(3) NOT NULL DEFAULT '0' COMMENT '叶⼦节点标识:1-是,0-否',     `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=12 DEFAULT CHARSET=utf8 COMMENT='卖家信息表';

(2)卖家组表

create table `seller_group` (     `id` bigint(40) primary key AUTO_INCREMENT COMMENT '主键',     `seller_group_id` int(10) not null comment '卖家组ID:30开头 + 4位随机数',     `seller_group_name` varchar(64) not null comment '卖家组名称',     `seller_group_type` tinyint(3) not null comment '卖家组类型:1-⾃营,2-POP',     `seller_group_status` tinyint(3) NOT NULL COMMENT '卖家组状态:1-⽣效,2-⽆效',     `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 '更新时间' ) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 COMMENT='卖家组表';

(3)卖家与卖家组关系表

create table seller_group_relation(     `id` bigint(40) primary key AUTO_INCREMENT COMMENT '主键',     `seller_group_id` int(10) not null comment '卖家组ID:30开头 + 4位随机数',     `seller_id` int(10) not null comment '卖家ID:20开头 + 6位随机数',     `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 '更新时间' ) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 COMMENT='卖家与卖家组关系表';

(4)卖家账户表

create table seller_account (     `id` bigint(40) primary key AUTO_INCREMENT COMMENT '主键',     `seller_id` int(10) not null comment '卖家ID:20开头+6位随机数',     `pay_channel` tinyint(3) not null comment '⽀付渠道:1-银联,2-微信,3-⽀付宝',     `account_no` varchar(64) not null 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 '更新时间' ) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 COMMENT='卖家账户表';

(5)卖家系统ID表

create table seller_auto_no(     `id` bigint(20) primary key auto_increment comment '主键',     `create_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',     `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间' ) ENGINE=InnoDB AUTO_INCREMENT=56 DEFAULT CHARSET=utf8mb4 COMMENT='卖家系统ID表';

(6)国家⾏政编号信息表

CREATE TABLE `national_code` (     `id` int(7) NOT NULL COMMENT '主键',     `name` varchar(40) DEFAULT NULL COMMENT '省市区名称',     `parent_id` int(7) DEFAULT NULL COMMENT '上级ID',     `short_name` varchar(40) DEFAULT NULL COMMENT '简称',     `level_type` tinyint(2) DEFAULT NULL COMMENT '级别:0-中国,1-⼤区,2-省/直辖市,3-市,4-区/县',     `city_code` varchar(7) DEFAULT NULL COMMENT '城市代码',     `zip_code` varchar(7) DEFAULT NULL COMMENT '邮编',     `lng` varchar(20) DEFAULT NULL COMMENT '经度',     `lat` varchar(20) DEFAULT NULL COMMENT '纬度',     `pinyin` varchar(40) DEFAULT NULL COMMENT '拼⾳',     `status` enum('0','1') DEFAULT '1' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='国家⾏政编号信息表';

(7)缓存结构设计

商品中心—9.商品卖家系统的技术文档

 

3.卖家系统核心接口与代码实现

(1)卖家接口

(2)卖家组接口

(3)卖家与卖家组关系

(4)卖家账户

 

(1)卖家接口

一.初始化卖家树接口

二.新增卖家接口

三.更新卖家接口

四.删除卖家接口

五.查询卖家接口

六.查询卖家RPC接口

 

一.初始化卖家树接口

向接口传⼊卖家类型,然后根据国标数据初始化全国卖家树。卖家树层级为:全国、⼤区、省/直辖市、城市、区/县。

 

卖家树模型可以看成是类目树模型。卖家节点也分为叶子节点和非叶子节点,非叶子节点的卖家节点可以看成是卖家所属的分类,叶子节点的卖家节点才是具体的某一个卖家。所以创建卖家节点之前,必须先根据全国地区编码初始化一次卖家树。初始化完之后,后续创建卖家节点就不需要再初始化卖家树了。

@Service public class SellerInfoServiceImpl implements SellerInfoService {     @Autowired     private SellerRepository sellerRepository;     ...          //卖家树信息初始化接口     @Override     @Transactional(rollbackFor = Exception.class)     public SellerInfoResultDTO initSellerTreeInfo(Integer sellerType) {         //1.生成全国卖家         Long nationwideSellerId = initNationwideSeller(sellerType);         //2.生成大区卖家         Map<String, Long> districtMap = initDistrictSeller(nationwideSellerId, sellerType);         //3.生成省/直辖市卖家         Map<String, Long> provinceMap = initDiffParentSeller(districtMap, sellerType, NationalCodeLevelEnum.PROVINCE, SellerPositionEnum.PROVINCE);         //4.生成城市卖家         Map<String, Long> cityMap = initDiffParentSeller(provinceMap, sellerType, NationalCodeLevelEnum.CITY, SellerPositionEnum.CITY);         //5.生成地区卖家         initDiffParentSeller(cityMap, sellerType, NationalCodeLevelEnum.REGION, SellerPositionEnum.REGION);         return new SellerInfoResultDTO(Boolean.TRUE);     }          //1.生成全国卖家     private Long initNationwideSeller(Integer sellerType) {         //查询出国家层级数据         List<NationalCodeDO> nationalCodeList = getNationalCode(NationalCodeLevelEnum.NATIONWIDE);         //只有一个全国卖家         NationalCodeDO nationalCode = nationalCodeList.get(0);         //生成sellerId         Long sellerId = sellerRepository.generateSellerId(SkuSellerRelationConstants.SELLER_PREFIX_NO, SELLER_ID_WIDTH);         SellerInfoDO sellerInfo = buildSellerInfoDO(sellerType, nationalCode, sellerId);         //保存全国卖家         sellerRepository.savelSellerInfoBatch(Collections.singletonList(sellerInfo));         return sellerId;     }          //查询某地区层级的国标数据     private List<NationalCodeDO> getNationalCode(NationalCodeLevelEnum province) {         NationalCodeRequest nationalRequest = new NationalCodeRequest();         nationalRequest.setLevelType(province.getCode());         return nationalCodeRepository.queryNationalCode(nationalRequest);     }          //构造卖家树节点数据     private SellerInfoDO buildSellerInfoDO(Integer sellerType, NationalCodeDO nationalCode, Long parentId, SellerPositionEnum province) {         SellerInfoDO sellerInfo = new SellerInfoDO();         //生成sellerId         Long sellerId = sellerRepository.generateSellerId(SkuSellerRelationConstants.SELLER_PREFIX_NO, SELLER_ID_WIDTH);         sellerInfo.setSellerId(sellerId);         sellerInfo.setSellerCode(String.valueOf(nationalCode.getId()));         sellerInfo.setSellerName(nationalCode.getName() + SkuSellerRelationConstants.SELLER_NAME_SUFFIX);         sellerInfo.setSellerPosition(province.getCode());         sellerInfo.setSellerType(sellerType);         sellerInfo.setSellerStatus(SellerInfoStatusEnum.OPEN_STATUS.getCode());         sellerInfo.setParentId(parentId);         sellerInfo.setLastNode(YesOrNoEnum.NO.getCode());         sellerInfo.initCommon();         return sellerInfo;     }          //2.生成地区卖家     private Map<String, Long> initDistrictSeller(Long nationwideSellerId, Integer sellerType) {         //查询出地区层级数据         List<NationalCodeDO> nationalCodeList = getNationalCode(NationalCodeLevelEnum.DISTRICT);         //国家以下层级有多个         List<SellerInfoDO> sellerInfoList = nationalCodeList.stream()             .map(nationalCode -> buildSellerInfoDO(sellerType, nationalCode, nationwideSellerId, SellerPositionEnum.DISTRICT))             .collect(Collectors.toList());         //批量保存         sellerRepository.savelSellerInfoBatch(sellerInfoList);         //转换为Map,key为卖家编码、value为卖家ID         return sellerInfoList.stream().collect(Collectors.toMap(SellerInfoDO::getSellerCode, SellerInfoDO::getSellerId));     }          //省/直辖市、城市、区县卖家都使用该接口生成     private Map<String, Long> initDiffParentSeller(Map<String, Long> districtMap, Integer sellerType, NationalCodeLevelEnum codeLevelEnum, SellerPositionEnum sellerPositionEnum) {         //查询出地区层级数据         List<NationalCodeDO> provinceCodeList = getNationalCode(codeLevelEnum);         //需要保存的卖家集合         List<SellerInfoDO> sellerInfoList = provinceCodeList.stream().map(nationalCode -> {             //获取该国标的上级卖家ID             Long parentId = districtMap.get(String.valueOf(nationalCode.getParentId()));             return buildSellerInfoDO(sellerType, nationalCode, parentId, sellerPositionEnum);         }).collect(Collectors.toList());         //批量保存         sellerRepository.savelSellerInfoBatch(sellerInfoList);         //转换为Map,key为卖家编码、value为卖家ID         return sellerInfoList.stream().collect(Collectors.toMap(SellerInfoDO::getSellerCode, SellerInfoDO::getSellerId));     }     ... }  @Repository public class SellerRepository {     ...     //生成卖家或卖家组ID,即sellerId、sellerGroupId生成     //sellerId格式:20开头,6位随机数     //sellerGroupId格式:30开头,4位随机数     public Long generateSellerId(String prefix, Integer width) {         return Long.parseLong(generateSellerNo(prefix, width));     }          //自营卖家叶子结点sellerCode生成     //格式:父卖家(区县)的首拼-4位随机数,如:西湖区 -> XH-1001     //@param prefix 前缀     //@param width  位数     public String generateSellerNo(String prefix, Integer width) {         SellerAutoNoDO sellerAutoNoDO = new SellerAutoNoDO();         sellerAutoNoMapper.insert(sellerAutoNoDO);         Long autoNo = sellerAutoNoDO.getId();         if (Objects.isNull(autoNo)) {             throw new BaseBizException(CommonErrorCodeEnum.SQL_ERROR);         }         return prefix + IDUtils.genId(autoNo, width);     }          //批量新增卖家     public void savelSellerInfoBatch(List<SellerInfoDO> sellerInfoList) {         List<Long> sellerIdList = sellerInfoList.stream().map(SellerInfoDO::getSellerId).collect(Collectors.toList());         //是否存在该记录         LambdaQueryWrapper<SellerInfoDO> queryWrapper = Wrappers.lambdaQuery();         queryWrapper.in(SellerInfoDO::getSellerId, sellerIdList);         int count = sellerInfoMapper.selectCount(queryWrapper);         if (count > 0) {             throw new BaseBizException(ProductErrorCodeEnum.PARAM_CHECK_ERROR, ProductErrorCodeEnum.PARAM_CHECK_ERROR.getErrorCode());         }         //批量插入         count = sellerInfoMapper.insertBatch(sellerInfoList);         if (count != sellerInfoList.size()) {             throw new BaseBizException(CommonErrorCodeEnum.SQL_ERROR);         }     }     ... }

二.新增卖家接口

新增微仓卖家节点,卖家分为⾃营卖家和POP卖家,只有⾃营卖家才有微仓层级。

@Service public class SellerInfoServiceImpl implements SellerInfoService {     //卖家ID,6位序列号     private static final int SELLER_ID_WIDTH = 6;          //自营卖家编码,4位序列号     private static final int SELLER_CODE_WIDTH = 4;          @Autowired     private SellerRepository sellerRepository;     ...          //新增卖家     @Override     @Transactional(rollbackFor = Exception.class)     public SellerInfoResultDTO saveSellerInfo(SellerInfoRequest request) {         //1.校验参数完整性         checkSaveSellerInfoRequest(request);         //2.父卖家是否存在         SellerInfoDO sellerInfo = checkParentSellerExists(request);         //3.sellerId生成         Long sellerId = sellerRepository.generateSellerId(SkuSellerRelationConstants.SELLER_PREFIX_NO, SELLER_ID_WIDTH);         request.setSellerId(sellerId);         //新增卖家的父卖家的sellerCode是国标,找到国标前缀         String sellerCodePrefix = getSellerCodePrefix(sellerInfo);         //4.sellerCode生成         String sellerCode = sellerRepository.generateSellerNo(sellerCodePrefix, SELLER_CODE_WIDTH);         request.setSellerCode(sellerCode);         //5.新增卖家数据         sellerRepository.saveSellerInfo(request);         return new SellerInfoResultDTO(request.getSellerId(), Boolean.TRUE);     }          //获取自营卖家叶子结点的sellerCode前缀     private String getSellerCodePrefix(SellerInfoDO parentSellerInfo) {         //父卖家编码         Integer sellerCode;         try {             sellerCode = Integer.parseInt(parentSellerInfo.getSellerCode());         } catch (NumberFormatException e) {             throw new BaseBizException(ProductErrorCodeEnum.PARAM_CHECK_ERROR, ProductErrorCodeEnum.PARAM_CHECK_ERROR.getErrorCode());         }         NationalCodeRequest request = new NationalCodeRequest();         request.setId(sellerCode);         List<NationalCodeDO> nationalCodeList = nationalCodeRepository.queryNationalCode(request);            NationalCodeDO nationalCode = nationalCodeList.get(0);         if (Objects.isNull(nationalCode) || StringUtils.isEmpty(nationalCode.getShortName())) {             throw new BaseBizException(ProductErrorCodeEnum.PARAM_CHECK_ERROR, ProductErrorCodeEnum.PARAM_CHECK_ERROR.getErrorCode());         }         //转换为拼音首字母简写         return BopomofoUtil.initialsTransfer(nationalCode.getShortName()) + SkuSellerRelationConstants.SELF_SELLER_CODE_SEPARATOR;     }     ... }  //卖家信息入参 @Data @Builder @AllArgsConstructor @NoArgsConstructor public class SellerInfoRequest extends PageRequest implements Serializable {     //卖家ID集合(限制100个)     List<Long> sellerIdList;     //卖家ID     private Long sellerId;     //卖家名称     private String sellerName;     //卖家编码 自营指微仓编码(WJ-1001),POP指区域编码(国标编码),上级编码用的是一套国标编码     private String sellerCode;     //卖家描述     private String sellerDesc;     //卖家位置:100-全国,200-大区,300-省(直辖市),400-城市,500-地区,600-微仓     private Integer sellerPosition;     //自营:1,pop:2     private Integer sellerType;     //卖家状态:1-开店,2-闭店,3-删除     private Integer sellerStatus;     //父卖家ID     private Integer parentId;     //是否叶子节点     private Integer lastNode;     //存储标签(1-常温,2-冷藏,3-冷冻,4-水产)     private List<Integer> storeLabelList;     //是否有试销标签(1-试销,0-非试销)     private Integer trialSaleLabel; }  @Repository public class SellerRepository {     ...     //生成卖家或卖家组ID,即sellerId、sellerGroupId生成     //sellerId格式:20开头,6位随机数     //sellerGroupId格式:30开头,4位随机数     public Long generateSellerId(String prefix, Integer width) {         return Long.parseLong(generateSellerNo(prefix, width));     }          //自营卖家叶子结点sellerCode生成     //格式:父卖家(区县)的首拼-4位随机数,如:西湖区 -> XH-1001     //@param prefix 前缀     //@param width  位数     public String generateSellerNo(String prefix, Integer width) {         SellerAutoNoDO sellerAutoNoDO = new SellerAutoNoDO();         sellerAutoNoMapper.insert(sellerAutoNoDO);         Long autoNo = sellerAutoNoDO.getId();         if (Objects.isNull(autoNo)) {             throw new BaseBizException(CommonErrorCodeEnum.SQL_ERROR);         }         return prefix + IDUtils.genId(autoNo, width);     }          //新增卖家     public void saveSellerInfo(SellerInfoRequest request) {         //是否存在该记录         LambdaQueryWrapper<SellerInfoDO> queryWrapper = Wrappers.lambdaQuery();         queryWrapper.eq(SellerInfoDO::getSellerId, request.getSellerId());         int count = sellerInfoMapper.selectCount(queryWrapper);         if (count > 0) {             throw new BaseBizException(ProductErrorCodeEnum.PARAM_CHECK_ERROR, ProductErrorCodeEnum.PARAM_CHECK_ERROR.getErrorCode());         }         //DO对象初始化         SellerInfoDO sellerInfo = initSellerInfoDO(request);         //保存到缓存         redisCache.set(SellerRedisKeyConstants.SELLER_INFO_LIST + sellerInfo.getSellerId(), JSON.toJSONString(sellerInfo), -1);         //新卖家落库         count = sellerInfoMapper.insert(sellerInfo);         if (count <= 0) {             throw new BaseBizException(CommonErrorCodeEnum.SQL_ERROR);         }     }          //新增卖家时初始化卖家信息     private SellerInfoDO initSellerInfoDO(SellerInfoRequest request) {         SellerInfoDO sellerInfo = sellerInfoConverter.requestToEntity(request);         sellerInfo.setSellerPosition(SellerPositionEnum.STORAGE.getCode());         sellerInfo.setSellerType(SellerTypeEnum.SELF.getCode());         sellerInfo.setLastNode(YesOrNoEnum.YES.getCode());         sellerInfo.initCommon();         return sellerInfo;     }     ... }

三.更新卖家接口

更新卖家的信息,允许对任意层级的卖家进⾏修改,但是仅允许修改:卖家名、卖家描述。

 

更新卖家状态,仅允许修改城市及城市以下(区县、微仓)卖家的状态。修改某个卖家状态后,该卖家下的⼦卖家状态也将同时修改。

@Service public class SellerInfoServiceImpl implements SellerInfoService {     ...     //更新卖家信息     //允许修改卖家名、卖家描述和卖家状态字段     //变更卖家状态后,所有子卖家状态也要变更,但仅允许修改城市及以下层级的卖家状态     @Override     @Transactional(rollbackFor = Exception.class)     public SellerInfoResultDTO updateSellerInfo(SellerInfoRequest request) {         //1.校验参数完整性         checkUpdateSellerInfoRequest(request);         //2.修改卖家数据         sellerRepository.updateSellerInfo(request);         //sellerStatus是否变更         if (Objects.nonNull(request.getSellerStatus())) {             //查询出所有的子卖家的sellerId             List<Long> sellerIdList = getChildSellerIdList(Collections.singletonList(request.getSellerId()), request.getSellerType());             //批量修改状态             sellerRepository.batchUpdateSellerInfo(sellerIdList, request.getSellerStatus());         }         return new SellerInfoResultDTO(request.getSellerId(), Boolean.TRUE);     }          //获取子卖家的sellerId     private List<Long> getChildSellerIdList(List<Long> parentIdList, Integer sellerType) {         if (Objects.isNull(sellerType)) {             throw new BaseBizException(ProductErrorCodeEnum.PARAM_CHECK_ERROR, ProductErrorCodeEnum.PARAM_CHECK_ERROR.getErrorCode());         }         List<Long> sellerIdList = Lists.newArrayList();         List<Long> sellerIds = sellerRepository.getSellerIdListByParentId(parentIdList, sellerType);         if (CollectionUtils.isNotEmpty(sellerIds)) {             sellerIdList.addAll(sellerIds);             sellerIdList.addAll(getChildSellerIdList(sellerIds, sellerType));         }         return sellerIdList;     }     ... }  @Repository public class SellerRepository {     ...     //修改卖家     public void updateSellerInfo(SellerInfoRequest request) {         //查询出数据库卖家信息         LambdaQueryWrapper<SellerInfoDO> queryWrapper = Wrappers.lambdaQuery();         queryWrapper.eq(SellerInfoDO::getSellerId, request.getSellerId());         SellerInfoDO sellerInfo = sellerInfoMapper.selectOne(queryWrapper);         if (Objects.isNull(sellerInfo)) {             throw new BaseBizException(ProductErrorCodeEnum.PARAM_CHECK_ERROR, ProductErrorCodeEnum.PARAM_CHECK_ERROR.getErrorCode());         }         //更新到缓存         updateSellerInfoFromCache(request, sellerInfo);         //更新到数据库         updateSellerInfoFromDB(request);     }          //更新卖家信息到数据库     private void updateSellerInfoFromDB(SellerInfoRequest request) {         SellerInfoDO requestInfo = sellerInfoConverter.requestToEntity(request);         LambdaUpdateWrapper<SellerInfoDO> updateWrapper = Wrappers.lambdaUpdate();         updateWrapper.eq(SellerInfoDO::getSellerId, request.getSellerId());         int count = sellerInfoMapper.update(requestInfo, updateWrapper);         if (count <= 0) {             throw new BaseBizException(CommonErrorCodeEnum.SQL_ERROR);         }     }          //更新卖家信息到缓存     private void updateSellerInfoFromCache(SellerInfoRequest request, SellerInfoDO sellerInfo) {         String redisKey = SellerRedisKeyConstants.SELLER_INFO_LIST + request.getSellerId();         if (StringUtils.isNotEmpty(request.getSellerName())) {             sellerInfo.setSellerName(request.getSellerName());         }         if (StringUtils.isNotEmpty(request.getSellerDesc())) {             sellerInfo.setSellerDesc(request.getSellerDesc());         }         if (Objects.nonNull(SellerInfoStatusEnum.getByCode(request.getSellerStatus()))) {             sellerInfo.setSellerStatus(request.getSellerStatus());         }         redisCache.set(redisKey, JSON.toJSONString(sellerInfo), -1);     }          //批量修改卖家状态     public void batchUpdateSellerInfo(List<Long> sellerIdList, Integer sellerStatus) {         LambdaUpdateWrapper<SellerInfoDO> updateWrapper = Wrappers.lambdaUpdate();         updateWrapper.in(Objects.nonNull(sellerIdList), SellerInfoDO::getSellerId, sellerIdList);         updateWrapper.set(SellerInfoDO::getSellerStatus, sellerStatus);         int count = sellerInfoMapper.update(null, updateWrapper);         if (count <= 0) {             throw new BaseBizException(CommonErrorCodeEnum.SQL_ERROR);         }     }     ... }

四.删除卖家接口

批量删除卖家接⼝,仅允许删除微仓卖家,也就是叶⼦结点卖家,⾮叶⼦结点卖家不允许删除。卖家树模型可以看成是类目树模型,卖家节点也分为叶子节点和非叶子节点。非叶子节点的卖家节点可以看成是卖家所属的分类,叶子节点的卖家节点才是具体的某一个卖家。

@Service public class SellerInfoServiceImpl implements SellerInfoService {     ...     //删除卖家     @Override     @Transactional(rollbackFor = Exception.class)     public SellerInfoResultDTO deleteSellerInfo(List<Integer> sellerIdList) {         //1.是否存在非叶子卖家         if (sellerRepository.checkNonLastSellerExists(sellerIdList)) {             throw new BaseBizException(ProductErrorCodeEnum.PARAM_CHECK_ERROR, ProductErrorCodeEnum.PARAM_CHECK_ERROR.getErrorCode());         }         //2.删除         sellerRepository.deleteSellerInfo(sellerIdList);         return new SellerInfoResultDTO(Boolean.TRUE);     }     ... }  @Repository public class SellerRepository {     ...     //检查是否存在非叶子卖家     public Boolean checkNonLastSellerExists(List<Integer> sellerIdList) {         LambdaQueryWrapper<SellerInfoDO> queryWrapper = Wrappers.lambdaQuery();         queryWrapper.eq(SellerInfoDO::getLastNode, YesOrNoEnum.NO.getCode());         queryWrapper.in(CollectionUtils.isNotEmpty(sellerIdList), SellerInfoDO::getSellerId, sellerIdList);         Integer count = sellerInfoMapper.selectCount(queryWrapper);         return Objects.nonNull(count) && count > 0;     }          //删除卖家     public void deleteSellerInfo(List<Integer> sellerIdList) {         //删除缓存卖家         List<String> redisKeyList = sellerIdList.stream().map(sellerId -> SellerRedisKeyConstants.SELLER_INFO_LIST + sellerId).collect(toList());         redisCache.delete(redisKeyList);         //删除数据库卖家         LambdaUpdateWrapper<SellerInfoDO> updateWrapper = Wrappers.lambdaUpdate();         //条件         updateWrapper.in(SellerInfoDO::getSellerId, sellerIdList);         updateWrapper.eq(SellerInfoDO::getLastNode, YesOrNoEnum.YES.getCode());         //删除标志         updateWrapper.set(SellerInfoDO::getDelFlag, YesOrNoEnum.NO.getCode());         int count = sellerInfoMapper.update(null, updateWrapper);         if (count <= 0) {             throw new BaseBizException(CommonErrorCodeEnum.SQL_ERROR);         }     }     ... }

五.查询卖家接口

根据卖家ID、卖家类型、卖家名、⽗卖家ID等字段,对卖家进⾏查询,该接⼝提供给运营⼈员进⾏操作。如果传⼊卖家ID集合或卖家类型参数,则先尝试从Redis中查询,没有查到再根据其他参数从数据库中查询。

 

这里使用了简化版的缓存 + DB读写逻辑。

@Service public class SellerInfoServiceImpl implements SellerInfoService {     @Autowired     private SellerRepository sellerRepository;         @Autowired     private SellerInfoCache sellerInfoCache;     ...          //查询卖家,用于运营人员前端界面筛选卖家操作     @Override     public List<SellerInfoResponse> querySellerInfo(SellerInfoRequest request) {         //校验参数完整性         checkQuerySellerInfoRequest(request);         if (CollectionUtils.isEmpty(request.getSellerIdList())) {             //根据sellerType获取该类型下的sellerId集合             Optional<List<Long>> sellerIdListOps = getSellerIdListBySellerType(request);             sellerIdListOps.ifPresent(request::setSellerIdList);         }            //根据sellerIdList从缓存或者数据库中查询卖家信息         Optional<List<SellerInfoResponse>> sellerInfoListOps = sellerInfoCache.listRedisStringDataByCache(request.getSellerIdList(),             SellerInfoResponse.class,             sellerId -> SellerRedisKeyConstants.SELLER_INFO_LIST + sellerId,             request,             req -> sellerRepository.querySellerInfo(request));         return sellerInfoListOps.orElse(Collections.emptyList());     }     ... }  @Repository public class SellerRepository {     ...     //根据条件分页查询出卖家列表     public Optional<List<SellerInfoResponse>> querySellerInfo(SellerInfoRequest request) {         LambdaQueryWrapper<SellerInfoDO> queryWrapper = Wrappers.lambdaQuery();         //类型         queryWrapper.eq(Objects.nonNull(request.getSellerType()), SellerInfoDO::getSellerType, request.getSellerType());         //卖家位置(层级)         queryWrapper.eq(Objects.nonNull(request.getSellerPosition()), SellerInfoDO::getSellerPosition, request.getSellerPosition());         //状态         queryWrapper.eq(Objects.nonNull(request.getSellerStatus()), SellerInfoDO::getSellerStatus, request.getSellerStatus());         //卖家ID         queryWrapper.eq(Objects.nonNull(request.getSellerId()), SellerInfoDO::getSellerId, request.getSellerId());         //卖家编码         queryWrapper.eq(StringUtils.isNotEmpty(request.getSellerCode()), SellerInfoDO::getSellerCode, request.getSellerCode());         //卖家名称         queryWrapper.like(StringUtils.isNotEmpty(request.getSellerName()), SellerInfoDO::getSellerName, request.getSellerName());         //父卖家ID         queryWrapper.eq(Objects.nonNull(request.getParentId()), SellerInfoDO::getParentId, request.getParentId());         //卖家ID集合         queryWrapper.in(CollectionUtils.isNotEmpty(request.getSellerIdList()), SellerInfoDO::getSellerId, request.getSellerIdList());            Page<SellerInfoDO> page = new Page<>(request.getPageNo(), request.getPageSize());         Page<SellerInfoDO> pageResult = sellerInfoMapper.selectPage(page, queryWrapper);         if (Objects.isNull(pageResult)) {             return Optional.of(Collections.emptyList());         }         return Optional.of(sellerInfoConverter.listEntityToResponse(pageResult.getRecords()));     }     ... }  @Service("sellerInfoCache") public class SellerInfoCache {     @Resource     private SellerRepository sellerRepository;          @Resource     private RedisCache redisCache;          @Resource     private RedisLock redisLock;     ...          //批量获取缓存数据     //@param keyList             关键字列表     //@param clazz               需要将缓存JSON转换的对象     //@param getRedisKeyFunction 获取redis key的方法     //@param request           查询数据源对象的参数     //@param getDbFuction        获取数据源对象的方法     public <T> Optional<List<T>> listRedisStringDataByCache(Collection<Long> keyList, Class<T> clazz,             Function<Long, String> getRedisKeyFunction, SellerInfoRequest request,             Function<SellerInfoRequest, Optional<List<T>>> getDbFuction) {         try {             List<T> list = Lists.newArrayList();             List<Long> pendingKeyList = keyList.stream().distinct().collect(toList());             List<String> redisKeyList = pendingKeyList.stream().map(getRedisKeyFunction).distinct().collect(toList());             List<String> cacheList = redisCache.mget(redisKeyList);             for (int i = 0; i < cacheList.size(); i++) {                 String cache = cacheList.get(i);                 //过滤无效缓存                 if (EMPTY_OBJECT_STRING.equals(cache)) {                     continue;                 }                 if (StringUtils.isNotBlank(cache)) {                     T t = JSON.parseObject(cache, clazz);                     list.add(t);                     continue;                 }                 //缓存没有则读库                 Optional<List<T>> optional = getRedisStringDataByDb(pendingKeyList.get(i), request, getRedisKeyFunction, getDbFuction);                 if (optional.isPresent()) {                     list.addAll(optional.get());                 }             }             return CollectionUtils.isEmpty(list) ? Optional.empty() : Optional.of(list);         } catch (Exception e) {             log.error("批量获取缓存数据异常 keyList={},clazz={}", keyList, clazz, e);             throw e;         }     }          //读取数据库表数据赋值到Redis     public <T> Optional<List<T>> getRedisStringDataByDb(Long key, SellerInfoRequest request,             Function<Long, String> getRedisKeyFunction, Function<SellerInfoRequest, Optional<List<T>>> getDbFuction) {         if (Objects.isNull(key) || Objects.isNull(request) || Objects.isNull(getDbFuction)) {             return Optional.empty();         }         try {             if (!redisLock.lock(String.valueOf(key))) {                 return Optional.empty();             }             String redisKey = getRedisKeyFunction.apply(key);             //从DB中获取数据             Optional<List<T>> optional = getDbFuction.apply(request);             if (!optional.isPresent()) {                 //把空对象暂存到Redis                 redisCache.setex(redisKey, EMPTY_OBJECT_STRING, RedisKeyUtils.redisKeyRandomTime(INT_EXPIRED_ONE_DAY, TimeUnit.HOURS, NUMBER_24));                 log.warn("发生缓存穿透 redisKey={}", redisKey);                 return optional;             }             //把表数据对象存到Redis             redisCache.setex(redisKey, JSON.toJSONString(optional.get()), RedisKeyUtils.redisKeyRandomTime(INT_EXPIRED_SEVEN_DAYS));             log.info("表数据对象存到redis redisKey={}, data={}", redisKey, optional.get());             return optional;         } finally {             redisLock.unlock(String.valueOf(key));         }     }     ... }

六.查询卖家RPC接口

提供给其他服务调⽤的RPC接⼝,仅允许通过卖家ID集合或卖家类型查询。

 

情况一:如果仅传⼊卖家ID集合,则根据ID查询

情况二:如果同时传⼊卖家ID集合与卖家类型,则根据卖家类型过滤查询到的类型不⼀致的卖家数据

情况三:如果仅传⼊卖家类型,则先查出2⻚卖家ID集合数据,再根据查出的卖家ID查询卖家集合

 

Redis缓存结构中1⻚存放100条卖家ID,这里也使用了简化版的缓存DB读写逻辑。

@Service public class SellerInfoServiceImpl implements SellerInfoService {     @Autowired     private SellerInfoCache sellerInfoCache;     ...          //不同系统间调用RPC接口,查询卖家     //卖家系统提供给外部系统调用的卖家查询接口,只允许通过sellerIdList或者sellerType两个参数进行查询     @Override     public List<SellerInfoResponse> querySellerInfoForRPC(SellerInfoRequest request) {         //参数校验,RPC接口根据sellerIdList和sellerType查询         checkQuerySellerInfoRequestByRPC(request);         //如果未传入sellerIdList         if (CollectionUtils.isEmpty(request.getSellerIdList())) {             //根据sellerType获取该类型下的sellerId集合             Optional<List<Long>> sellerIdListOps = getSellerIdListBySellerType(request);             //如果类型下没有sellerId数据,直接返回空卖家集合             if (!sellerIdListOps.isPresent()) {                 return Collections.emptyList();             }             //将根据sellerType查询到的sellerIdList数据set到request中             request.setSellerIdList(sellerIdListOps.get());         }         //根据sellerIdList从缓存或者数据库中查询卖家信息         Optional<List<SellerInfoResponse>> sellerInfoListOps = sellerInfoCache.listRedisStringDataByCache(request.getSellerIdList(),             SellerInfoResponse.class,             sellerId -> SellerRedisKeyConstants.SELLER_INFO_LIST + sellerId,             //根据sellerId从DB中获取SellerInfo数据             sellerId -> sellerRepository.querySellerInfoBySellerId(sellerId));         if (!sellerInfoListOps.isPresent()) {             return Collections.emptyList();         }         //过滤类型不一致的卖家信息         return filterAccordantSellerInfo(sellerInfoListOps.get(), request);     }     ... }  @Repository public class SellerRepository {     ...     //根据sellerId查询SellerInfo数据     public Optional<SellerInfoResponse> querySellerInfoBySellerId(Long sellerId) {         LambdaQueryWrapper<SellerInfoDO> queryWrapper = Wrappers.lambdaQuery();         queryWrapper.eq(Objects.nonNull(sellerId), SellerInfoDO::getSellerId, sellerId);         return Optional.ofNullable(sellerInfoConverter.entityToResponse(sellerInfoMapper.selectOne(queryWrapper)));     } }  @Service("sellerInfoCache") public class SellerInfoCache {     @Resource     private SellerRepository sellerRepository;          @Resource     private RedisCache redisCache;          @Resource     private RedisLock redisLock;     ...          //批量获取缓存数据     //@param keyList             关键字列表     //@param clazz               需要将缓存JSON转换的对象     //@param getRedisKeyFunction 获取redis key的方法     //@param getDbFuction        获取数据源对象的方法     public <T> Optional<List<T>> listRedisStringDataByCache(Collection<Long> keyList, Class<T> clazz,             Function<Long, String> getRedisKeyFunction, Function<Long, Optional<T>> getDbFuction) {         try {             List<T> list = Lists.newArrayList();             List<Long> pendingKeyList = keyList.stream().distinct().collect(toList());             List<String> redisKeyList = pendingKeyList.stream().map(getRedisKeyFunction).distinct().collect(toList());             List<String> cacheList = redisCache.mget(redisKeyList);             if (CollectionUtils.isEmpty(cacheList)) {                 for (Long pendingKey : pendingKeyList) {                     //缓存没有则读库                     Optional<T> optional = getRedisStringDataByDb(pendingKey, getRedisKeyFunction, getDbFuction);                     if (optional.isPresent()) {                         list.add(optional.get());                     }                 }                 return CollectionUtils.isEmpty(list) ? Optional.empty() : Optional.of(list);             }             for (int i = 0; i < cacheList.size(); i++) {                 String cache = cacheList.get(i);                 //过滤无效缓存                 if (EMPTY_OBJECT_STRING.equals(cache)) {                     continue;                 }                 if (StringUtils.isNotBlank(cache)) {                     T t = JSON.parseObject(cache, clazz);                     list.add(t);                     continue;                 }                 //缓存没有则读库                 Optional<T> optional = getRedisStringDataByDb(pendingKeyList.get(i), getRedisKeyFunction, getDbFuction);                 if (optional.isPresent()) {                     list.add(optional.get());                 }             }             return CollectionUtils.isEmpty(list) ? Optional.empty() : Optional.of(list);         } catch (Exception e) {             log.error("批量获取缓存数据异常 keyList={},clazz={}", keyList, clazz, e);             throw e;         }     }          //读取数据库表数据赋值到redis     public <T> Optional<T> getRedisStringDataByDb(Long key, Function<Long, String> getRedisKeyFunction, Function<Long, Optional<T>> getDbFuction) {         if (Objects.isNull(key) || Objects.isNull(getDbFuction)) {             return Optional.empty();         }         try {             if (!redisLock.lock(String.valueOf(key))) {                 return Optional.empty();             }             String redisKey = getRedisKeyFunction.apply(key);             Optional<T> optional = getDbFuction.apply(key);             if (!optional.isPresent()) {                 //把空对象暂存到Redis                 redisCache.setex(redisKey, EMPTY_OBJECT_STRING, RedisKeyUtils.redisKeyRandomTime(INT_EXPIRED_ONE_DAY, TimeUnit.HOURS, NUMBER_24));                 log.warn("发生缓存穿透 redisKey={}", redisKey);                 return optional;             }             //把表数据对象存到Redis             redisCache.setex(redisKey, JSON.toJSONString(optional.get()), RedisKeyUtils.redisKeyRandomTime(INT_EXPIRED_SEVEN_DAYS));             log.info("表数据对象存到redis redisKey={}, data={}", redisKey, optional.get());             return optional;         } finally {             redisLock.unlock(String.valueOf(key));         }     }     ... }

(2)卖家组接口

一.新增卖家组接口

二.更新卖家组接口

三.查询卖家组接口

四.删除卖家组接口

 

一.新增卖家组接口

新增⼀个卖家组,⼀个卖家组原则上不允许圈定不同区域的卖家,卖家组只限定其下的卖家类型要与卖家组保持⼀致。

@Service public class SellerGroupServiceImpl implements SellerGroupService {     //卖家组,4位序列号     private static final int GROUP_WIDTH = 4;          @Autowired     private SellerRepository sellerRepository;     ...          //新增卖家组     @Override     @Transactional(rollbackFor = Exception.class)     public SellerGroupResultDTO saveSellerGroupInfo(SellerGroupRequest request) {         //1.参数检查         checkSaveSellerGroupRequest(request);         //2.sellerGroupId生成         Long sellerGroupId = sellerRepository.generateSellerId(SkuSellerRelationConstants.SELLER_GROUP_PREFIX_NO, GROUP_WIDTH);         request.setSellerGroupId(sellerGroupId);         //3.新增卖家组数据         sellerRepository.saveSellerGroup(request);         return new SellerGroupResultDTO(request.getSellerGroupId(), Boolean.TRUE);     }     ... }  //卖家组入参 @Data @Builder @AllArgsConstructor @NoArgsConstructor public class SellerGroupRequest extends PageRequest implements Serializable {     //卖家组ID     private Long sellerGroupId;     //卖家组名称     private String sellerGroupName;     //卖家组类型:1-自营,2-POP     private Integer sellerGroupType;     //卖家组ID集合(限制100个)     private List<Long> sellerGroupIdList;     //卖家组状态:1-有效,0-无效     private Integer sellerGroupStatus;     //是否需要卖家信息     private Boolean needSellerInfo = false; }  @Repository public class SellerRepository {     ...     //生成卖家或卖家组ID,即sellerId、sellerGroupId生成     //sellerId格式:20开头,6位随机数     //sellerGroupId格式:30开头,4位随机数     public Long generateSellerId(String prefix, Integer width) {         return Long.parseLong(generateSellerNo(prefix, width));     }          //自营卖家叶子结点sellerCode生成     //格式:父卖家(区县)的首拼-4位随机数,如:西湖区 -> XH-1001     //@param prefix 前缀     //@param width  位数     public String generateSellerNo(String prefix, Integer width) {         SellerAutoNoDO sellerAutoNoDO = new SellerAutoNoDO();         sellerAutoNoMapper.insert(sellerAutoNoDO);         Long autoNo = sellerAutoNoDO.getId();         if (Objects.isNull(autoNo)) {             throw new BaseBizException(CommonErrorCodeEnum.SQL_ERROR);         }         return prefix + IDUtils.genId(autoNo, width);     }      //新增卖家组     public void saveSellerGroup(SellerGroupRequest request) {         //是否存在该记录         LambdaQueryWrapper<SellerGroupDO> queryWrapper = Wrappers.lambdaQuery();         queryWrapper.eq(SellerGroupDO::getSellerGroupId, request.getSellerGroupId());         int count = sellerGroupMapper.selectCount(queryWrapper);         if (count > 0) {             throw new BaseBizException(ProductErrorCodeEnum.PARAM_CHECK_ERROR, ProductErrorCodeEnum.PARAM_CHECK_ERROR.getErrorCode());         }            //DO对象初始化         SellerGroupDO sellerGroup = sellerGroupConverter.requestToEntity(request);         sellerGroup.initCommon();         //新卖家落库         count = sellerGroupMapper.insert(sellerGroup);         if (count <= 0) {             throw new BaseBizException(CommonErrorCodeEnum.SQL_ERROR);         }     }     ... }

二.更新卖家组接口

只允许更新卖家组的名称和状态,不允许修改卖家组的类型。

@Service public class SellerGroupServiceImpl implements SellerGroupService {     @Autowired     private SellerRepository sellerRepository;     ...          //更新卖家组信息     @Override     @Transactional(rollbackFor = Exception.class)     public SellerGroupResultDTO updateSellerGroupInfo(SellerGroupRequest request) {         //1.参数检查         checkUpdateSellerGroupRequest(request);         //2.修改卖家组数据         sellerRepository.updateSellerGroup(request);         return new SellerGroupResultDTO(request.getSellerGroupId(), Boolean.TRUE);     }     ... }  @Repository public class SellerRepository {     ...     //修改卖家组数据,卖家组类型禁止修改     public void updateSellerGroup(SellerGroupRequest request) {         LambdaUpdateWrapper<SellerGroupDO> updateWrapper = Wrappers.lambdaUpdate();         updateWrapper.set(StringUtils.isNotEmpty(request.getSellerGroupName()), SellerGroupDO::getSellerGroupName, request.getSellerGroupName());         updateWrapper.set(Objects.nonNull(request.getSellerGroupStatus()), SellerGroupDO::getSellerGroupStatus, request.getSellerGroupStatus());         updateWrapper.eq(SellerGroupDO::getSellerGroupId, request.getSellerGroupId());         int count = sellerGroupMapper.update(null, updateWrapper);         if (count <= 0) {             throw new BaseBizException(CommonErrorCodeEnum.SQL_ERROR);         }     }     ... }

三.查询卖家组接口

批量查询出卖家组,允许携带卖家组下的卖家信息。

@Service public class SellerGroupServiceImpl implements SellerGroupService {     @Autowired     private SellerRepository sellerRepository;     ...          //查询卖家组     @Override     public PageResult<SellerGroupResponse> querySellerGroupInfo(SellerGroupRequest request) {         //1.校验参数完整性         checkQuerySellerGroupRequest(request);         //2.根据条件分页查询出卖家组         PageResult<SellerGroupResponse> sellerGroupResponsePage = sellerRepository.querySellerGroup(request);         //3.判断是否需要获取卖家组对应的卖家信息         if (!request.getNeedSellerInfo()) {             return sellerGroupResponsePage;         }         //4.返回带有卖家数据的响应结果         return sellerRepository.querySellerInfoByGroupList(sellerGroupResponsePage);     }     ... }  @Repository public class SellerRepository {     ...     //查询卖家组     public PageResult<SellerGroupResponse> querySellerGroup(SellerGroupRequest request) {         LambdaQueryWrapper<SellerGroupDO> queryWrapper = Wrappers.lambdaQuery();         //卖家组ID         queryWrapper.eq(Objects.nonNull(request.getSellerGroupId()), SellerGroupDO::getSellerGroupId, request.getSellerGroupId());         //卖家组名称         queryWrapper.like(StringUtils.isNotEmpty(request.getSellerGroupName()), SellerGroupDO::getSellerGroupName, request.getSellerGroupName());         //卖家组状态         queryWrapper.eq(Objects.nonNull(request.getSellerGroupStatus()), SellerGroupDO::getSellerGroupStatus, request.getSellerGroupStatus());         //卖家组ID集合         queryWrapper.in(CollectionUtils.isNotEmpty(request.getSellerGroupIdList()), SellerGroupDO::getSellerGroupId, request.getSellerGroupIdList());         queryWrapper.eq(SellerGroupDO::getDelFlag, YesOrNoEnum.YES.getCode());         Page<SellerGroupDO> page = new Page<>(request.getPageNo(), request.getPageSize());         Page<SellerGroupDO> pageResult = sellerGroupMapper.selectPage(page, queryWrapper);         if (Objects.isNull(pageResult)) {             return new PageResult<>();         }            List<SellerGroupDO> groupList = pageResult.getRecords();         List<SellerGroupResponse> sellerGroupResponseList = sellerGroupConverter.listEntityToResponse(groupList);         return new PageResult<>(sellerGroupResponseList);     }          //根据group信息查询对应的卖家信息     public PageResult<SellerGroupResponse> querySellerInfoByGroupList(PageResult<SellerGroupResponse> page) {         //提取groupIdList,用于查询对应的卖家数据信息         List<Long> groupIdList = page.getContent().stream().map(SellerGroupResponse::getSellerGroupId).collect(Collectors.toList());         //查询出卖家数据与卖家组id映射关系         Map<Long, List<SellerInfoDTO>> sellerInfoMap = querySellerInfoBySellerIdList(groupIdList);            //组装卖家数据到响应数据体中         List<SellerGroupResponse> sellerGroupResponseList = page.getContent().stream()             .peek(sellerGroupResponse -> sellerGroupResponse.setSellerInfoDTOList(sellerInfoMap.get(sellerGroupResponse.getSellerGroupId())))             .collect(Collectors.toList());         return new PageResult<>(sellerGroupResponseList);     }          //根据卖家组ID集合查询出对应的卖家集合     private Map<Long, List<SellerInfoDTO>> querySellerInfoBySellerIdList(List<Long> groupIdList) {         //查询卖家与卖家组关系集合         List<SellerGroupRelationDTO> relationList = querySellerGroupRelationInfo(groupIdList);         //卖家ID和卖家组ID的映射关系         Map<Long, Long> sellerGroupIdRelationMap = new HashMap<>();         //卖家ID集合         List<Long> sellerIdList = new ArrayList<>();         for (SellerGroupRelationDTO relation : relationList) {             sellerGroupIdRelationMap.put(relation.getSellerId(), relation.getSellerGroupId());             sellerIdList.add(relation.getSellerId());         }         SellerInfoRequest request = new SellerInfoRequest();         request.setSellerIdList(sellerIdList);         //根据条件分页查询出卖家列表         Optional<List<SellerInfoResponse>> sellerInfoResponseListOps = querySellerInfo(request);         if (!sellerInfoResponseListOps.isPresent()) {             return Collections.emptyMap();         }            List<SellerInfoResponse> sellerInfoResponseList = sellerInfoResponseListOps.get();         Map<Long, List<SellerInfoDTO>> result = new HashMap<>();         for (SellerInfoResponse sellerInfoResponse : sellerInfoResponseList) {             Long groupId = sellerGroupIdRelationMap.get(sellerInfoResponse.getSellerId());             List<SellerInfoDTO> sellerInfoList = result.get(groupId);             if (CollectionUtils.isEmpty(sellerInfoList)) {                 sellerInfoList = new ArrayList<>();             }             sellerInfoList.add(sellerInfoConverter.responseToDTO(sellerInfoResponse));             result.put(groupId, sellerInfoList);         }         return result;     }          //查询卖家与卖家关系集合     private List<SellerGroupRelationDTO> querySellerGroupRelationInfo(List<Long> groupIdList) {         List<SellerGroupRelationDO> relationList = new ArrayList<>();         //一次最大查询200个数据,多个分页查询,这里做数据切割         List<List<Long>> splitList = DataCuttingUtil.dataCuttingString(groupIdList, ProductConstants.QUERY_ITEM_MAX_COUNT);         for (List<Long> groupIds : splitList) {             LambdaQueryWrapper<SellerGroupRelationDO> queryWrapper = Wrappers.lambdaQuery();             queryWrapper.in(Objects.nonNull(groupIds), SellerGroupRelationDO::getSellerGroupId, groupIds);             List<SellerGroupRelationDO> relations = sellerGroupRelationMapper.selectList(queryWrapper);             if (!CollectionUtils.isEmpty(relations)) {                 relationList.addAll(relations);             }         }         return sellerGroupRelationConverter.listEntityToDTO(relationList);     }          //根据条件分页查询出卖家列表     public Optional<List<SellerInfoResponse>> querySellerInfo(SellerInfoRequest request) {         LambdaQueryWrapper<SellerInfoDO> queryWrapper = Wrappers.lambdaQuery();         //类型         queryWrapper.eq(Objects.nonNull(request.getSellerType()), SellerInfoDO::getSellerType, request.getSellerType());         //卖家位置(层级)         queryWrapper.eq(Objects.nonNull(request.getSellerPosition()), SellerInfoDO::getSellerPosition, request.getSellerPosition());         //状态         queryWrapper.eq(Objects.nonNull(request.getSellerStatus()), SellerInfoDO::getSellerStatus, request.getSellerStatus());         //卖家ID         queryWrapper.eq(Objects.nonNull(request.getSellerId()), SellerInfoDO::getSellerId, request.getSellerId());         //卖家编码         queryWrapper.eq(StringUtils.isNotEmpty(request.getSellerCode()), SellerInfoDO::getSellerCode, request.getSellerCode());         //卖家名称         queryWrapper.like(StringUtils.isNotEmpty(request.getSellerName()), SellerInfoDO::getSellerName, request.getSellerName());         //父卖家ID         queryWrapper.eq(Objects.nonNull(request.getParentId()), SellerInfoDO::getParentId, request.getParentId());         //卖家ID集合         queryWrapper.in(CollectionUtils.isNotEmpty(request.getSellerIdList()), SellerInfoDO::getSellerId, request.getSellerIdList());            Page<SellerInfoDO> page = new Page<>(request.getPageNo(), request.getPageSize());         Page<SellerInfoDO> pageResult = sellerInfoMapper.selectPage(page, queryWrapper);         if (Objects.isNull(pageResult)) {             return Optional.of(Collections.emptyList());         }         return Optional.of(sellerInfoConverter.listEntityToResponse(pageResult.getRecords()));     }     ... }

四.删除卖家组接口

根据传⼊的sellerGroupIdList(卖家组ID集合)批量删除卖家组。

@Service public class SellerGroupServiceImpl implements SellerGroupService {     @Autowired     private SellerRepository sellerRepository;     ...          //删除卖家组     @Override     @Transactional(rollbackFor = Exception.class)     public SellerGroupResultDTO deleteSellerGroupInfo(List<Long> sellerGroupIdList) {         sellerRepository.deleteSellerGroup(sellerGroupIdList);         return new SellerGroupResultDTO(Boolean.TRUE);     }     ... }  @Repository public class SellerRepository {     ...     //删除卖家组     public void deleteSellerGroup(List<Long> sellerGroupIdList) {         LambdaUpdateWrapper<SellerGroupDO> updateWrapper = Wrappers.lambdaUpdate();         //条件         updateWrapper.in(SellerGroupDO::getSellerGroupId, sellerGroupIdList);         //删除标志         updateWrapper.set(SellerGroupDO::getDelFlag, YesOrNoEnum.NO.getCode());         int count = sellerGroupMapper.update(null, updateWrapper);         if (count <= 0) {             throw new BaseBizException(CommonErrorCodeEnum.SQL_ERROR);         }     }     ... }

(3)卖家与卖家组关系

一.新增卖家与卖家组关系

二.查询卖家与卖家组关系

三.删除卖家与卖家组关系

 

一.新增卖家与卖家组关系

新增卖家与卖家关系时,需要保证卖家与卖家组的类型是⼀样的,否则⽆法添加。

@Service public class SellerGroupRelationServiceImpl implements SellerGroupRelationService {     @Autowired     private SellerRepository sellerRepository;     ...          //新增卖家组与卖家关系     @Override     public SellerGroupRelationResultDTO saveSellerGroupRelationInfo(SellerGroupRelationRequest request) {         //参数检查         checkSaveSellerGroupRelationRequest(request);         //卖家ID类型是否有和卖家组的类型不一致的         checkAndGetSellerTypeConsistency(request);         //过滤掉已经添加过相同关系的卖家与卖家组关系         request = filterIfExist(request);         //批量插入         log.info("request:{}", JSON.toJSONString(request));         sellerRepository.saveSellerGroupRelationInfo(request);         SellerGroupRelationResultDTO result = new SellerGroupRelationResultDTO(request.getSellerGroupId(), request.getSellerIdList(), Boolean.TRUE);         return result;     }      private SellerGroupRelationRequest filterIfExist(SellerGroupRelationRequest request) {         SellerGroupRelationRequest relationRequest = SellerGroupRelationRequest.builder().sellerIdList(request.getSellerIdList()).sellerGroupId(request.getSellerGroupId()).build();         List<SellerGroupRelationDTO> sellerGroupRelationDTOS = sellerRepository.querySellerGroupRelationInfo(relationRequest);         List<Long> existSellerIds = sellerGroupRelationDTOS.stream().map(relation -> relation.getSellerId()).collect(Collectors.toList());         List<Long> filteredSellerIds = request.getSellerIdList().stream().filter(sellerId -> !existSellerIds.contains(sellerId)).collect(Collectors.toList());         log.info("filteredSellerIds:{}", JSON.toJSONString(filteredSellerIds));         return SellerGroupRelationRequest.builder().sellerGroupId(request.getSellerGroupId()).sellerIdList(filteredSellerIds).build();     }     ... }  //卖家与卖家组关系入参 @Data @Builder @AllArgsConstructor @NoArgsConstructor public class SellerGroupRelationRequest extends PageRequest implements Serializable {     //卖家组ID     @NotNull(message = "sellerGroupId不能为空")     private Long sellerGroupId;          //卖家id列表     @Size(min = 1, max = 100, message = "sellerIdList不能为空,且最多同时操作200个")     private List<Long> sellerIdList;         //卖家组ID集合     private List<Long> sellerGroupIdList; }  @Repository public class SellerRepository {     ...     //根据卖家组id列表,卖家组类型查询卖家与卖家关系     public List<SellerGroupRelationDTO> querySellerGroupRelationInfo(SellerGroupRelationRequest request) {         LambdaQueryWrapper<SellerGroupRelationDO> queryWrapper = Wrappers.lambdaQuery();         queryWrapper.eq(Objects.nonNull(request.getSellerGroupId()), SellerGroupRelationDO::getSellerGroupId, request.getSellerGroupId());         //分页查询存放数据的总集合         List<SellerGroupRelationDO> results = new ArrayList<>();         Page<SellerGroupRelationDO> page = new Page<>(request.getPageNo(), request.getPageSize());         //查询分页数据         Page<SellerGroupRelationDO> pageResult = sellerGroupRelationMapper.selectPage(page, queryWrapper);         results.addAll(pageResult.getRecords());         return sellerGroupRelationConverter.convertAccountsTODTO(results);     }          //批量保存卖家与卖家组信息     public void saveSellerGroupRelationInfo(SellerGroupRelationRequest request) {         //经过前置sellerId过滤,sellerId为空说明本批次的relation关系已经保存过         //直接返回即可         if (CollectionUtils.isEmpty(request.getSellerIdList())) {             return;         }         List<SellerGroupRelationDO> relationList = request.getSellerIdList().stream().map(sellerId -> {             SellerGroupRelationDO relation = new SellerGroupRelationDO();             relation.setSellerGroupId(request.getSellerGroupId());             relation.setSellerId(sellerId);             relation.initCommon();             return relation;         }).collect(Collectors.toList());            Integer count = sellerGroupRelationMapper.insertBatch(relationList);         if (Objects.isNull(count) || count <= 0) {             throw new BaseBizException(CommonErrorCodeEnum.SQL_ERROR);         }     }     ... }

二.查询卖家与卖家组关系

根据传⼊的sellerGroupId(卖家组ID)查询卖家与卖家组关系。

@Service public class SellerGroupRelationServiceImpl implements SellerGroupRelationService {     @Autowired     private SellerRepository sellerRepository;     ...          //查询卖家组与卖家关系信息     @Override     public List<SellerGroupRelationDTO> querySellerGroupRelationInfo(SellerGroupRelationRequest request) {         return sellerRepository.querySellerGroupRelationInfo(request);     }     ... }  @Repository public class SellerRepository {     ...     //根据卖家组id列表,卖家组类型查询卖家与卖家关系     public List<SellerGroupRelationDTO> querySellerGroupRelationInfo(SellerGroupRelationRequest request) {         LambdaQueryWrapper<SellerGroupRelationDO> queryWrapper = Wrappers.lambdaQuery();         queryWrapper.eq(Objects.nonNull(request.getSellerGroupId()), SellerGroupRelationDO::getSellerGroupId, request.getSellerGroupId());         //分页查询存放数据的总集合         List<SellerGroupRelationDO> results = new ArrayList<>();         Page<SellerGroupRelationDO> page = new Page<>(request.getPageNo(), request.getPageSize());         //查询分页数据         Page<SellerGroupRelationDO> pageResult = sellerGroupRelationMapper.selectPage(page, queryWrapper);         results.addAll(pageResult.getRecords());         return sellerGroupRelationConverter.convertAccountsTODTO(results);     }     ... }

三.删除卖家与卖家组关系

根据sellerGroupId(卖家组ID)和sellerIdList(卖家ID)删除卖家与卖家组关系。

@Service public class SellerGroupRelationServiceImpl implements SellerGroupRelationService {     @Autowired     private SellerRepository sellerRepository;     ...          //根据卖家id和卖家组id删除卖家与卖家组关系     @Override     @Transactional(rollbackFor = Exception.class)     public Boolean deleteBySellerId(SellerGroupRelationRequest request) {         //校验参数         checkSaveSellerGroupRelationRequest(request);         return sellerRepository.deleteRelationBySellerId(request.getSellerIdList(), request.getSellerGroupId());     }     ... }  @Repository public class SellerRepository {     ...     //逻辑删除卖家与卖家组关系     public Boolean deleteRelationBySellerId(List<Long> sellerIds, Long sellerGroupId) {         int count = sellerGroupRelationMapper.deleteBySellerId(sellerIds, sellerGroupId, YesOrNoEnum.NO.getCode());         if (count <= 0) {             throw new ProductBizException(CommonErrorCodeEnum.SQL_ERROR);         }         return true;     }     ... }

(4)卖家账户

一.新增卖家账户

二.更新支付渠道

三.查询卖家的所有账户信息

四.删除一个卖家账户信息

 

一.新增卖家账户

新增卖家与卖家关系时,需保证卖家与卖家组类型是⼀样,否则⽆法添加。

@Service public class SellerAccountServiceImpl implements SellerAccountService {     @Autowired     private SellerRepository sellerRepository;     ...          //保存一个用户账号信息     @Override     @Transactional(rollbackFor = Exception.class)     public Boolean saveSellerAccountInfo(SellerAccountRequest request) {         //校验参数是否为null         checkAccountParam(request);         return sellerRepository.saveSellerAccountInfo(request);     }     ... }  @Repository public class SellerRepository {     ...     //保存一个卖家账户信息     public Boolean saveSellerAccountInfo(SellerAccountRequest request) {         SellerAccountDO accountDO = sellerAccountConverter.convertToDO(request);         //初始化默认参数         accountDO.initCommon();         Integer count = sellerAccountMapper.insert(accountDO);         if (count <= 0) {             throw new ProductBizException(CommonErrorCodeEnum.SQL_ERROR);         }         return true;     }     ... }

二.更新支付渠道

修改某个卖家账户下的⽀付渠道。

@Service public class SellerAccountServiceImpl implements SellerAccountService {     @Autowired     private SellerRepository sellerRepository;     ...          //更新支付渠道信息     @Override     @Transactional(rollbackFor = Exception.class)     public Boolean updateSellerAccountInfo(SellerAccountRequest request) {         //校验参数是否为null         checkAccountParam(request);         return sellerRepository.updateSellerAccountInfo(request);     }         ... }  @Repository public class SellerRepository {     ...     //更新卖家账户的支付渠道信息     public Boolean updateSellerAccountInfo(SellerAccountRequest request) {         SellerAccountDO accountDO = sellerAccountConverter.convertToDO(request);         //根据卖家id查询账户信息         LambdaQueryWrapper<SellerAccountDO> queryWrapper = Wrappers.lambdaQuery();         queryWrapper.eq(SellerAccountDO::getSellerId, accountDO.getSellerId());         queryWrapper.eq(SellerAccountDO::getAccountNo, accountDO.getAccountNo());         queryWrapper.eq(SellerAccountDO::getDelFlag, YesOrNoEnum.YES.getCode());         SellerAccountDO sellerAccountDO = sellerAccountMapper.selectOne(queryWrapper);         if (Objects.isNull(sellerAccountDO)) {             throw new BaseBizException("该卖家的待更新账户信息不存在");         }         //设置更新字段,执行更新操作         sellerAccountDO.setPayChannel(accountDO.getPayChannel());         sellerAccountDO.setUpdateTime(new Date());         int count = sellerAccountMapper.updateById(sellerAccountDO);            if (count <= 0) {             throw new ProductBizException(CommonErrorCodeEnum.SQL_ERROR);         }         return true;     }     ... }

三.查询卖家的所有账户信息

根据sellerId(卖家ID)查询该卖家的所有⽀付渠道。

@Service public class SellerAccountServiceImpl implements SellerAccountService {     @Autowired     private SellerRepository sellerRepository;     ...          //根据卖家id查询卖家全部的账号信息     @Override     public List<SellerAccountDTO> queryAccountsBySellerId(Long sellerId) {         return sellerRepository.queryAccountsBySellerId(sellerId);     }     ... }  @Repository public class SellerRepository {     ...     //根据sellerId查询所有卖家相关的账号     public List<SellerAccountDTO> queryAccountsBySellerId(Long sellerId) {         LambdaQueryWrapper<SellerAccountDO> queryWrapper = Wrappers.lambdaQuery();         queryWrapper.eq(SellerAccountDO::getSellerId, sellerId);         queryWrapper.eq(SellerAccountDO::getDelFlag, YesOrNoEnum.YES.getCode());         List<SellerAccountDO> accountDOS = sellerAccountMapper.selectList(queryWrapper);            //如果查询结果为空集合或者null         if (CollectionUtils.isEmpty(accountDOS)) {             return new ArrayList<>();         }         return sellerAccountConverter.convertAccountsTODTO(accountDOS);     }     ... }

四.删除一个卖家账户信息

删除某个卖家账户。

@Service public class SellerAccountServiceImpl implements SellerAccountService {     @Autowired     private SellerRepository sellerRepository;     ...          //删除一个卖家账号     @Override     @Transactional(rollbackFor = Exception.class)     public Boolean deleteAccount(SellerAccountRequest request) {         //校验参数是否为null         checkAccountParam(request);         return sellerRepository.deleteAccount(request);     }     ... }  @Repository public class SellerRepository {     ...     //逻辑删除一个账号     public Boolean deleteAccount(SellerAccountRequest request) {         SellerAccountDO accountDO = sellerAccountConverter.convertToDO(request);         //根据卖家id查询账户信息         LambdaQueryWrapper<SellerAccountDO> queryWrapper = Wrappers.lambdaQuery();         queryWrapper.eq(SellerAccountDO::getSellerId, accountDO.getSellerId());         queryWrapper.eq(SellerAccountDO::getAccountNo, accountDO.getAccountNo());         queryWrapper.eq(SellerAccountDO::getDelFlag, YesOrNoEnum.YES.getCode());         SellerAccountDO sellerAccountDO = sellerAccountMapper.selectOne(queryWrapper);         if (Objects.isNull(sellerAccountDO)) {             throw new BaseBizException("待删除账户信息不存在");         }         //设置账号信息为失效         sellerAccountDO.setDelFlag(YesOrNoEnum.NO.getCode());         sellerAccountDO.setUpdateTime(new Date());         int count = sellerAccountMapper.updateById(sellerAccountDO);            if (count <= 0) {             throw new ProductBizException(CommonErrorCodeEnum.SQL_ERROR);         }         return true;     }     ... }

 

发表评论

评论已关闭。

相关文章

当前内容话题
  • 0