微信小程序 支付后台java实现实例

前言:
前些天使用 LeanCloud 云引擎写了个小程序的支付相关 以前只做过 APP 支付 这次在小程序支付爬了两天的坑 把代码也分享出来
支付流程:
1.小程序前端获取微信 openId 以及订单号 传给后台
2,后台根据 openId 和订单号进行签名 post 微信统一下单接口
3.后台获取微信返回的xml字符串 解析 二次签名以后返回给前端
4.前端调起支付微信支付 API
先看支付函数:
//获取支付信息
@EngineFunction("getPayInformation")
public static Map<String, Object> getPayInformation(
@EngineFunctionParam("orderId") String orderId
) throws AVException, UnsupportedEncodingException, DocumentException {
Map<String, Object> reqMap = new TreeMap<String, Object>(
new Comparator<String>() {
public int compare(String obj1, String obj2) {
// 升序排序
return obj1.compareTo(obj2);
}
});
if (AVUser.getCurrentUser() != null) {
String authDataJson = JSONArray.toJSONString(AVUser.getCurrentUser().get("authData"));
JSONObject jsonObject = JSON.parseObject(authDataJson);
jsonObject.get("lc_weapp");
JSONObject j2 = JSON.parseObject(jsonObject.get("lc_weapp").toString());
String openId = (String) j2.get("openid");
AVQuery<Order> query = AVObject.getQuery(Order.class);
Order order = query.get(orderId);
reqMap.put("appid", System.getenv("appid"));
reqMap.put("mch_id", System.getenv("mch_id"));
reqMap.put("nonce_str", WXPayUtil.getNonce_str());
reqMap.put("body", new String(order.getDishesList().toString().getBytes("UTF-8")));
reqMap.put("openid", openId);
reqMap.put("out_trade_no", order.getObjectId());
reqMap.put("total_fee", 1); //订单总金额,单位为分
reqMap.put("spbill_create_ip", "192.168.0.1"); //用户端ip
reqMap.put("notify_url", System.getenv("notify_url")); //通知地址
reqMap.put("trade_type", System.getenv("trade_type")); //trade_type=JSAPI时(即公众号支付),此参数必传,此参数为微信用户在商户对应appid下的唯一标识
String reqStr = WXPayUtil.map2Xml(reqMap);
String resultXml = HttpRequest.sendPost(reqStr);
System.out.println("微信请求返回:" + resultXml);
//解析微信返回串 如果状态成功 则返回给前端
if (WXPayUtil.getReturnCode(resultXml) != null && WXPayUtil.getReturnCode(resultXml).equals("SUCCESS")) {
//成功
Map<String, Object> resultMap = new TreeMap<>(
new Comparator<String>() {
public int compare(String obj1, String obj2) {
// 升序排序
return obj1.compareTo(obj2);
}
});
resultMap.put("appId", System.getenv("appid"));
resultMap.put("nonceStr", WXPayUtil.getNonceStr(resultXml));//解析随机字符串
resultMap.put("package", "prepay_id=" + WXPayUtil.getPrepayId(resultXml));
resultMap.put("signType", "MD5");
resultMap.put("timeStamp", String.valueOf((System.currentTimeMillis() / 1000)));//时间戳
String paySign = WXPayUtil.getSign(resultMap);
resultMap.put("paySign", paySign);
return resultMap;
} else {
throw new AVException(999, "微信请求支付失败");
}
} else {
throw new AVException(98, "当前未登录用户");
}
}
其中appid和mch_id可以用系统常量
PS:这里注意一个坑
二次签名的时候使用 appId nonceStr package signType timeStamp 这五个key生成签名(这里无视微信官方文档 以及注意 appId 的大小写)
前端调起API支付时 按照官方文档就可以
网络请求类:
HttpRequest
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 URL 所代表远程资源的响应结果
*/
public static String sendGet(String url, String param) {
String result = "";
BufferedReader in = null;
try {
String urlNameString = url + "?" + param;
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 param) {
PrintWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL("https://api.mch.weixin.qq.com/pay/unifiedorder");
// 打开和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)");
// conn.setRequestProperty("Pragma:", "no-cache");
// conn.setRequestProperty("Cache-Control", "no-cache");
// conn.setRequestProperty("Content-Type", "text/xml;charset=utf-8");
// 发送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 result;
}
}
XML解析工具类
WXPayUtil
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import java.util.Random;
public class WXPayUtil {
//生成随机字符串
public static String getNonce_str() {
String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random random = new Random();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 15; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
//map转xml 加上签名信息
public static String map2Xml(Map<String, Object> map) throws UnsupportedEncodingException {
StringBuffer sb = new StringBuffer();
StringBuilder sb2 = new StringBuilder();
sb2.append("<xml>");
for (String key : map.keySet()) {
sb.append(key);
sb.append('=');
sb.append(map.get(key));
sb.append('&');
// sb2是用来做请求的xml参数
sb2.append("<" + key + ">");
// sb2.append("<![CDATA[" + map.get(key) + "]]>");
sb2.append(map.get(key));
sb2.append("</" + key + ">");
}
sb.append(System.getenv("signKey"));
String sign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
sb2.append("<sign>");
sb2.append(sign);
sb2.append("</sign>");
sb2.append("</xml>");
return sb2.toString();
}
//解析微信返回return_code SUCCESS或FILE
//根据微信返回resultXml再次生成签名
public static String getSign(Map<String, Object> map) {
StringBuffer sb = new StringBuffer();
for (String key : map.keySet()) {
sb.append(key);
sb.append('=');
sb.append(map.get(key));
sb.append('&');
}
sb.append(System.getenv("signKey"));
System.out.println("第二次签名内容:" + sb);
System.out.println("第二次签名SING:" + MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase());
return MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
}
//解析微信返回return_code SUCCESS或FILE
public static String getReturnCode(String resultXml) {
String nonceStr;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
try {
builder = dbf.newDocumentBuilder();
InputStream inputStream = new ByteArrayInputStream(resultXml.getBytes());
org.w3c.dom.Document doc = builder.parse(inputStream); //
// 下面开始读取
org.w3c.dom.Element root = doc.getDocumentElement(); // 获取根元素
NodeList nl = root.getElementsByTagName("return_code");
org.w3c.dom.Element el = (org.w3c.dom.Element) nl.item(0);
org.w3c.dom.Node nd = el.getFirstChild();
nonceStr = nd.getNodeValue();
return nonceStr;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
//解析微信返回return_msg
public static String getReturn_msg(String resultXml) {
String nonceStr;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
try {
builder = dbf.newDocumentBuilder();
InputStream inputStream = new ByteArrayInputStream(resultXml.getBytes());
org.w3c.dom.Document doc = builder.parse(inputStream); //
// 下面开始读取
org.w3c.dom.Element root = doc.getDocumentElement(); // 获取根元素
NodeList nl = root.getElementsByTagName("return_msg");
org.w3c.dom.Element el = (org.w3c.dom.Element) nl.item(0);
org.w3c.dom.Node nd = el.getFirstChild();
nonceStr = nd.getNodeValue();
return nonceStr;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
//解析微信返回appid
public static String getAppId(String resultXml) {
String nonceStr;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
try {
builder = dbf.newDocumentBuilder();
InputStream inputStream = new ByteArrayInputStream(resultXml.getBytes());
org.w3c.dom.Document doc = builder.parse(inputStream); //
// 下面开始读取
org.w3c.dom.Element root = doc.getDocumentElement(); // 获取根元素
NodeList nl = root.getElementsByTagName("appid");
org.w3c.dom.Element el = (org.w3c.dom.Element) nl.item(0);
org.w3c.dom.Node nd = el.getFirstChild();
nonceStr = nd.getNodeValue();
return nonceStr;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
//解析微信返回mch_id
public static String getMchId(String resultXml) {
String nonceStr;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
try {
builder = dbf.newDocumentBuilder();
InputStream inputStream = new ByteArrayInputStream(resultXml.getBytes());
org.w3c.dom.Document doc = builder.parse(inputStream); //
// 下面开始读取
org.w3c.dom.Element root = doc.getDocumentElement(); // 获取根元素
NodeList nl = root.getElementsByTagName("mch_id");
org.w3c.dom.Element el = (org.w3c.dom.Element) nl.item(0);
org.w3c.dom.Node nd = el.getFirstChild();
nonceStr = nd.getNodeValue();
return nonceStr;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
//解析微信返回nonce_str
public static String getNonceStr(String resultXml) {
String nonceStr;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
try {
builder = dbf.newDocumentBuilder();
InputStream inputStream = new ByteArrayInputStream(resultXml.getBytes());
org.w3c.dom.Document doc = builder.parse(inputStream); //
// 下面开始读取
org.w3c.dom.Element root = doc.getDocumentElement(); // 获取根元素
NodeList nl = root.getElementsByTagName("nonce_str");
org.w3c.dom.Element el = (org.w3c.dom.Element) nl.item(0);
org.w3c.dom.Node nd = el.getFirstChild();
nonceStr = nd.getNodeValue();
return nonceStr;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
//解析微信返回prepay_id
public static String getPrepayId(String resultXml) {
String nonceStr;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
try {
builder = dbf.newDocumentBuilder();
InputStream inputStream = new ByteArrayInputStream(resultXml.getBytes());
org.w3c.dom.Document doc = builder.parse(inputStream); //
// 下面开始读取
org.w3c.dom.Element root = doc.getDocumentElement(); // 获取根元素
NodeList nl = root.getElementsByTagName("prepay_id");
org.w3c.dom.Element el = (org.w3c.dom.Element) nl.item(0);
org.w3c.dom.Node nd = el.getFirstChild();
nonceStr = nd.getNodeValue();
return nonceStr;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
# 微信小程序
# 支付后台java实现
# 小程序
# 后台java支付程序
# java遇到微信小程序 "支付验证签名失败" 问题解决
# Java后端对接微信支付(小程序、APP、PC端扫码)包含查单退款
# SpringBoot整合weixin-java-pay实现微信小程序支付的示例代码
# 利用微信小程序+JAVA实现微信支付的全过程
# 升序
# 应该是
# 文档
# 可以用
# 遍历
# 两天
# 希望能
# 做过
# 写了
# 谢谢大家
# 商户
# 先看
# 下单
# 爬了
# 总金额
# 两行
# 就可以
# 这五
# 前些天
# 是用来
相关文章:
C++中引用和指针有什么区别?(代码说明)
香港服务器建站指南:免备案优势与SEO优化技巧全解析
网站网页制作专业公司,怎样制作自己的网页?
高端建站三要素:定制模板、企业官网与响应式设计优化
三星网站视频制作教程下载,三星w23网页如何全屏?
建站一年半SEO优化实战指南:核心词挖掘与长尾流量提升策略
音响网站制作视频教程,隆霸音响官方网站?
建站之星ASP如何实现CMS高效搭建与安全管理?
宝塔建站教程:一键部署配置流程与SEO优化实战指南
如何挑选高效建站主机与优质域名?
css网站制作参考文献有哪些,易聊怎么注册?
品牌网站制作公司有哪些,买正品品牌一般去哪个网站买?
内网网站制作软件,内网的网站如何发布到外网?
广州顶尖建站服务:企业官网建设与SEO优化一体化方案
惠州网站建设制作推广,惠州市华视达文化传媒有限公司怎么样?
建站之星如何快速生成多端适配网站?
电商网站制作价格怎么算,网上拍卖流程以及规则?
网站制作软件免费下载安装,有哪些免费下载的软件网站?
如何实现建站之星域名转发设置?
如何快速搭建响应式可视化网站?
如何在阿里云购买域名并搭建网站?
制作公司内部网站有哪些,内网如何建网站?
如何在VPS电脑上快速搭建网站?
如何在阿里云虚拟主机上快速搭建个人网站?
网站制作公司广州有几家,广州尚艺美发学校网站是多少?
如何选择域名并搭建高效网站?
C++如何编写函数模板?(泛型编程入门)
如何处理“XML格式不正确”错误 常见XML well-formed问题解决方法
建站之星后台密码遗忘如何找回?
南阳网站制作公司推荐,小学电子版试卷去哪里找资源好?
交易网站制作流程,我想开通一个网站,注册一个交易网址,需要那些手续?
建站IDE高效指南:快速搭建+SEO优化+自适应模板全解析
香港代理服务器配置指南:高匿IP选择、跨境加速与SEO优化技巧
网站制作员失业,怎样查看自己网站的注册者?
如何在Golang中处理模块冲突_解决依赖版本不兼容问题
图片制作网站免费软件,有没有免费的网站或软件可以将图片批量转为A4大小的pdf?
建站主机是否等同于虚拟主机?
制作网站的公司有哪些,做一个公司网站要多少钱?
免费制作海报的网站,哪位做平面的朋友告诉我用什么软件做海报比较好?ps还是cd还是ai这几个软件我都会些我是做网页的?
济南企业网站制作公司,济南社保单位网上缴费步骤?
临沂网站制作公司有哪些,临沂第四中学官网?
建站主机空间推荐 高性价比配置与快速部署方案解析
如何选择高效稳定的ISP建站解决方案?
建站OpenVZ教程与优化策略:配置指南与性能提升
婚礼视频制作网站,学习*后期制作的网站有哪些?
建站之星如何开启自定义404页面避免用户流失?
如何快速配置高效服务器建站软件?
上海网站制作网页,上海本地的生活网站有哪些?最好包括生活的各个方面的?
如何在企业微信快速生成手机电脑官网?
建站之星如何助力网站排名飙升?揭秘高效技巧
*请认真填写需求信息,我们会在24小时内与您取得联系。