五一节秒杀、团购 -- 商城总结

        大家好,好长时间没有更新博客。是因为单位五一节针对广大用户发起了一次秒杀以及拼团的活动。 在肝了2周后活动正式上线并取得不错的销售成绩,今天正好来总结一下相关的业务以及使用的相关技术。 
      
        说起秒杀、拼团作为程序员的小伙伴们肯定都十分熟悉,但是亲力亲为完成秒杀的可能不多,比如我!在开发的时候也遇到了很多坑,今天就给小伙伴们总结下其中遇到的坑。
        
        秒杀:所谓“秒杀”,就是网络卖家发布一些超低价格的商品,所有买家在同一时间网上抢购的一种销售方式。由于商品价格低廉,往往一上架就被抢购一空,有时只用一秒钟。秒杀就会涉及到大量的用户在同一个时间段对同一个商品进行操作,这也就是我们说的高并发。由于高并发的场景,由之衍生出来的就会有另一个问题--数据的可靠性。


        首先我们先总结一下整个流程:
        管理端结构:

       app端操作流程:

        

管理端的业务在上图处理的比较清晰,这里我就不做过多的介绍。重点是放在app端的业务和设计到的相关技术做一个大致的描写。


app端拼团:

     1.首先是用户有意向发起拼团,下单成功后生成订单,此时的订单状态为 待成团 ,同时会生成一个口令,这个口令里面存了该用户相关信息、产品信息。同时会在mq中启动一个定时任务,如果早指定的拼团时间内没有人拼团就会发起退款退券操作。并将团长订单信息存入拼团活动表。

扫描二维码关注公众号,回复: 11185204 查看本文章

mq配置如下:

/**
 * Author: sangfor
 * Date: 2020/4/21 18:20
 */
@Configuration
public class RabbitmqQueue {
    /*------------------------拼团--------------------------------*/
    public final static String GROUP_EXCHANGE = "GROUP_EXCHANGE";
    public final static String DELAY_GROUP_EXCHANGE = "DELAY_GROUP_EXCHANGE";

    public final static String GROUP_QUEUE = "GROUP_QUEUE";
    public final static String DELAY_GROUP_QUEUE = "DELAY_GROUP_QUEUE";

    public final static String GROUP_ROUTINGKEY = "GROUP_ROUTINGKEY";

    @Bean
    public Queue delayDonationQueue() {
        return QueueBuilder.durable(DELAY_GROUP_QUEUE)
                .withArgument("x-dead-letter-exchange", GROUP_EXCHANGE)
                .withArgument("x-dead-letter-routing-key", GROUP_ROUTINGKEY)
                .build();
    }

    @Bean
    public Queue donationQueue() {
        return QueueBuilder.durable(GROUP_QUEUE)
                .build();
    }
    @Bean
    public Exchange delayDonationExchange() {
        return ExchangeBuilder
                .directExchange(DELAY_GROUP_EXCHANGE)
                .durable(true)
                .build();
    }
    @Bean
    public Exchange donationExchange() {
        return ExchangeBuilder
                .directExchange(GROUP_EXCHANGE)
                .durable(true)
                .build();
    }
    @Bean
    public Binding delayDonationBinding() {
        return BindingBuilder.bind(delayDonationQueue())
                .to(delayDonationExchange())
                .with(GROUP_ROUTINGKEY).noargs();
    }
    @Bean
    public Binding donationBinding() {
        return BindingBuilder.bind(donationQueue())
                .to(donationExchange())
                .with(GROUP_ROUTINGKEY).noargs();
    }


}

提供者和消费者:

/**
 * Author: sangfor
 * Date: 2020/4/21 18:25
 */
@Component
@Slf4j
public class RabbitMqService {

    private static final Logger logger = LoggerFactory.getLogger(RabbitMqService.class);

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private SalesOrderInfoServiceImpl salesOrderInfoService;

    /**
     *
     * @param data 数据
     * @param expiration 延时 单位毫秒
     */
    public void sendMessage(Object data, String expiration) {
        // 消息发送时间
        logger.info("准备发送拼团延时消息" + JSONObject.toJSONString(data));
        // 设置发送时间,开始发送
        try {
            CorrelationData correlationId = new CorrelationData(String.valueOf(ObjectId.get()));
            //根据任务类型,进不同队列
            //指定路由,指定routingKey,指定传输数据,指定消息,CorrelationData(可靠性投递)
            rabbitTemplate.convertAndSend(RabbitmqQueue.DELAY_GROUP_EXCHANGE, RabbitmqQueue.GROUP_ROUTINGKEY, data,
                    // 设置message过期时间
                    message -> {
                        message.getMessageProperties().setExpiration(expiration);
                        return message;
                    },
                    // 消息可靠性投递
                    correlationId
            );
            logger.info("------------------------发送拼团延时消息成功,延时" + expiration);
        } catch (AmqpException e) {
            logger.error("已购代帮消息发送失败: {}", e);
        }
    }


    @RabbitListener(queues = RabbitmqQueue.GROUP_QUEUE)
    @RabbitHandler  // 此注解加上之后可以接受对象型消息
    public void messageListener(@Payload String data, Message message, Channel channel)
            throws Exception {
        log.info("---------------------------接受成团延时消息----------------------------");
        try {
            salesOrderInfoService.groupFail(data);
        } catch (Exception e) {
            log.error("成团失败业务处理异常", e);
        }
        // 消息确认机制
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }


}

     2.口令解析:将这个口令复制到app中就能解析出来分享人以及分享的产品信息。

     3.拼单成功,首先通过数据库中的拼团活动中的团长及其订单信息取出并修改订单状态,然后再对团员下单。

     4.下单失败,对团长的订单进行退款退券,同时修改订单状态。

   

秒杀:

       1.秒杀列表,秒杀列表是放在redis中的,采用了两个结构,hash 、String。目前采用这两种redis的数据结构比较合理的。

        list:

             key -- 活动的时间段id :periodId  

             vaule -- 商品信息  goodsVo

       String:

              key -- 商品id :goodsId

             value -- 库存 :count

       2.秒杀活动中的高并发和数据安全性处理。

          处理秒杀活动的核心处理点就是对秒杀商品的库存加锁以及利用mq做延时下单处理。废话不多说直接上代码:

 commitOrderByActivityRequestVo.setSourceType(goodsGoodsService.selectMallTypeByGoodsId(commitOrderByActivityRequestVo.getGoodsId()));

        JSONObject json = new JSONObject();
        try {
            Optional<CustomerLoginResponse> optional = Optional.ofNullable(LoginSessionUtils.getUser());
            optional.ifPresent(m -> commitOrderByActivityRequestVo.setAppUserId(m.getCustomerId()));
        } catch (Exception e) {
            log.error("==>  团购秒杀订单获取用户ID异常 " + e.getMessage());
            return ApiResponse.buildResponse(ApiConst.Code.CODE_COMMON_ERROR.code(), json, "团购秒杀订单获取用户ID异常");
        }

        if (commitOrderByActivityRequestVo.getGoodsCount() == 0) {
            return ApiResponse.buildResponse(ApiConst.Code.CODE_COMMON_ERROR.code(), json, "商品数量不能为0");
        }
        if (commitOrderByActivityRequestVo.getArea() == "" || commitOrderByActivityRequestVo.getCity() == "") {
            return ApiResponse.buildResponse(ApiConst.Code.CODE_COMMON_ERROR.code(), json, "收货地址不完整");
        }

        // ====================验证是否达到了购买上限======================
        CheckActivityLimtStuatusReqVo checkActivityLimtStuatusReqVo = new CheckActivityLimtStuatusReqVo();
        checkActivityLimtStuatusReqVo.setType(commitOrderByActivityRequestVo.getOrderType());
        BeanUtils.copyProperties(commitOrderByActivityRequestVo, checkActivityLimtStuatusReqVo);
        if (checkActivityLimtStuatusReqVo.getType() == 1) {
            int limit;
            //区分商城和电子城秒杀
            if (commitOrderByActivityRequestVo.getSourceType() < 2) {
                limit = seckillService.querySeckillLimitStuatus(checkActivityLimtStuatusReqVo);
            } else {
                //同名类
                com.cdzg.shop.cooperation.service.api.vo.request.activity.group.CheckActivityLimtStuatusReqVo checkActivityLimtStuatusReqVo2 = new com.cdzg.shop.cooperation.service.api.vo.request.activity.group.CheckActivityLimtStuatusReqVo();
                BeanCopyUtil.copyProperties(checkActivityLimtStuatusReqVo, checkActivityLimtStuatusReqVo2);
                limit = cooperationSeckillService.querySeckillLimitStuatus(checkActivityLimtStuatusReqVo2);
            }
            String goodsId = checkActivityLimtStuatusReqVo.getGoodsId();
            String activityId = checkActivityLimtStuatusReqVo.getActivityId();
            String appUserId = checkActivityLimtStuatusReqVo.getAppUserId();
            int limtGoodsCount = orderService.queryOrderNumberbyActivitySeckill(goodsId, activityId, appUserId);
            if (commitOrderByActivityRequestVo.getGoodsCount() > limit) {
                return ApiResponse.buildResponse(ApiConst.Code.CODE_COMMON_ERROR.code(), json, "超过活动购买上限!");
            }
            limtGoodsCount = limtGoodsCount + commitOrderByActivityRequestVo.getGoodsCount();
            if (limtGoodsCount > limit) {
                return ApiResponse.buildResponse(ApiConst.Code.CODE_COMMON_ERROR.code(), json, "已达到活动购买上限!");
            }

        } else {
            int limit;
            List<String> list = new ArrayList<>();
            //区分商城来源
            if (commitOrderByActivityRequestVo.getSourceType() > 1) {
                com.cdzg.shop.cooperation.service.api.vo.request.activity.group.CheckActivityLimtStuatusReqVo checkActivityLimtStuatusReqVo2 =
                        new com.cdzg.shop.cooperation.service.api.vo.request.activity.group.CheckActivityLimtStuatusReqVo();
                BeanCopyUtil.copyProperties(checkActivityLimtStuatusReqVo, checkActivityLimtStuatusReqVo2);

                limit = cooperationGroupPurchaseService.queryGroupPurchaseLimitStuatus(checkActivityLimtStuatusReqVo2);
                list = cooperationGroupPurchaseService.queryGroupPurchaseOrder(checkActivityLimtStuatusReqVo2);
            } else {
                limit = groupPurchaseService.queryGroupPurchaseLimitStuatus(checkActivityLimtStuatusReqVo);
                list = groupPurchaseService.queryGroupPurchaseOrder(checkActivityLimtStuatusReqVo);
            }


            if (list.size() > 0 && !list.isEmpty()) {
                int i = orderService.queryOrderNumberbyActivity(list);
                if (i >= limit) {
                    return ApiResponse.buildResponse(ApiConst.Code.CODE_COMMON_ERROR.code(), json, "已达到活动购买上限!");
                }
            }
        }

        // ====================验证完毕======================


        Object object = redisTemplate.opsForValue().get(commitOrderByActivityRequestVo.getPayCode());

        if (object == null) {
            return ApiResponse.buildResponse(ApiConst.Code.CODE_COMMON_ERROR.code(), json, "交易超时,请重新返回结算页面进行提交");
        }
        if (object.toString().equals("0")) {
            redisTemplate.opsForValue().set(commitOrderByActivityRequestVo.getPayCode(), "1", 600, TimeUnit.SECONDS);
        } else {
            return ApiResponse.buildResponse(ApiConst.Code.CODE_COMMON_ERROR.code(), json, "请勿重复提交");
        }

        // 验证活动是否在进行中
        if (commitOrderByActivityRequestVo.getOrderType() == 1) {
            Object querySecKillActivityStatusRespVo;
            if (commitOrderByActivityRequestVo.getSourceType() < 2) {
                querySecKillActivityStatusRespVo = seckillService.QuerySecKillActivityStatus(commitOrderByActivityRequestVo.getActivityId());
            } else {
                querySecKillActivityStatusRespVo = cooperationSeckillService.QuerySecKillActivityStatus(commitOrderByActivityRequestVo.getActivityId());
            }
            if (querySecKillActivityStatusRespVo == null) {
                return ApiResponse.buildResponse(ApiConst.Code.CODE_COMMON_ERROR.code(), json, "该秒杀活动未在进行中!");
            }
        } else {
            //区分商城来源
            int i = 0;
            if (commitOrderByActivityRequestVo.getSourceType() > 1) {
                i = cooperationGroupPurchaseService.queryGroupPurchaseStatus(commitOrderByActivityRequestVo.getActivityId());
            } else {
                i = groupPurchaseService.queryGroupPurchaseStatus(commitOrderByActivityRequestVo.getActivityId());
            }
            if (i != 2) {
                return ApiResponse.buildResponse(ApiConst.Code.CODE_COMMON_ERROR.code(), json, "该团购活动未在进行中!");
            }
        }


        // 拿出SKUID 保持和以前一样的接口传值对象,所以用list
        List<String> skuIdList = new ArrayList<>();
        skuIdList.add(commitOrderByActivityRequestVo.getSkuId());

        // 查询商品信息
        List<GoodsByCartRepVo> goodsCartBySkuId = goodsSkuService.findGoodsCartBySkuId(skuIdList);


        //拆分数据生成子订单
        List<AddOrderItemByActivityRequest> addOrderItemList = new ArrayList<>();
        AddOrderItemByActivityRequest addOrderItemRequest = new AddOrderItemByActivityRequest();

        // 设置子订单参数
        String payNumber = String.valueOf(ObjectId.get());
        commitOrderByActivityRequestVo.setId(String.valueOf(ObjectId.get()));
        commitOrderByActivityRequestVo.setOrderId(String.valueOf(ObjectId.get()));
        commitOrderByActivityRequestVo.setOrderNumber(String.valueOf(ObjectId.get()));
        commitOrderByActivityRequestVo.setPayNumber(payNumber);
        commitOrderByActivityRequestVo.setSourceType(goodsCartBySkuId.get(0).getIsWelfareGoods());
        BeanUtils.copyProperties(commitOrderByActivityRequestVo, addOrderItemRequest);

        // 运算订单总金额
        BigDecimal totalMoney = new BigDecimal(commitOrderByActivityRequestVo.getGoodsRealPrice()).multiply(new BigDecimal((commitOrderByActivityRequestVo.getGoodsCount()))).add(new BigDecimal(commitOrderByActivityRequestVo.getFreight()));
        addOrderItemRequest.setTotalMoney(totalMoney);
        addOrderItemList.add(addOrderItemRequest);

        // 子订单金额参数设置完毕

        int totalOriginalPrice = commitOrderByActivityRequestVo.getGoodsOriginalPrice() * commitOrderByActivityRequestVo.getGoodsCount() + commitOrderByActivityRequestVo.getFreight();


        // 金额校验开始 1 秒杀 2 团购

        JSONObject jsonObject1 = new JSONObject();
        if (commitOrderByActivityRequestVo.getOrderType() == 1) {
            GoodsSkuReqVo goodsSkuReqVo = new GoodsSkuReqVo();
            goodsSkuReqVo.setSeckillId(commitOrderByActivityRequestVo.getActivityId());
            goodsSkuReqVo.setSkuId(skuIdList.get(0));
            GoodsSkuInfoDTO seckillGoodsSkuInfo = null;
            if (commitOrderByActivityRequestVo.getSourceType() < 2) {
                seckillGoodsSkuInfo = seckillService.getGoodsSkuInfo(goodsSkuReqVo);
            } else {
                com.cdzg.shop.cooperation.service.api.vo.request.activity.seckill.GoodsSkuReqVo goodsSkuReqVo2 = new com.cdzg.shop.cooperation.service.api.vo.request.activity.seckill.GoodsSkuReqVo();
                BeanCopyUtil.copyProperties(goodsSkuReqVo, goodsSkuReqVo2);
                seckillGoodsSkuInfo = BeanCopyUtil.copyProperties(cooperationSeckillService.getGoodsSkuInfo(goodsSkuReqVo2), GoodsSkuInfoDTO.class, 0);
            }
            if (seckillGoodsSkuInfo == null) {
                return ApiResponse.buildResponse(ApiConst.Code.CODE_COMMON_ERROR.code(), json, "没有查询到该活动或商品!");
            }
            long activitySelling = seckillGoodsSkuInfo.getSeckillPrice().multiply(BigDecimal.valueOf(100)).multiply(BigDecimal.valueOf(commitOrderByActivityRequestVo.getGoodsCount())).add(BigDecimal.valueOf(commitOrderByActivityRequestVo.getFreight())).longValue();
            if (!(totalMoney.longValue() == activitySelling)) {
                return ApiResponse.buildResponse(ApiConst.Code.CODE_COMMON_ERROR.code(), json, "订单金额不匹配!提交失败");
            }
        } else {
            String skuId = skuIdList.get(0);
            String groupPurchaseId = commitOrderByActivityRequestVo.getActivityId();
            QueryGoodsPriceRespVo queryGoodsPriceRespVo = new QueryGoodsPriceRespVo();
            //区分商城来源
            if (commitOrderByActivityRequestVo.getSourceType() > 1) {
                com.cdzg.shop.cooperation.service.api.vo.response.activity.group.QueryGoodsPriceRespVo
                        queryGoodsPriceRespVo2 = cooperationGroupPurchaseService.queryGoodsPrice(skuId, groupPurchaseId);
                BeanCopyUtil.copyProperties(queryGoodsPriceRespVo2, queryGoodsPriceRespVo);
            } else {
                queryGoodsPriceRespVo = groupPurchaseService.queryGoodsPrice(skuId, groupPurchaseId);
            }

            if (queryGoodsPriceRespVo == null) {
                return ApiResponse.buildResponse(ApiConst.Code.CODE_COMMON_ERROR.code(), json, "没有查询到该活动或商品!");
            }
            long activitySelling = queryGoodsPriceRespVo.getGroupPurchasePrice().multiply(BigDecimal.valueOf(100)).multiply(BigDecimal.valueOf(commitOrderByActivityRequestVo.getGoodsCount())).add(BigDecimal.valueOf(commitOrderByActivityRequestVo.getFreight())).longValue();
            if (!(totalMoney.longValue() == activitySelling)) {
                return ApiResponse.buildResponse(ApiConst.Code.CODE_COMMON_ERROR.code(), json, "订单金额不匹配!提交失败");
            }
        }

        // 金额校验结束


        // 提交订单
        int i = 0;
        if (commitOrderByActivityRequestVo.getOrderType() == 1) {
            addOrderItemRequest.setOrderType(1);
            String skuId = commitOrderByActivityRequestVo.getSkuId();
            String key = STOCK + commitOrderByActivityRequestVo.getActivityId() + ":" + skuId;
            String lockKey = redissonLock + commitOrderByActivityRequestVo.getActivityId() + ":" + skuId;
            Boolean hasKey = redisTemplate.hasKey(key);
            /**
             * 提交订单,预减库存,利用分布式锁预减库存
             */
            if (hasKey) {
                Boolean flag = RedissonUtil.tryLock(lockKey, TimeUnit.MILLISECONDS, 1000, 1000);
                if (!flag) {
                    return ApiResponse.buildResponse(ApiConst.Code.CODE_COMMON_ERROR.code(), json, "服务器繁忙,请稍后重试");
                }
//                Boolean flag =redisLock.lock(key, 2000);
                log.info("秒杀锁------------>" + flag);
                Integer stock = (Integer) redisTemplate.opsForValue().get(key);
                if (stock < commitOrderByActivityRequestVo.getGoodsCount()) {
                    return ApiResponse.buildResponse(ApiConst.Code.CODE_COMMON_ERROR.code(), json, "商品库存不足");
                }
                if (stock <= 0) {
                    return ApiResponse.buildResponse(ApiConst.Code.CODE_COMMON_ERROR.code(), json, "当前商品已售罄");
                }
            } else {
                log.error("==>  团购秒杀订单获取商品skuId {} 库存异常", skuId);
                return ApiResponse.buildResponse(ApiConst.Code.CODE_COMMON_ERROR.code(), json, "检测商品库存异常");
            }
            // 需要考虑订单取消、订单关闭、订单超时后的缓存库存返还,使用redis分布式锁+1
            try {
                // 库存-1
                redisTemplate.opsForValue().increment(key, -commitOrderByActivityRequestVo.getGoodsCount());
            } catch (Exception e) {
                log.error("=>  分布式锁操作异常 " + e.getMessage());
                log.error("==>  商品SKU {} 预减库存失败 ");
                return ApiResponse.buildResponse(ApiConst.Code.CODE_COMMON_ERROR.code(), json, "提交异常");
            } finally {
                RedissonUtil.unlock(lockKey);
//                redisLock.releaseLock(key);
            }

            log.info("==>  商品SKU {} 预减库存成功 ", skuId);

            // 秒杀订单提交到MQ处理
            Map<String, Object> addOrderItemListMap = new HashMap<>();
            List<Map<String, Object>> secKillOrderMqList = new ArrayList<>();
            CommitOrderSeckillReqVo commitOrderSeckillReqVo = new CommitOrderSeckillReqVo();
            // 建立order_id和秒杀ID的关联关系 用于支付回调的时候
            commitOrderSeckillReqVo.setOrderId(addOrderItemList.get(0).getOrderId());
            commitOrderSeckillReqVo.setSeckillId(commitOrderByActivityRequestVo.getActivityId());
            commitOrderSeckillReqVo.setGoodsId(commitOrderByActivityRequestVo.getGoodsId());
            commitOrderSeckillReqVo.setAppUserId(commitOrderByActivityRequestVo.getAppUserId());
            commitOrderSeckillReqVo.setPayNumber(commitOrderByActivityRequestVo.getPayNumber());
            commitOrderSeckillReqVo.setGoodsCount(commitOrderByActivityRequestVo.getGoodsCount());
            commitOrderSeckillReqVo.setSkuId(commitOrderByActivityRequestVo.getSkuId());
            Map<String, Object> commitOrderSeckillReqVoMap = new HashMap<>();
            addOrderItemListMap.put("addOrderItemListMap", addOrderItemList);
            commitOrderSeckillReqVoMap.put("commitOrderSeckillReqVoMap", commitOrderSeckillReqVo);
            secKillOrderMqList.add(addOrderItemListMap);
            secKillOrderMqList.add(commitOrderSeckillReqVoMap);
            new Thread() {
                @Override
                public void run() {
                    logger.info("==> 开始处理秒杀活动的订单, id: {}");
                    orderService.commitOrderByActivity(addOrderItemList);
                    orderService.commitOrderSeckill(commitOrderSeckillReqVo);
                }
            }.start();
            QueryCallBackAddressRequestVo queryCallBackAddressRequestVo = new QueryCallBackAddressRequestVo();
            queryCallBackAddressRequestVo.setType((short) 5);
            ApiResponse apiResponse = orderItemService.queryCallbackAddress(queryCallBackAddressRequestVo);
            logger.info(apiResponse.getData().toString());
            String jsonObject = JSONObject.toJSONString(apiResponse.getData());
            logger.info(jsonObject);
            jsonObject1 = JSONObject.parseObject(jsonObject);
            logger.info(jsonObject1.toString());
        } else {
            addOrderItemRequest.setOrderType(2);
            String peroidId = commitOrderByActivityRequestVo.getPeroidId();
            String activityId = commitOrderByActivityRequestVo.getActivityId();
            String groupGoodsId = commitOrderByActivityRequestVo.getGroupGoodsId();

            String groupSmallId = null;
            Boolean flag = redisTemplate.hasKey(peroidId + "groupPurchase" + groupGoodsId);
            if (!flag) {
                String groupId = ObjectId.get().toString();
                redisTemplate.opsForValue().set(peroidId + "groupPurchase" + groupGoodsId, groupId);
                redisTemplate.opsForValue().set(groupId, 0);
                groupSmallId = groupId;
                QueryUserGroupPurchaseStatusReqVo queryUserGroupPurchaseStatusReqVo = new QueryUserGroupPurchaseStatusReqVo();
                queryUserGroupPurchaseStatusReqVo.setAppUserId(commitOrderByActivityRequestVo.getAppUserId());
                queryUserGroupPurchaseStatusReqVo.setGroupSmallId(groupId);
                queryUserGroupPurchaseStatusReqVo.setGoodsId(commitOrderByActivityRequestVo.getGoodsId());
                boolean flagUser;
                //区分商城来源
                if (commitOrderByActivityRequestVo.getSourceType() > 1) {
                    com.cdzg.shop.cooperation.service.api.vo.request.activity.group.QueryUserGroupPurchaseStatusReqVo
                            queryUserGroupPurchaseStatusReqVo2 = new com.cdzg.shop.cooperation.service.api.vo.request.activity.group.QueryUserGroupPurchaseStatusReqVo();
                    BeanCopyUtil.copyProperties(queryUserGroupPurchaseStatusReqVo, queryUserGroupPurchaseStatusReqVo2);
                    flagUser = cooperationGroupPurchaseService.queryUserGroupPurchaseStatus(queryUserGroupPurchaseStatusReqVo2);
                } else {
                    flagUser = groupPurchaseService.queryUserGroupPurchaseStatus(queryUserGroupPurchaseStatusReqVo);
                }

                if (flagUser) {
                    return ApiResponse.buildResponse(ApiConst.Code.CODE_COMMON_ERROR.code(), json, "您已经参与了该团购活动!");
                }
            } else {
//                redisLock.lock(peroidId+"groupPurchase"+groupGoodsId, 10);
                String groupId = redisTemplate.opsForValue().get(peroidId + "groupPurchase" + groupGoodsId).toString();
//                redisLock.lock(groupId, 10);
                if (!RedissonUtil.tryLock(redissonLock + peroidId + "groupPurchase" + groupGoodsId, TimeUnit.MILLISECONDS, 1000, 1000) || !RedissonUtil.tryLock(redissonLock + groupId, 1000, 1000)) {
                    return ApiResponse.buildResponse(ApiConst.Code.CODE_COMMON_ERROR.code(), json, "服务器繁忙!请稍后重试");
                }
                int groupCompeleteNumber = Integer.parseInt(redisTemplate.opsForValue().get(groupId).toString());
                if (groupCompeleteNumber == commitOrderByActivityRequestVo.getGroupNumber()) {
                    String groupIdNew = ObjectId.get().toString();
                    redisTemplate.opsForValue().set(peroidId + "groupPurchase" + groupGoodsId, groupIdNew);
                    redisTemplate.opsForValue().set(groupIdNew, 0);
                    RedissonUtil.unlock(redissonLock + peroidId + "groupPurchase" + groupGoodsId);
                    RedissonUtil.unlock(redissonLock + groupId);
//                    redisLock.releaseLock(peroidId+"groupPurchase"+groupGoodsId);
//                    redisLock.releaseLock(groupId);
                    groupSmallId = groupIdNew;
                } else {
                    groupSmallId = groupId;
                    RedissonUtil.unlock(redissonLock + peroidId + "groupPurchase" + groupGoodsId);
                    RedissonUtil.unlock(redissonLock + groupId);
//                    redisLock.releaseLock(peroidId+"groupPurchase"+groupGoodsId);
//                    redisLock.releaseLock(groupId);
                    QueryUserGroupPurchaseStatusReqVo queryUserGroupPurchaseStatusReqVo = new QueryUserGroupPurchaseStatusReqVo();
                    queryUserGroupPurchaseStatusReqVo.setAppUserId(commitOrderByActivityRequestVo.getAppUserId());
                    queryUserGroupPurchaseStatusReqVo.setGroupSmallId(groupId);
                    queryUserGroupPurchaseStatusReqVo.setGoodsId(commitOrderByActivityRequestVo.getGoodsId());
                    boolean flagUser;
                    //区分商城来源
                    if (commitOrderByActivityRequestVo.getSourceType() > 1) {
                        com.cdzg.shop.cooperation.service.api.vo.request.activity.group.QueryUserGroupPurchaseStatusReqVo
                                queryUserGroupPurchaseStatusReqVo2 = new com.cdzg.shop.cooperation.service.api.vo.request.activity.group.QueryUserGroupPurchaseStatusReqVo();
                        BeanCopyUtil.copyProperties(queryUserGroupPurchaseStatusReqVo, queryUserGroupPurchaseStatusReqVo2);
                        flagUser = cooperationGroupPurchaseService.queryUserGroupPurchaseStatus(queryUserGroupPurchaseStatusReqVo2);
                    } else {
                        flagUser = groupPurchaseService.queryUserGroupPurchaseStatus(queryUserGroupPurchaseStatusReqVo);
                    }
                    if (flagUser) {
                        return ApiResponse.buildResponse(ApiConst.Code.CODE_COMMON_ERROR.code(), json, "您已经参与了该团购活动!");
                    }
                }
            }
            // 团购校验和减库存
            int groupPurchaseCount;
            //区分商城来源
            if (commitOrderByActivityRequestVo.getSourceType() > 1) {
                groupPurchaseCount = cooperationGroupPurchaseService.reduceCount(commitOrderByActivityRequestVo.getGroupSkuId(), commitOrderByActivityRequestVo.getGoodsCount());
            } else {
                groupPurchaseCount = groupPurchaseService.reduceCount(commitOrderByActivityRequestVo.getGroupSkuId(), commitOrderByActivityRequestVo.getGoodsCount());
            }

            if (groupPurchaseCount == 0) {
                return ApiResponse.buildResponse(ApiConst.Code.CODE_COMMON_ERROR.code(), json, "团购商品库存不足!");
            }
            orderService.commitOrderByActivity(addOrderItemList);
            CommitGroupOrderReqVo commitGroupOrderReqVo = new CommitGroupOrderReqVo();
            commitGroupOrderReqVo.setAppUserId(commitOrderByActivityRequestVo.getAppUserId());
            commitGroupOrderReqVo.setOrderId(commitOrderByActivityRequestVo.getOrderId());
            commitGroupOrderReqVo.setGroupId(activityId);
            commitGroupOrderReqVo.setGroupNumber(commitOrderByActivityRequestVo.getGroupNumber());
            commitGroupOrderReqVo.setGoodsId(commitOrderByActivityRequestVo.getGoodsId());
            commitGroupOrderReqVo.setGroupSmallId(groupSmallId);
            commitGroupOrderReqVo.setGroupPurchaseEndTime(commitOrderByActivityRequestVo.getGroupPurchaseEndTime());
            commitGroupOrderReqVo.setPeroidId(peroidId);
            commitGroupOrderReqVo.setPayNumber(commitOrderByActivityRequestVo.getPayNumber());
            commitGroupOrderReqVo.setGroupGoodsId(groupGoodsId);
            //区分商城来源
            if (commitOrderByActivityRequestVo.getSourceType() > 1) {
                com.cdzg.shop.cooperation.service.api.vo.request.activity.group.CommitGroupOrderReqVo commitGroupOrderReqVo2 =
                        new com.cdzg.shop.cooperation.service.api.vo.request.activity.group.CommitGroupOrderReqVo();
                BeanCopyUtil.copyProperties(commitGroupOrderReqVo, commitGroupOrderReqVo2);
                cooperationGroupPurchaseService.commitGroupOrder(commitGroupOrderReqVo2);
            } else {
                groupPurchaseService.commitGroupOrder(commitGroupOrderReqVo);
            }
            // 查询回调地址
            QueryCallBackAddressRequestVo queryCallBackAddressRequestVo = new QueryCallBackAddressRequestVo();
            queryCallBackAddressRequestVo.setType((short) 6);
            ApiResponse apiResponse = orderItemService.queryCallbackAddress(queryCallBackAddressRequestVo);
            logger.info(apiResponse.getData().toString());
            String jsonObject = JSONObject.toJSONString(apiResponse.getData());
            logger.info(jsonObject);
            jsonObject1 = JSONObject.parseObject(jsonObject);
            logger.info(jsonObject1.toString());
        }
        // 提交订单成功返回参数
        // 查询支付回调地址与数据一起返回给前段

        //  加销量  ygf
        List<GoodsSaleLogInsertReqVo> batchGoodsSale = new ArrayList<>();
        addOrderItemList.stream().forEach(a -> {
            GoodsSaleLogInsertReqVo goodsSaleLogInsertReqVo = new GoodsSaleLogInsertReqVo();
            goodsSaleLogInsertReqVo.setCreateBy(a.getAppUserId());
            goodsSaleLogInsertReqVo.setGoodsId(a.getGoodsId());
            goodsSaleLogInsertReqVo.setHandleType(0);
            goodsSaleLogInsertReqVo.setSaleCount(a.getGoodsCount());
            goodsSaleLogInsertReqVo.setOrderId(a.getOrderId());
            batchGoodsSale.add(goodsSaleLogInsertReqVo);
        });
//        goodsGoodsService.batchGoodsSaleLogInsert(batchGoodsSale);
        List<Map<String, Object>> listMq = new ArrayList<>();
        Map<String, Object> mapMqRepertory = new HashMap<>();
        Map<String, Object> mapMqSale = new HashMap<>();
        mapMqRepertory.put("batchRepertoryOperationReqVo", "null");
        mapMqSale.put("batchGoodsSale", batchGoodsSale);
        listMq.add(mapMqRepertory);
        listMq.add(mapMqSale);
        rabbitmqUtil.orderUpdateGoods(listMq);
        String url = jsonObject1.getString("url");
        CommitOrderByActivityResponseVo commitOrderByActivityResponseVo = new CommitOrderByActivityResponseVo();
        commitOrderByActivityResponseVo.setPayNumber(payNumber);
        commitOrderByActivityResponseVo.setTotalCouponsAmount(commitOrderByActivityRequestVo.getCouponsAmount());
        commitOrderByActivityResponseVo.setTotalUnionAmount(commitOrderByActivityRequestVo.getUnionAmount());
        commitOrderByActivityResponseVo.setTotalSelling((int) totalMoney.longValue());
        commitOrderByActivityResponseVo.setTotalOriginalPrice(totalOriginalPrice);
        commitOrderByActivityResponseVo.setGoodsFavorablePrice(commitOrderByActivityRequestVo.getGoodsFavorablePrice());
        commitOrderByActivityResponseVo.setBackUrl(url);
        return ApiResponse.buildResponse(ApiConst.Code.CODE_SUCCESS.code(), commitOrderByActivityResponseVo, "提交成功");

          这上面这段代码就是我的五一节电商活动中的秒杀、团购(拼单)的核心代码,希望在做电商的伙伴有帮助!

          铁汁们,三连走一波!爱你们

原创文章 18 获赞 3 访问量 1629

猜你喜欢

转载自blog.csdn.net/qq_39941165/article/details/105946632
今日推荐