Pārlūkot izejas kodu

【代码优化】商城: 限时折扣活动

puhui999 7 mēneši atpakaļ
vecāks
revīzija
71c40cf5ad

+ 2 - 2
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/discount/DiscountActivityApi.java

@@ -15,9 +15,9 @@ public interface DiscountActivityApi {
     /**
      * 获得商品匹配的的限时折扣信息
      *
-     * @param skuIds 商品 SKU 编号数组
+     * @param spuIds 商品 spu 编号数组
      * @return 限时折扣信息
      */
-    List<DiscountProductRespDTO> getMatchDiscountProductList(Collection<Long> skuIds);
+    List<DiscountProductRespDTO> getMatchDiscountProductList(Collection<Long> spuIds);
 
 }

+ 3 - 3
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/discount/DiscountActivityApiImpl.java

@@ -3,10 +3,10 @@ package cn.iocoder.yudao.module.promotion.api.discount;
 import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO;
 import cn.iocoder.yudao.module.promotion.convert.discount.DiscountActivityConvert;
 import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService;
+import jakarta.annotation.Resource;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
-import jakarta.annotation.Resource;
 import java.util.Collection;
 import java.util.List;
 
@@ -23,8 +23,8 @@ public class DiscountActivityApiImpl implements DiscountActivityApi {
     private DiscountActivityService discountActivityService;
 
     @Override
-    public List<DiscountProductRespDTO> getMatchDiscountProductList(Collection<Long> skuIds) {
-        return DiscountActivityConvert.INSTANCE.convertList02(discountActivityService.getMatchDiscountProductList(skuIds));
+    public List<DiscountProductRespDTO> getMatchDiscountProductList(Collection<Long> spuIds) {
+        return DiscountActivityConvert.INSTANCE.convertList02(discountActivityService.getMatchDiscountProductList(spuIds));
     }
 
 }

+ 17 - 4
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountProductMapper.java

@@ -1,10 +1,11 @@
 package cn.iocoder.yudao.module.promotion.dal.mysql.discount;
 
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import org.apache.ibatis.annotations.Mapper;
-import org.apache.ibatis.annotations.Param;
 
 import java.util.Collection;
 import java.util.List;
@@ -27,9 +28,6 @@ public interface DiscountProductMapper extends BaseMapperX<DiscountProductDO> {
         return selectList(DiscountProductDO::getActivityId, activityIds);
     }
 
-    // TODO @zhangshuai:逻辑里,尽量避免写 join 语句哈,你可以看看这个查询,有什么办法优化?目前的一个思路,是分 2 次查询,性能也是 ok 的
-    List<DiscountProductDO> getMatchDiscountProductList(@Param("skuIds") Collection<Long> skuIds);
-
     /**
      * 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号
      *
@@ -45,4 +43,19 @@ public interface DiscountProductMapper extends BaseMapperX<DiscountProductDO> {
                 .groupBy("spu_id"));
     }
 
+    default List<DiscountProductDO> selectListBySpuIdsAndStatus(Collection<Long> spuIds, Integer status) {
+        return selectList(new LambdaQueryWrapperX<DiscountProductDO>()
+                .in(DiscountProductDO::getSpuId, spuIds)
+                .eq(DiscountProductDO::getActivityStatus, status));
+    }
+
+    default void updateByActivityId(DiscountProductDO discountProductDO) {
+        update(discountProductDO, new LambdaUpdateWrapper<DiscountProductDO>()
+                .eq(DiscountProductDO::getActivityId, discountProductDO.getActivityId()));
+    }
+
+    default void deleteByActivityId(Long activityId) {
+        delete(DiscountProductDO::getActivityId, activityId);
+    }
+
 }

+ 2 - 2
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityService.java

@@ -24,10 +24,10 @@ public interface DiscountActivityService {
      *
      * 注意,匹配的条件,仅仅是日期符合,并且处于开启状态
      *
-     * @param skuIds SKU 编号数组
+     * @param spuIds SKU 编号数组
      * @return 匹配的限时折扣商品
      */
-    List<DiscountProductDO> getMatchDiscountProductList(Collection<Long> skuIds);
+    List<DiscountProductDO> getMatchDiscountProductList(Collection<Long> spuIds);
 
     /**
      * 创建限时折扣活动

+ 25 - 8
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImpl.java

@@ -18,7 +18,6 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivit
 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
 import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountActivityMapper;
 import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountProductMapper;
-import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
 import cn.iocoder.yudao.module.promotion.util.PromotionUtils;
 import jakarta.annotation.Resource;
 import org.springframework.stereotype.Service;
@@ -55,8 +54,22 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
     private ProductSkuApi productSkuApi;
 
     @Override
-    public List<DiscountProductDO> getMatchDiscountProductList(Collection<Long> skuIds) {
-        return discountProductMapper.getMatchDiscountProductList(skuIds);
+    public List<DiscountProductDO> getMatchDiscountProductList(Collection<Long> spuIds) {
+        // 1.1 查询出 spu 对应的开启的限时折扣商品
+        List<DiscountProductDO> productList = discountProductMapper.selectListBySpuIdsAndStatus(spuIds,
+                CommonStatusEnum.ENABLE.getStatus());
+        if (CollUtil.isEmpty(productList)) {
+            return Collections.emptyList();
+        }
+        // 1.2 查询出符合的限时折扣活动
+        List<DiscountActivityDO> activityList = discountActivityMapper.selectListByIdsAndDateTimeLt(
+                convertSet(productList, DiscountProductDO::getActivityId), LocalDateTime.now());
+        if (CollUtil.isEmpty(productList)) {
+            return Collections.emptyList();
+        }
+
+        // 2. 获得这些活动的商品列表
+        return discountProductMapper.selectListByActivityId(convertList(activityList, DiscountActivityDO::getId));
     }
 
     @Override
@@ -182,9 +195,11 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
             throw exception(DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED);
         }
 
-        // 更新
-        DiscountActivityDO updateObj = new DiscountActivityDO().setId(id).setStatus(PromotionActivityStatusEnum.CLOSE.getStatus());
-        discountActivityMapper.updateById(updateObj);
+        // 更新活动状态
+        discountActivityMapper.updateById(new DiscountActivityDO().setId(id).setStatus(CommonStatusEnum.DISABLE.getStatus()));
+        // 更新活动商品状态
+        discountProductMapper.updateByActivityId(new DiscountProductDO().setActivityId(id).setActivityStatus(
+                CommonStatusEnum.DISABLE.getStatus()));
     }
 
     @Override
@@ -195,8 +210,10 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
             throw exception(DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED);
         }
 
-        // 删除
+        // 删除活动
         discountActivityMapper.deleteById(id);
+        // 删除活动商品
+        discountProductMapper.deleteByActivityId(id);
     }
 
     private DiscountActivityDO validateDiscountActivityExists(Long id) {
@@ -224,7 +241,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
 
     @Override
     public List<DiscountProductDO> getDiscountProductsByActivityId(Collection<Long> activityIds) {
-        return discountProductMapper.selectList("activity_id", activityIds);
+        return discountProductMapper.selectList(DiscountProductDO::getActivityId, activityIds);
     }
 
     @Override

+ 0 - 19
yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/discount/DiscountProductMapper.xml

@@ -2,23 +2,4 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountProductMapper">
 
-
-    <select id="getMatchDiscountProductList"   resultType="cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO">
-        SELECT pdp.*
-        FROM promotion_discount_product pdp
-        LEFT JOIN promotion_discount_activity pda
-        ON pdp.activity_id = pda.id
-        <where>
-            <if test="skuIds != null and skuIds.size > 0">
-                AND pdp.sku_id in
-                <foreach collection="skuIds" item="skuId" index="index" open="(" close=")" separator=",">
-                    #{skuId}
-                </foreach>
-            </if>
-            AND pda.start_time &lt;= CURRENT_TIME AND pda.end_time &gt;= CURRENT_TIME
-            AND pda.`status` = 20
-            AND pda.deleted != 1
-        </where>
-    </select>
-
 </mapper>

+ 4 - 3
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDiscountActivityPriceCalculator.java

@@ -10,15 +10,16 @@ import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum;
 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
+import jakarta.annotation.Resource;
 import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Component;
 
-import jakarta.annotation.Resource;
 import java.util.List;
 import java.util.Map;
 
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.common.util.number.MoneyUtils.calculateRatePrice;
 import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper.formatPrice;
 
 /**
@@ -41,7 +42,7 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato
         }
         // 获得 SKU 对应的限时折扣活动
         List<DiscountProductRespDTO> discountProducts = discountActivityApi.getMatchDiscountProductList(
-                convertSet(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSkuId));
+                convertSet(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSpuId));
         if (CollUtil.isEmpty(discountProducts)) {
             return;
         }
@@ -79,7 +80,7 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato
         if (PromotionDiscountTypeEnum.PRICE.getType().equals(discountProduct.getDiscountType())) { // 减价
             price -= discountProduct.getDiscountPrice() * orderItem.getCount();
         } else if (PromotionDiscountTypeEnum.PERCENT.getType().equals(discountProduct.getDiscountType())) { // 打折
-            price = price * discountProduct.getDiscountPercent() / 100;
+            price = calculateRatePrice(price, discountProduct.getDiscountPercent() / 100.0);
         } else {
             throw new IllegalArgumentException(String.format("优惠活动的商品(%s) 的优惠类型不正确", discountProduct));
         }