1.RabbitMqConfig

/***      * 延时队列交换机*      * 注意这里的交换机类型:CustomExchange*      **      * @return*      */
@Bean
public CustomExchange delayExchange() {Map<String, Object> args = new HashMap<>();args.put("x-delayed-type", "direct");//属性参数 交换机名称 交换机类型 是否持久化 是否自动删除 配置参数return new CustomExchange("delay_exchange", "x-delayed-message", true, false, args);
}
/*** 延迟拼团队列* @return*/
@Bean
public Queue delayTuanQueue(){//属性参数 队列名称 是否持久化return new Queue("delay_tuan", true);
}/*** 给延时队列绑定交换机* @return*/
@Bean
public Binding tuanDelayBinding(){return BindingBuilder.bind(delayTuanQueue()).to(delayExchange()).with("tuan").noargs();
}

2.在拼团活动订单支付回调接口里面触发,支付回调接口

@Transactional
public String callback(HttpServletRequest request) {String result = "";Date date = new Date();try (Jedis jedis = jedisPool.getResource();InputStream inStream = request.getInputStream();ByteArrayOutputStream outSteam = new ByteArrayOutputStream()) {byte[] buffer = new byte[1024];int len = 0;while ((len = inStream.read(buffer)) != -1) {outSteam.write(buffer, 0, len);}result = new String(outSteam.toByteArray(), StandardCharsets.UTF_8);logger.info("wechat callback result:" + result);//处理返回结果Map<String, Object> data = XmlUtil.xmlToMap(result);String orderNo = (String) data.get("out_trade_no");String transactionId = (String) data.get("transaction_id");logger.info("回调订单号:{}", orderNo);ActivityOrder order = activityOrderService.queryByOrderNo(orderNo);if (order == null) {return failReturn;}PayConfig payConfig = payConfigService.queryByToken(order.getProgramToken());if (!SignUtil.getSign(data, payConfig.getKey()).equals(data.get("sign"))) {logger.info("处理返回结果失败:验签错误");return failReturn;}logger.info("回调参数:{}", JsonUtil.toJson(data));if (order.getStatus().equals(PayEnum.PAYING_SUSS.getValue())) {return successReturn;}order.setCallBackStr(result);order.setWechatNo(transactionId);logger.info("回调参数保存成功");//处理返回数据if (!"SUCCESS".equals(data.get("return_code"))) {logger.info("支付失败");order.setOrderStatus(PayEnum.PAYING_FAIL.getValue());order.setUpdateTime(new Date());activityOrderService.updateActivityOrder(order);return successReturn;}String checkNo = NumberUtil.getRandomNumber(8);while (true) {if (activityOrderService.countByCheckNo(checkNo, order.getShopId()) > 0) {checkNo = NumberUtil.getRandomNumber(8);} else {break;}}order.setCheckNo(checkNo);order.setOrderStatus(PayEnum.PAYING_SUSS.getValue());order.setUpdateTime(new Date());order.setPayTime(new Date());MiniProgram miniProgram = miniProgramService.queryByToken(order.getProgramToken());UserWechatAccessToken userWechatAccessToken = userWechatAccessTokenService.queryByAppid(miniProgram.getAppid());String token = userWechatAccessToken == null ? "" : userWechatAccessToken.getAccessToken();Activity activity = activityService.getActivity(order.getActivityId());if(order.getIsMain() && activity.getTimeLimit()){//设置延迟时间long minute=activity.getDayLimit()*24*60+activity.getHourLimit()*60+activity.getMinuteLimit();//第一个参数是前面RabbitMqConfig的交换机名称 第二个参数的路由名称 第三个参数是传递的参数 第四个参数是配置属性template.convertAndSend("delay_exchange", "tuan", order.getGroupNo(), message -> {//配置消息的过期时间message.getMessageProperties().setDelay((int) (minute * 60 * 1000));return message;});}String path = "";if (ActivityTypeEnum.GROUP.getName().equals(activity.getaType())) {path = "pages/joinActive3/main";} else if (ActivityTypeEnum.INVITE_CARD.getName().equals(activity.getaType())) {path = "pages/joinZan1/main";}order.setQrCode(imageBo.getQrCode(order.getId(), order.getActivityId(), path, token));activityOrderService.updateActivityOrder(order);logger.info("更新订单结果");return successReturn;} catch (Exception e) {logger.info("sbsbsbsbsbs:{}", failReturn);e.printStackTrace();logger.info(e.getMessage());return failReturn;}}

3.OrderConsumer

//拼团时间到期处理未成团
@RabbitListener(queues = "delay_tuan")
public void consumeTuanOrderMessage(String groupNo, @Header(AmqpHeaders.DELIVERY_TAG) long tag, Channel channel) {logger.info("拼团时间到期处理未成团活动订单:{}", groupNo);try {List<ActivityOrder> orderList=activityOrderService.queryByGroupNo(groupNo);if (orderList == null || orderList.size()==0) {channel.basicAck(tag, true);return;}Activity activity=activityService.getActivity(orderList.get(0).getActivityId());PayConfig payConfig=payConfigService.queryByToken(activity.getProgramToken);if(!activity.getAutoGroup()){if(orderList.size()<activity.getMinAmount()){for(ActivityOrder order:orderList){logger.info("开始处理拼团到期退款:拼团号{}",groupNo);refund(order.getOrderNo(), payConfig);}}}channel.basicAck(tag, true);} catch (Exception e) {logger.error("拼团时间到期延迟队列消息时抛出异常 , e = {}", e.getMessage());//重新放回到队列里面try {Thread.sleep(50);channel.basicNack(tag, false, true);} catch (IOException | InterruptedException e1) {logger.error("拼团时间到期延迟队列消息时抛出异常 , e = {}" + e.getMessage());}e.printStackTrace();}}

退款

public void refund(String orderNo, PayConfig payConfig){ActivityOrder order = activityOrderService.queryByOrderNo(orderNo);String refundNo = OrderNoUtil.generateRefundOrderNo();//准备预支付Map<String, Object> param = new HashMap<>();param.put("appid", payConfig.getAppid());param.put("mch_id", payConfig.getMchId());param.put("nonce_str", NumberUtil.getRandomStr(18));param.put("out_trade_no", orderNo);param.put("total_fee", order.getOrderAmount());param.put("refund_fee", order.getOrderAmount());param.put("out_refund_no", refundNo);String sign = SignUtil.getSign(param, payConfig.getKey());param.put("sign", sign);String result = "";Map<String, Object> map = null;try {String requestData = XmlUtil.mapToXml(param);URL url = new URL(payConfig.getFilePath());HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(5 * 1000);InputStream inputStream = conn.getInputStream();logger.info("退款请求参数:{}", requestData);result = requestOnce(requestData, payConfig, inputStream,true, refundUrl);map = XmlUtil.xmlToMap(result);} catch (Exception e) {e.printStackTrace();}if (map == null) {logger.info("请求失败");return;}Refund refund = new Refund();refund.setCreateTime(new Date());refund.setResultStr(result);refund.setRefundNo(refundNo);refund.setOrderId(order.getId());refund.setResultStr(result);logger.info("退款请求返回参数:{}", result);if ("FAIL".equals(map.get("return_code"))) {logger.info("退款失败");refund.setStatus("FAIL");refundService.addRefund(refund);order.setOrderStatus("REFUND_FAIL");order.setStatus("OVERDATE");activityOrderService.updateActivityOrder(order);return;}if ("FAIL".equals(map.get("result_code"))) {logger.info("退款失败");refund.setStatus("FAIL");refundService.addRefund(refund);order.setOrderStatus("REFUND_FAIL");order.setStatus("OVERDATE");activityOrderService.updateActivityOrder(order);return;}refund.setStatus("SUCCESS");refund.setOrderNo((String) map.get("out_trade_no"));refund.setWechatNo((String)map.get("transaction_id"));refundService.addRefund(refund);order.setOrderStatus("REFUND");order.setStatus("OVERDATE");activityOrderService.updateActivityOrder(order);
}

最开始本人使用的是定时任务

/*** 处理拼团时间到期*/
//    @Async
//    @Scheduled(cron = "0 0/1 * * * *")public void updatePinTuanEnd(){Date date=new Date();List<Activity> activityList=activityService.queryStarting(date);List<GroupDataBase> activityOrderList=null;List<ActivityOrder> orders=null;List<ActivityOrder> groupOrder=null;Map<String,GroupDataBase> map=null;Date pintuanTime=null;for(Activity activity:activityList){if(activity.getTimeLimit()){//设置拼团时间限制activityOrderList=activityOrderService.queryGroupData(activity.getId());map=activityOrderList.stream().collect(Collectors.toMap(GroupDataBase::getGroupNo, Function.identity(), (key1, key2) -> key2));orders=activityOrderService.queryByActivityIdAndIsMain(activity.getId());if(orders !=null && orders.size()>0){for(ActivityOrder order:orders){pintuanTime=TimeUtils.addDate(order.getPayTime(),activity.getDayLimit(),activity.getHourLimit(),activity.getMinuteLimit());if(new Date().after(pintuanTime)){if(!activity.getAutoGroup()){logger.info("activityId={}",activity.getId());if(map.get(order.getGroupNo()).getAmount()<activity.getMinAmount()){groupOrder=activityOrderService.queryByActivityIdAndGroupNo(activity.getId(),order.getGroupNo());for(ActivityOrder order1:groupOrder){order1.setOrderStatus(ActivityOrderStatusEnum.REFUND.getName());order1.setStatus(ActivityOrderServiceEnum.OVERDATE.getName());activityOrderService.updateActivityOrder(order1);}}}}}}}}}

定时任务也可以实现

定时任务与消息队列的区别

1.定时任务很消耗系统内存

2.定时任务倾向于批处理,消息队列倾向于逐条处理

消息延迟队列处理拼团时间到期相关推荐

  1. 【RocketMQ】延迟消息(延迟队列)

    文章目录 1. 什么是延迟消息 1.1 延时消息的使用场景 2. 示例 3. 原理 参考 1. 什么是延迟消息 发送消息后,消费者要等待一定的时间才能消费到该消息. RocketMQ 不支持任意时间自 ...

  2. 消息队列处理秒杀/拼团活动的高并发问题

    人工智能,零基础入门!http://www.captainbed.net/inner 1.消息队列(以下简称MQ)天生就是处理高并发的有力工具,因为他可以把一个完整的流程拆为多部分,并发进行,或者不是 ...

  3. ribbonmq超时配置_使用RabbitMQ实现订单超时取消(延迟队列)

    使用RabbitMQ实现订单超时取消,大致流程: 生产者生产一条设置了TTL的延迟取消订单消息=>延迟队列交换机(通过绑定路由键)=>消息投递至延迟队列=>消息延迟队列时间到期=&g ...

  4. 电商产品设计:后台营销功能模块设计-拼团活动(一)

    提起拼团,大家自然而然地想到拼多多,在流量红利已经触底的情况下,以拼团这种新模式杀出一条血路. 页面上的"发起拼团"或"去拼团"按钮大家都看的到,但是否真正思考 ...

  5. 实例讲解:拼团活动如何设计?

    营销手段除了优惠券,还有拼团这种常见模式.提起拼团,大家自然而然地想到拼多多,在流量红利已经触底的情况下,以拼团这种新模式杀出一条血路. 传闻今年3月份,拼多多月GMV已经达到400亿的规模,交易额超 ...

  6. 电商产品设计:后台营销功能模块设计-拼团活动(二)

    营销手段是电商中灵魂所在,今天要讲解的是"拼团"这一模式.我们熟知的拼多多就是在流量红利已经触底的情况下,以拼团这种模式杀出一条血路.现在我们一起来看一下拼团所涉及的逻辑关系及其作 ...

  7. 拼团系统设计熊猫拼U拼拼团产品设计思路

    营销手段除了优惠券,还有拼团这种常见模式. 提起拼团,大家自然而然地想到拼多多,在流量红利已经触底的情况下,以拼团这种新模式杀出一条血路. 市面上还有有很多电商拼团系统,例如幸运拼,熊猫拼,U拼,拼快 ...

  8. 拼团设计思路(转载)

    链接地址:https://blog.csdn.net/qq_32795773/article/details/81281515 营销手段除了优惠券,还有拼团这种常见模式.提起拼团,大家自然而然地想到拼 ...

  9. 实战:拼团活动如何设计?

    营销手段除了优惠券,还有拼团这种常见模式.提起拼团,大家自然而然地想到拼多多,在流量红利已经触底的情况下,以拼团这种新模式杀出一条血路. 传闻今年3月份,拼多多月GMV已经达到400亿的规模,交易额超 ...

最新文章

  1. SQL 编程思想:一切皆关系
  2. python下载网页里面所有的图片-python批量下载图片的三种方法
  3. 二叉树(中序遍历)非递归
  4. 关于nsurlsession
  5. sensor曝光量和曝光行的区别_拼多多新手商家怎样快速提高曝光量?
  6. Spring-Cloud中的 熔断、限流、降级
  7. java 多线程异常_java多线程执行异常
  8. 我的世界java服务器刷_一个教程, 叫你如何在服务器刷op
  9. Python学习笔记总结
  10. [渝粤教育] 盐城工学院 大学物理(力学、振动与波动) 参考 资料
  11. 基于 Mean-shift的稳健性可视跟踪研究
  12. 基于Python的《庆余年》评论分析
  13. 12.sql语句增删改查快速回顾
  14. opencv cv2.copyMakeBorder()函数详解
  15. android 下的虚拟机下载地址,Android x86 虚拟机镜像下介绍及下载
  16. Linux----Ubuntu系统官网下载iso镜像文件
  17. amr转mp3,amr怎么转换mp3?
  18. SpringDataJPA之Specification复杂查询
  19. 用html制作四种九九乘法表,JavaScript制作九九乘法表
  20. 正则表达式匹配中英文姓名

热门文章

  1. 深入浅出Rust Future - Part 1
  2. Rancher部署Traefik实现微服务的快速发现
  3. Python基础笔记1
  4. 怎样用VB编写.DLL动态链接库文件
  5. 杭电oj1384--Intervals(差分约束)
  6. 自定义堆栈(回文检测)
  7. 1-2-Active Directory 域服务准备概述
  8. 编程基础 垃圾回收_为什么我回收编程问题
  9. 降维后的高维特征的参数_高维超参数调整简介
  10. 领域驱动设计 敏捷_反馈失败:发现敏捷数据驱动的致命弱点的风险