流程分析
完整代码
package com.qfedu.fmmall.websocket;
import org.springframework.stereotype.Component;
import javax.websocket.OnClose;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author beyondx
* @date Created in 2022/08/21/ 14:31
*/
@Component
@ServerEndpoint("/webSocket/{oid}") // 表示这个类, 可以接收 别人的请求; 接收 websocket请求
public class WebSocketServer {
private static ConcurrentHashMap<String, Session> sessionMap = new ConcurrentHashMap<>();
/**
* 前端发送请求, 建立 webSocket链接, 就会执行 @OnOpen方法
* @param orderId 订单id
* @param session 代表连接
*/
@OnOpen
public void open(@PathParam("oid") String orderId, Session session) {
System.out.println("------------建立连接:" + orderId);
sessionMap.put(orderId, session);
}
/**
* 前端 关闭页面, 或者 主动关闭 webSocket连接, 都会执行close
* @param orderId
*/
@OnClose
public void close(@PathParam("oid") String orderId) {
sessionMap.remove(orderId);
}
/**
* 发送消息, 工具方法
* @param orderId
* @param msg
*/
public static void sendMsg(String orderId, String msg) {
try {
Session session = sessionMap.get(orderId);
session.getBasicRemote().sendText(msg);
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.qfedu.fmmall.controller;
import com.github.wxpay.sdk.WXPayUtil;
import com.qfedu.fmmall.service.OrderService;
import com.qfedu.fmmall.websocket.WebSocketServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.websocket.Session;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* 回调接口
* @author beyondx
* @date Created in 2022/08/20/ 21:17
*/
@RestController
@RequestMapping("/pay")
public class PayController {
@Autowired
private OrderService orderService;
/**
* 支付回调; 接收 微信支付平台的 请求(通知)
* 支付回到: 当用户支付成功之后, 支付凭条会向我们指定的服务器接口 放请求, 传递 订单支付状态数据
* 1.接收微信支付平台传递的数据(使用request的输入流接收)
*/
@RequestMapping("/callback")
public String paySuccess(HttpServletRequest request) throws Exception {
System.out.println("-----------------callback");
ServletInputStream is = request.getInputStream();
byte[] bs = new byte[1024];
int len = -1;
StringBuilder builder = new StringBuilder();
while((len = is.read()) != -1) {
builder.append(new String(bs, 0, len));
}
String s = builder.toString();
// 使用帮助类, 将 xml结构的 字符串, 转化为 Map
// 将接收得到的 (微信响应给到的数据) 转化为 Map
// 以标签名作为 key, 标签中的值, 作为 value
Map<String, String> map = WXPayUtil.xmlToMap(s);
if(map != null && "success".equalsIgnoreCase(map.get("result_code"))) {
// 支付成功; 2件事要做
// 1.修改订单状态 为 待发货(已支付); 数据库操作; 直接使用 tkMapper操作的w
// 订单 是 我们的 组件
String orderId = map.get("out_treade_no");
int i = orderService.updateOrderStatus(orderId, "2");
System.out.println("--orderId: " + orderId);
// 3.通过websocket连接, 向前端推送消息
// 这个session 就是 跟 支付页面对应的 连接对象
WebSocketServer.sendMsg(orderId, "1");
// 2.响应 微信支付平台; 否则 微信支付平台, 会一直 发信息
// 注意: 响应的时候, 最好不要用 原来的map, 这里是 新构造了一个map(resp)
if(i > 0) {
HashMap<String, String> resp = new HashMap<>();
resp.put("return_code", "success");
resp.put("return_msg", "OK");
resp.put("appid", map.get("appid"));
resp.put("result_code", "success");
return WXPayUtil.mapToXml(resp);
}
// 这里没有 else也可以, 订单状态修改失败, 我希望你再通知我一次, 我再修改
// else {
// return null;
// }
}
return null;
}
}
<script type="text/javascript">
var baseUrl = "http://localhost:8080/";
var webSocketBaseUrl = "ws://localhost:8080/";
var vm = new Vue({
el: "#container",
data: {
orderInfo: {}
},
// vue声明周期:创建对象--beforeCreate--初始化data--created--加载模块--beforeMount--渲染数据--mounted
created: function () {
var jsonstr = localStorage.getItem("orderInfo");
if(jsonstr != null) {
localStorage.removeItem("orderInfo");
}
this.orderInfo = eval("("+jsonstr+")");
console.log(this.orderInfo.payUrl);
},
// mounted表示 vue的 渲染已经结束
mounted: function () {
// 渲染(显示)二维码
var str = this.orderInfo.payUrl;
var qrcode = new QRCode($("#payQrcodeDiv")[0], {
width: 200,
height: 200
});
qrcode.makeCode(this.orderInfo.payUrl);
// 前端发送websocket连接请求, 创建和 后端 socket的连接
console.log("-----1111");
// 建立 长连接
var webSocketUrl = webSocketBaseUrl + "webSocket/" + this.orderInfo.orderId;
websocket = new WebSocket(webSocketUrl);
// 只要后端通过 websocket 向次连接发消息, 就会触发 onmessage事件
websocket.onmessage = function (event) {
var msg = event.data;
if(msg == "1") {
// 订单支付完成
$("#div1").html("<label style='font-size: 20px; color: green'>订单支付完成!</label>");
}
}
}
});
</script>