一. 延迟消息队列

1. 在提交支付之后,可以发送一个延迟检查的队列,来主动查询用户在支付宝上的支付状态

在mq的配置/conf/activeMq.xml的broker实例上配置加上schedulerSupport="true",如下图所示

2 延迟检查如果失败,则从新发送新的检查队列,并且要将检查次数减一

// 没有支付,再次发送检查队列
System.out.println("订单号:"+out_trade_no+"尚未支付成功,再次发送检查队列,剩余检查次数:"+count);
if(count>0){
    System.out.println("订单号:"+out_trade_no+"检查次数尚未用尽,再次发送检查队列"+count);
    count --;
    paymentService.sendDelayPaymentCheckQueue(out_trade_no,count);
}else {


System.out.println("订单号:"+out_trade_no+"检查次数耗尽,停止检查,调用关单服务");

}

二. 幂等性检查

调用相同的服务,返回的结果始终一样,叫做幂等性检查.

例子:

第一步,在支付的controller层发起延迟队列

@RequestMapping("/alipay/submit")
@ResponseBody
public String alipay(Model model, HttpServletRequest request,String orderSn){ // 查询对应订单信息
OmsOrder omsOrder = orderService.getOrderBySn(orderSn); AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();//创建API对应的request
alipayRequest.setReturnUrl(AlipayConfig.return_payment_url);
alipayRequest.setNotifyUrl(AlipayConfig.notify_payment_url);//在公共参数中设置回跳和通知地址 Map<String,Object> requestMap= new HashMap<>();
requestMap.put("out_trade_no",orderSn);
requestMap.put("product_code","FAST_INSTANT_TRADE_PAY");
requestMap.put("total_amount",0.01);
requestMap.put("subject",omsOrder.getOmsOrderItems().get(0).getProductName()); alipayRequest.setBizContent(JSON.toJSONString(requestMap));//填充业务参数
String form="";
try {
form = alipayClient.pageExecute(alipayRequest).getBody(); //调用SDK生成表单
} catch (AlipayApiException e) {
e.printStackTrace();
} // 保存支付数据
PaymentInfo paymentInfo = new PaymentInfo();
paymentInfo.setOrderSn(orderSn);
paymentInfo.setPaymentStatus("0");
paymentInfo.setTotalAmount(omsOrder.getPayAmount());
paymentInfo.setSubject(omsOrder.getOmsOrderItems().get(0).getProductName());
paymentInfo.setOrderId(omsOrder.getId());
paymentService.addPayment(paymentInfo); System.out.println(form); // 发送一个检查支付结果的队列(延迟队列)
paymentService.sendDelayPaymentCheckQueue(orderSn,7);// 调用支付宝的支付状态接口程序 return form;
}

@Override
public void sendDelayPaymentCheckQueue(String orderSn,long count) {
// 发送orderSn的延迟检查队列
ConnectionFactory connectionFactory = activeMQUtil.getConnectionFactory(); Connection connection = null;
Session session = null;// 开启消息事务
Queue paymentResultQueue = null; // 队列
MessageProducer producer = null;
try {
connection = connectionFactory.createConnection();
connection.start();
session = connection.createSession(true, Session.SESSION_TRANSACTED);
paymentResultQueue = session.createQueue("PAYMENT_CHECK_QUEUE");
//text文本格式,map键值格式
MapMessage mapMessage=new ActiveMQMapMessage();
mapMessage.setString("out_trade_no",orderSn);
mapMessage.setLong("count",count); //消息延迟消费
mapMessage.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY,1000*30); producer = session.createProducer(paymentResultQueue);// 消息的生成者
producer.send(mapMessage);
session.commit();
} catch (JMSException e) {
e.printStackTrace();
}finally {
try {
producer.close();
session.close();
connection.close();
} catch (JMSException e) {
e.printStackTrace();
}
} }

@Component
public class PaymentConsumer { @Autowired
PaymentService paymentService; @JmsListener(containerFactory = "jmsQueueListener",destination = "PAYMENT_CHECK_QUEUE")
public void consumePaymentCheckQueue(MapMessage mapMessage) throws JMSException {
String out_trade_no = mapMessage.getString("out_trade_no");
long count = mapMessage.getLong("count"); System.out.println("开始检查支付状态。。。订单号:"+out_trade_no); // 系统支付的幂等性检查
String status = paymentService.checkPayStatus(out_trade_no);
if(status!=null&&!status.equals("已支付")){
// 检查支付状态
Map<String,Object> map = paymentService.checkPayment(out_trade_no); if(map!=null&&(((String)map.get("trade_status")).equals("TRADE_SUCCESS")||((String)map.get("trade_status")).equals("TRADE_FINISHED"))){
// 保存支付信息,发送支付成功队列
System.out.println("订单号:"+out_trade_no+"已经支付成功,继续后续操作");
//
}else{
// 没有支付,再次发送检查队列
System.out.println("订单号:"+out_trade_no+"尚未支付成功,再次发送检查队列,剩余检查次数:"+count);
if(count>0){
System.out.println("订单号:"+out_trade_no+"检查次数尚未用尽,再次发送检查队列"+count);
count --;
paymentService.sendDelayPaymentCheckQueue(out_trade_no,count);
}else {
System.out.println("订单号:"+out_trade_no+"检查次数耗尽,停止检查,调用关单服务"); }
}
} }
}

@Override
public String checkPayStatus(String order_sn) { PaymentInfo paymentInfo = new PaymentInfo();
paymentInfo.setOrderSn(order_sn);
PaymentInfo paymentInfo1 = paymentInfoMapper.selectOne(paymentInfo); return paymentInfo1.getPaymentStatus();
}

@Override
public Map<String, Object> checkPayment(String out_trade_no) { // 调用支付宝,检查支付状态
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest(); Map<String,Object> map = new HashMap<>();
map.put("out_trade_no",out_trade_no);
request.setBizContent(JSON.toJSONString(map));
AlipayTradeQueryResponse response = null;
try {
response = alipayClient.execute(request);
} catch (AlipayApiException e) {
e.printStackTrace();
} if(response.isSuccess()){// isSuccess
System.out.println("调用成功,交易已经创建");
String tradeNo = response.getTradeNo();
String tradeStatus = response.getTradeStatus();
map.put("trade_no",tradeNo);
map.put("trade_status",tradeStatus);
return map;
} else {
System.out.println("调用失败,用户尚未创建交易");//
} return null;
} 以上,就完成了!

activemq 的延迟队列和幂等性检查的更多相关文章

  1. Dyno-queues 分布式延迟队列 之 生产消费

    Dyno-queues 分布式延迟队列 之 生产消费 目录 Dyno-queues 分布式延迟队列 之 生产消费 0x00 摘要 0x01 前情回顾 1.1 设计目标 1.2 选型思路 0x02 产生 ...

  2. 【RabbitMQ】一文带你搞定RabbitMQ延迟队列

    本文口味:鱼香肉丝   预计阅读:10分钟 一.说明 在上一篇中,介绍了RabbitMQ中的死信队列是什么,何时使用以及如何使用RabbitMQ的死信队列.相信通过上一篇的学习,对于死信队列已经有了更 ...

  3. 【RabbitMQ 实战指南】一 延迟队列

    1.什么是延迟队列 延迟队列中存储延迟消息,延迟消息是指当消息被发送到队列中不会立即消费,而是等待一段时间后再消费该消息. 延迟队列很多应用场景,一个典型的应用场景是订单未支付超时取消,用户下单之后3 ...

  4. PHP基于Redis实现轻量级延迟队列

    延迟队列,顾名思义它是一种带有延迟功能的消息队列. 那么,是在什么场景下我才需要这样的队列呢? 一.背景 先看看一下业务场景: 1.会员过期前3天发送召回通知 2.订单支付成功后,5分钟后检测下游环节 ...

  5. Dyno-queues 分布式延迟队列 之 基本功能

    Dyno-queues 分布式延迟队列 之 基本功能 目录 Dyno-queues 分布式延迟队列 之 基本功能 0x00 摘要 0x01 Dyno-queues分布式延迟队列 1.1 设计目标 1. ...

  6. Dyno-queues 分布式延迟队列 之 辅助功能

    Dyno-queues 分布式延迟队列 之 辅助功能 目录 Dyno-queues 分布式延迟队列 之 辅助功能 0x00 摘要 0x01 前文回顾 0x2 Ack机制 2.1 加入Un-ack集合 ...

  7. 消息队列RabbitMQ(五):死信队列与延迟队列

    死信队列 引言 死信队列,英文缩写:DLX .Dead Letter Exchange(死信交换机),其实应该叫做死信交换机才更恰当. 当消息成为Dead message后,可以被重新发送到另一个交换 ...

  8. C#实现rabbitmq 延迟队列功能

    最近在研究rabbitmq,项目中有这样一个场景:在用户要支付订单的时候,如果超过30分钟未支付,会把订单关掉.当然我们可以做一个定时任务,每个一段时间来扫描未支付的订单,如果该订单超过支付时间就关闭 ...

  9. Java 延迟队列使用

    延时队列,第一他是个队列,所以具有对列功能第二就是延时,这就是延时对列,功能也就是将任务放在该延时对列中,只有到了延时时刻才能从该延时对列中获取任务否则获取不到…… 应用场景比较多,比如延时1分钟发短 ...

随机推荐

  1. Redis开发与运维:数据迁移(下)

    上一篇,有朋友留言redis-port,借此机会我尝试使用一下redis-port这个同步工具 redis-port 已编译版 https://github.com/CodisLabs/redis-p ...

  2. nishang的介绍与使用

    0x01前言 Nishang是一个PowerShell攻击框架,它是PowerShell攻击脚本和有效载荷的一个集合.Nishang被广泛应用于渗透测试的各个阶段,本文主要介绍如何使用Nishang的 ...

  3. 域渗透-Kerberos协议中spn的应用

    0x01 关于SPN 服务主体名称(SPN)是Kerberos客户端用于唯一标识给特定Kerberos目标计算机的服务实例名称. 服务主体名称是服务实例(可以理解为一个服务,比如 HTTP.MSSQL ...

  4. web项目中登陆超时的功能实现(基于C#)

    当我们登陆进网站后,中途去看别的东西,没有再与该网站的服务器交互,就会弹出一个js窗口,登陆超时请重新登陆,并跳转到登陆页面. 步骤1.实现原理,在web.config中配置session的超时时间, ...

  5. Twitter-Snowflake:自增ID算法

    简介 Twitter 早期用 MySQL 存储数据,随着用户的增长,单一的 MySQL 实例没法承受海量的数据,后来团队就研究如何产生完美的自增ID,以满足两个基本的要求: 每秒能生成几十万条 ID ...

  6. kafka里的一些管理脚本

    kafka-server-start脚本 ------启动kafka server kafka-server-stop脚本 ------关闭kafka server kafka-topics脚本 -- ...

  7. unity 截屏总结

    转载与https://www.cnblogs.com/MissLi/p/8005342.html 1.针对指定的相机进行截屏 此中方式要添加yield return waitfortheEndofFr ...

  8. Pandas | 17 缺失数据处理

    数据丢失(缺失)在现实生活中总是一个问题. 机器学习和数据挖掘等领域由于数据缺失导致的数据质量差,在模型预测的准确性上面临着严重的问题. 在这些领域,缺失值处理是使模型更加准确和有效的重点. 使用重构 ...

  9. 机器学习回顾篇(9):K-means聚类算法. slides

    .caret, .dropup > .btn > .caret { border-top-color: #000 !important; } .label { border: 1px so ...

  10. 常用 UML 类图

    一. 类 类图分三层: 第一层是类的名称,如果是抽象类,则用斜体显示. 第二层是类的特性,通常就是字段和属性. 第三层是类的操作,通常是方法或行为.注意 '+' 表示 public,'-' 表示 pr ...