微信小程序 支付后臺(tái)java實(shí)現(xiàn)實(shí)例
微信小程序 支付后臺(tái)java實(shí)現(xiàn)實(shí)例
前言:
前些天使用 LeanCloud 云引擎寫了個(gè)小程序的支付相關(guān) 以前只做過 APP 支付 這次在小程序支付爬了兩天的坑 把代碼也分享出來
支付流程:
1.小程序前端獲取微信 openId 以及訂單號(hào) 傳給后臺(tái)
2,后臺(tái)根據(jù) openId 和訂單號(hào)進(jìn)行簽名 post 微信統(tǒng)一下單接口
3.后臺(tái)獲取微信返回的xml字符串 解析 二次簽名以后返回給前端
4.前端調(diào)起支付微信支付 API
先看支付函數(shù):
//獲取支付信息
@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時(shí)(即公眾號(hào)支付),此參數(shù)必傳,此參數(shù)為微信用戶在商戶對(duì)應(yīng)appid下的唯一標(biāo)識(shí)
String reqStr = WXPayUtil.map2Xml(reqMap);
String resultXml = HttpRequest.sendPost(reqStr);
System.out.println("微信請(qǐng)求返回:" + resultXml);
//解析微信返回串 如果狀態(tài)成功 則返回給前端
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));//解析隨機(jī)字符串
resultMap.put("package", "prepay_id=" + WXPayUtil.getPrepayId(resultXml));
resultMap.put("signType", "MD5");
resultMap.put("timeStamp", String.valueOf((System.currentTimeMillis() / 1000)));//時(shí)間戳
String paySign = WXPayUtil.getSign(resultMap);
resultMap.put("paySign", paySign);
return resultMap;
} else {
throw new AVException(999, "微信請(qǐng)求支付失敗");
}
} else {
throw new AVException(98, "當(dāng)前未登錄用戶");
}
}
其中appid和mch_id可以用系統(tǒng)常量
PS:這里注意一個(gè)坑
二次簽名的時(shí)候使用 appId nonceStr package signType timeStamp 這五個(gè)key生成簽名(這里無視微信官方文檔 以及注意 appId 的大小寫)
前端調(diào)起API支付時(shí) 按照官方文檔就可以
網(wǎng)絡(luò)請(qǐng)求類:
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發(fā)送GET方法的請(qǐng)求
*
* @param url 發(fā)送請(qǐng)求的URL
* @param param 請(qǐng)求參數(shù),請(qǐng)求參數(shù)應(yīng)該是 name1=value1&name2=value2 的形式。
* @return URL 所代表遠(yuǎn)程資源的響應(yīng)結(jié)果
*/
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();
// 設(shè)置通用的請(qǐng)求屬性
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 建立實(shí)際的連接
connection.connect();
// 獲取所有響應(yīng)頭字段
Map<String, List<String>> map = connection.getHeaderFields();
// 遍歷所有的響應(yīng)頭字段
for (String key : map.keySet()) {
System.out.println(key + "--->" + map.get(key));
}
// 定義 BufferedReader輸入流來讀取URL的響應(yīng)
in = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("發(fā)送GET請(qǐng)求出現(xiàn)異常!" + e);
e.printStackTrace();
}
// 使用finally塊來關(guān)閉輸入流
finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return result;
}
/**
* 向指定 URL 發(fā)送POST方法的請(qǐng)求
*
* @param url 發(fā)送請(qǐng)求的 URL
* @param param 請(qǐng)求參數(shù),請(qǐng)求參數(shù)應(yīng)該是 name1=value1&name2=value2 的形式。
* @return 所代表遠(yuǎn)程資源的響應(yīng)結(jié)果
*/
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();
// 設(shè)置通用的請(qǐng)求屬性
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");
// 發(fā)送POST請(qǐng)求必須設(shè)置如下兩行
conn.setDoOutput(true);
conn.setDoInput(true);
// 獲取URLConnection對(duì)象對(duì)應(yīng)的輸出流
out = new PrintWriter(conn.getOutputStream());
// 發(fā)送請(qǐng)求參數(shù)
out.print(param);
// flush輸出流的緩沖
out.flush();
// 定義BufferedReader輸入流來讀取URL的響應(yīng)
in = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("發(fā)送 POST 請(qǐng)求出現(xiàn)異常!" + e);
e.printStackTrace();
}
//使用finally塊來關(guān)閉輸出流、輸入流
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 {
//生成隨機(jī)字符串
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轉(zhuǎn)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是用來做請(qǐng)求的xml參數(shù)
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
//根據(jù)微信返回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("第二次簽名內(nèi)容:" + 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;
}
}
}
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
微信小程序 flex實(shí)現(xiàn)導(dǎo)航實(shí)例詳解
這篇文章主要介紹了微信小程序 flex實(shí)現(xiàn)導(dǎo)航實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-04-04

