Commit 71c40cf5adfba02f7d7e1181d75536c5d66889e6

Authored by puhui999
1 parent ad1ceaaf

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

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 { @@ -15,9 +15,9 @@ public interface DiscountActivityApi {
15 /** 15 /**
16 * 获得商品匹配的的限时折扣信息 16 * 获得商品匹配的的限时折扣信息
17 * 17 *
18 - * @param skuIds 商品 SKU 编号数组 18 + * @param spuIds 商品 spu 编号数组
19 * @return 限时折扣信息 19 * @return 限时折扣信息
20 */ 20 */
21 - List<DiscountProductRespDTO> getMatchDiscountProductList(Collection<Long> skuIds); 21 + List<DiscountProductRespDTO> getMatchDiscountProductList(Collection<Long> spuIds);
22 22
23 } 23 }
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; @@ -3,10 +3,10 @@ package cn.iocoder.yudao.module.promotion.api.discount;
3 import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO; 3 import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO;
4 import cn.iocoder.yudao.module.promotion.convert.discount.DiscountActivityConvert; 4 import cn.iocoder.yudao.module.promotion.convert.discount.DiscountActivityConvert;
5 import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService; 5 import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService;
  6 +import jakarta.annotation.Resource;
6 import org.springframework.stereotype.Service; 7 import org.springframework.stereotype.Service;
7 import org.springframework.validation.annotation.Validated; 8 import org.springframework.validation.annotation.Validated;
8 9
9 -import jakarta.annotation.Resource;  
10 import java.util.Collection; 10 import java.util.Collection;
11 import java.util.List; 11 import java.util.List;
12 12
@@ -23,8 +23,8 @@ public class DiscountActivityApiImpl implements DiscountActivityApi { @@ -23,8 +23,8 @@ public class DiscountActivityApiImpl implements DiscountActivityApi {
23 private DiscountActivityService discountActivityService; 23 private DiscountActivityService discountActivityService;
24 24
25 @Override 25 @Override
26 - public List<DiscountProductRespDTO> getMatchDiscountProductList(Collection<Long> skuIds) {  
27 - return DiscountActivityConvert.INSTANCE.convertList02(discountActivityService.getMatchDiscountProductList(skuIds)); 26 + public List<DiscountProductRespDTO> getMatchDiscountProductList(Collection<Long> spuIds) {
  27 + return DiscountActivityConvert.INSTANCE.convertList02(discountActivityService.getMatchDiscountProductList(spuIds));
28 } 28 }
29 29
30 } 30 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountProductMapper.java
1 package cn.iocoder.yudao.module.promotion.dal.mysql.discount; 1 package cn.iocoder.yudao.module.promotion.dal.mysql.discount;
2 2
3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  4 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
4 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; 5 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
5 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 6 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  7 +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
6 import org.apache.ibatis.annotations.Mapper; 8 import org.apache.ibatis.annotations.Mapper;
7 -import org.apache.ibatis.annotations.Param;  
8 9
9 import java.util.Collection; 10 import java.util.Collection;
10 import java.util.List; 11 import java.util.List;
@@ -27,9 +28,6 @@ public interface DiscountProductMapper extends BaseMapperX&lt;DiscountProductDO&gt; { @@ -27,9 +28,6 @@ public interface DiscountProductMapper extends BaseMapperX&lt;DiscountProductDO&gt; {
27 return selectList(DiscountProductDO::getActivityId, activityIds); 28 return selectList(DiscountProductDO::getActivityId, activityIds);
28 } 29 }
29 30
30 - // TODO @zhangshuai:逻辑里,尽量避免写 join 语句哈,你可以看看这个查询,有什么办法优化?目前的一个思路,是分 2 次查询,性能也是 ok 的  
31 - List<DiscountProductDO> getMatchDiscountProductList(@Param("skuIds") Collection<Long> skuIds);  
32 -  
33 /** 31 /**
34 * 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号 32 * 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号
35 * 33 *
@@ -45,4 +43,19 @@ public interface DiscountProductMapper extends BaseMapperX&lt;DiscountProductDO&gt; { @@ -45,4 +43,19 @@ public interface DiscountProductMapper extends BaseMapperX&lt;DiscountProductDO&gt; {
45 .groupBy("spu_id")); 43 .groupBy("spu_id"));
46 } 44 }
47 45
  46 + default List<DiscountProductDO> selectListBySpuIdsAndStatus(Collection<Long> spuIds, Integer status) {
  47 + return selectList(new LambdaQueryWrapperX<DiscountProductDO>()
  48 + .in(DiscountProductDO::getSpuId, spuIds)
  49 + .eq(DiscountProductDO::getActivityStatus, status));
  50 + }
  51 +
  52 + default void updateByActivityId(DiscountProductDO discountProductDO) {
  53 + update(discountProductDO, new LambdaUpdateWrapper<DiscountProductDO>()
  54 + .eq(DiscountProductDO::getActivityId, discountProductDO.getActivityId()));
  55 + }
  56 +
  57 + default void deleteByActivityId(Long activityId) {
  58 + delete(DiscountProductDO::getActivityId, activityId);
  59 + }
  60 +
48 } 61 }
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 { @@ -24,10 +24,10 @@ public interface DiscountActivityService {
24 * 24 *
25 * 注意,匹配的条件,仅仅是日期符合,并且处于开启状态 25 * 注意,匹配的条件,仅仅是日期符合,并且处于开启状态
26 * 26 *
27 - * @param skuIds SKU 编号数组 27 + * @param spuIds SKU 编号数组
28 * @return 匹配的限时折扣商品 28 * @return 匹配的限时折扣商品
29 */ 29 */
30 - List<DiscountProductDO> getMatchDiscountProductList(Collection<Long> skuIds); 30 + List<DiscountProductDO> getMatchDiscountProductList(Collection<Long> spuIds);
31 31
32 /** 32 /**
33 * 创建限时折扣活动 33 * 创建限时折扣活动
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 @@ -18,7 +18,6 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivit
18 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; 18 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
19 import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountActivityMapper; 19 import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountActivityMapper;
20 import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountProductMapper; 20 import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountProductMapper;
21 -import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;  
22 import cn.iocoder.yudao.module.promotion.util.PromotionUtils; 21 import cn.iocoder.yudao.module.promotion.util.PromotionUtils;
23 import jakarta.annotation.Resource; 22 import jakarta.annotation.Resource;
24 import org.springframework.stereotype.Service; 23 import org.springframework.stereotype.Service;
@@ -55,8 +54,22 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { @@ -55,8 +54,22 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
55 private ProductSkuApi productSkuApi; 54 private ProductSkuApi productSkuApi;
56 55
57 @Override 56 @Override
58 - public List<DiscountProductDO> getMatchDiscountProductList(Collection<Long> skuIds) {  
59 - return discountProductMapper.getMatchDiscountProductList(skuIds); 57 + public List<DiscountProductDO> getMatchDiscountProductList(Collection<Long> spuIds) {
  58 + // 1.1 查询出 spu 对应的开启的限时折扣商品
  59 + List<DiscountProductDO> productList = discountProductMapper.selectListBySpuIdsAndStatus(spuIds,
  60 + CommonStatusEnum.ENABLE.getStatus());
  61 + if (CollUtil.isEmpty(productList)) {
  62 + return Collections.emptyList();
  63 + }
  64 + // 1.2 查询出符合的限时折扣活动
  65 + List<DiscountActivityDO> activityList = discountActivityMapper.selectListByIdsAndDateTimeLt(
  66 + convertSet(productList, DiscountProductDO::getActivityId), LocalDateTime.now());
  67 + if (CollUtil.isEmpty(productList)) {
  68 + return Collections.emptyList();
  69 + }
  70 +
  71 + // 2. 获得这些活动的商品列表
  72 + return discountProductMapper.selectListByActivityId(convertList(activityList, DiscountActivityDO::getId));
60 } 73 }
61 74
62 @Override 75 @Override
@@ -182,9 +195,11 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { @@ -182,9 +195,11 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
182 throw exception(DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED); 195 throw exception(DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED);
183 } 196 }
184 197
185 - // 更新  
186 - DiscountActivityDO updateObj = new DiscountActivityDO().setId(id).setStatus(PromotionActivityStatusEnum.CLOSE.getStatus());  
187 - discountActivityMapper.updateById(updateObj); 198 + // 更新活动状态
  199 + discountActivityMapper.updateById(new DiscountActivityDO().setId(id).setStatus(CommonStatusEnum.DISABLE.getStatus()));
  200 + // 更新活动商品状态
  201 + discountProductMapper.updateByActivityId(new DiscountProductDO().setActivityId(id).setActivityStatus(
  202 + CommonStatusEnum.DISABLE.getStatus()));
188 } 203 }
189 204
190 @Override 205 @Override
@@ -195,8 +210,10 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { @@ -195,8 +210,10 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
195 throw exception(DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED); 210 throw exception(DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED);
196 } 211 }
197 212
198 - // 删除 213 + // 删除活动
199 discountActivityMapper.deleteById(id); 214 discountActivityMapper.deleteById(id);
  215 + // 删除活动商品
  216 + discountProductMapper.deleteByActivityId(id);
200 } 217 }
201 218
202 private DiscountActivityDO validateDiscountActivityExists(Long id) { 219 private DiscountActivityDO validateDiscountActivityExists(Long id) {
@@ -224,7 +241,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { @@ -224,7 +241,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
224 241
225 @Override 242 @Override
226 public List<DiscountProductDO> getDiscountProductsByActivityId(Collection<Long> activityIds) { 243 public List<DiscountProductDO> getDiscountProductsByActivityId(Collection<Long> activityIds) {
227 - return discountProductMapper.selectList("activity_id", activityIds); 244 + return discountProductMapper.selectList(DiscountProductDO::getActivityId, activityIds);
228 } 245 }
229 246
230 @Override 247 @Override
yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/discount/DiscountProductMapper.xml
@@ -2,23 +2,4 @@ @@ -2,23 +2,4 @@
2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
3 <mapper namespace="cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountProductMapper"> 3 <mapper namespace="cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountProductMapper">
4 4
5 -  
6 - <select id="getMatchDiscountProductList" resultType="cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO">  
7 - SELECT pdp.*  
8 - FROM promotion_discount_product pdp  
9 - LEFT JOIN promotion_discount_activity pda  
10 - ON pdp.activity_id = pda.id  
11 - <where>  
12 - <if test="skuIds != null and skuIds.size > 0">  
13 - AND pdp.sku_id in  
14 - <foreach collection="skuIds" item="skuId" index="index" open="(" close=")" separator=",">  
15 - #{skuId}  
16 - </foreach>  
17 - </if>  
18 - AND pda.start_time &lt;= CURRENT_TIME AND pda.end_time &gt;= CURRENT_TIME  
19 - AND pda.`status` = 20  
20 - AND pda.deleted != 1  
21 - </where>  
22 - </select>  
23 -  
24 </mapper> 5 </mapper>
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; @@ -10,15 +10,16 @@ import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum;
10 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; 10 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
11 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; 11 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
12 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; 12 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
  13 +import jakarta.annotation.Resource;
13 import org.springframework.core.annotation.Order; 14 import org.springframework.core.annotation.Order;
14 import org.springframework.stereotype.Component; 15 import org.springframework.stereotype.Component;
15 16
16 -import jakarta.annotation.Resource;  
17 import java.util.List; 17 import java.util.List;
18 import java.util.Map; 18 import java.util.Map;
19 19
20 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; 20 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
21 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; 21 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  22 +import static cn.iocoder.yudao.framework.common.util.number.MoneyUtils.calculateRatePrice;
22 import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper.formatPrice; 23 import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper.formatPrice;
23 24
24 /** 25 /**
@@ -41,7 +42,7 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato @@ -41,7 +42,7 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato
41 } 42 }
42 // 获得 SKU 对应的限时折扣活动 43 // 获得 SKU 对应的限时折扣活动
43 List<DiscountProductRespDTO> discountProducts = discountActivityApi.getMatchDiscountProductList( 44 List<DiscountProductRespDTO> discountProducts = discountActivityApi.getMatchDiscountProductList(
44 - convertSet(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSkuId)); 45 + convertSet(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSpuId));
45 if (CollUtil.isEmpty(discountProducts)) { 46 if (CollUtil.isEmpty(discountProducts)) {
46 return; 47 return;
47 } 48 }
@@ -79,7 +80,7 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato @@ -79,7 +80,7 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato
79 if (PromotionDiscountTypeEnum.PRICE.getType().equals(discountProduct.getDiscountType())) { // 减价 80 if (PromotionDiscountTypeEnum.PRICE.getType().equals(discountProduct.getDiscountType())) { // 减价
80 price -= discountProduct.getDiscountPrice() * orderItem.getCount(); 81 price -= discountProduct.getDiscountPrice() * orderItem.getCount();
81 } else if (PromotionDiscountTypeEnum.PERCENT.getType().equals(discountProduct.getDiscountType())) { // 打折 82 } else if (PromotionDiscountTypeEnum.PERCENT.getType().equals(discountProduct.getDiscountType())) { // 打折
82 - price = price * discountProduct.getDiscountPercent() / 100; 83 + price = calculateRatePrice(price, discountProduct.getDiscountPercent() / 100.0);
83 } else { 84 } else {
84 throw new IllegalArgumentException(String.format("优惠活动的商品(%s) 的优惠类型不正确", discountProduct)); 85 throw new IllegalArgumentException(String.format("优惠活动的商品(%s) 的优惠类型不正确", discountProduct));
85 } 86 }