一. 延迟消息队列

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. python服务端工程师就业面试指导☝☝☝

    python服务端工程师就业面试指导 由Python专业面试官打造的课,少之又少,专业代表着经验,代表着对考察点的通透理解,更代表着对你负责 第1章 Python工程师offer直通车(视频+教辅文档 ...

  2. Java基础-开篇

    之前在新浪博客写了不少springmvc的相关技术,但新浪博客毕竟不是专业的技术博客,添加代码很不方便,就开始在博客园试试了. 使用java开发也不少年了,准备再次整理一些java基础知识,当然,这次 ...

  3. 毕业生想学习web前端,应该怎么学才能最快找到工作?

    首先无论你要学习任何技能,必须有一个清晰的版图,什么是清晰的版图呢?首先了解你学的技术将来要从事什么工作,这个工作的条件是哪些? 然后你要有一个非常清晰的学习大纲,切记学习任何东西都要系统,不可胡乱的 ...

  4. Webshell免杀绕过waf

    转自圈子404师傅 0x01 前言# 尽最大努力在一文中让大家掌握一些有用的WEBSHELL免杀技巧 0x02 目录# 关于eval 于 assert 字符串变形 定义函数绕过 回调函数 回调函数变形 ...

  5. [JZOJ5772]【NOIP2008模拟】今天你AK了吗?

    Description AK:All kill“你为什么没背书?”“没有为什么,我就是没背书.”“……我去年买了个表,G—U—N!”头铁王InFleaKing把背书的时间都拿去列排列了......n= ...

  6. [JZOJ5456]【NOIP2017提高A组冲刺11.6】奇怪的队列

    Description nodgd的粉丝太多了,每天都会有很多人排队要签名.今天有

  7. Halcon一日一练:获取孔位

    本例程是用于获取安装螺丝孔在图像中对应的坐标位置,并显示该坐标位,如上图所示. read_image(Image,'rim.png')//读取图像 dev_close_window()//关闭窗口 g ...

  8. spark上 spark-shell和java -jar访问hdfs路径问题

    部署spark集群 使用spark包 spark-1.0.2-bin-hadoop2.tgz 在spark-shell和java -jar访问hadoop hdfs上的文件写法是有区别的 在spark ...

  9. JSONP安全防御要点

    严格安全地实现CSRF方式调用JSON文件:限制Referer.部署一次性token等. 严格安装JSON格式标准输出Content-Type及编码(Content-Type: application ...

  10. SpringCloud之整合Zipkin+Sleuth(十四)

    1.添加依赖 在项目的pom.xml文件中添加下面依赖 <!--里面包含两个依赖--> <dependency> <groupId>org.springframew ...