Java微信扫码支付模式二Demo ,websocket直接运行版本
概述
详细
功能演示
本地版本:
穿透版本:
一、相关配置
微信公众号AppID(登录微信公众平台-->开发-->基本设置-->开发者ID(AppID))
微信公众号AppSecret(登录微信公众平台-->开发-->基本设置-->开发者密码(AppSecret))
微信支付商户号(登录微信商户平台-->账户中心-->商户信息-->基本账户信息-->微信支付商户号)
微信支付商户API密钥(登录微信商户平台-->账户中心-->API安全-->API密钥-->设置API密钥)
application.properties 文件 (Demo上都有官网的默认值,不需要修改直接使用,省心!)
支付扫码模式二,流程图
https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5
SDK与DEMO下载
https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=11_1
二、目录结构
三、准备工作
(1)内网穿透工具
让外网能直接访问,你本地的服务,场景用于,接口调试,支付方面等等。
为了大家找了一个,免费配置简单的。绝对不是卖广告,之前用过花生壳,麻烦到要死坑哇~,现在的所有穿透都要身份证登记,很正常国家出了对应的法规。
下载地址:https://natapp.cn/#download
配置和使用说明:https://blog.csdn.net/kingrome2017/article/details/77989442
四、功能演示
本地版本:请看最上面视频及流程图,访问链接 http://127.0.0.1:8080
穿透版本:请看最上面视频及流程图,访问链接 必须使用穿透工具,步骤请看视频~
支付流程:
五、前端代码
<html> <head > <title>微信支付二维码生成</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <script type="text/javascript" src="/js/jquery/jquery-3.3.1.min.js"></script> <script type="text/javascript" src="/js/websocket/sockjs.min.js"></script> <script type="text/javascript" src="/js/websocket/stomp.min.js"></script> <script type='text/javascript'> $(function () { wxQRCode(); }); //当前查询次数 var nowQueryCount = 0; //生成二维码 function wxQRCode(){ getOutTradeNo(); var outTradeNo = $("#outTradeNo").val(); $("#payImg").attr("src",'/wxPay/payUrl'+"?totalFee="+ $("#totalFee").val()+"&outTradeNo=" + outTradeNo + "&random=" + new Date().getTime()); //重置查询次数 nowQueryCount = 0; queryOrder(); } //获取流水号 function getOutTradeNo(){ $.ajax({ type : "POST", url : '/wxPay/outTradeNo', async : false, success : function(jsonData) { if(jsonData.code == 200){ var outTradeNo = jsonData.data; $("h2").html(outTradeNo); $("#outTradeNo").val(outTradeNo); //启动webSocket监听器 webSocketListener(outTradeNo); }else{ alert(jsonData.message); } return false; }, error:function(XMLHttpRequest,textStatus,errorThrown){ alert("服务器错误!状态码:"+XMLHttpRequest.status); // 状态 console.log(XMLHttpRequest.readyState); // 错误信息 console.log(textStatus); return false; } }); } var stompClient = null; //webSocketListener 监听器 是否已经支付 function webSocketListener(outTradeNo){ //多次生成二维码,关闭上一次webSocket,避免浏览器负担 closeWebSocket(); if ("WebSocket" in window){ var socket = new SockJS('/websocket'); stompClient = Stomp.over(socket); stompClient.connect({}, function (frame) { console.log('Connected: ' + frame); stompClient.subscribe('/member/'+outTradeNo+'/send/message', function(jsonData) { jsonData = JSON.parse(jsonData.body); if(jsonData.code == 200){ var data = jsonData.data; var outTradeNo = data.outTradeNo; var transactionId = data.transactionId; var payDateStr = data.payDateStr; console.log("WebSocket:"+"\n"+"商户订单号:"+outTradeNo +"\n"+"微信支付订单号:"+transactionId+"\n"+"支付时间:"+payDateStr); alert("WebSocket:"+"\n"+"商户订单号:"+outTradeNo +"\n"+"微信支付订单号:"+transactionId+"\n"+"支付时间:"+payDateStr); closeWebSocket(); return false; } }); }); }else{ alert('我不兼容WebSocket'); } } //关闭webSocket function closeWebSocket(){ if (stompClient != null) { stompClient.disconnect(); } } //查询订单总次数 var autoQueryCount = 100; //定时器 var queryOrderSetTimeout = null; //查询订单状态 function queryOrder(){ nowQueryCount ++; var outTradeNo = $("#outTradeNo").val(); $.ajax({ type : "POST", url : '/wxPay/payStatus?outTradeNo='+ outTradeNo +"&random=" + new Date().getTime(), async : false, success : function(jsonData) { if(jsonData.code == 200){ var data = jsonData.data; var outTradeNo = data.outTradeNo; var transactionId = data.transactionId; var payDateStr = data.payDateStr; console.log("查询订单:"+"\n"+"商户订单号:"+outTradeNo +"\n"+"微信支付订单号:"+transactionId+"\n"+"支付时间:"+payDateStr); alert("查询订单:"+"\n"+"商户订单号:"+outTradeNo +"\n"+"微信支付订单号:"+transactionId+"\n"+"支付时间:"+payDateStr); //已支付,清除定时器 clearTimeout(queryOrderSetTimeout); return false; }else{ if(nowQueryCount < autoQueryCount){ //定时查询订单状态,5秒查询一次 console.log(currentTime()+" queryOrder:"+jsonData.message+" 查询次数:"+nowQueryCount); queryOrderSetTimeout = setTimeout(queryOrder,5*1000); }else{ console.log(currentTime()+" queryOrder:"+jsonData.message+" 查询结束"); //超过查询次数,清除定时器 clearTimeout(queryOrderSetTimeout); return false; } } }, error:function(XMLHttpRequest,textStatus,errorThrown){ alert("服务器错误!状态码:"+XMLHttpRequest.status); // 状态 console.log(XMLHttpRequest.readyState); // 错误信息 console.log(textStatus); return false; } }); } //当时时间 function currentTime(){ var date = new Date(); this.year = date.getFullYear(); this.month = date.getMonth() + 1; this.date = date.getDate(); this.hour = date.getHours() < 10 ? "0" + date.getHours() : date.getHours(); this.minute = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes(); this.second = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds(); var currentTime = this.year+'-'+this.month + '-' + this.date + ' ' + this.hour + ':' + this.minute + ':' + this.second; return currentTime; } </script> </head> <body> <p>订单流水号:<h2></h2></p> 支付金额:<input id="totalFee" type="text" value="0.01"/> <button type="button" onclick="wxQRCode();" style="cursor: pointer">生成二维码</button> <input id="outTradeNo" type="hidden" /> <img id="payImg" width="300" height="300" > </body> </html>
六、后端代码
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.juno</groupId> <artifactId>weixin-websoket</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>weixin-websoket</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.0</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <commons-lang3.version>3.7</commons-lang3.version> <commons-collections.version>3.2.2</commons-collections.version> <com.google.zxing.version>3.3.3</com.google.zxing.version> <fastjson.version>1.2.46</fastjson.version> </properties> <dependencies> <!-- mvc支持--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <!-- 热部署模块 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- Commons utils begin --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>${commons-lang3.version}</version> </dependency> <dependency> <groupId>commons-collections</groupId> <artifactId>commons-collections</artifactId> <version>${commons-collections.version}</version> </dependency> <!-- Commons utils end --> <!-- google 生成二维码 begin--> <dependency> <groupId>com.google.zxing</groupId> <artifactId>javase</artifactId> <version>${com.google.zxing.version}</version> </dependency> <!-- google 生成二维码 end--> <!-- JSONObject JSONArray begin --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>${fastjson.version}</version> </dependency> <!-- JSONObject JSONArray end --> <!-- websocket begin --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> <!-- websocket end --> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <fork>true</fork> </configuration> </plugin> </plugins> </build> </project>
WxPayController.java
package com.juno.weixin.modules.controller.wx; import com.juno.weixin.modules.common.util.JSONResponse; import com.juno.weixin.modules.common.wx.WxConfig; import com.juno.weixin.modules.common.wx.WxConstants; import com.juno.weixin.modules.common.wx.WxUtil; import com.juno.weixin.modules.service.WxMenuService; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; /** * 微信支付控制类 * @author lujunjie * @date 2020/12/31 */ @Controller public class WxPayController { @Autowired private WxMenuService wxMenuService; /** * 二维码首页 */ @RequestMapping(value = {"/"}, method = RequestMethod.GET) public String wxPayList(Model model){ return "/wxPayList"; } /** * 获取流水号 */ @RequestMapping(value = {"/wxPay/outTradeNo"}) @ResponseBody public JSONResponse getOutTradeNo(){ //商户订单号 return JSONResponse.success(WxUtil.mchOrderNo()); } final private String signType = WxConstants.SING_MD5; /** * 统一下单-生成二维码 */ @RequestMapping(value = {"/wxPay/payUrl"}) public void payUrl(HttpServletRequest request, HttpServletResponse response, @RequestParam(value = "totalFee")Double totalFee, @RequestParam(value = "outTradeNo")String outTradeNo) throws Exception{ WxUtil.writerPayImage(response,wxMenuService.wxPayUrl(totalFee,outTradeNo,signType)); } /** * 查询订单状态 */ @RequestMapping(value = {"/wxPay/payStatus"}) @ResponseBody public JSONResponse payStatus(HttpServletRequest request, HttpServletResponse response, @RequestParam(value = "outTradeNo")String outTradeNo) throws Exception{ return this.wxMenuService.queryOrder(outTradeNo,signType); } @Autowired private SimpMessagingTemplate simpMessagingTemplate; /** * 统一下单-通知链接 */ @RequestMapping(value = {"/wxPay/unifiedorderNotify"}) public void unifiedorderNotify(HttpServletRequest request, HttpServletResponse response) throws Exception{ //商户订单号 String outTradeNo = null; String xmlContent = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[签名失败]]></return_msg>" + "</xml>"; try{ String requstXml = WxUtil.getStreamString(request.getInputStream()); Map<String,String> map = WxUtil.xmlToMap(requstXml); String returnCode= map.get(WxConstants.RETURN_CODE); //校验一下 ,判断是否已经支付成功 if(StringUtils.isNotBlank(returnCode) && StringUtils.equals(returnCode,"SUCCESS") && WxUtil.isSignatureValid(map, WxConfig.key,signType)){ System.out.println("------------"+"统一下单-通知链接:支付成功"+"------------"); System.out.println("统一下单-通知链接:"+"requstXml : " + requstXml); //商户订单号 outTradeNo = map.get("out_trade_no"); System.out.println("统一下单-通知链接 "+"outTradeNo : "+ outTradeNo); //微信支付订单号 String transactionId = map.get("transaction_id"); System.out.println("统一下单-通知链接 "+"transactionId : "+ transactionId); //支付完成时间 SimpleDateFormat payFormat= new SimpleDateFormat("yyyyMMddHHmmss"); Date payDate = payFormat.parse(map.get("time_end")); SimpleDateFormat systemFormat= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String payDateStr = systemFormat.format(payDate); System.out.println("统一下单-通知链接 "+"支付时间:" + payDateStr); HashMap<String,Object> returnMap = new HashMap<>(); returnMap.put("outTradeNo",outTradeNo); returnMap.put("transactionId",transactionId); returnMap.put("payDateStr",payDateStr); //通知前台,我完成支付了 simpMessagingTemplate.convertAndSendToUser(outTradeNo,"/send/message",JSONResponse.success(returnMap)); xmlContent = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml>"; } }catch (Exception e){ e.printStackTrace(); } //返回信息给微信 WxUtil.responsePrint(response,xmlContent); } }
联系方式
QQ:359355126 蓝蓝的天