package com.iotechn.unimall.admin.api.product; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.dobbinsoft.fw.core.exception.AdminServiceException; import com.dobbinsoft.fw.core.exception.CoreExceptionDefinition; import com.dobbinsoft.fw.core.exception.ServiceException; import com.dobbinsoft.fw.support.component.CacheComponent; import com.dobbinsoft.fw.support.model.Page; import com.dobbinsoft.fw.support.storage.StorageClient; import com.iotechn.unimall.biz.executor.GlobalExecutor; import com.iotechn.unimall.biz.service.category.CategoryBizService; import com.iotechn.unimall.biz.service.product.ProductBizService; import com.iotechn.unimall.data.constant.CacheConst; import com.iotechn.unimall.data.domain.*; import com.iotechn.unimall.data.dto.product.AdminSpuDTO; import com.iotechn.unimall.data.dto.product.SpuDTO; import com.iotechn.unimall.data.dto.product.SpuTreeNodeDTO; import com.iotechn.unimall.data.enums.*; import com.iotechn.unimall.data.exception.ExceptionDefinition; import com.iotechn.unimall.data.mapper.*; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionSynchronization; import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; import java.util.*; import java.util.stream.Collectors; /** * Created by rize on 2019/7/11. */ @Service public class AdminProductServiceImpl implements AdminProductService { @Autowired private CategoryMapper categoryMapper; @Autowired private FreightTemplateMapper freightTemplateMapper; @Autowired private AdvertMapper advertMapper; @Autowired private SpuMapper spuMapper; @Autowired private SkuMapper skuMapper; @Autowired private SpuAttributeMapper spuAttributeMapper; @Autowired private ImgMapper imgMapper; @Autowired private CartMapper cartMapper; @Autowired private SpuSpecificationMapper spuSpecificationMapper; @Autowired private CategoryBizService categoryBizService; @Autowired private CacheComponent cacheComponent; @Autowired private ProductBizService productBizService; // @Autowired(required = false) // private SearchEngine searchEngine; @Autowired private StorageClient storageClient; /** * 后台低频接口,无需缓存,用于选择商品,需要 * * @return * @throws ServiceException */ public List getSpuBigTree(Long adminId) throws ServiceException { List categoryDOS = categoryMapper.selectList(new QueryWrapper().orderByAsc("level")); List spuDOS = spuMapper.getSpuTitleAll(); HashMap> productMap = new HashMap<>(); for (int i = 0; i < spuDOS.size(); i++) { SpuDO spuDO = spuDOS.get(i); List orDefault = productMap.getOrDefault(spuDO.getCategoryId(), new ArrayList<>()); SpuTreeNodeDTO dtoOnK = new SpuTreeNodeDTO(); dtoOnK.setLabel(spuDO.getTitle()); dtoOnK.setValue("G_" + spuDO.getId()); dtoOnK.setId(spuDO.getId()); orDefault.add(dtoOnK); productMap.put(spuDO.getCategoryId(),orDefault); } List list = new ArrayList<>(); Integer recordLevelOne = 0; for (int i = 0; i < categoryDOS.size(); i++) { if (i != 0 && categoryDOS.get(i - 1).getLevel().equals(CategoryLevelType.ONE.getCode()) && categoryDOS.get(i).getLevel().equals(CategoryLevelType.TWO.getCode())) { recordLevelOne = i; } } for (int i = 0; i < recordLevelOne; i++) { CategoryDO categoryOnI = categoryDOS.get(i); //一级类目 SpuTreeNodeDTO dtoOnI = new SpuTreeNodeDTO(); dtoOnI.setLabel(categoryOnI.getTitle()); dtoOnI.setValue("C_" + categoryOnI.getId()); dtoOnI.setId(categoryOnI.getId()); dtoOnI.setChildren(new LinkedList<>()); for (int j = recordLevelOne; j < categoryDOS.size(); j++) { CategoryDO categoryOnJ = categoryDOS.get(j); //二级类目 if (!categoryOnJ.getParentId().equals(dtoOnI.getId())) { continue; } SpuTreeNodeDTO dtoOnJ = new SpuTreeNodeDTO(); dtoOnJ.setLabel(categoryOnJ.getTitle()); dtoOnJ.setValue("C_" + categoryOnJ.getId()); dtoOnJ.setId(categoryOnJ.getId()); List spuTreeNodeDTOS = productMap.get(categoryOnJ.getId()); if (spuTreeNodeDTOS == null) { dtoOnJ.setChildren(new ArrayList<>()); } else { dtoOnJ.setChildren(spuTreeNodeDTOS); } dtoOnI.getChildren().add(dtoOnJ); } list.add(dtoOnI); } return list; } @Override @Transactional(rollbackFor = Exception.class) public String create(AdminSpuDTO adminSpuDTO, Long adminId) throws ServiceException { return productBizService.create(adminSpuDTO); } @Override @Transactional(rollbackFor = Exception.class) public String edit(AdminSpuDTO spuDTO, Long adminId) throws ServiceException { return productBizService.edit(spuDTO); } @Override public Page list(Integer page, Integer limit, Long categoryId, String title, String barcode, Integer status, Long adminId) throws ServiceException { // 1. 构建搜索条件 QueryWrapper wrapper = new QueryWrapper().select(ProductBizService.SPU_EXCLUDE_DETAIL_FIELDS); // 1.1.标题搜索 if (!ObjectUtils.isEmpty(title)) { wrapper.like("title", title); } // 1.2.类目搜索 if (categoryId != null && categoryId != 0L) { List categorySelfAndChildren = categoryBizService.getCategorySelfAndChildren(categoryId); wrapper.in("category_id", categorySelfAndChildren); } // 1.3.状态搜索 if (status != null) { wrapper.eq("status", status.intValue() <= SpuStatusType.STOCK.getCode() ? SpuStatusType.STOCK.getCode() : SpuStatusType.SELLING.getCode()); } // 1.4.条码搜索 if (!ObjectUtils.isEmpty(barcode)) { List skuDOList = skuMapper.selectList(new QueryWrapper().eq("bar_code", barcode)); if (!CollectionUtils.isEmpty(skuDOList)) { SkuDO skuDO = skuDOList.get(0); wrapper.eq("id", skuDO.getSpuId()); } } Page domainPage = spuMapper.selectPage(Page.div(page, limit, SpuDO.class), wrapper); // 返回空页 if (CollectionUtils.isEmpty(domainPage.getItems())) { return domainPage.trans(item -> { SpuDTO spuDTO = new SpuDTO(); BeanUtils.copyProperties(item, spuDTO); return spuDTO; }); } // 2. 连接其他表 // 2.1. SKU表 List spuIds = domainPage.getItems().stream().map(SpuDO::getId).collect(Collectors.toList()); Map> skuMap = skuMapper.selectList(new QueryWrapper().in("spu_id", spuIds)).stream().collect(Collectors.groupingBy(SkuDO::getSpuId)); // 2.2. 类目表 Set categoryIds = domainPage.getItems().stream().map(SpuDO::getCategoryId).collect(Collectors.toSet()); Map categoryMap = categoryMapper.selectList( new QueryWrapper() .in("id", categoryIds) .or() .eq("level", CategoryLevelType.ONE.getCode())).stream().collect(Collectors.toMap(CategoryDO::getId, v -> v)); // 2.3. 运费模板 Map freightTemplateMap = freightTemplateMapper.selectList( new QueryWrapper() .select("id", "title")) .stream().collect(Collectors.toMap(FreightTemplateDO::getId, FreightTemplateDO::getTitle)); Page dtoPage = domainPage.trans(item -> { SpuDTO spuDTO = new SpuDTO(); BeanUtils.copyProperties(item, spuDTO); List skuList = skuMap.get(item.getId()); spuDTO.setSkuList(skuList); CategoryDO leaf = categoryMap.get(item.getCategoryId()); if (leaf.getParentId() != null && leaf.getParentId().intValue() != 0) { CategoryDO parentCategory = categoryMap.get(leaf.getParentId()); spuDTO.setCategoryFullTitle(parentCategory.getTitle() + "/" + leaf.getTitle()); } else { spuDTO.setCategoryFullTitle(leaf.getTitle()); } spuDTO.setFreightTemplateTitle(freightTemplateMap.get(item.getFreightTemplateId())); return spuDTO; }); return dtoPage; } @Override public AdminSpuDTO detail(Long spuId, Long adminId) throws ServiceException { SpuDO spuDO = spuMapper.selectById(spuId); AdminSpuDTO adminSpuDTO = new AdminSpuDTO(); BeanUtils.copyProperties(spuDO, adminSpuDTO); // 0. imgList List imgList = imgMapper.getImgs(BizType.GOODS.getCode(), spuId); adminSpuDTO.setImgList(imgList); // 1. skuList List skuList = skuMapper.selectList( new QueryWrapper() .eq("spu_id", spuId)); adminSpuDTO.setSkuList(skuList); // 2. Spu属性 List attributeList = spuAttributeMapper.selectList(new QueryWrapper().eq("spu_id", spuId)); adminSpuDTO.setAttributeList(attributeList); // 3. categoryIds List categoryIds = categoryBizService.getCategoryFamily(adminSpuDTO.getCategoryId()); adminSpuDTO.setCategoryIds(categoryIds); // 4. spu specificationList List specificationList = spuSpecificationMapper.selectList( new QueryWrapper() .eq("spu_id", spuId)); adminSpuDTO.setSpecificationList(specificationList); return adminSpuDTO; } @Override @Transactional(rollbackFor = Exception.class) public String delete(Long spuId, Long adminId) throws ServiceException { // 校验是否有关联此商品的广告 SpuDO spuDOBefore = spuMapper.selectById(spuId); // 校验是否有关联广告 this.checkUnionAdvert(Arrays.asList(spuId.toString())); // 校验是否有不可下架的活动 this.checkProductActivity(spuDOBefore); if (spuMapper.deleteById(spuId) <= 0) { throw new AdminServiceException(ExceptionDefinition.PRODUCT_NOT_EXIST); } // 将需要删除的图片路径取出来 List deleteImgList = imgMapper.getImgs(BizType.GOODS.getCode(), spuId); cartMapper.delete(new QueryWrapper().in("sku_id", skuMapper.getSkuIds(spuId))); skuMapper.delete(new QueryWrapper().eq("spu_id", spuId)); imgMapper.delete(new QueryWrapper().eq("biz_id", spuId).eq("biz_type", BizType.GOODS.getCode())); spuAttributeMapper.delete(new QueryWrapper().eq("spu_id", spuId)); TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { @Override public void afterCommit() { productBizService.deleteSpuCache(spuDOBefore); productBizService.deleteSearchEngine(spuDOBefore.getId()); GlobalExecutor.execute(new Runnable() { @Override public void run() { for (String img : deleteImgList) { storageClient.delete(img); } } }); } }); return "ok"; } private void checkUnionAdvert(List ids) throws ServiceException { List list1 = advertMapper.selectList( new QueryWrapper() .eq("union_type", AdvertUnionType.PRODUCT.getCode()) .in("union_value", ids).last("LIMIT 1")); if (!CollectionUtils.isEmpty(list1)) { throw new AdminServiceException(CoreExceptionDefinition.buildVariableException(ExceptionDefinition.PRODUCT_EXIST_ADVERT, list1.get(0).getTitle())); } } @Override @Transactional(rollbackFor = Exception.class) public String batchDelete(String idsJson, Long adminId) throws ServiceException { List ids = JSONObject.parseArray(idsJson, Long.class); // 校验是否有广告关联 List idStrList = ids.stream().map(item -> item.toString()).collect(Collectors.toList()); this.checkUnionAdvert(idStrList); List beforeSpuList = spuMapper.selectBatchIds(ids); // 校验商品是否有不可下架的活动 for (SpuDO spuDO : beforeSpuList) { this.checkProductActivity(spuDO); } if (CollectionUtils.isEmpty(ids)) { throw new AdminServiceException(ExceptionDefinition.PRODUCT_NOT_EXIST); } if (spuMapper.delete(new QueryWrapper().in("id", ids)) <= 0) { throw new AdminServiceException(ExceptionDefinition.PRODUCT_NOT_EXIST); } List skuIds = skuMapper.selectSkuIdsBySpuIds(ids); cartMapper.delete(new QueryWrapper().in("sku_id", skuIds)); skuMapper.delete(new QueryWrapper().in("spu_id", ids)); imgMapper.delete(new QueryWrapper().in("biz_id", ids).eq("biz_type", BizType.GOODS.getCode())); spuAttributeMapper.delete(new QueryWrapper().in("spu_id", ids)); TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { @Override public void afterCommit() { for (SpuDO spuDOBefore : beforeSpuList) { productBizService.deleteSpuCache(spuDOBefore); productBizService.deleteSearchEngine(spuDOBefore.getId()); } } }); return "ok"; } @Override public String rebuildProductCache(Long adminId) throws ServiceException { // 1.删除旧缓存 cacheComponent.delPrefixKey(CacheConst.PRT_CATEGORY_ORDER_ID_ZSET); cacheComponent.delPrefixKey(CacheConst.PRT_CATEGORY_ORDER_PRICE_ZSET); cacheComponent.delPrefixKey(CacheConst.PRT_CATEGORY_ORDER_SALES_ZSET); cacheComponent.delPrefixKey(CacheConst.PRT_SKU_STOCK_BUCKET); cacheComponent.delPrefixKey(CacheConst.PRT_SPU_DETAIL_HASH_BUCKET); cacheComponent.delPrefixKey(CacheConst.PRT_SPU_HASH_BUCKET); // 2.重建新缓存 List spuDOS = spuMapper.selectList(new QueryWrapper<>()); for (SpuDO spuDO : spuDOS) { // 2.1. 重建主表缓存 productBizService.createSpuCache(spuDO); // 2.2. 重建SKU缓存 List skuList = skuMapper.selectList(new QueryWrapper().eq("spu_id", spuDO.getId())); for (SkuDO skuDO : skuList) { cacheComponent.putHashRaw(CacheConst.PRT_SKU_STOCK_BUCKET, "K" + skuDO.getId(), skuDO.getStock() + ""); } } return null; } @Override @Transactional(rollbackFor = Exception.class) public AdminSpuDTO freezeOrActivation(Long spuId, Integer status, Long adminId) throws ServiceException { SpuDO spuDO = spuMapper.selectById(spuId); if (spuDO == null) { throw new AdminServiceException(ExceptionDefinition.PRODUCT_NOT_EXIST); } status = status <= SpuStatusType.STOCK.getCode() ? SpuStatusType.STOCK.getCode() : SpuStatusType.SELLING.getCode(); // 不可下架活动校验 if (status == SpuStatusType.STOCK.getCode()) { this.checkProductActivity(spuDO); } if (spuDO.getStatus().intValue() == status.intValue()) { throw new AdminServiceException(ExceptionDefinition.SYSTEM_BUSY); } spuDO.setStatus(status); spuDO.setGmtUpdate(new Date()); if (spuMapper.updateById(spuDO) <= 0) { throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION); } AdminSpuDTO spuDTO = new AdminSpuDTO(); BeanUtils.copyProperties(spuDO, spuDTO); List skuDOList = skuMapper.selectList(new QueryWrapper().eq("spu_id", spuDO.getId())); spuDTO.setSkuList(skuDOList); TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { @Override public void afterCommit() { if (spuDO.getStatus() > 0) { //1. 重建商品列表缓存 productBizService.createSpuCache(spuDO); //2. 重建Sku库存缓存 for (SkuDO skuDO : spuDTO.getSkuList()) { cacheComponent.putHashRaw(CacheConst.PRT_SKU_STOCK_BUCKET, "K" + skuDO.getId(), skuDO.getStock() + ""); } //3. 更新搜索引擎缓存 productBizService.transmissionSearchEngine(spuId); } else { // 删除商品列表缓存 productBizService.deleteSpuCache(spuDO); // 更新搜索引擎 productBizService.deleteSearchEngine(spuId); } } }); return spuDTO; } /** * 校验SPU是否有团购这样的,不允许删除或下架的活动 * * @param spuDO * @throws ServiceException */ private void checkProductActivity(SpuDO spuDO) throws ServiceException { if (spuDO.getActivityType() != null && spuDO.getActivityType() == SpuActivityType.GROUP_SHOP.getCode()) { throw new AdminServiceException(ExceptionDefinition.PRODUCT_UNION_ACTIVITY_CAN_NOT_BE_OFF_SHELF); } } }