JavaScript

超轻量级php框架startmvc

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

更新时间:2020-05-11 00:06 作者:startmvc
微信小程序支付后台java实现实例前言:前些天使用LeanCloud云引擎写了个小程序的支付相关

微信小程序 支付后台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;
 }
 }


}

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!