04推送支付通知

4.推送支付通知

4.1 需求分析

當用戶完成掃碼支付後,跳轉到支付成功頁面

4.2 服務端推送方案

我們需要將支付的結果通知前端頁面,其實就是我們通過所說的服務器端推送,主要有三種實現方案
(1)Ajax 短輪詢 Ajax 輪詢主要通過頁面端的 JS 定時異步刷新任務來實現數據的加載
如果我們使用ajax短輪詢方式,需要後端提供方法,通過調用微信支付接口實現根據訂單號查詢支付狀態的方法(參見查詢訂單API) 。 前端每間隔三秒查詢一次,如果後端返回支付成功則執行頁面跳轉。
缺點:這種方式實時效果較差,而且對服務端的壓力也較大。不建議使用
(2)長輪詢
長輪詢主要也是通過 Ajax 機制,但區別於傳統的 Ajax 應用,長輪詢的服務器端會在沒有數據時阻塞請求直到有新的數據產生或者請求超時才返回,之後客戶端再重新建立連接獲取數據。
如果使用長輪詢,也同樣需要後端提供方法,通過調用微信支付接口實現根據訂單號查詢支付狀態的方法,只不過循環是寫在後端的。
缺點:長輪詢服務端會長時間地佔用資源,如果消息頻繁發送的話會給服務端帶來較大的壓力。不建議使用
(3)WebSocket 雙向通信 WebSocket 是 HTML5 中一種新的通信協議,能夠實現瀏覽器與服務器之間全雙工通信。如果瀏覽器和服務端都支持 WebSocket 協議的話,該方式實現的消息推送無疑是最高效、簡潔的。並且最新版本的 IE、Firefox、Chrome 等瀏覽器都已經支持 WebSocket 協議,ApacheTomcat 7.0.27 以後的版本也開始支持 WebSocket。

4.3 RabbitMQ Web STOMP 插件

藉助於 RabbitMQ 的 Web STOMP 插件,實現瀏覽器與服務端的全雙工通信。從本質上說,RabbitMQ的 Web STOMP 插件也是利用 WebSocket 對 STOMP 協議進行了一次橋接,從而實現瀏覽器與服務端
在這裏插入圖片描述

4.3.1 STOMP協議

STOMP即Simple (or Streaming) Text Orientated Messaging Protocol,簡單(流)文本定向消息協議。前身是TTMP協議(一個簡單的基於文本的協議),專爲消息中間件設計。它提供了一個可互操作的連接格式,允許STOMP客戶端與任意STOMP消息代理(Broker)進行交互。STOMP協議由於設計簡單,易於開發客戶端,因此在多種語言和多種平臺上得到廣泛地應用。

4.3.2 插件安裝

我們進入rabbitmq容器,執行下面的命令開啓stomp插件

rabbitmq-plugins enable rabbitmq_web_stomp rabbitmq_web_stomp_examples

將當前的容器提交爲新的鏡像

docker commit 3989ec68bf3c rabbitmq:stomp

停止當前的容器

docker stop 3989ec68bf3c

根據新的鏡像創建容器

docker run -di --name=changgou_rabbitmq -p 5671:5617 -p 5672:5672 -p 4369:4369 -p 15671:15671 -p 15672:15672 -p 25672:25672 -p 15670:15670 -p 15674:15674
rabbitmq:stomp

4.3.3 消息推送測試

我們在瀏覽器訪問http://192.168.200.128:15670 可以看到stomp的例子代碼 。
我們根據stomp的例子代碼創建一個頁面,內容如下:

<html>
<head>
	<title>RabbitMQ Web STOMP Examples : Echo Server</title>
	<meta charset="UTF-8">
	<script src="js/stomp.min.js"></script>
</head>
<script>
	var client = Stomp.client('ws://localhost:15674/ws');
	var on_connect = function(x) {
		id = client.subscribe("/exchange/paynotify", function(d) {
			alert(d.body);
		});
	};
	var on_error = function() {
		console.log('error');
	};
	client.connect('guest', 'guest', on_connect, on_error, '/');
</script>
</body>
</html>

1./exchange/

對於 SUBCRIBE frame,destination 一般爲/exchange//[/pattern] 的形式。該 destination 會創建一個唯一的、自動刪除的、名爲的 queue,並根據 pattern 將該 queue 綁定到所給的exchange,實現對該隊列的消息訂閱。 對於 SEND frame,destination 一般爲/exchange//[/routingKey] 的形式。這種情況下消息就會被髮送到定義的 exchange 中,並且指定了 routingKey。
2./queue/ 對於 SUBCRIBE frame,destination 會定義的共享 queue,並且實現對該隊列的消息訂閱。 對於 SEND frame,destination 只會在第一次發送消息的時候會定義的共享queue。該消息會被髮送到默認的 exchange 中,routingKey 即爲。
3./amq/queue/ 這種情況下無論是 SUBCRIBE frame 還是 SEND frame 都不會產生queue。但如果該 queue 不存在,SUBCRIBE frame 會報錯。 對於 SUBCRIBE frame,destination 會實現對隊列的消息訂閱。 對於 SEND frame,消息會通過默認的 exhcange直接被髮送到隊列中。
4./topic/ 對於 SUBCRIBE frame,destination 創建出自動刪除的、非持久的 queue 並根據routingkey 爲綁定到 amq.topic exchange 上,同時實現對該 queue 的訂閱。 對於 SENDframe,消息會被髮送到 amq.topic exchange 中,routingKey 爲。

我們在rabbitmq中創建一個叫paynotify的交換機(fanout類型)測試,我們在rabbitmq管理界面中向paynotify交換機發送消息,頁面就會接收這個消息。爲了安全,我們在頁面上不能用我們的rabbitmq的超級管理員用戶guest,所以我們需要在rabbitmq中新建一個普通用戶webguest(普通用戶無法登錄管理後臺)

在這裏插入圖片描述

4.4 代碼實現

實現思路:後端在收到回調通知後發送訂單號給mq(paynotify交換器),前端通過stomp連接到mq訂閱paynotify交換器的消息,判斷接收的訂單號是不是當前頁面的訂單號,如果是則進行頁面的跳轉。

(1)修改notifyLogic方法,在 “SUCCESS”.equals(map.get(“result_code”)) 後添加

rabbitTemplate.convertAndSend("paynotify","",map.get("out_trade_no"));

(2)修改wxpay.html ,渲染js代碼訂單號和支付金額部分

let client = Stomp.client('ws://192.168.200.128:15674/ws');
let on_connect = function(x) {
	id = client.subscribe("/exchange/paynotify", function(d) {
		let orderId=[[${orderId}]];
		if(d.body==orderId){
			location.href='/api/wxpay/topaysuccess?payMoney='+[[${payMoney}]];
		//參數支付金額
		}
	});
};
let on_error = function() {
	console.log('error');
};
client.connect('webguest', 'itcast', on_connect, on_error, '/');

(3)將paysuccess.html拷貝到static文件夾 。
(4)changgou_web_order的PayController中新增跳轉支付成功接口

@GetMapping("/topaysuccess")
public String topaysuccess(String payMoney,Model model){
	model.addAttribute("payMoney",payMoney);
	return "paysuccess";
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章