微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)
  rk9eeCbx5EiP 2023年11月02日 128 0

​微信支付-JASPI:准备工作[微信公众平台配置,微信商户平台配置]​


 微信支付所需的条件配置已经完成,接下来就开始实现(以下仅供参考)

一,实现前准备

①,阅读官方支付文档,主要是业务流程这一点​​https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_4​

②,官方demo下载 ​​https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1​

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_xml

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_java_02

​编辑③,js支付请求方式选择(我选择的是chooseWXPay,这个根据自身情况选择)

1.商户平台:网页通过JavaScript调用getBrandWCPayRequest接口,发起微信支付请求

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_xml_03

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_xml_04

​编辑2.公众平台:调用chooseWXPay实现

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_java_05

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_xml_06

​编辑

3.两者区别:选择getBrandWCPayRequest的话,支付页面不需要引入任何的js,选用chooseWXPay的话,需要引入JS文件

二,代码实现

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_微信_07

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_xml_08

​编辑

1.前端页面核心代码

①,引入js

"http://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_xml_09

②,config接口注入权限验证(requestUrl为当前页面的路由地址)

var reUrl =window.location.href;

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_java_10

ajax({
url: "/wxPay/getWXConfig?requestUrl="+encodeURIComponent(reUrl),
dataType: "json",
async: false,
type: "GET",
success: function (data) {
wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: data.appId, // 必填,公众号的唯一标识
timestamp:data.timestamp, // 必填,生成签名的时间戳
nonceStr: data.nonceStr, // 必填,生成签名的随机串
signature: data.signature,// 必填,签名
jsApiList: ['chooseWXPay'] // 必填,需要使用的JS接口列表

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_xml_11

geWxConfig的实现方法可参考:​​微信分享开发:代码实现[前端+后端](二)​

③,支付调用统一下单接口(请根据自身业务定义后端接口

<button style="width:90%;  margin-left:5%; margin-bottom:20px; height:40px;line-height:40px;background-color:#4395FF;color:white;border:none; font-size:11pt;font-weight:bold " onclick="SaveOrWxPay();">保存并缴费</button>

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_xml_12

SaveOrWxPay() {
$.ajax({
url: "/wxPay/pay2?openId="+ GetPar("token")+"&totalFee="+$("#labTotalCost").text()+"&operationNO="+$("#labOperationNO").text()+"&userName="+$("#UserName").val()+"&userPhone="+$("#UserPhone").val(),
dataType: "json",
async: false,
type: "GET",
success: function (data) {
wx.chooseWXPay({
timestamp: data.timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
nonceStr: data.nonceStr, // 支付签名随机串,不长于 32 位
package: data.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*)
signType: data.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
paySign: data.paySign, // 支付签名
success: function (res) {
//此处为支付成功后点击[完成]后的回调,可根据自身业务需求做相应处理

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_微信_13

2.后端核心代码

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_java_14

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_java_15

​编辑

根据统一订单API,必备的参数有:

appid:公众账号ID          mch_id:商户号                   nonce_str:随机字符串            sign:签名     

body:商品描述              out_trade_no:商户订单号   total_fee:标价金额                 spbill_create_ip:终端IP   

trade_type:交易类型        openid:用户标识,授权登录公众号获得                   

notify_url:通知地址(我们可以在这个里面处理支付成功后的业务逻辑,比如修改支付状态)

①openid获取可参考​​微信授权登录:移动端[unionid](一)​​,自行修改

②接下来就是关于支付的核心代码了

/**
* @description: 微信支付-统一下单
* @author: lvyq
* @date: 2020/9/16 16:30
* @version
@ApiOperation(value = "微信支付-统一下单")
@RequestMapping(value = "/pay2", method = {RequestMethod.POST, RequestMethod.GET})
public Object Orders(HttpServletRequest request, String openId, String tradeNo, String totalFee,String operationNO,String userName,String userPhone) {
CommonUtils commonUtils = new CommonUtils();
totalFee=String.format("%.0f", Float.valueOf(totalFee)*100);
//TODO 订单号暂自生成
tradeNo = new CommonUtils().getRandomStringByLength(32);
String nonce_str = WXPayUtil.generateNonceStr();
try {
Map<String, String> paraMap = new HashMap<>();
//获取请求ip地址
String ip = commonUtils.getIPAddress(request);
paraMap.put("appid", appid);
paraMap.put("mch_id", mchid);
paraMap.put("nonce_str", nonce_str);
//签名
String sign = WXPayUtil.generateSignature(paraMap, paternerKey);
paraMap.put("sign", sign);
paraMap.put("body", "维护管理服务费结算");
paraMap.put("out_trade_no", tradeNo);
paraMap.put("total_fee", totalFee);
paraMap.put("spbill_create_ip", ip);
// TODO 支付异步回调地址
//此处对中文进行转码
String RuserName=URLEncoder.encode(userName, "UTF-8");
paraMap.put("notify_url", commonUtils.getDomainName(request).toString() + "/wxPay/callback2/"+operationNO+"/"+RuserName+"/"+userPhone);
System.out.print("notify_url==="+commonUtils.getDomainName(request).toString() + "/wxPay/callback2/"+operationNO+"/"+RuserName+"/"+userPhone);
paraMap.put("trade_type", "JSAPI");
paraMap.put("openid", openId);
paraMap.put("sign_type", "MD5");
//将所有参数(map)转xml格式
// String xml = WXPayUtil.mapToXml(paraMap);
String xml = WXPayUtil.generateSignedXml(paraMap, paternerKey);
//发送post请求"统一下单接口"返回预支付id:prepay_id
String xmlStr = HttpRequest.sendPost(unifiedorderUrl, xml);
String prepay_id = "";//预支付id
if (xmlStr.indexOf("SUCCESS") != -1) {
Map<String, String> map = WXPayUtil.xmlToMap(xmlStr);
prepay_id = (String) map.get("prepay_id");
}
Map<String, String> payMap = new HashMap<String, String>();
payMap.put("appId", appid);
payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp() + "");
payMap.put("nonceStr", WXPayUtil.generateNonceStr());
payMap.put("signType", "MD5");
payMap.put("package", "prepay_id=" + prepay_id);
String paySign = WXPayUtil.generateSignature(payMap, paternerKey);
payMap.put("paySign", paySign);
return payMap;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

/**
* @description: 支付回调地址
* @author: lvyq
* @date: 2020/9/17 16:06
* @version
@ApiOperation(value = "支付回调地址")
@RequestMapping(value = "/callback2/{operationNO}/{userName}/{userPhone}", method = {RequestMethod.POST, RequestMethod.GET})
public String CallBack(HttpServletRequest request, HttpServletResponse response,@PathVariable("operationNO") String operationNO,@PathVariable("userName") String userName,@PathVariable("userPhone") throws Exception {
InputStream is = null;
//解码
String RuserName=URLDecoder.decode(userName,"UTF-8");
System.out.print("RuserName==="+RuserName+"userName=="+userName);
try {
//获取请求的流信息(这里是微信发的xml格式所有只能使用流来读)
is = request.getInputStream();
String xml = commonUtils.nputStream2String(is);
//将微信发的xml转map
Map<String, String> notifyMap = WXPayUtil.xmlToMap(xml);
if (WXPayUtil.isSignatureValid(notifyMap,paternerKey)) {
if (notifyMap.get("return_code").equals("SUCCESS")) {
if (notifyMap.get("result_code").equals("SUCCESS")) {
//TODO 业务代码,对数据增删改查等。。。
}
}
}else {
// 签名错误,如果数据里没有sign字段,也认为是签名错误
}
//告诉微信服务器收到信息了,防止微信重复回调
response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>");
is.close();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_微信_16

③,以下附上commonUtil部分代码

package com.jmdz.util;

import com.alibaba.fastjson.JSONObject;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.ConnectException;
import java.net.URL;
import java.util.Random;

/**
* @description: 公共工具
* @author: lvyq
* @date: 2020/9/15 11:35
* @version
public class CommonUtils {

/**
* @description: 获取域名(协议+域名)
* @author: lvyq
* @date: 2020/9/15 11:36
* @version
public String getDomainName(HttpServletRequest request){
// return request.getServerName()+":"+request.getServerPort();
return request.getScheme()+"://"+request.getServerName();
}

public String getIPAddress(HttpServletRequest request){
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
if (ip.indexOf(",") != -1) {
String[] ips = ip.split(",");
ip = ips[0].trim();
}
return ip;
}


public static String getRandomStringByLength(int {
String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}


public static String nputStream2String(InputStream in) {
InputStreamReader reader = null;
try {
reader = new InputStreamReader(in, "UTF-8");
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
BufferedReader br = new BufferedReader(reader);
StringBuilder sb = new StringBuilder();
String line = "";
try {
while ((line = br.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}
return

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_xml_17

③.HttpRequest

package com.jmdz.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;

public class HttpRequest {

/**
* 向指定URL发送GET方法的请求
*
* @param url
* 发送请求的URL
* @param param
* 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return
public static String sendGet(String url, String param) {
String result = "";
BufferedReader in = null;
try {
String urlNameString = url + "?" + param;
System.out.println(urlNameString);
URL realUrl = new URL(urlNameString);
// 打开和URL之间的连接
URLConnection connection = realUrl.openConnection();
// 设置通用的请求属性
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 建立实际的连接
connection.connect();
// 获取所有响应头字段
Map<String, List<String>> map = connection.getHeaderFields();
// 遍历所有的响应头字段
for (String key : map.keySet()) {
System.out.println(key + "--->" + map.get(key));
}
// 定义 BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送GET请求出现异常!" + e);
e.printStackTrace();
}
// 使用finally块来关闭输入流
finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return result;
}

/**
* 向指定 URL 发送POST方法的请求
*
* @param url
* 发送请求的 URL
* @param param
* 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return
public static String sendPost(String url, String param) {
PrintWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
out = new PrintWriter(conn.getOutputStream());
// 发送请求参数
out.print(param);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送 POST 请求出现异常!"+e);
e.printStackTrace();
}
//使用finally块来关闭输出流、输入流
finally{
try{
if(out!=null){
out.close();
}
if(in!=null){
in.close();
}
}
catch(IOException ex){
ex.printStackTrace();
}
}
return

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_java_18

④,WXPayUtil (这个官网提供的demo里面就有,直接拿来用就行。我就不贴代码了)

三,查看效果

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_微信_19

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_java_20

​编辑

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_微信_21

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_xml_22

​编辑

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_java_23

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_java_24

​编辑

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_java_25

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_微信_26

编辑

==============================分割线==============================

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_微信_27

微信支付-JSAPI:代码实现(支付异步回调中传中文参数解决)_xml_28

​编辑

1.为了notify_url接口里面接受参数,我们的接口采用restful。伪造一个不带参数的url

2.回调地址含中文的话无法回调地址,故在统一下单时,对中文参数进行编码,接收时再解码即可


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  M5nxXzKbD3Q7   2023年11月12日   24   0   0 xmlmavenjar
  ehrZuhofWJiC   2024年04月26日   42   0   0 日志Java
rk9eeCbx5EiP