微信小程式支付 java
話不多說,直接開擼。
支付流程步驟:
1)首先呼叫wx.login方法獲取code,通過code獲取openid;
2)java後臺呼叫統一下單支付介面(這裡會進行第一次簽名),用來獲取prepay_id;
3)java後臺再次呼叫簽名(這裡會進行第二次簽名),並返回支付需要用使用的引數;
4)小程式前端wx.requestPayment方法發起微信支付;
5)java後臺接收來自微信伺服器的通知並處理結果。
詳細步驟可參考:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_4&index=3
demo連結: https://pan.baidu.com/s/1v8QWUE1m2EnA4uAoAZtRRQ 密碼: cgrt
一、獲取openid,
這裡的程式碼可以參考博主的另外一篇文章http://blog.csdn.net/zhourenfei17/article/details/77714600中的 3.1 程式碼模組,程式碼先貼上,如果瞭解更多點選連結檢視
小程式端程式碼
wx.login({ success: function (res) { var service_url = 'https://???/???/weixin/api/login?code=' + res.code;//需要將伺服器域名新增到小程式的request合法域名中,而且必須是https開頭 wx.request({ url: l, data: {}, method: 'GET', success: function (res) { console.log(res); if (res.data != null && res.data != undefined && res.data != '') { wx.setStorageSync("openid", res.data.openid);//將獲取的openid存到快取中 } } }); } });
java後端程式碼
/** * 小程式後臺登入,向微信平臺傳送獲取access_token請求,並返回openId * @param code * @return 使用者憑證 * @throws WeixinException * @throws IOException * @throws JsonMappingException * @throws JsonParseException */ @RequestMapping("login") @ResponseBody public Map<String, Object> login(String code, HttpServletRequest request) throws WeixinException, JsonParseException, JsonMappingException, IOException { if (code == null || code.equals("")) { throw new WeixinException("invalid null, code is null."); } Map<String, Object> ret = new HashMap<String, Object>(); //拼接引數 String param = "?grant_type=" + grant_type + "&appid=" + appid + "&secret=" + secret + "&js_code=" + code; System.out.println("https://api.weixin.qq.com/sns/jscode2session" + param); //建立請求物件 HttpsClient http = new HttpsClient(); //呼叫獲取access_token介面 Response res = http.get("https://api.weixin.qq.com/sns/jscode2session" + param); //根據請求結果判定,是否驗證成功 JSONObject jsonObj = res.asJSONObject(); if (jsonObj != null) { Object errcode = jsonObj.get("errcode"); if (errcode != null) { //返回異常資訊 throw new WeixinException(getCause(Integer.parseInt(errcode.toString()))); } ObjectMapper mapper = new ObjectMapper(); OAuthJsToken oauthJsToken = mapper.readValue(jsonObj.toJSONString(),OAuthJsToken.class); ret.put("openid", oauthJsToken.getOpenid()); } return ret; }
二、小程式呼叫java後端介面,生成最終簽名和相關引數小程式端程式碼:
var that = this;
wx.request({
url: service_url + 'wxPay',
data: { },
method: 'GET',
success: function (res) {
console.log(res);
that.doWxPay(res.data);
}
});
java端程式碼:
/**
* @Description: 發起微信支付
* @param request
*/
public Map<String, Object> wxPay(Integer openid, HttpServletRequest request){
try{
//生成的隨機字串
String nonce_str = StringUtils.getRandomStringByLength(32);
//商品名稱
String body = "測試商品名稱";
//獲取客戶端的ip地址
String spbill_create_ip = IpUtil.getIpAddr(request);
//組裝引數,使用者生成統一下單介面的簽名
Map<String, String> packageParams = new HashMap<String, String>();
packageParams.put("appid", WxPayConfig.appid);
packageParams.put("mch_id", WxPayConfig.mch_id);
packageParams.put("nonce_str", nonce_str);
packageParams.put("body", body);
packageParams.put("out_trade_no", "123456789");//商戶訂單號
packageParams.put("total_fee", "1");//支付金額,這邊需要轉成字串型別,否則後面的簽名會失敗
packageParams.put("spbill_create_ip", spbill_create_ip);
packageParams.put("notify_url", WxPayConfig.notify_url);//支付成功後的回撥地址
packageParams.put("trade_type", WxPayConfig.TRADETYPE);//支付方式
packageParams.put("openid", openid);
String prestr = PayUtil.createLinkString(packageParams); // 把陣列所有元素,按照“引數=引數值”的模式用“&”字元拼接成字串
//MD5運算生成簽名,這裡是第一次簽名,用於呼叫統一下單介面
String mysign = PayUtil.sign(prestr, WxPayConfig.key, "utf-8").toUpperCase();
//拼接統一下單介面使用的xml資料,要將上一步生成的簽名一起拼接進去
String xml = "<xml>" + "<appid>" + WxPayConfig.appid + "</appid>"
+ "<body><![CDATA[" + body + "]]></body>"
+ "<mch_id>" + WxPayConfig.mch_id + "</mch_id>"
+ "<nonce_str>" + nonce_str + "</nonce_str>"
+ "<notify_url>" + WxPayConfig.notify_url + "</notify_url>"
+ "<openid>" + openid + "</openid>"
+ "<out_trade_no>" + "123456789" + "</out_trade_no>"
+ "<spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>"
+ "<total_fee>" + "1" + "</total_fee>"
+ "<trade_type>" + WxPayConfig.TRADETYPE + "</trade_type>"
+ "<sign>" + mysign + "</sign>"
+ "</xml>";
System.out.println("除錯模式_統一下單介面 請求XML資料:" + xml);
//呼叫統一下單介面,並接受返回的結果
String result = PayUtil.httpRequest(WxPayConfig.pay_url, "POST", xml);
System.out.println("除錯模式_統一下單介面 返回XML資料:" + result);
// 將解析結果儲存在HashMap中
Map map = PayUtil.doXMLParse(result);
String return_code = (String) map.get("return_code");//返回狀態碼
Map<String, Object> response = new HashMap<String, Object>();//返回給小程式端需要的引數
if(return_code.equals("SUCCESS")){
String prepay_id = (String) map.get("prepay_id");//返回的預付單資訊
response.put("nonceStr", nonce_str);
response.put("package", "prepay_id=" + prepay_id);
Long timeStamp = System.currentTimeMillis() / 1000;
response.put("timeStamp", timeStamp + "");//這邊要將返回的時間戳轉化成字串,不然小程式端呼叫wx.requestPayment方法會報簽名錯誤
//拼接簽名需要的引數
String stringSignTemp = "appId=" + WxPayConfig.appid + "&nonceStr=" + nonce_str + "&package=prepay_id=" + prepay_id+ "&signType=MD5&timeStamp=" + timeStamp;
//再次簽名,這個簽名用於小程式端呼叫wx.requesetPayment方法
String paySign = PayUtil.sign(stringSignTemp, WxPayConfig.key, "utf-8").toUpperCase();
response.put("paySign", paySign);
}
response.put("appid", WxPayConfig.appid);
return response;
}catch(Exception e){
e.printStackTrace();
}
return null;
}
/**
* StringUtils工具類方法
* 獲取一定長度的隨機字串,範圍0-9,a-z
* @param length:指定字串長度
* @return 一定長度的隨機字串
*/
public static String getRandomStringByLength(int length) {
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();
}
/**
* IpUtils工具類方法
* 獲取真實的ip地址
* @param request
* @return
*/
public static String getIpAddr(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){
//多次反向代理後會有多個ip值,第一個ip才是真實ip
int index = ip.indexOf(",");
if(index != -1){
return ip.substring(0,index);
}else{
return ip;
}
}
ip = request.getHeader("X-Real-IP");
if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){
return ip;
}
return request.getRemoteAddr();
}
WxPayConfig小程式配置檔案
/**
* 小程式微信支付的配置檔案
* @author
*
*/
public class WxPayConfig {
//小程式appid
public static final String appid = "";
//微信支付的商戶id
public static final String mch_id = "";
//微信支付的商戶金鑰
public static final String key = "";
//支付成功後的伺服器回撥url
public static final String notify_url = "https://??/??/weixin/api/wxNotify";
//簽名方式,固定值
public static final String SIGNTYPE = "MD5";
//交易型別,小程式支付的固定值為JSAPI
public static final String TRADETYPE = "JSAPI";
//微信統一下單介面地址
public static final String pay_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
}
PayUtils工具類
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.SignatureException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.codec.digest.DigestUtils;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
public class PayUtil {
/**
* 簽名字串
* @param text需要簽名的字串
* @param key 金鑰
* @param input_charset編碼格式
* @return 簽名結果
*/
public static String sign(String text, String key, String input_charset) {
text = text + "&key=" + key;
return DigestUtils.md5Hex(getContentBytes(text, input_charset));
}
/**
* 簽名字串
* @param text需要簽名的字串
* @param sign 簽名結果
* @param key金鑰
* @param input_charset 編碼格式
* @return 簽名結果
*/
public static boolean verify(String text, String sign, String key, String input_charset) {
text = text + key;
String mysign = DigestUtils.md5Hex(getContentBytes(text, input_charset));
if (mysign.equals(sign)) {
return true;
} else {
return false;
}
}
/**
* @param content
* @param charset
* @return
* @throws SignatureException
* @throws UnsupportedEncodingException
*/
public static byte[] getContentBytes(String content, String charset) {
if (charset == null || "".equals(charset)) {
return content.getBytes();
}
try {
return content.getBytes(charset);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("MD5簽名過程中出現錯誤,指定的編碼集不對,您目前指定的編碼集是:" + charset);
}
}
private static boolean isValidChar(char ch) {
if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))
return true;
if ((ch >= 0x4e00 && ch <= 0x7fff) || (ch >= 0x8000 && ch <= 0x952f))
return true;// 簡體中文漢字編碼
return false;
}
/**
* 除去陣列中的空值和簽名引數
* @param sArray 簽名引數組
* @return 去掉空值與簽名引數後的新簽名引數組
*/
public static Map<String, String> paraFilter(Map<String, String> sArray) {
Map<String, String> result = new HashMap<String, String>();
if (sArray == null || sArray.size() <= 0) {
return result;
}
for (String key : sArray.keySet()) {
String value = sArray.get(key);
if (value == null || value.equals("") || key.equalsIgnoreCase("sign")
|| key.equalsIgnoreCase("sign_type")) {
continue;
}
result.put(key, value);
}
return result;
}
/**
* 把陣列所有元素排序,並按照“引數=引數值”的模式用“&”字元拼接成字串
* @param params 需要排序並參與字元拼接的引數組
* @return 拼接後字串
*/
public static String createLinkString(Map<String, String> params) {
List<String> keys = new ArrayList<String>(params.keySet());
Collections.sort(keys);
String prestr = "";
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);
if (i == keys.size() - 1) {// 拼接時,不包括最後一個&字元
prestr = prestr + key + "=" + value;
} else {
prestr = prestr + key + "=" + value + "&";
}
}
return prestr;
}
/**
*
* @param requestUrl請求地址
* @param requestMethod請求方法
* @param outputStr引數
*/
public static String httpRequest(String requestUrl,String requestMethod,String outputStr){
// 建立SSLContext
StringBuffer buffer = null;
try{
URL url = new URL(requestUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod(requestMethod);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.connect();
//往伺服器端寫內容
if(null !=outputStr){
OutputStream os=conn.getOutputStream();
os.write(outputStr.getBytes("utf-8"));
os.close();
}
// 讀取伺服器端返回的內容
InputStream is = conn.getInputStream();
InputStreamReader isr = new InputStreamReader(is, "utf-8");
BufferedReader br = new BufferedReader(isr);
buffer = new StringBuffer();
String line = null;
while ((line = br.readLine()) != null) {
buffer.append(line);
}
br.close();
}catch(Exception e){
e.printStackTrace();
}
return buffer.toString();
}
public static String urlEncodeUTF8(String source){
String result=source;
try {
result=java.net.URLEncoder.encode(source, "UTF-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
/**
* 解析xml,返回第一級元素鍵值對。如果第一級元素有子節點,則此節點的值是子節點的xml資料。
* @param strxml
* @return
* @throws JDOMException
* @throws IOException
*/
public static Map doXMLParse(String strxml) throws Exception {
if(null == strxml || "".equals(strxml)) {
return null;
}
/*============= !!!!注意,修復了微信官方反饋的漏洞,更新於2018-10-16 ===========*/
try {
Map<String, String> data = new HashMap<String, String>();
// TODO 在這裡更換
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
documentBuilderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
documentBuilderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
documentBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
documentBuilderFactory.setXIncludeAware(false);
documentBuilderFactory.setExpandEntityReferences(false);
InputStream stream = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
org.w3c.dom.Document doc = documentBuilderFactory.newDocumentBuilder().parse(stream);
doc.getDocumentElement().normalize();
NodeList nodeList = doc.getDocumentElement().getChildNodes();
for (int idx = 0; idx < nodeList.getLength(); ++idx) {
Node node = nodeList.item(idx);
if (node.getNodeType() == Node.ELEMENT_NODE) {
org.w3c.dom.Element element = (org.w3c.dom.Element) node;
data.put(element.getNodeName(), element.getTextContent());
}
}
try {
stream.close();
} catch (Exception ex) {
// do nothing
}
return data;
} catch (Exception ex) {
throw ex;
}
}
/**
* 獲取子結點的xml
* @param children
* @return String
*/
public static String getChildrenText(List children) {
StringBuffer sb = new StringBuffer();
if(!children.isEmpty()) {
Iterator it = children.iterator();
while(it.hasNext()) {
Element e = (Element) it.next();
String name = e.getName();
String value = e.getTextNormalize();
List list = e.getChildren();
sb.append("<" + name + ">");
if(!list.isEmpty()) {
sb.append(getChildrenText(list));
}
sb.append(value);
sb.append("</" + name + ">");
}
}
return sb.toString();
}
public static InputStream String2Inputstream(String str) {
return new ByteArrayInputStream(str.getBytes());
}
}
三、小程式端發起最終支付,呼叫微信付款
doWxPay(param){
//小程式發起微信支付
wx.requestPayment({
timeStamp: param.data.timeStamp,//記住,這邊的timeStamp一定要是字串型別的,不然會報錯,我這邊在java後端包裝成了字串型別了
nonceStr: param.data.nonceStr,
package: param.data.package,
signType: 'MD5',
paySign: param.data.paySign,
success: function (event) {
// success
console.log(event);
wx.showToast({
title: '支付成功',
icon: 'success',
duration: 2000
});
},
fail: function (error) {
// fail
console.log("支付失敗")
console.log(error)
},
complete: function () {
// complete
console.log("pay complete")
}
});
}
四、微信伺服器通知java後端
/**
* @Description:微信支付
* @return
* @throws Exception
*/
@RequestMapping(value="/wxNotify")
@ResponseBody
public void wxNotify(HttpServletRequest request,HttpServletResponse response) throws Exception{
BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream)request.getInputStream()));
String line = null;
StringBuilder sb = new StringBuilder();
while((line = br.readLine()) != null){
sb.append(line);
}
br.close();
//sb為微信返回的xml
String notityXml = sb.toString();
String resXml = "";
System.out.println("接收到的報文:" + notityXml);
Map map = PayUtil.doXMLParse(notityXml);
String returnCode = (String) map.get("return_code");
if("SUCCESS".equals(returnCode)){
//驗證簽名是否正確
Map<String, String> validParams = PayUtil.paraFilter(map); //回撥驗籤時需要去除sign和空值引數
String validStr = PayUtil.createLinkString(validParams);//把陣列所有元素,按照“引數=引數值”的模式用“&”字元拼接成字串
String sign = PayUtil.sign(validStr, WxPayConfig.key, "utf-8").toUpperCase();//拼裝生成伺服器端驗證的簽名
//根據微信官網的介紹,此處不僅對回撥的引數進行驗籤,還需要對返回的金額與系統訂單的金額進行比對等
if(sign.equals(map.get("sign"))){
/**此處新增自己的業務邏輯程式碼start**/
/**此處新增自己的業務邏輯程式碼end**/
//通知微信伺服器已經支付成功
resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
}
}else{
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[報文為空]]></return_msg>" + "</xml> ";
}
System.out.println(resXml);
System.out.println("微信支付回撥資料結束");
BufferedOutputStream out = new BufferedOutputStream(
response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
}
相關推薦
微信小程式支付JAVA後臺邏輯
① 小程式前端會通過呼叫wx.login介面獲取得到登陸憑據code。這個code獲取之後5分鐘內如果再次呼叫wx.login獲取code並傳遞給②就會報錯,code非法,這個需要注意下。② 小程式將code登陸憑據和orderId訂單編號穿給後臺服務端,服務端呼叫https
微信小程式支付 java
話不多說,直接開擼。 支付流程步驟: 1)首先呼叫wx.login方法獲取code,通過code獲取openid; 2)java後臺呼叫統一下單支付介面(這裡會進行第一次簽名),用來獲取prepay_id; 3)java後臺再次呼叫簽名(這裡會進行第二次簽名),並返回
java服務端微信小程式支付demo
一丶項目錄結構 demo下載地址 小程式支付demo下載 二丶實現步驟 1.在小程式中獲取使用者的登入資訊,成功後可以獲取到使用者的程式碼值 2.在使用者自己的服務端請求微信獲取使用者的OpenID介面,成功後可以電子雜誌使用者的OpenID的值 微信
JAVA之微信小程式支付退款(PKCS12證書設定與SSL請求封裝)
問題背景 話說有小程式支付就有小程式退款,退款和支付是對應的,不能憑空退。 解決方案 解決方案有點長,我們分兩個部分,一個是業務引數拼接與Sign簽名,一個是https請求/ssl請求與pkcs12證書,用到的包org.apache.httpcomponents/httpcl
java微信小程式支付完整流程
用到的jar包就不貼了 1、小程式內呼叫登入介面,獲取到使用者的openid,api參見公共api【小程式登入API】 public String getOpenId(String code) throws BusinessException { try
java-微信小程式支付程式碼分享
按照微信支付的流程來進行:1.小程式呼叫後臺介面生成預支付訂單:package com.stonedt.controller; import java.io.BufferedOutputStream; import java.io.BufferedReader; impo
java微信小程式支付,退款,回撥函式
package com.pay;import java.util.Date;import java.util.Map;public class test { /** * 生成統一下單 * @throws Exception */public s
微信小程式支付(Java)
相信進行過微信公眾號支付的同學對於微信小程式支付的開發上手很快,如下是微信官方對三種接入方式的對比注意坑一:發起支付必須是HTTPS流程然後我們整理下發起訂單的思路。如下是官方給的流程圖,發起支付已經做了標註。由此可見,伺服器端發起訂單需要以下五小步,我們來各個擊破。第一步:
微信小程式 支付
var app = getApp(); Page({ data: {}, onLoad: function (options) { // 頁面初始化 options為頁面跳轉所帶來的引數 var that = this //登陸獲取code wx.
微信小程式支付流程
使用者在微信端使用小程式,發起微信支付;(使用者) 小程式呼叫微信api(wx.login()),獲取到使用者登入憑證code(五分鐘內有效),小程式將code、需要支付的商品資訊等一起傳送給自己的商戶系統後臺;(小程式端) a、商戶系統後臺獲取到小程式傳遞過來
php微信小程式支付
<?php class WxpayModel { //介面API URL字首 const API_URL_PREFIX = 'https://api.mch.weixin.qq.com'; //下單地址URL const UN
微信小程式支付全問題解決
這幾天在做小程式的支付,沒有用官方的SDK,這裡就純用官方的文件搞一發。 * 注作者使用的PHP,不過支付流程都是這樣 開發前必讀 主要流程 小程式前端傳送求參請求 接受請求封裝 “統一下單” 獲取package 小程式接受 “統一下單” 獲取的package值帶入wx.reque
微信小程式支付統一下單介面
微信小程式——支付 1.通過code獲取openId code:使用者登入憑證(有效期五分鐘)。開發者需要在開發者伺服器後臺呼叫 api,使用 code 換取 openid 和 session_key 等資訊 openid: 使用者唯一標識 session_key: 會
微信小程式支付(thinkphp)
之前一直想學下微信支付,這次終於有機會來操作一下,還是記錄下來,跟大家分享分享。 一、首先,我們要在微信官方網站上去下載支付介面,然後改個名方便呼叫(例如:WeiXinpay),然後將下載的檔案放入thinkphp的Vendor檔案下面; 二、然後去官網下載商戶操作證書:https://pa
說說微信小程式支付
最近有機會嘗試了小程式的支付開發,總結下期間碰到的問題。 小程式支付和以往的網頁、APP微信支付大同小異,應該說小程式的支付更簡便了些,不需要設定支付目錄、不需要授權域名等操作。其實主要的流程就兩步: 開發者服務端向微信發起統一下單請求,小程式調起微信支付。 接下來
微信小程式支付證書及SSL證書使用
小程式使用微信支付包括:電腦管理控制檯匯入證書->修改程式碼為搜尋證書->授權IIS使用證書->設定TSL加密級別為1.2 描述: 1、通常呼叫微信生成訂單介面的時候,使用的證書都是直接路徑指向就行了,但是這種方法在IIS是不適用的 2、IIS網站繫結SSL證書之後,證書加密級別預設為
微信小程式支付和退款
微信小程式支付的主要邏輯集中在後端,前端只需攜帶支付所需的資料請求後端介面然後根據返回結果做相應成功失敗處理即可。 本篇文章後端使用的是php,側重於整個支付的流程和一些細節方面的東西。所以使用其他後端語言的朋友有需要也是可以看一下的。 很多時候開發的需求和相應問題的解決
微信小程式支付流程,非同步回撥及訊息模板呼叫(php原始碼)
首先還是老樣子把流程圖給大家發一下 商戶系統和微信支付系統主要互動: 1、小程式內呼叫登入介面,獲取到使用者的openid,api參見公共api【小程式登入API】 2、商戶server呼叫支付統一下單,api參見公共api【統一下單API】 3、商戶server呼叫再次簽
微信小程式支付以及微信退款開發
最近公司專案急著測試,需要開發微信小程式+微信支付+微信退款,本著這幾天的一些研究,決定記錄一下開發的過程。 本著知識分享的原則,希望對大家有所幫助。 本篇針對的是微信小程式的支付開發,如果有對微信公眾號的支付開發需要的,可以去我的github上看看,有個sell的專案很好的完成了公眾號方面的支付與退款,程式
服務端微信小程式支付/退款詳解
賬號支援:小程式appid,小程式secret,商戶號mchid,商戶secret 服務端和微信支付系統主要互動: 1、小程式內呼叫登入介面,獲取到使用者的openid,api參見公共api【小程式登入API】 前端呼叫介面wx.login() 獲取臨時登入憑