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

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

app端操作流程:

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

app端拼团:

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

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";@Beanpublic Queue delayDonationQueue() {return QueueBuilder.durable(DELAY_GROUP_QUEUE).withArgument("x-dead-letter-exchange", GROUP_EXCHANGE).withArgument("x-dead-letter-routing-key", GROUP_ROUTINGKEY).build();}@Beanpublic Queue donationQueue() {return QueueBuilder.durable(GROUP_QUEUE).build();}@Beanpublic Exchange delayDonationExchange() {return ExchangeBuilder.directExchange(DELAY_GROUP_EXCHANGE).durable(true).build();}@Beanpublic Exchange donationExchange() {return ExchangeBuilder.directExchange(GROUP_EXCHANGE).durable(true).build();}@Beanpublic Binding delayDonationBinding() {return BindingBuilder.bind(delayDonationQueue()).to(delayDonationExchange()).with(GROUP_ROUTINGKEY).noargs();}@Beanpublic 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);@Autowiredprivate RabbitTemplate rabbitTemplate;@Autowiredprivate 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 保持和以前一样的接口传值对象,所以用listList<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.QueryGoodsPriceRespVoqueryGoodsPriceRespVo2 = 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分布式锁+1try {// 库存-1redisTemplate.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() {@Overridepublic 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.QueryUserGroupPurchaseStatusReqVoqueryUserGroupPurchaseStatusReqVo2 = 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.QueryUserGroupPurchaseStatusReqVoqueryUserGroupPurchaseStatusReqVo2 = 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());}// 提交订单成功返回参数// 查询支付回调地址与数据一起返回给前段//  加销量  ygfList<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, "提交成功");

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

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

五一节秒杀、团购 -- 商城总结相关推荐

  1. uniapp团购商城源码在哪里下载?

    uniapp团购商城源码即以在线团购的形式为基础,用户通过平台分享的方式向周围的人发出拼团申请或直接在平台上等待他人拼单,拼单完成后,用户可通过拼团的方式以团购价购得商品,反之,若拼团不成功则会退款. ...

  2. HTML+CSS+JS商城网站设计——蛋糕团购商城模板 (4页) 蛋糕团购网页设计制作 简单静态HTML网页作品 商城网页作业成品 网购网站模板

    HTML5期末大作业:蛋糕团购商城网站设计--蛋糕团购商城模板 (4页) 蛋糕团购网页设计制作 简单静态HTML网页作品 商城网页作业成品 一.作品展示 二.文件目录 三.代码实现 <!doct ...

  3. HTML5期末大作业:商城网站设计——仿团购商城(1页) 简单个人网页设计作业 静态HTML旅行主题网页作业 DW个人网站模板下载 大学生简单个人网页作品代码 个人网页制作 学生个人网页Dreamwe

    HTML5期末大作业:商城网站设计--仿团购商城(1页) 简单个人网页设计作业 静态HTML旅行主题网页作业 DW个人网站模板下载 大学生简单个人网页作品代码 个人网页制作 学生个人网页Dreamwe ...

  4. 多模板DIY代付社区团购商城小程序开发

    多模板DIY代付社区团购商城小程序开发 后台功能 商家端强大基础功能.店铺管理.商品管理.订单管理.会员管理.营销管理.财务管理.分销配置.商城设置.系统配置.模板市场.实体商品.订单列表.会员信息. ...

  5. java项目第17期-小程序团购+商城源码【毕业设计】

    java项目第17期-小程序团购+代理商城源码 1.产品介绍 java小程序+大后台web商城源码 基于ssm的一款电子商城,系统采用maven的父子结构, 1.后台web商城包含的模块有: 会员管理 ...

  6. 基于Java的社区团购系统丨团购商城系统

    <基于Java的社区团购系统>该项目含有源码.论文等资料.配套开发软件.软件安装教程.项目发布教程等 使用技术: 开发语言:Java 框架:ssm 技术:JSP JDK版本:JDK1.8 ...

  7. HTML+CSS大作业——仿团购商城(1页) 简单个人网页设计作业 静态HTML旅行主题网页作业 DW个人网站模板下载 大学生简单个人网页作品代码 个人网页制作 学生个人网页Dreamwe

    HTML5期末大作业 文章目录 HTML5期末大作业 一.作品展示 二.文件目录 三.代码实现 四.学习资料 一.作品展示 二.文件目录 三.代码实现 <!doctype html> &l ...

  8. 基于PHP+html+MySQL的团购商城电商平台设计

    目录 目录 摘 要 1 Abstract 2 目录 3 商家评分更新触发器(shop_star_update) 10 5 用户年龄检查触发器(check_user_age) 11 5 商品详情检查触发 ...

  9. HTML5期末大作业:蛋糕团购商城网站设计——蛋糕团购商城模板 (4页) 蛋糕团购网页设计制作 简单静态HTML网页作品 商城网页作业成品 网购网站模板

    常见网页设计作业题材有 个人. 美食. 公司. 学校. 旅游. 电商. 宠物. 电器. 茶叶. 家居. 酒店. 舞蹈. 动漫. 明星. 服装. 体育. 化妆品. 物流. 环保. 书籍. 婚纱. 军事. ...

最新文章

  1. saspython知乎_评分模型效用度量指标如何解析?(含Python、R、SAS代码)
  2. 【数据库】MongoDB数据库的操作及练习
  3. matlab imwrite函数保存jpg格式图像丢失数据或改变图像
  4. nat123软件windows版
  5. 全向轮底盘磁导轨寻迹
  6. 【转】C#执行rar,zip文件压缩的几种方法及我遇到的坑总结
  7. Eclipse如何打出war包
  8. 专访阿里云技术掌舵人蒋江伟:中台是企业的未来
  9. hashmap删除指定key_Java集合:HashMap底层实现和原理(源码解析)
  10. 极路由1 1s 2 3 刷机 / 恢复 /强刷教程
  11. google code的使用方法
  12. 基于Neo4j计算网络节点中心性(Closeness、betweenness Centrality)
  13. QQ vx 刷屏神器!!
  14. bootstrap实现开关切换
  15. 三大强者效应:鲶鱼效应,鳄鱼效应,鲦鱼效应
  16. STM32的USART3(PC10,PC11)异常,USART3_TX(PC10)持续低电平(0V)
  17. Linux杀掉挖矿病毒(qW3xT.2)
  18. 不同平台下移植x264
  19. windowsXP命令集锦
  20. TextCNN文本分类(keras实现)

热门文章

  1. 广西北海打击涉嫌传销“一日游” 一周查获7辆涉传大巴
  2. ADS系列 - 定向耦合器设计教程1
  3. 刘二大人 PyTorch深度学习实践 笔记 P6 逻辑斯蒂回归
  4. XML fragments parsed from previous mappers already contains value for XXX
  5. python 分类变量编码_深度学习编码分类变量的3种方法——AIU人工智能学院
  6. SqlServer数据库测评
  7. 设计模式 ---- 工厂模式
  8. 欢迎光临Simon个人空间
  9. SQL Server 替换越南语(越南文)音标SQL脚本
  10. PowerDesigner导出ER图和表结构方法