统计数据归档查询、商品数据分类缓存、已知问题修复

This commit is contained in:
Tankaikai
2025-04-16 15:24:32 +08:00
parent ff8a1e5de2
commit 954f2329bc
29 changed files with 611 additions and 273 deletions

View File

@@ -14,29 +14,31 @@ import com.czg.exception.CzgException;
import com.czg.product.dto.ProdConsRelationDTO;
import com.czg.product.dto.ProdSkuDTO;
import com.czg.product.dto.ProductDTO;
import com.czg.product.dto.ShopProdCategoryDTO;
import com.czg.product.entity.*;
import com.czg.product.enums.*;
import com.czg.product.param.*;
import com.czg.product.service.ConsStockFlowService;
import com.czg.product.service.ProductService;
import com.czg.product.service.ProductStockFlowService;
import com.czg.product.service.SensitiveOperationService;
import com.czg.product.service.*;
import com.czg.product.vo.ProductStatisticsVo;
import com.czg.product.vo.ProductVO;
import com.czg.sa.StpKit;
import com.czg.service.RedisService;
import com.czg.service.product.mapper.*;
import com.czg.utils.PageUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.DbChain;
import com.mybatisflex.core.update.UpdateChain;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
@@ -73,6 +75,10 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
private final ConsStockFlowService consStockFlowService;
private final SensitiveOperationService sensitiveOperationService;
private final ProdGroupRelationMapper prodGroupRelationMapper;
private final RedisService redisService;
@Resource
@Lazy
private ShopProdCategoryService shopProdCategoryService;
private QueryWrapper buildQueryWrapper(ProductDTO param) {
QueryWrapper queryWrapper = PageUtil.buildSortQueryWrapper();
@@ -107,8 +113,11 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
queryWrapper.eq(Product::getIsSale, YesNoEnum.NO.value());
}
}
Long shopId = StpKit.USER.getShopId(0L);
queryWrapper.eq(Product::getShopId, shopId);
if (param.getShopId() == null) {
Long shopId = StpKit.USER.getShopId(0L);
param.setShopId(shopId);
}
queryWrapper.eq(Product::getShopId, param.getShopId());
queryWrapper.eq(Product::getIsDel, DeleteEnum.NORMAL.value());
queryWrapper.orderBy(Product::getIsSoldStock, true);
queryWrapper.orderBy(Product::getIsSale, false);
@@ -162,7 +171,6 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
}
@Override
@Cacheable(value = ADMIN_CLIENT_PRODUCT_LIST, key = "#param.shopId", unless = "#result.isEmpty()")
public List<ProductDTO> getProductList(ProductDTO param) {
QueryWrapper queryWrapper = buildFullQueryWrapper(param);
//queryWrapper.eq(Product::getIsSale, YesNoEnum.YES.value());
@@ -171,6 +179,92 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
return records;
}
@Override
public List<ProductDTO> getProductCacheList(ProductDTO param) {
Long shopId = param.getShopId();
initProductCache(shopId);
String prefix = ADMIN_CLIENT_PRODUCT_LIST + "::" + shopId + "::";
List<ProductDTO> list;
if (param.getCategoryId() == null) {
list = new ArrayList<>();
Set<String> keys = redisService.rightLikeKey(prefix);
for (String key : keys) {
List<ProductDTO> prodList = redisService.getJsonToBeanList(key, ProductDTO.class);
list.addAll(prodList);
}
} else {
String key = prefix + param.getCategoryId();
list = redisService.getJsonToBeanList(key, ProductDTO.class);
}
if (StrUtil.isNotEmpty(param.getName())) {
list = list.stream().filter(obj -> StrUtil.contains(obj.getName(), param.getName())).toList();
}
// 重新进行排序
list = list.stream()
.sorted(Comparator.comparingInt(ProductDTO::getIsSoldStock))
.sorted(Comparator.comparingInt(ProductDTO::getIsSale).reversed())
.sorted(Comparator.comparingInt(ProductDTO::getSort).reversed())
.sorted(Comparator.comparingLong(ProductDTO::getId).reversed())
.toList();
return list;
}
/**
* 初始化商品缓存数据
*/
private void initProductCache(Long shopId) {
ProductDTO param = new ProductDTO();
param.setShopId(shopId);
List<ProductDTO> productList = getProductList(param);
Map<Long, List<ProductDTO>> categoryMap = productList.stream().filter(item -> item.getCategoryId() != null).collect(Collectors.groupingBy(ProductDTO::getCategoryId));
ShopProdCategoryDTO dto = new ShopProdCategoryDTO();
dto.setShopId(shopId);
List<ShopProdCategoryDTO> categoryList = shopProdCategoryService.getShopProdCategoryList(dto);
String prefix = ADMIN_CLIENT_PRODUCT_LIST + "::" + shopId + "::";
for (ShopProdCategoryDTO category : categoryList) {
String key = prefix + category.getId();
boolean b = redisService.hasKey(key);
if (!b) {
List<ProductDTO> list = categoryMap.get(category.getId());
if (CollUtil.isNotEmpty(list)) {
redisService.setJsonStr(key, list);
} else {
List<ProductDTO> empty = new ArrayList<>();
redisService.setJsonStr(key, empty);
}
}
}
}
/**
* 清除某个商品分类的缓存
*/
@Override
public void clearProductCache(Long... categoryIds) {
Long shopId = StpKit.USER.getShopId(0L);
String prefix = ADMIN_CLIENT_PRODUCT_LIST + "::" + shopId + "::";
for (Long categoryId : categoryIds) {
redisService.del(prefix + categoryId);
}
}
/**
* 系统启动会一次性加载商品缓存数据,防止首次访问时加载缓慢的问题
*/
@PostConstruct
public void initProductListCache() {
log.info("系统启动后初始化商品列表缓存,开始...");
List<Long> shopIdList = DbChain.table("tb_shop_info").select("id").objListAs(Long.class);
for (Long shopId : shopIdList) {
log.info("商品列表缓存>>当前店铺:{}", shopId);
ProductDTO dto = new ProductDTO();
dto.setShopId(shopId);
getProductCacheList(dto);
log.info("商品列表缓存>>当前店铺:{},初始化结束", shopId);
}
log.info("系统启动后初始化商品列表缓存,结束。");
}
/**
* 计算是否在可售时间内
*
@@ -223,7 +317,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
@Override
@Transactional(rollbackFor = Exception.class)
@CacheEvict(value = {CacheConstant.USER_CLIENT_HOTS_PRODUCT, CacheConstant.USER_CLIENT_GROUPS_PRODUCT, ADMIN_CLIENT_PRODUCT_LIST}, key = "#dto.shopId", allEntries = true)
@CacheEvict(value = {CacheConstant.USER_CLIENT_HOTS_PRODUCT, CacheConstant.USER_CLIENT_GROUPS_PRODUCT}, key = "#dto.shopId", allEntries = true)
public void addProduct(ProductDTO dto) {
Long shopId = StpKit.USER.getShopId(0L);
boolean exists = super.exists(query().eq(Product::getName, dto.getName()).eq(Product::getShopId, shopId).eq(Product::getIsDel, DeleteEnum.NORMAL.value()));
@@ -246,6 +340,8 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
entity.setShopId(shopId);
super.save(entity);
dto.setId(entity.getId());
// 清除商品分类列表缓存
clearProductCache(entity.getCategoryId());
List<ProdSkuDTO> skuList = dto.getSkuList();
if (CollUtil.isNotEmpty(skuList)) {
List<ProdSku> prodSkuList = new ArrayList<>();
@@ -283,7 +379,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
@Override
@Transactional(rollbackFor = Exception.class)
@CacheEvict(value = {CacheConstant.USER_CLIENT_HOTS_PRODUCT, CacheConstant.USER_CLIENT_GROUPS_PRODUCT, ADMIN_CLIENT_PRODUCT_LIST}, key = "#dto.shopId", allEntries = true)
@CacheEvict(value = {CacheConstant.USER_CLIENT_HOTS_PRODUCT, CacheConstant.USER_CLIENT_GROUPS_PRODUCT}, key = "#dto.shopId", allEntries = true)
public void updateProduct(ProductDTO dto) {
Long shopId = StpKit.USER.getShopId(0L);
dto.setShopId(shopId);
@@ -307,11 +403,16 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
}
entity.setIsDel(DeleteEnum.NORMAL.value());
entity.setShopId(shopId);
if(!ProductTypeEnum.SKU.value().equals(entity.getType())){
if (!ProductTypeEnum.SKU.value().equals(entity.getType())) {
entity.setSpecId(null);
}
entity.setSpecId(null);
super.updateById(entity);
// 清除商品分类列表缓存
if (!old.getCategoryId().equals(dto.getCategoryId())) {
// 清除旧分类缓存&新分类缓存
clearProductCache(old.getCategoryId(), entity.getCategoryId());
}
List<ProdSkuDTO> skuList = dto.getSkuList();
// 商品SKU-ID列表
List<Long> skuIdList = prodSkuMapper.selectListByQueryAs(query().select(ProdSku::getId).eq(ProdSku::getProductId, dto.getId()), Long.class);
@@ -425,8 +526,10 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
}
@Override
@CacheEvict(value = {CacheConstant.USER_CLIENT_HOTS_PRODUCT, CacheConstant.USER_CLIENT_GROUPS_PRODUCT, ADMIN_CLIENT_PRODUCT_LIST}, key = "#shopId", allEntries = true)
@CacheEvict(value = {CacheConstant.USER_CLIENT_HOTS_PRODUCT, CacheConstant.USER_CLIENT_GROUPS_PRODUCT}, key = "#shopId", allEntries = true)
public void deleteProduct(Long shopId, Long id) {
Product old = getById(id);
Long categoryId = old.getCategoryId();
UpdateChain.of(Product.class)
.set(Product::getIsDel, DeleteEnum.DELETED.value())
.eq(Product::getId, id)
@@ -434,11 +537,13 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
.update();
prodGroupRelationMapper.deleteByQuery(query().eq(ProdGroupRelation::getProductId, id));
prodConsRelationMapper.deleteByQuery(query().eq(ProdConsRelation::getProductId, id));
// 清除商品分类列表缓存
clearProductCache(categoryId);
}
@Override
@Transactional(rollbackFor = Exception.class)
@CacheEvict(value = {CacheConstant.USER_CLIENT_HOTS_PRODUCT, CacheConstant.USER_CLIENT_GROUPS_PRODUCT, ADMIN_CLIENT_PRODUCT_LIST}, key = "#param.shopId", allEntries = true, beforeInvocation = true)
@CacheEvict(value = {CacheConstant.USER_CLIENT_HOTS_PRODUCT, CacheConstant.USER_CLIENT_GROUPS_PRODUCT}, key = "#param.shopId", allEntries = true, beforeInvocation = true)
public void onOffProduct(ProductIsSaleParam param) {
Long shopId = StpKit.USER.getShopId(0L);
String type = param.getType();
@@ -450,6 +555,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
} else {
sensitiveOperation = "下架";
}
Long prodId = null;
if (ProductIsSaleTypeEnum.SKU.value().equals(type)) {
ProdSku prodSku = prodSkuMapper.selectOneById(id);
if (prodSku == null) {
@@ -468,6 +574,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
.eq(Product::getId, prodSku.getProductId())
.eq(Product::getShopId, shopId)
.update();
prodId = prodSku.getProductId();
}
Long productId = prodSku.getProductId();
Product product = mapper.selectOneById(productId);
@@ -484,19 +591,25 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
.eq(ProdSku::getShopId, shopId)
.update();
Product product = mapper.selectOneById(id);
prodId = product.getId();
sensitiveOperation = sensitiveOperation + "商品:" + product.getName();
}
sensitiveOperationService.send(sensitiveOperation);
// 清除商品分类列表缓存
Product old = getById(prodId);
Long categoryId = old.getCategoryId();
clearProductCache(categoryId);
}
@Override
@Transactional(rollbackFor = Exception.class)
@CacheEvict(value = {CacheConstant.USER_CLIENT_HOTS_PRODUCT, CacheConstant.USER_CLIENT_GROUPS_PRODUCT, ADMIN_CLIENT_PRODUCT_LIST}, key = "#param.shopId", allEntries = true, beforeInvocation = true)
@CacheEvict(value = {CacheConstant.USER_CLIENT_HOTS_PRODUCT, CacheConstant.USER_CLIENT_GROUPS_PRODUCT}, key = "#param.shopId", allEntries = true, beforeInvocation = true)
public void markProductIsSoldOut(ProductIsSoldOutParam param) {
Long shopId = StpKit.USER.getShopId(0L);
String type = param.getType();
Long id = param.getId();
Integer isSoldOut = param.getIsSoldOut();
Long prodId = null;
if (ProductIsSaleTypeEnum.SKU.value().equals(type)) {
ProdSku prodSku = prodSkuMapper.selectOneById(id);
if (prodSku == null) {
@@ -516,6 +629,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
.eq(Product::getShopId, shopId)
.update();
}
prodId = prodSku.getProductId();
} else if (ProductIsSaleTypeEnum.PRODUCT.value().equals(type)) {
UpdateChain.of(Product.class)
.set(Product::getIsSoldStock, isSoldOut)
@@ -527,7 +641,12 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
.eq(ProdSku::getProductId, id)
.eq(ProdSku::getShopId, shopId)
.update();
prodId = id;
}
// 清除商品分类列表缓存
Product old = getById(prodId);
Long categoryId = old.getCategoryId();
clearProductCache(categoryId);
}
@Override

View File

@@ -6,6 +6,7 @@ import com.czg.enums.StatusEnum;
import com.czg.exception.CzgException;
import com.czg.product.dto.ShopProdCategoryDTO;
import com.czg.product.entity.ShopProdCategory;
import com.czg.product.service.ProductService;
import com.czg.product.service.ShopProdCategoryService;
import com.czg.sa.StpKit;
import com.czg.service.product.mapper.ShopProdCategoryMapper;
@@ -14,6 +15,8 @@ import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.update.UpdateChain;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import java.util.List;
@@ -27,13 +30,20 @@ import java.util.List;
@Service
public class ShopProdCategoryServiceImpl extends ServiceImpl<ShopProdCategoryMapper, ShopProdCategory> implements ShopProdCategoryService {
@Resource
@Lazy
private ProductService productService;
private QueryWrapper buildQueryWrapper(ShopProdCategoryDTO param) {
QueryWrapper queryWrapper = PageUtil.buildSortQueryWrapper();
if (StrUtil.isNotEmpty(param.getName())) {
queryWrapper.like(ShopProdCategory::getName, param.getName());
}
Long shopId = StpKit.USER.getShopId(0L);
queryWrapper.eq(ShopProdCategory::getShopId, shopId);
if (param.getShopId() == null) {
Long shopId = StpKit.USER.getShopId(0L);
param.setShopId(shopId);
}
queryWrapper.eq(ShopProdCategory::getShopId, param.getShopId());
queryWrapper.orderBy(ShopProdCategory::getSort, true);
queryWrapper.orderBy(ShopProdCategory::getId, false);
return queryWrapper;
@@ -93,6 +103,7 @@ public class ShopProdCategoryServiceImpl extends ServiceImpl<ShopProdCategoryMap
public void deleteShopProdCategory(Long id) {
Long shopId = StpKit.USER.getShopId(0L);
super.remove(query().eq(ShopProdCategory::getId, id).eq(ShopProdCategory::getShopId, shopId));
productService.clearProductCache(id);
}
@Override
@@ -103,6 +114,7 @@ public class ShopProdCategoryServiceImpl extends ServiceImpl<ShopProdCategoryMap
.eq(ShopProdCategory::getId, id)
.eq(ShopProdCategory::getShopId, shopId)
.update();
productService.clearProductCache(id);
}
@Override
@@ -113,6 +125,7 @@ public class ShopProdCategoryServiceImpl extends ServiceImpl<ShopProdCategoryMap
.eq(ShopProdCategory::getId, id)
.eq(ShopProdCategory::getShopId, shopId)
.update();
productService.clearProductCache(id);
}
}