Browse Source

day14
策略模式+工厂模式优化商品结算

it_lv 1 week ago
parent
commit
88c2231ce1

+ 54 - 0
service/service-order/src/main/java/com/atguigu/tingshu/order/pattern/AbstractTradeOrderStrategy.java

@@ -0,0 +1,54 @@
+package com.atguigu.tingshu.order.pattern;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.IdUtil;
+import com.atguigu.tingshu.common.constant.RedisConstant;
+import com.atguigu.tingshu.common.util.AuthContextHolder;
+import com.atguigu.tingshu.order.helper.SignHelper;
+import com.atguigu.tingshu.order.pattern.strategy.TradeOrderStrategy;
+import com.atguigu.tingshu.vo.order.OrderInfoVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 策略模式抽象类:封装复用代码
+ * @author: atguigu
+ * @create: 2025-03-25 16:22
+ */
+public abstract class AbstractTradeOrderStrategy implements TradeOrderStrategy {
+
+
+    @Autowired
+    private RedisTemplate redisTemplate;
+
+    /**
+     * 为本次订单结算生成流水号
+     * @param orderInfoVo
+     */
+    protected void generateTradeNo(OrderInfoVo orderInfoVo) {
+        Long userId = AuthContextHolder.getUserId();
+        String tradeNo = IdUtil.randomUUID();
+        String tradeKey = RedisConstant.ORDER_TRADE_NO_PREFIX + userId;
+        redisTemplate.opsForValue().set(tradeKey, tradeNo, RedisConstant.ORDER_TRADE_EXPIRE, TimeUnit.MINUTES);
+        orderInfoVo.setTradeNo(tradeNo);
+    }
+
+
+    /**
+     * 为本次订单生成签名值
+     * @param orderInfoVo
+     */
+    protected void generateSign(OrderInfoVo orderInfoVo) {
+        orderInfoVo.setTimestamp(System.currentTimeMillis());
+        //将订单VO转为Map TODO:VO中包含付款方式"payWay"此时为空 生成签名将排除掉payWay字段,故暂时不参与签名
+        Map<String, Object> map = BeanUtil.beanToMap(orderInfoVo, false, true);
+        String sign = SignHelper.getSign(map);
+        orderInfoVo.setSign(sign);
+    }
+
+
+
+}

+ 28 - 0
service/service-order/src/main/java/com/atguigu/tingshu/order/pattern/factory/TradeOrderStrategyFactory.java

@@ -0,0 +1,28 @@
+package com.atguigu.tingshu.order.pattern.factory;
+
+import com.atguigu.tingshu.order.pattern.strategy.TradeOrderStrategy;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @author: atguigu
+ * @create: 2025-03-25 16:23
+ */
+@Component
+public class TradeOrderStrategyFactory {
+
+    @Autowired
+    private Map<String, TradeOrderStrategy> tradeOrderStrategyMap;
+
+
+    /**
+     * 根据商品类别返回策略实现类对象
+     * @param type
+     * @return
+     */
+    public TradeOrderStrategy getTradeOrderStrategy(String type) {
+        return tradeOrderStrategyMap.get(type);
+    }
+}

+ 119 - 0
service/service-order/src/main/java/com/atguigu/tingshu/order/pattern/strategy/AlbumTradeOrderStrategy.java

@@ -0,0 +1,119 @@
+package com.atguigu.tingshu.order.pattern.strategy;
+
+import cn.hutool.core.lang.Assert;
+import com.atguigu.tingshu.album.AlbumFeignClient;
+import com.atguigu.tingshu.common.util.AuthContextHolder;
+import com.atguigu.tingshu.model.album.AlbumInfo;
+import com.atguigu.tingshu.order.pattern.AbstractTradeOrderStrategy;
+import com.atguigu.tingshu.user.client.UserFeignClient;
+import com.atguigu.tingshu.vo.order.OrderDerateVo;
+import com.atguigu.tingshu.vo.order.OrderDetailVo;
+import com.atguigu.tingshu.vo.order.OrderInfoVo;
+import com.atguigu.tingshu.vo.order.TradeVo;
+import com.atguigu.tingshu.vo.user.UserInfoVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import static com.atguigu.tingshu.common.constant.SystemConstant.ORDER_DERATE_ALBUM_DISCOUNT;
+
+/**
+ * 商品类别为专辑:策略实现类
+ * @author: atguigu
+ * @create: 2025-03-25 16:24
+ */
+@Component("1001")
+public class AlbumTradeOrderStrategy extends AbstractTradeOrderStrategy {
+
+    @Autowired
+    private UserFeignClient userFeignClient;
+
+    @Autowired
+    private AlbumFeignClient albumFeignClient;
+    /**
+     * 处理结算商品类别为:专辑
+     * @param tradeVo
+     * @return
+     */
+    @Override
+    public void handleTrade(TradeVo tradeVo, OrderInfoVo orderInfoVo) {
+        Long userId = AuthContextHolder.getUserId();
+        //3. 处理购买商品类别:专辑
+        //3.1 远程调用"用户服务"判断是否重复购买专辑 如果是:业务终止
+        Long albumId = tradeVo.getItemId();
+        Boolean isPaid = userFeignClient.isPaidAlbum(albumId).getData();
+        Assert.state(!isPaid, "用户已购买专辑:{}", albumId);
+
+        //3.2 远程调用"专辑服务"获取专辑信息
+        AlbumInfo albumInfo = albumFeignClient.getAlbumInfo(albumId).getData();
+        Assert.notNull(albumInfo, "专辑:{}不存在", albumId);
+        //3.2.1 专辑价格
+        BigDecimal price = albumInfo.getPrice();
+        //3.2.2 普通用户折扣
+        BigDecimal discount = albumInfo.getDiscount();
+        //3.2.3 VIP用户折扣
+        BigDecimal vipDiscount = albumInfo.getVipDiscount();
+
+        //3.3 远程调用"用户服务"判断用户身份
+        Boolean isVIP = false;
+        UserInfoVo userInfoVo = userFeignClient.getUserInfoVo(userId).getData();
+        Assert.notNull(userInfoVo, "用户:{}不存在", userId);
+        if (userInfoVo.getIsVip().intValue() == 1 && userInfoVo.getVipExpireTime().after(new Date())) {
+            isVIP = true;
+        }
+        //3.4 计算相关价格
+        //3.4.1 暂时让订单价等于原价
+        BigDecimal originalAmount = price;
+        BigDecimal orderAmount = originalAmount;
+        BigDecimal derateAmount = new BigDecimal("0.00");
+        //3.4.2 如果是普通用户且专辑设置普通用户折扣,则订单价=原价*普通用户折扣
+        if (!isVIP && discount.doubleValue() != -1) {
+            orderAmount =
+                    originalAmount.multiply(discount).divide(new BigDecimal("10"), 2, RoundingMode.HALF_UP);
+            derateAmount = originalAmount.subtract(orderAmount);
+        }
+        //3.4.3 如果是VIP用户且专辑设置VIP用户折扣,则订单价=原价*VIP用户折扣
+        if (isVIP && vipDiscount.doubleValue() != -1) {
+            orderAmount =
+                    originalAmount.multiply(vipDiscount).divide(new BigDecimal("10"), 2, RoundingMode.HALF_UP);
+            derateAmount = originalAmount.subtract(orderAmount);
+        }
+        //3.5 封装订单明细列表、优惠列表
+        List<OrderDetailVo> orderDetailVoList = new ArrayList<>();
+        OrderDetailVo orderDetailVo = new OrderDetailVo();
+        orderDetailVo.setItemId(albumId);
+        orderDetailVo.setItemName("专辑:" + albumInfo.getAlbumTitle());
+        orderDetailVo.setItemUrl(albumInfo.getCoverUrl());
+        orderDetailVo.setItemPrice(originalAmount);
+        orderDetailVoList.add(orderDetailVo);
+
+        //3.6 封装订单优惠列表
+        List<OrderDerateVo> orderDerateVoList = new ArrayList<>();
+
+        if (originalAmount.compareTo(orderAmount) == 1) {
+            OrderDerateVo orderDerateVo = new OrderDerateVo();
+            orderDerateVo.setDerateType(ORDER_DERATE_ALBUM_DISCOUNT);
+            orderDerateVo.setDerateAmount(derateAmount);
+            orderDerateVo.setRemarks("专辑限时减免:" + derateAmount);
+            orderDerateVoList.add(orderDerateVo);
+        }
+
+        orderInfoVo.setOriginalAmount(originalAmount);
+        orderInfoVo.setOrderAmount(orderAmount);
+        orderInfoVo.setDerateAmount(derateAmount);
+        //5.2 为商品列表、优惠列表赋值
+        orderInfoVo.setOrderDetailVoList(orderDetailVoList);
+        orderInfoVo.setOrderDerateVoList(orderDerateVoList);
+
+        //5.3 为订单VO其他杂项赋值:购买商品类别
+        orderInfoVo.setItemType(tradeVo.getItemType());
+        //5.4 流水号、时间戳及签名
+        this.generateTradeNo(orderInfoVo);
+        this.generateSign(orderInfoVo);
+    }
+}

+ 74 - 0
service/service-order/src/main/java/com/atguigu/tingshu/order/pattern/strategy/TrackTradeOrderStrategy.java

@@ -0,0 +1,74 @@
+package com.atguigu.tingshu.order.pattern.strategy;
+
+import cn.hutool.core.lang.Assert;
+import com.atguigu.tingshu.album.AlbumFeignClient;
+import com.atguigu.tingshu.model.album.AlbumInfo;
+import com.atguigu.tingshu.model.album.TrackInfo;
+import com.atguigu.tingshu.order.pattern.AbstractTradeOrderStrategy;
+import com.atguigu.tingshu.vo.order.OrderDetailVo;
+import com.atguigu.tingshu.vo.order.OrderInfoVo;
+import com.atguigu.tingshu.vo.order.TradeVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 商品类别为声音:策略实现类
+ * @author: atguigu
+ * @create: 2025-03-25 16:24
+ */
+@Component("1002")
+public class TrackTradeOrderStrategy extends AbstractTradeOrderStrategy {
+
+    @Autowired
+    private AlbumFeignClient albumFeignClient;
+    /**
+     * 处理结算商品类别为:声音
+     * @param tradeVo
+     * @return
+     */
+    @Override
+    public void handleTrade(TradeVo tradeVo, OrderInfoVo orderInfoVo) {
+        //4.处理购买商品类别:声音
+        //4.1 远程调用"专辑服务"获取待结算声音列表
+        Long trackId = tradeVo.getItemId();
+        List<TrackInfo> waitBuyTrackList = albumFeignClient.getWaitBuyTrackList(trackId, tradeVo.getTrackCount()).getData();
+        Assert.notNull(waitBuyTrackList, "不存在待结算商品");
+
+        //4.2 远程调用"专辑服务"查询专辑信息,得到声音单价
+        Long albumId = waitBuyTrackList.get(0).getAlbumId();
+        AlbumInfo albumInfo = albumFeignClient.getAlbumInfo(albumId).getData();
+        Assert.notNull(albumInfo, "声音所属专辑:{}不存在", albumId);
+        BigDecimal price = albumInfo.getPrice();
+
+        //4.3 计算相关价格 声音不支持折扣
+        BigDecimal originalAmount = price.multiply(BigDecimal.valueOf(tradeVo.getTrackCount()));
+        BigDecimal orderAmount = originalAmount;
+
+        //4.4 封装订单明细列表
+        List<OrderDetailVo> orderDetailVoList = waitBuyTrackList
+                .stream()
+                .map(trackInfo -> {
+                    OrderDetailVo orderDetailVo = new OrderDetailVo();
+                    orderDetailVo.setItemId(trackInfo.getId());
+                    orderDetailVo.setItemName("声音:" + trackInfo.getTrackTitle());
+                    orderDetailVo.setItemUrl(trackInfo.getCoverUrl());
+                    orderDetailVo.setItemPrice(price);
+                    return orderDetailVo;
+                }).collect(Collectors.toList());
+
+        orderInfoVo.setOriginalAmount(originalAmount);
+        orderInfoVo.setOrderAmount(orderAmount);
+        //5.2 为商品列表赋值
+        orderInfoVo.setOrderDetailVoList(orderDetailVoList);
+
+        //5.3 为订单VO其他杂项赋值:购买商品类别
+        orderInfoVo.setItemType(tradeVo.getItemType());
+        //5.4 流水号、时间戳及签名
+        this.generateTradeNo(orderInfoVo);
+        this.generateSign(orderInfoVo);
+    }
+}

+ 17 - 0
service/service-order/src/main/java/com/atguigu/tingshu/order/pattern/strategy/TradeOrderStrategy.java

@@ -0,0 +1,17 @@
+package com.atguigu.tingshu.order.pattern.strategy;
+
+import com.atguigu.tingshu.vo.order.OrderInfoVo;
+import com.atguigu.tingshu.vo.order.TradeVo;
+
+/**
+ * 订单结算抽象接口
+ */
+public interface TradeOrderStrategy {
+
+    /**
+     * 不同商品订单结算
+     * @param tradeVo
+     * @return
+     */
+    public void handleTrade(TradeVo tradeVo, OrderInfoVo orderInfoVo);
+}

+ 78 - 0
service/service-order/src/main/java/com/atguigu/tingshu/order/pattern/strategy/VIPTradeOrderStrategy.java

@@ -0,0 +1,78 @@
+package com.atguigu.tingshu.order.pattern.strategy;
+
+import cn.hutool.core.lang.Assert;
+import com.atguigu.tingshu.model.user.VipServiceConfig;
+import com.atguigu.tingshu.order.pattern.AbstractTradeOrderStrategy;
+import com.atguigu.tingshu.user.client.UserFeignClient;
+import com.atguigu.tingshu.vo.order.OrderDerateVo;
+import com.atguigu.tingshu.vo.order.OrderDetailVo;
+import com.atguigu.tingshu.vo.order.OrderInfoVo;
+import com.atguigu.tingshu.vo.order.TradeVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.atguigu.tingshu.common.constant.SystemConstant.ORDER_DERATE_VIP_SERVICE_DISCOUNT;
+
+/**
+ * 商品类别为VIP:策略实现类
+ * @author: atguigu
+ * @create: 2025-03-25 16:24
+ */
+@Component("1003")
+public class VIPTradeOrderStrategy extends AbstractTradeOrderStrategy {
+
+    @Autowired
+    private UserFeignClient userFeignClient;
+
+    /**
+     * 处理结算商品类别为:VIP会员
+     * @param tradeVo
+     * @return
+     */
+    @Override
+    public void handleTrade(TradeVo tradeVo, OrderInfoVo orderInfoVo) {
+        //2.1 远程调用"用户服务"获取套餐详情
+        VipServiceConfig vipServiceConfig = userFeignClient.getVipServiceConfig(tradeVo.getItemId()).getData();
+        Assert.notNull(vipServiceConfig, "套餐:{}不存在", tradeVo.getItemId());
+        //2.2 计算订单相关价格 订单价=原价-减免价
+        BigDecimal originalAmount = vipServiceConfig.getPrice();
+        BigDecimal orderAmount = vipServiceConfig.getDiscountPrice();
+        BigDecimal derateAmount = originalAmount.subtract(orderAmount);
+
+        //2.3 封装订单明细列表
+        List<OrderDetailVo> orderDetailVoList = new ArrayList<>();
+        OrderDetailVo orderDetailVo = new OrderDetailVo();
+        orderDetailVo.setItemId(tradeVo.getItemId());
+        orderDetailVo.setItemName("VIP套餐:" + vipServiceConfig.getName());
+        orderDetailVo.setItemUrl(vipServiceConfig.getImageUrl());
+        orderDetailVo.setItemPrice(originalAmount);
+        orderDetailVoList.add(orderDetailVo);
+
+        //2.4 封装订单优惠列表
+        List<OrderDerateVo> orderDerateVoList = new ArrayList<>();
+        if (originalAmount.compareTo(orderAmount) == 1) {
+            OrderDerateVo orderDerateVo = new OrderDerateVo();
+            //订单减免类型 1405-专辑折扣 1406-VIP服务折
+            orderDerateVo.setDerateType(ORDER_DERATE_VIP_SERVICE_DISCOUNT);
+            orderDerateVo.setDerateAmount(derateAmount);
+            orderDerateVo.setRemarks("套餐限时减免:" + derateAmount);
+            orderDerateVoList.add(orderDerateVo);
+        }
+        orderInfoVo.setOriginalAmount(originalAmount);
+        orderInfoVo.setOrderAmount(orderAmount);
+        orderInfoVo.setDerateAmount(derateAmount);
+        //5.2 为商品列表、优惠列表赋值
+        orderInfoVo.setOrderDetailVoList(orderDetailVoList);
+        orderInfoVo.setOrderDerateVoList(orderDerateVoList);
+
+        //5.3 为订单VO其他杂项赋值:购买商品类别
+        orderInfoVo.setItemType(tradeVo.getItemType());
+        //5.4 流水号、时间戳及签名
+        this.generateTradeNo(orderInfoVo);
+        this.generateSign(orderInfoVo);
+    }
+}

+ 23 - 14
service/service-order/src/main/java/com/atguigu/tingshu/order/service/impl/OrderInfoServiceImpl.java

@@ -3,24 +3,21 @@ package com.atguigu.tingshu.order.service.impl;
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.lang.Assert;
-import cn.hutool.core.util.IdUtil;
 import com.atguigu.tingshu.account.AccountFeignClient;
 import com.atguigu.tingshu.album.AlbumFeignClient;
 import com.atguigu.tingshu.common.constant.RedisConstant;
 import com.atguigu.tingshu.common.execption.GuiguException;
 import com.atguigu.tingshu.common.result.Result;
 import com.atguigu.tingshu.common.util.AuthContextHolder;
-import com.atguigu.tingshu.model.album.AlbumInfo;
-import com.atguigu.tingshu.model.album.TrackInfo;
 import com.atguigu.tingshu.model.order.OrderDerate;
 import com.atguigu.tingshu.model.order.OrderDetail;
 import com.atguigu.tingshu.model.order.OrderInfo;
-import com.atguigu.tingshu.model.user.VipServiceConfig;
 import com.atguigu.tingshu.order.helper.SignHelper;
 import com.atguigu.tingshu.order.mapper.OrderDerateMapper;
 import com.atguigu.tingshu.order.mapper.OrderDetailMapper;
 import com.atguigu.tingshu.order.mapper.OrderInfoMapper;
+import com.atguigu.tingshu.order.pattern.factory.TradeOrderStrategyFactory;
+import com.atguigu.tingshu.order.pattern.strategy.TradeOrderStrategy;
 import com.atguigu.tingshu.order.service.OrderDetailService;
 import com.atguigu.tingshu.order.service.OrderInfoService;
 import com.atguigu.tingshu.user.client.UserFeignClient;
@@ -29,7 +26,6 @@ import com.atguigu.tingshu.vo.order.OrderDerateVo;
 import com.atguigu.tingshu.vo.order.OrderDetailVo;
 import com.atguigu.tingshu.vo.order.OrderInfoVo;
 import com.atguigu.tingshu.vo.order.TradeVo;
-import com.atguigu.tingshu.vo.user.UserInfoVo;
 import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
 import com.baomidou.mybatisplus.core.toolkit.IdWorker;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -40,10 +36,9 @@ import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.data.redis.core.script.DefaultRedisScript;
 import org.springframework.stereotype.Service;
 
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.*;
-import java.util.concurrent.TimeUnit;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
 import java.util.stream.Collectors;
 
 import static com.atguigu.tingshu.common.constant.SystemConstant.*;
@@ -77,7 +72,21 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo
     @Autowired
     private AccountFeignClient accountFeignClient;
 
+    @Autowired
+    private TradeOrderStrategyFactory tradeOrderStrategyFactory;
+
 
+    @Override
+    public OrderInfoVo trade(Long userId, TradeVo tradeVo) {
+        //1.创建订单VO
+        OrderInfoVo orderInfoVo = new OrderInfoVo();
+        //2.获取购买商品类别:付款项目类型: 1001-专辑 1002-声音 1003-vip会员
+        String itemType = tradeVo.getItemType();
+        //3.从工厂获取策略实现类对象
+        TradeOrderStrategy tradeOrderStrategy = tradeOrderStrategyFactory.getTradeOrderStrategy(itemType);
+        tradeOrderStrategy.handleTrade(tradeVo, orderInfoVo);
+        return orderInfoVo;
+    }
     /**
      * 对购买商品(VIP会员、专辑、声音)封装订单结算页所需要数据
      *
@@ -85,11 +94,13 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo
      * @param tradeVo {购买商品类别,商品ID,声音数量}
      * @return
      */
-    @Override
+    /*@Override
     public OrderInfoVo trade(Long userId, TradeVo tradeVo) {
         //1.创建订单VO
         OrderInfoVo orderInfoVo = new OrderInfoVo();
 
+        //获取购买商品类别:付款项目类型: 1001-专辑 1002-声音 1003-vip会员
+        String itemType = tradeVo.getItemType();
         //1.1.初始化订单结算页三个价格:原价、减免价、订单价
         BigDecimal originalAmount = new BigDecimal("0.00");
         BigDecimal derateAmount = new BigDecimal("0.00");
@@ -98,8 +109,6 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo
         List<OrderDetailVo> orderDetailVoList = new ArrayList<>();
         List<OrderDerateVo> orderDerateVoList = new ArrayList<>();
 
-        //获取购买商品类别:付款项目类型: 1001-专辑 1002-声音 1003-vip会员
-        String itemType = tradeVo.getItemType();
         //2.处理购买商品类别:VIP套餐
         if (ORDER_ITEM_TYPE_VIP.equals(itemType)) {
             //2.1 远程调用"用户服务"获取套餐详情
@@ -238,7 +247,7 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo
         orderInfoVo.setSign(sign);
         //6.响应订单VO
         return orderInfoVo;
-    }
+    }*/
 
     /**
      * 提交订单