用户端商品缓存+商品信息修改缓存自动清空

This commit is contained in:
Tankaikai 2025-03-01 17:35:10 +08:00
parent af56a1e9ea
commit 4b5f62705d
14 changed files with 94 additions and 22 deletions

View File

@ -5,12 +5,14 @@ import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* @author ww
*/
@SpringBootApplication
@EnableDiscoveryClient
@EnableTransactionManagement
@EnableDubbo
@MapperScan("com.czg.service.product.mapper")
public class ProductApplication {

View File

@ -11,6 +11,7 @@ import com.czg.product.param.ProductIsSoldOutParam;
import com.czg.product.service.ProdConsRelationService;
import com.czg.product.service.ProductService;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.czg.utils.AssertUtil;
import com.czg.validator.ValidatorUtil;
import com.czg.validator.group.DefaultGroup;
@ -70,6 +71,8 @@ public class ProductController {
for (ProdSkuDTO prodSkuDTO : dto.getSkuList()) {
ValidatorUtil.validateEntity(prodSkuDTO, DefaultGroup.class);
}
Long shopId = StpKit.USER.getShopId(0L);
dto.setShopId(shopId);
productService.addProduct(dto);
return CzgResult.success();
}
@ -78,6 +81,8 @@ public class ProductController {
@OperationLog("商品-修改")
//@SaAdminCheckPermission("product:update")
public CzgResult<Void> updateProduct(@RequestBody @Validated({UpdateGroup.class, DefaultGroup.class}) ProductDTO dto) {
Long shopId = StpKit.USER.getShopId(0L);
dto.setShopId(shopId);
productService.updateProduct(dto);
return CzgResult.success();
}
@ -88,7 +93,8 @@ public class ProductController {
public CzgResult<Void> deleteProduct(@PathVariable("id") Long id) {
//效验数据
AssertUtil.isNull(id, "{}不能为空", "id");
productService.deleteProduct(id);
Long shopId = StpKit.USER.getShopId(0L);
productService.deleteProduct(shopId, id);
return CzgResult.success();
}
@ -99,6 +105,8 @@ public class ProductController {
@OperationLog("商品-上下架")
//@SaAdminCheckPermission("product:on-off")
public CzgResult<Void> onOffProduct(@RequestBody @Validated({DefaultGroup.class}) ProductIsSaleParam param) {
Long shopId = StpKit.USER.getShopId(0L);
param.setShopId(shopId);
productService.onOffProduct(param);
return CzgResult.success();
}
@ -110,6 +118,8 @@ public class ProductController {
@OperationLog("商品-标记售罄")
//@SaAdminCheckPermission("product:markIsSoldOut")
public CzgResult<Void> markIsSoldOutProduct(@RequestBody @Validated({DefaultGroup.class}) ProductIsSoldOutParam param) {
Long shopId = StpKit.USER.getShopId(0L);
param.setShopId(shopId);
productService.markProductIsSoldOut(param);
return CzgResult.success();
}

View File

@ -7,6 +7,7 @@ import com.czg.product.vo.ShopProductInfoVo;
import com.czg.product.vo.ShopProductSkuInfoVo;
import com.czg.product.vo.ShopProductVo;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.czg.utils.AssertUtil;
import com.czg.validator.ValidatorUtil;
import com.czg.validator.group.DefaultGroup;
@ -36,7 +37,8 @@ public class UProductController {
*/
@GetMapping("/miniApp/hots/query")
public CzgResult<List<ShopProductVo>> queryHotsProductList() {
List<ShopProductVo> list = uProductService.queryHotsProductList();
Long shopId = StpKit.USER.getShopId(0L);
List<ShopProductVo> list = uProductService.queryHotsProductList(shopId);
return CzgResult.success(list);
}
@ -45,7 +47,8 @@ public class UProductController {
*/
@GetMapping("/miniApp/group/query")
public CzgResult<List<ShopGroupProductVo>> queryGroupProductList() {
List<ShopGroupProductVo> list = uProductService.queryGroupProductList();
Long shopId = StpKit.USER.getShopId(0L);
List<ShopGroupProductVo> list = uProductService.queryGroupProductList(shopId);
return CzgResult.success(list);
}

View File

@ -1,5 +1,6 @@
package com.czg.product.param;
import com.alibaba.fastjson2.annotation.JSONField;
import com.czg.validator.group.DefaultGroup;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
@ -34,4 +35,11 @@ public class ProdRefundToStockParam implements Serializable {
@Min(value = 0, message = "是否退回库存值必须是0或1", groups = DefaultGroup.class)
@Max(value = 1, message = "是否退回库存值必须是0或1", groups = DefaultGroup.class)
private Integer isReturn;
/**
* 店铺id
*/
@JSONField(serialize = false)
private Long shopId;
}

View File

@ -1,5 +1,6 @@
package com.czg.product.param;
import com.alibaba.fastjson2.annotation.JSONField;
import com.czg.validator.group.DefaultGroup;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
@ -39,4 +40,10 @@ public class ProductIsSaleParam implements Serializable {
@NotNull(message = "是否上下架不能为空", groups = DefaultGroup.class)
private Integer isSale;
/**
* 店铺id
*/
@JSONField(serialize = false)
private Long shopId;
}

View File

@ -1,5 +1,6 @@
package com.czg.product.param;
import com.alibaba.fastjson2.annotation.JSONField;
import com.czg.validator.group.DefaultGroup;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
@ -43,4 +44,10 @@ public class ProductIsSoldOutParam implements Serializable {
@Max(value = 1, message = "是否售罄必须是0或1", groups = DefaultGroup.class)
private Integer isSoldOut;
/**
* 店铺id
*/
@JSONField(serialize = false)
private Long shopId;
}

View File

@ -14,16 +14,18 @@ public interface ProductRpcService {
/**
* 订单支付成功扣减库存
*
* @param shopId 店铺ID
* @param orderId 订单ID
* @param dataList 库存扣减数据
*/
void paySuccessSubtractStock(Long orderId, List<Map<String, Object>> dataList);
void paySuccessSubtractStock(Long shopId, Long orderId, List<Map<String, Object>> dataList);
/**
* 订单取消后恢复库存
*
* @param shopId 店铺id
* @param orderId 订单ID
* @param dataList 库存恢复数据
*/
void orderCancelRecoverStock(Long orderId, List<Map<String, Object>> dataList);
void orderCancelRecoverStock(Long shopId, Long orderId, List<Map<String, Object>> dataList);
}

View File

@ -58,9 +58,10 @@ public interface ProductService extends IService<Product> {
/**
* 删除商品
*
* @param shopId 店铺ID
* @param id 商品ID
*/
void deleteProduct(Long id);
void deleteProduct(Long shopId, Long id);
/**
* 上架/下架商品

View File

@ -20,15 +20,17 @@ public interface UProductService extends IService<Product> {
/**
* 用户端获取热门商品
*
* @param shopId 店铺ID
* @return 热门商品
*/
List<ShopProductVo> queryHotsProductList();
List<ShopProductVo> queryHotsProductList(Long shopId);
/**
* 用户端获取分组商品
* @param shopId 店铺ID
* @return 分组商品
*/
List<ShopGroupProductVo> queryGroupProductList();
List<ShopGroupProductVo> queryGroupProductList(Long shopId);
/**
* 用户端获取商品详情

View File

@ -0,0 +1,22 @@
package com.czg.constant;
/**
* 缓存的key 常量
*
* @author tankaikai
* @since 2025-03-01 16:59
*/
public interface CacheConstant {
/**
* 用户端商品信息
*/
String USER_CLIENT_PRODUCT_INFO = "user_client_product_info:";
/**
* 热销商品
*/
String USER_CLIENT_HOTS_PRODUCT = USER_CLIENT_PRODUCT_INFO + "hots";
/**
* 分组商品
*/
String USER_CLIENT_GROUPS_PRODUCT = USER_CLIENT_PRODUCT_INFO + "groups";
}

View File

@ -112,8 +112,6 @@ public class OrderInfoRpcServiceImpl implements OrderInfoRpcService {
}
@Override
@GlobalTransactional
@Transactional(rollbackFor = Exception.class)
public void paySuccessCallback(Long orderId) {
// 下单后商品库存扣减耗材扣减流水记录
OrderInfo orderInfo = orderInfoMapper.selectOneById(orderId);
@ -139,7 +137,7 @@ public class OrderInfoRpcServiceImpl implements OrderInfoRpcService {
dataList.add(data);
}
// 调用商品服务扣减库存
productRpcService.paySuccessSubtractStock(orderId, dataList);
productRpcService.paySuccessSubtractStock(shopId, orderId, dataList);
}
@Override
@ -170,7 +168,7 @@ public class OrderInfoRpcServiceImpl implements OrderInfoRpcService {
dataList.add(data);
}
// 调用商品服务恢复库存
productRpcService.orderCancelRecoverStock(orderId, dataList);
productRpcService.orderCancelRecoverStock(shopId, orderId, dataList);
}
@Override

View File

@ -3,6 +3,7 @@ package com.czg.service.product.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import com.czg.constant.CacheConstant;
import com.czg.product.dto.ProductStockSubtractDTO;
import com.czg.product.entity.ConsInfo;
import com.czg.product.entity.ConsStockFlow;
@ -18,6 +19,7 @@ import com.czg.service.product.mapper.ProductMapper;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -50,7 +52,8 @@ public class ProductRpcServiceImpl implements ProductRpcService {
@Override
@Transactional(rollbackFor = Exception.class)
public void paySuccessSubtractStock(Long orderId, List<Map<String, Object>> dataList) {
@CacheEvict(value = {CacheConstant.USER_CLIENT_HOTS_PRODUCT, CacheConstant.USER_CLIENT_GROUPS_PRODUCT}, key = "#shopId", allEntries = true, beforeInvocation = true)
public void paySuccessSubtractStock(Long shopId, Long orderId, List<Map<String, Object>> dataList) {
List<ProductStockSubtractDTO> list = BeanUtil.copyToList(dataList, ProductStockSubtractDTO.class);
if (CollUtil.isEmpty(list)) {
return;
@ -81,7 +84,6 @@ public class ProductRpcServiceImpl implements ProductRpcService {
// 更新耗材库存数量
consInfoMapper.update(consInfo);
// 插入耗材流水记录
Long shopId = consInfo.getShopId();
ConsStockFlow consStockFlow = new ConsStockFlow();
consStockFlow.setShopId(shopId);
consStockFlow.setVendorId(null);
@ -109,7 +111,8 @@ public class ProductRpcServiceImpl implements ProductRpcService {
@Override
@Transactional(rollbackFor = Exception.class)
public void orderCancelRecoverStock(Long orderId, List<Map<String, Object>> dataList) {
@CacheEvict(value = {CacheConstant.USER_CLIENT_HOTS_PRODUCT, CacheConstant.USER_CLIENT_GROUPS_PRODUCT}, key = "#shopId", allEntries = true, beforeInvocation = true)
public void orderCancelRecoverStock(Long shopId, Long orderId, List<Map<String, Object>> dataList) {
List<ProductStockSubtractDTO> list = BeanUtil.copyToList(dataList, ProductStockSubtractDTO.class);
if (CollUtil.isEmpty(list)) {
return;
@ -140,7 +143,6 @@ public class ProductRpcServiceImpl implements ProductRpcService {
// 更新耗材库存数量
consInfoMapper.update(consInfo);
// 插入耗材流水记录
Long shopId = consInfo.getShopId();
ConsStockFlow consStockFlow = new ConsStockFlow();
consStockFlow.setShopId(shopId);
consStockFlow.setInOutType(InOutTypeEnum.IN.value());

View File

@ -7,6 +7,7 @@ import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONWriter;
import com.czg.constant.CacheConstant;
import com.czg.enums.DeleteEnum;
import com.czg.enums.YesNoEnum;
import com.czg.exception.CzgException;
@ -37,6 +38,7 @@ import com.mybatisflex.spring.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -171,6 +173,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}, 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));
@ -210,6 +213,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
}
@Override
@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);
@ -264,8 +268,8 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
}
@Override
public void deleteProduct(Long id) {
Long shopId = StpKit.USER.getShopId(0L);
@CacheEvict(value = {CacheConstant.USER_CLIENT_HOTS_PRODUCT, CacheConstant.USER_CLIENT_GROUPS_PRODUCT}, key = "#shopId", allEntries = true)
public void deleteProduct(Long shopId, Long id) {
UpdateChain.of(Product.class)
.set(Product::getIsDel, DeleteEnum.DELETED.value())
.eq(Product::getId, id)
@ -275,6 +279,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}, key = "#param.shopId", allEntries = true, beforeInvocation = true)
public void onOffProduct(ProductIsSaleParam param) {
Long shopId = StpKit.USER.getShopId(0L);
String type = param.getType();
@ -296,6 +301,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}, key = "#param.shopId", allEntries = true, beforeInvocation = true)
public void markProductIsSoldOut(ProductIsSoldOutParam param) {
Long shopId = StpKit.USER.getShopId(0L);
String type = param.getType();

View File

@ -3,6 +3,7 @@ package com.czg.service.product.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.czg.constant.CacheConstant;
import com.czg.enums.DeleteEnum;
import com.czg.enums.StatusEnum;
import com.czg.enums.YesNoEnum;
@ -26,6 +27,7 @@ import com.czg.service.product.mapper.ProductMapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.time.DayOfWeek;
@ -55,8 +57,8 @@ public class UProductServiceImpl extends ServiceImpl<ProductMapper, Product> imp
private final ProdGroupRelationMapper prodGroupRelationMapper;
@Override
public List<ShopProductVo> queryHotsProductList() {
Long shopId = StpKit.USER.getShopId(0L);
@Cacheable(value = CacheConstant.USER_CLIENT_HOTS_PRODUCT, key = "#shopId", unless = "#result.isEmpty()")
public List<ShopProductVo> queryHotsProductList(Long shopId) {
List<ShopProductVo> list = productMapper.selectHotsProductList(shopId);
list.forEach(item -> {
item.setIsSaleTime(calcIsSaleTime(item.getDays(), item.getStartTime(), item.getEndTime()));
@ -67,8 +69,8 @@ public class UProductServiceImpl extends ServiceImpl<ProductMapper, Product> imp
}
@Override
public List<ShopGroupProductVo> queryGroupProductList() {
Long shopId = StpKit.USER.getShopId(0L);
@Cacheable(value = CacheConstant.USER_CLIENT_GROUPS_PRODUCT, key = "#shopId", unless = "#result.isEmpty()")
public List<ShopGroupProductVo> queryGroupProductList(Long shopId) {
List<ShopGroupProductVo> groupList = prodGroupMapper.selectListByQueryAs(query().select(ProdGroup::getId, ProdGroup::getName).eq(ProdGroup::getShopId, shopId).eq(ProdGroup::getStatus, StatusEnum.ENABLED.value()).orderBy(ProdGroup::getSort, true), ShopGroupProductVo.class);
List<ShopProductVo> productAllList = productMapper.selectGroupProductList(shopId);
productAllList.forEach(item -> {