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

大纲

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

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

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

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

(1)卖家模型

(2)卖家组模型

(3)业务流程详解

(1)卖家模型

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

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

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

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

一.自营卖家树体系

二.POP卖家树体系

(2)卖家组模型

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

(3)业务流程详解

一.建立卖家体系

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

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

二.建立卖家组

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

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

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

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

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

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)缓存结构设计

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;
    }
    ...
}
相关推荐
东阳马生架构2 天前
商品中心—8.商品C端处理高并发的技术文档
商品系统
东阳马生架构7 天前
商品中心—1.B端建品和C端缓存的技术文档一
缓存·商品系统
东阳马生架构8 天前
商品中心—3.商品可采可补可售的技术文档上
商品系统
东阳马生架构9 天前
商品中心—4.商品属性与状态流转的技术文档
商品系统