微信H5支付(Java)
一、場景介紹
微信H5支付是在手機移動瀏覽器端調起微信支付的方式。本文中僅介紹後臺開發端的API對接,具體怎麼開通H5支付,微信商戶平臺相關的內容請參考微信開發文件。
開通微信H5支付後,獲取到APPID,商戶號mch_id,商戶支付金鑰key等備用。
二、開發準備
1、域名
要求商戶已有H5商城網站,並且域名已經過ICP備案。
(所以,對於個人開發demo測試並不適合)
2、專案
本文中一律使用SpringBoot專案下的配置。
3、配置檔案
建立配置檔案:api.properties,其中關鍵支付引數資料:
# APPID wap.appid=wx1803e3r3f31614a6 # 商戶號 wap.mchid=1494336672 # 支付金鑰 wap.key=gOxGoTq6aYlg2ZFWvB2uhAR4Xh81l9U9 # 微信H5支付API地址 wap.unifiedorder=https://api.mch.weixin.qq.com/pay/unifiedorder
自定義配置檔案的類,讀取配置檔案
@ConfigurationProperties(prefix = "wap", locations = "classpath:api.properties") @Component public class ApiConfig { private String appid; private String mchid; private String key; private String unifiedorder; public String getUnifiedorder() { return unifiedorder; } public void setUnifiedorder(String unifiedorder) { this.unifiedorder = unifiedorder; } public String getAppid() { return appid; } public void setAppid(String appid) { this.appid = appid; } public String getMchid() { return mchid; } public void setMchid(String mchid) { this.mchid = mchid; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } }
三、準備開發
1、訂單建立
支付的必要條件是必須建立完訂單,獲取到訂單的一系列資料,包括商戶訂單號,商品名稱,商品介紹等。(每個商城都有自己的訂單建立方式,此處不做詳細介紹)
2、獲取使用者真實IP
由於安全性考慮,H5支付要求商戶在統一下單介面中上傳使用者真實ip地址“spbill_create_ip”,保證微信端獲取的使用者ip地址與商戶端獲取的一致。
3、API對接
首先是一個Controller方法:
@ResponseBody @RequestMapping("/wechatPay") public String wechatPay(HttpServletRequest request, JSONObject order) { JSONObject ret = new JSONObject(); ret.put("success", false); ret.put("msg", "請求失敗[CCO01]"); try { // 獲取使用者真實IP String ip = getClientIpAddress(request); // 微信API呼叫相關 JSONObject wxPayJson = wxInfoService.getWXPayJSON(order,ip); logger.info("微信支付返回引數 "+wxPayJson); if("success".equalsIgnoreCase(wxPayJson.getString("return_code"))){ if("success".equalsIgnoreCase(wxPayJson.getString("result_code"))){ // 儲存支付資訊什麼的 insertOrderPadPay(order, wxPayJson.getString("prepay_id")); ret.put("success", true); ret.put("msg", "ok"); ret.put("data", wxPayJson); ret.put("orderNO", order.getString("orderNo")); } if("fail".equalsIgnoreCase(wxPayJson.getString("result_code"))){ ret.put("success", false); ret.put("msg", wxPayJson.getString("err_code_des")); ret.put("data", wxPayJson); ret.put("orderNO", order.getString("orderNo")); } }else { ret.put("success", false); ret.put("msg", wxPayJson.getString("err_code_des")); ret.put("data", wxPayJson); ret.put("orderNO", order.getString("orderNo")); } } catch (Exception e) { e.printStackTrace(); ret.put("msg", e.getMessage()); } return ret.toString(); }
其中的獲取使用者IP的方法是:
private static final String[] HEADERS_TO_TRY = { "X-Forwarded-For", "Proxy-Client-IP", "WL-Proxy-Client-IP",
"HTTP_X_FORWARDED_FOR", "HTTP_X_FORWARDED", "HTTP_X_CLUSTER_CLIENT_IP", "HTTP_CLIENT_IP",
"HTTP_FORWARDED_FOR", "HTTP_FORWARDED", "HTTP_VIA", "REMOTE_ADDR", "PROXY_FORWARDED_FOR", "X-Real-IP"};
/**
* getClientIpAddress:(獲取使用者ip,可穿透代理).
* @author SongYapeng
* @Date 2018年3月2日下午4:41:47
* @param request
* @since JDK 1.8
*/
public static String getClientIpAddress(HttpServletRequest request) {
for (String header : HEADERS_TO_TRY) {
String ip = request.getHeader(header);
if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
if (ip != null && ip.indexOf(",") != -1) {
String[] ips = ip.split(",");
for (int i = 0; i < ips.length; i++) {
String ipMulti = (String) ips[i];
if (!("unknown".equalsIgnoreCase(ipMulti))) {
ip = ipMulti;
break;
}
}
}
return ip;
}
}
return request.getRemoteAddr();
}
接著getWXPayJSON方法實現如下:
public JSONObject getWXPayJSON(JSONObject order, String ip) throws Exception {
Map<String, String> map = new HashMap<String, String>();
/**
* order 商戶訂單資訊
* appid 微信分配的公眾賬號ID(企業號corpid即為此appId)
* wap_url 網站域名
* nonce_str 隨機字串
* mch_id 微信支付分配的商戶號
* notify_url 回撥地址,支付結束後,根據相應的結果執行相應的步驟(如修改oms訂單狀態為已支付)
* out_trade_no 訂單號
* total_fee 訂單總金額,單位為分
* trade_type 支付方式微信h5支付
*/
String appid = apiConfig.getAppid();
String wap_url = apiConfig.getWap_url();
// 生成指定長度的隨機字串方法
String nonce_str = CommonUtil.createNonceStr(10);
// 商品描述
String body = Constants.WAP_NAME + "訂單號:" + order.getString("orderNo");
String mch_id = apiConfig.getMchid();
String notify_url = wap_url + "/notify.html";
// 商戶訂單號
String out_trade_no = order.getString("orderNo");
String spbill_create_ip = ip;
// 支付金額,單位 分
Double saleMoney = order.getDouble("needSaleMoneySum") * 100;
BigDecimal total_fee = new BigDecimal(saleMoney);
total_fee = total_fee.setScale(0, BigDecimal.ROUND_HALF_UP);
// 交易型別 微信H5支付
String trade_type = "MWEB";
JSONObject json = new JSONObject();
// 場景資訊
JSONObject scene_info = new JSONObject();
json.put("type", "WAP");
json.put("wap_url", wap_url);
// 網站名稱,自定義
json.put("wap_name", Constants.WAP_NAME);
scene_info.put("h5_info", json);
map.put("appid", appid);
map.put("nonce_str", nonce_str);
map.put("body", body);
map.put("mch_id", mch_id);
map.put("notify_url", notify_url);
map.put("out_trade_no", out_trade_no);
map.put("spbill_create_ip", spbill_create_ip);
map.put("total_fee", total_fee + "");
map.put("trade_type", trade_type);
map.put("scene_info", scene_info.toString());
// 簽名,很重要
map.put("sign", createSign(map, true));
return getUnifiedorder(map);
}
getWXPayJSON方法中的簽名方法createSign(map, true)具體實現如下:
public String createSign(Map<String, String> map, boolean isLowerCase) throws Exception {
// map取出空值
Map<String, String> preMap = CommonUtil.delNull(map, isLowerCase);
// 排序並把陣列所有元素按照引數=引數名 的模式用&字元拼接成字串
String temp = CommonUtil.createSortParams(preMap, false, isLowerCase);
// 拼上key=key(商戶支付祕鑰)進行md5運算,再將得到的字串所有字元轉換為大寫
String signStr = temp + "&key=" + apiConfig.getKey();
logger.info("待簽名字串:"+signStr);
String sign = CommonUtil.Sign(temp, apiConfig.getKey());
return sign;
}
getWXPayJSON方法中的getUnifiedorder方法如下:
public JSONObject getUnifiedorder(Map<String, String> map) throws Exception {
String unifiedorder = apiConfig.getUnifiedorder();
String xml = CommonUtil.map2xml(map, false);
String result = HttpClientUtil.httpPostXml(unifiedorder, null, xml);
JSONObject json = CommonUtil.xml2JSON(result);
logger.info("支付請求引數:"+map+";支付返回引數" + json);
return json;
}
上面方法中多次用到CommonUtil工具類中的方法,現呈上CommonUtil工具類:
package net.shopin.wap.common.util;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
public class CommonUtil {
/**
* 指定長度uuid
* @param length 長度
* @return String
*/
public static String createUUID(int length) {
if (length > 36) {
throw new RuntimeException("請控制長度在36位以內!");
} else {
String[] chars = new String[]{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
"p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8",
"9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S",
"T", "U", "V", "W", "X", "Y", "Z"};
StringBuffer shortBuffer = new StringBuffer();
String uuid = UUID.randomUUID().toString().replace("-", "");
for (int i = 0; i < length; i++) {
String str = uuid.substring(i * 4, i * 4 + 4);
int x = Integer.parseInt(str, 16);
shortBuffer.append(chars[x % 0x3E]);
}
return shortBuffer.toString().toLowerCase();
}
}
/**
* 生成指定長度的隨機數字
* @param length 長度
* @return String
*/
public static String createNonceNum(int length) {
String chars = "0123456789";
String res = "";
for (int i = 0; i < length; i++) {
Random rd = new Random();
res += chars.charAt(rd.nextInt(chars.length() - 1));
}
return res;
}
/**
* 生成指定長度的隨機字串
* @param length 長度
* @return String
*/
public static String createNonceStr(int length) {
String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
String res = "";
for (int i = 0; i < length; i++) {
Random rd = new Random();
res += chars.charAt(rd.nextInt(chars.length() - 1));
}
return res;
}
/**
* xml2JSON:(xml轉為fastJson).
* @param xml
* @return
* @throws DocumentException
* @author SongYapeng
* @Date 2017年12月19日下午2:13:16
* @since JDK 1.7
*/
public static JSONObject xml2JSON(String xml) throws DocumentException {
return elementToJSONObject(strToDocument(xml).getRootElement());
}
public static Document strToDocument(String xml) throws DocumentException {
return DocumentHelper.parseText(xml);
}
public static JSONObject elementToJSONObject(Element node) {
JSONObject result = new JSONObject();
/**
* 當前節點的名稱、文字內容和屬性
* 當前節點的所有屬性的list
*/
@SuppressWarnings("unchecked")
List<Attribute> listAttr = node.attributes();
for (Attribute attr : listAttr) {
result.put(attr.getName(), attr.getValue());
}
/**
* 遞迴遍歷當前節點所有的子節點
* 所有一級子節點的list
*/
@SuppressWarnings("unchecked")
List<Element> listElement = node.elements();
if (!listElement.isEmpty()) {
/**
* 遍歷所有一級子節點
*/
for (Element e : listElement) {
/**
* 判斷一級節點是否有屬性和子節點
* 沒有則將當前節點作為上級節點的屬性對待
*/
if (e.attributes().isEmpty() && e.elements().isEmpty())
result.put(e.getName(), e.getTextTrim());
else {
/**
* 判斷父節點是否存在該一級節點名稱的屬性
* 沒有則建立
* 將該一級節點放入該節點名稱的屬性對應的值中
*/
if (!result.containsKey(e.getName()))
result.put(e.getName(), new JSONArray());
((JSONArray) result.get(e.getName())).add(elementToJSONObject(e));
}
}
}
return result;
}
/**
* Map 轉 XML
* @param map
* @param isLowerCase
* @return
*/
public static String map2xml(Map<String, String> map, boolean isLowerCase) {
map = CommonUtil.delNull(map, isLowerCase);
/**
* 開始對map進行解析
*/
if (map == null)
throw new NullPointerException("map 資料為空,不能解析!");
Document document = DocumentHelper.createDocument();
Element nodeElement = document.addElement("xml");
for (Object obj : map.keySet()) {
Element keyElement = nodeElement.addElement(String.valueOf(obj));
keyElement.setText(String.valueOf(map.get(obj)));
}
return doc2String(document);
}
/**
* Document 轉 String
* @param document
* @return String
*/
public static String doc2String(Document document) {
String s = "";
try {
/**
* 使用輸出流來進行轉化
*/
ByteArrayOutputStream out = new ByteArrayOutputStream();
OutputFormat format = new OutputFormat(" ", true, "UTF-8");
XMLWriter writer = new XMLWriter(out, format);
writer.write(document);
s = out.toString("UTF-8");
} catch (Exception ex) {
ex.printStackTrace();
}
return s;
}
/**
* 去除Map中的空值
* @param map
* @return 去掉空值後的map
*/
public static Map<String, String> delNull(Map<String, String> map, boolean isLowerCase) {
Map<String, String> result = new HashMap<String, String>();
if (map == null || map.size() <= 0) {
return result;
}
for (String key : map.keySet()) {
String value = map.get(key);
if (value == null || value.equals("") || value.equals("null")) {
continue;
}
if (isLowerCase) {
result.put(key.toLowerCase(), value);
} else {
result.put(key, value);
}
}
return result;
}
/**
* 把Map所有元素排序,並按照“引數=引數值”的模式用“&”字元拼接成字串
* @param params 需要排序並參與字元拼接的Map
* @param isEncode 是否對value進行urlencode
* @param isLowerCase 是否轉換小寫
* @return 拼接後字串
*/
public static String createSortParams(Map<String, String> params, boolean isEncode, boolean isLowerCase) {
String result = "";
try {
List<String> keys = new ArrayList<String>(params.keySet());
Collections.sort(keys);
if (isEncode) {
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
if (isLowerCase) {
key = key.toLowerCase();
}
String value = URLEncoder.encode(params.get(key), "UTF-8");
result = result + key + "=" + value + "&";
}
} else {
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
if (isLowerCase) {
key = key.toLowerCase();
}
String value = params.get(key);
result = result + key + "=" + value + "&";
}
}
} catch (Exception e) {
e.printStackTrace();
}
return result.substring(0, result.length() - 1);
}
/**
* MD5簽名,微信專用
* @param content 內容
* @param key key值
* @return
*/
public static String Sign(String content, String key) throws Exception {
String signStr = "";
if ("" == key) {
throw new Exception("財付通簽名key不能為空!");
}
if ("" == content) {
throw new Exception("財付通簽名內容不能為空");
}
signStr = content + "&key=" + key;
return MD5(signStr).toUpperCase();
}
/**
* MD5 加密
* @param data
* @return
*/
public final static String MD5(String data) {
char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
try {
byte[] btInput = data.getBytes();
/**
* 獲得MD5摘要演算法的 MessageDigest 物件
*/
MessageDigest mdInst = MessageDigest.getInstance("MD5");
/**
* 使用指定的位元組更新摘要
*/
mdInst.update(btInput);
/**
* 獲得密文
*/
byte[] md = mdInst.digest();
/**
* 把密文轉換成十六進位制的字串形式
*/
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* sh1 加密
* @param s
* @return
*/
public final static String Sha1(String s) {
char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
try {
byte[] btInput = s.getBytes();
/**
* 獲得MD5摘要演算法的 MessageDigest 物件
*/
MessageDigest mdInst = MessageDigest.getInstance("sha-1");
/**
* 使用指定的位元組更新摘要
*/
mdInst.update(btInput);
/**
* 獲得密文
*/
byte[] md = mdInst.digest();
/**
* 把密文轉換成十六進位制的字串形式
*/
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 將cookie封裝到Map裡面
* @param request
* @return
*/
public static Map<String, Cookie> getCookieMap(HttpServletRequest request) {
Map<String, Cookie> cookieMap = new HashMap<String, Cookie>();
Cookie[] cookies = request.getCookies();
if (null != cookies) {
for (Cookie cookie : cookies) {
cookieMap.put(cookie.getName(), cookie);
}
}
return cookieMap;
}
/**
* 保留兩位小數的double
* @param number
* @return
*/
public static String formatDouble(Double number) {
return new DecimalFormat("######0.00").format(number);
}
public static String formatDouble1(Double number) {
return new DecimalFormat("######0.0").format(number);
}
/**
* 從request 中獲取字串
*/
public static String getStringFrom(HttpServletRequest request) throws Exception {
InputStream in = request.getInputStream();
StringBuffer out = new StringBuffer();
byte[] b = new byte[1024];
for (int n; (n = in.read(b)) != -1; ) {
out.append(new String(b, 0, n));
}
return out.toString();
}
/**
* 隨機生成 指定範圍的小數 min :最小值範圍 max:最大值範圍
*/
public static BigDecimal getDecimalNum(int min, int max) {
Random random = new Random();
int s = random.nextInt(max) % (max - min + 1) + min;
String temp = "0." + s;
BigDecimal number = new BigDecimal(temp);
return number;
}
}
通過以上程式碼請求,最終可獲取到支付跳轉連結:mweb_url,mweb_url為拉起微信支付收銀臺的中間頁面,可通過訪問該url來拉起微信客戶端,完成支付,mweb_url的有效期為5分鐘。
具體更多API引數請參考微信支付文件:微信H5支付文件
相關推薦
微信H5支付(Java)
一、場景介紹 微信H5支付是在手機移動瀏覽器端調起微信支付的方式。本文中僅介紹後臺開發端的API對接,具體怎麼開通H5支付,微信商戶平臺相關的內容請參考微信開發文件。 開通微信H5支付後,獲取到APPID,商戶號mch_id,商戶支付金鑰key等備用。 二、開
微信H5支付(公司專案筆記)
1.跳轉後臺 mui.openWindow({ url: "後臺網址PayH5.php?payMoney=" + n + "&buyContent=" + buyContent + "&uid=" + uid, wa
微信H5開發(一)
H5開發,一般是指移動端的頁面開發。移動端可分為app和普通瀏覽頁面。從嵌入的環境來歸類:可以分為app、微信H5及手機瀏覽器裡面開啟的頁面。 以前粗略的涉略過h5開發的一些知識,感覺H5並不是很難。在這半年內,接手並完成了兩個微信H5專案(一期)的過程中,發
微信H5支付開發全過程(除內置微信以外的瀏覽器)
app 獲取ip getenv 過程 comm ati psi 初始 cli 前言:網上都是~ 呵呵 自己搞 只要花時間 多問客服總會有的 只說程序不說準備工作 自己ID 或者秘鑰都準備好了 寫的有點兒亂 可以把所有的方法 放在一個文件中調用 public funct
關於微信公眾號支付 微信H5支付和微信APP支付的問題 (PHP)TP+VUE
話不多說 直接上原始碼 在寫支付之前一定要確定好微信要求配置的相關回調域名 安全支付域名還有雜七雜八的哪些地址都準備好了 要不然是沒法實現的 微信公眾平臺 微信商戶平臺 還有開發者平臺 什麼的 這點比較噁心 1.微信公眾號支付 公眾號支付和H5支付最大的不同就在於公眾號支付使用者有ope
微信H5支付三步輕鬆搞定(C#)
目前,從商城網站、餐廳、商場、超市到菜市、小賣部、路邊攤,移動支付無處不在,極大地方便了我們的生活。特別是微信支付,應用極廣,很受大眾歡迎。然而,對於擁有H5移動商城的商家來說,微信支付只能在微信客戶端內實現,而在微信中又無法使用支付寶,這是令人非常蛋疼的事。 現在,好訊
微信H5支付問題(前端部分)(內附jssdk使用方法)
微信公眾號支付(內附jssdk使用方法) 微信內H5發起支付一共有兩種方法: 1.呼叫微信內建js物件 WeixinJSBridge 發起支付具體方法為 WeixinJSBridge.invoke( 'getBrandWCPayRequest',
黃聰:詳解申請微信h5支付方法,開通微信h5網頁支付介面(轉)
現在大街小巷的商家都在使用微信支付,但是一些商家使用的是個人微信收款,這個雖然很便利,但是如果你想要資料統計彙總,讓客戶在網路上線上付款,就需要用到微信的h5支付。 微信h5支付 今天子恆老師跟你分享一下,怎麼開通h5支付。 一、 申請開通微信h5支付前要做的準備 並不是每個人都能
微信小程式支付(Java)
相信進行過微信公眾號支付的同學對於微信小程式支付的開發上手很快,如下是微信官方對三種接入方式的對比注意坑一:發起支付必須是HTTPS流程然後我們整理下發起訂單的思路。如下是官方給的流程圖,發起支付已經做了標註。由此可見,伺服器端發起訂單需要以下五小步,我們來各個擊破。第一步:
用Java搭建微信公眾號(二)生成access_token
當自己的程式需要訪問微信的HTTP介面時,需要傳遞access_token作為校驗的引數。access_token需要通過APPID和APPSecret祕鑰來生成,有效期是7200秒,2小時。access_token最好是做成全域性變數共享,然後由一個執行緒定時去重新整理,這樣可以減少access_
Java微信H5支付實際例子
最近看過不少微信H5支付的例子,我是根據這個網址來配置的:https://blog.csdn.net/leigelg/article/details/80456758 這裡已經說的很明白,就是在支付的時候老是提示“網路環境未能通過安全驗證,請稍後重試”後來發現真是IP地址問題,這是我實際專案
微信H5支付開發(maven倉庫版)
官方文件:https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_1 開發之前確認開通了H5支付功能 一、安裝微信sdk 二、建立config類 package com.xiuchefang.config; impo
java開發記錄-微信H5支付
一點點關於微信H5支付開發的總結. 接入成功後就可以進行程式碼設計啦. 此次測試開發是在springboot環境下完成的,下面列出微信支付用到的相關依賴: <dependency> <groupId>com.g
小程式登入、微信網頁授權(Java版)
首先呢,“登入”、“授權”、“授權登入”,是一樣的意思,不用糾結。 寫小程式授權登入的程式碼前,需要了解清楚openid與unionid的區別,這裡再簡單介紹一下: 騰訊有個 “微信·開放平臺”,只有企業才能註冊賬號,可理解為微信體系裡,最頂級的賬號。官網地址:https://open.w
Java 微信公眾號(二)——獲取access_token
微信開發者文件會發現——>access_token是公眾號的全域性唯一介面呼叫憑據,公眾號呼叫各介面時都需使用access_token。開發者需要進行妥善儲存。access_token的儲存至少要保留512個字元空間。access_token的有效期目前為2個小時,需定
實現微信開啟網頁時,獲取當前微信使用者資訊(Java)(基於snsapi_userinfo方式)
/** * 1 第一步:使用者同意授權,獲取code * 2 第二步:通過code換取網頁授權access_token * 3 第三步:重新整理access_token(如果需要) * 4 第四步:拉取使用者資訊(需scope為 snsapi_user
Java整合微信H5支付/支付寶手機網站支付
微信H5支付:1,微信外部H5支付:名詞解釋:就是在自己的H5網站頁面裡呼叫微信支付功能,注意,這裡只能是在微信外部支付,在微信內開啟網站是無法支付的,要另外使用微信公眾號支付呼叫微信H5支付介面前提條件:1,註冊公眾號並且通過認證2,在公眾號裡申請微信支付,成為商戶號3,在
java實現微信h5支付
微信h5支付需要在微信商戶平臺-》產品中心開通h5支付。 官網提供的開發文件中需要的引數: h5支付主要是scene_info中的引數wap_url必須是可以訪問到的地址。spbill_create_ip的獲取必須和調起微信支付的ip一致。
java微信H5支付中遇到的問題都已解決 java程式碼 和html程式碼
1,開通賬號,申請商戶賬號 開啟連線https://pay.weixin.qq.com/index.php/partner/public/home (如圖1) (圖1) 2,完成註冊以後登入 進入(圖2) (圖2) 點選H5支付開通3,如果已開通
「小程序JAVA實戰」運行微信官方demo(四)
格式 http nsh 兩個 下載源 img 式表 start dem 轉自:https://idig8.com/2018/08/09/xiaochengxu-chuji-04/ 微信官方小程序的demo 介紹 https://mp.weixin.qq.com/cgi