Commit 71c40cf5adfba02f7d7e1181d75536c5d66889e6
1 parent
ad1ceaaf
【代码优化】商城: 限时折扣活动
Showing
7 changed files
with
53 additions
and
41 deletions
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<DiscountProductDO> { |
| 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<DiscountProductDO> { |
| 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 <= CURRENT_TIME AND pda.end_time >= 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 | } | ... | ... |