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 15 /**
16 16 * 获得商品匹配的的限时折扣信息
17 17 *
18   - * @param skuIds 商品 SKU 编号数组
  18 + * @param spuIds 商品 spu 编号数组
19 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 3 import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO;
4 4 import cn.iocoder.yudao.module.promotion.convert.discount.DiscountActivityConvert;
5 5 import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService;
  6 +import jakarta.annotation.Resource;
6 7 import org.springframework.stereotype.Service;
7 8 import org.springframework.validation.annotation.Validated;
8 9  
9   -import jakarta.annotation.Resource;
10 10 import java.util.Collection;
11 11 import java.util.List;
12 12  
... ... @@ -23,8 +23,8 @@ public class DiscountActivityApiImpl implements DiscountActivityApi {
23 23 private DiscountActivityService discountActivityService;
24 24  
25 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 1 package cn.iocoder.yudao.module.promotion.dal.mysql.discount;
2 2  
3 3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  4 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
4 5 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
5 6 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  7 +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
6 8 import org.apache.ibatis.annotations.Mapper;
7   -import org.apache.ibatis.annotations.Param;
8 9  
9 10 import java.util.Collection;
10 11 import java.util.List;
... ... @@ -27,9 +28,6 @@ public interface DiscountProductMapper extends BaseMapperX&lt;DiscountProductDO&gt; {
27 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 32 * 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号
35 33 *
... ... @@ -45,4 +43,19 @@ public interface DiscountProductMapper extends BaseMapperX&lt;DiscountProductDO&gt; {
45 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 24 *
25 25 * 注意,匹配的条件,仅仅是日期符合,并且处于开启状态
26 26 *
27   - * @param skuIds SKU 编号数组
  27 + * @param spuIds SKU 编号数组
28 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 18 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
19 19 import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountActivityMapper;
20 20 import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountProductMapper;
21   -import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
22 21 import cn.iocoder.yudao.module.promotion.util.PromotionUtils;
23 22 import jakarta.annotation.Resource;
24 23 import org.springframework.stereotype.Service;
... ... @@ -55,8 +54,22 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
55 54 private ProductSkuApi productSkuApi;
56 55  
57 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 75 @Override
... ... @@ -182,9 +195,11 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
182 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 205 @Override
... ... @@ -195,8 +210,10 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
195 210 throw exception(DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED);
196 211 }
197 212  
198   - // 删除
  213 + // 删除活动
199 214 discountActivityMapper.deleteById(id);
  215 + // 删除活动商品
  216 + discountProductMapper.deleteByActivityId(id);
200 217 }
201 218  
202 219 private DiscountActivityDO validateDiscountActivityExists(Long id) {
... ... @@ -224,7 +241,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
224 241  
225 242 @Override
226 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 247 @Override
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/discount/DiscountProductMapper.xml
... ... @@ -2,23 +2,4 @@
2 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
3 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 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 10 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
11 11 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
12 12 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
  13 +import jakarta.annotation.Resource;
13 14 import org.springframework.core.annotation.Order;
14 15 import org.springframework.stereotype.Component;
15 16  
16   -import jakarta.annotation.Resource;
17 17 import java.util.List;
18 18 import java.util.Map;
19 19  
20 20 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
21 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 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 42 }
42 43 // 获得 SKU 对应的限时折扣活动
43 44 List<DiscountProductRespDTO> discountProducts = discountActivityApi.getMatchDiscountProductList(
44   - convertSet(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSkuId));
  45 + convertSet(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSpuId));
45 46 if (CollUtil.isEmpty(discountProducts)) {
46 47 return;
47 48 }
... ... @@ -79,7 +80,7 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato
79 80 if (PromotionDiscountTypeEnum.PRICE.getType().equals(discountProduct.getDiscountType())) { // 减价
80 81 price -= discountProduct.getDiscountPrice() * orderItem.getCount();
81 82 } else if (PromotionDiscountTypeEnum.PERCENT.getType().equals(discountProduct.getDiscountType())) { // 打折
82   - price = price * discountProduct.getDiscountPercent() / 100;
  83 + price = calculateRatePrice(price, discountProduct.getDiscountPercent() / 100.0);
83 84 } else {
84 85 throw new IllegalArgumentException(String.format("优惠活动的商品(%s) 的优惠类型不正确", discountProduct));
85 86 }
... ...