1. 程式人生 > >微信公眾號支付——預支付訂單

微信公眾號支付——預支付訂單

  1.需要一個可以登陸微信商戶平臺的賬號,此賬號是服務號並開通了微信支付,商戶在申請開通時,客服會發送郵件到你的郵箱,

上圖中有幾個重要資訊:商戶號和appid,務必記住商戶號和appid。其中登陸賬號和密碼用於登陸微信支付首頁點選開啟連結

2.點選上圖中的下載api證書,設定api密碼。這個證書主要在微信支付api中需要證書的地方使用中的退款等功能提示需要證書。

:什麼時候載入使用該證書?當要實現微信退款時,發起退款請求前,需要先載入安全證書

package com.jy.common.pay.weixinpay;

import java.io.File;
import java.io.FileInputStream;
import java.net.URL;
import java.security.KeyStore;

import javax.net.ssl.SSLContext;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

/*
 * 載入安全證書、退款等需要證書的請求使用此類中的方法
 * */
public class ClientCustomSSL {
	public static String doRefund(String url, String data) throws Exception {
		KeyStore keyStore = KeyStore.getInstance("PKCS12");
		URL luj = Thread.currentThread().getContextClassLoader().getResource("apiclient_cert.p12");//src目錄下的證書檔案
		FileInputStream is = new FileInputStream(new File(luj.toURI()));
		try {
		keyStore.load(is, "這個是你設定的安全證書的密碼".toCharArray());// 這裡寫密碼..預設是你的mchid,也就是前面傳送給你的
郵件中的商戶號
		} finally {
		is.close();
		}

		// Trust own CA and all self-signed certs
		SSLContext sslcontext = SSLContexts.custom()
		.loadKeyMaterial(keyStore, "商戶號".toCharArray())// 這裡也是寫密碼的
		.build();
		// Allow TLSv1 protocol only
		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
		CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
		try {
		HttpPost httpost = new HttpPost(url); // 設定響應頭資訊
		httpost.addHeader("Connection", "keep-alive");
		httpost.addHeader("Accept", "*/*");
		httpost.addHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
		httpost.addHeader("Host", "api.mch.weixin.qq.com");
		httpost.addHeader("X-Requested-With", "XMLHttpRequest");
		httpost.addHeader("Cache-Control", "max-age=0");
		httpost.addHeader("User-Agent","Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
		httpost.setEntity(new StringEntity(data, "UTF-8"));
		CloseableHttpResponse response = httpclient.execute(httpost);
		try {
		HttpEntity entity = response.getEntity();

		String jsonStr = EntityUtils.toString(response.getEntity(),
		"UTF-8");
		EntityUtils.consume(entity);
		return jsonStr;
		} finally {
		response.close();
		}
		} finally {
		httpclient.close();
		}
	}
}
上面返回的jsonStr則是:你發起退款時返回的一些json資訊,這裡一般將其轉為map方便使用。

其中上面呼叫的方法需要2個引數:url,data

url:微信支付提供的退款介面https://api.mch.weixin.qq.com/secapi/pay/refund

data:這個引數微信支付官方推薦使用xml格式,所以一般都是用String字串構造一個xml,這個xml和官方文件一樣

<xml>
<appid>wx2421b1c4370ec43b</appid>
<mch_id>10000100</mch_id>
<nonce_str>6cefdb308e1e2e8aabd48cf79e546a02</nonce_str>
<out_refund_no>1415701182</out_refund_no>
<out_trade_no>1415757673</out_trade_no>
<refund_fee>1</refund_fee>
<total_fee>1</total_fee>
<transaction_id></transaction_id>
<sign>FE56DD4AA85C0EECA82C35595A69E153</sign>
</xml> 

data就是上面這個xml的字串,一般先將退款介面需要的引數放入到map中,在將map轉為xml字串。

3.在實現預支付訂單前應先獲取到開發需要的一些引數:如openid、隨機字串、簽名、

1.openid獲取:

String url="https://api.weixin.qq.com/sns/oauth2/access_token?"
        + "appid="
+你的appid

+ "&secret="+你的secret
        + "&code="+code
        + "&grant_type=authorization_code";
JSONObject jsonObject=HttpGet.getRes(url);
String usersWeixinId=jsonObject.getString("openid");

     secret是公眾號的appsecret,這個在微信支付平臺中的開發者中心可以找到

code是應用授權作用域,官方提供兩個,任選一個:snsapi_base(不彈出授權視窗,只獲取openid),snsapi_userinfo(彈出授權視窗.....)

2.隨機字串獲取:這個引數一般是32位以內的大寫字母和0-9數字的隨機組合,不能超出32位

獲取簽名步驟:

根據上圖中的引數生成字串

stringA="appid=wxd930ea5d5a258f4f&body=test&device_info=1000&mch_id=10000100&nonce_str=ibuaiVcKdpRxkhJA";

再接著串聯:

stringSignTemp=stringA+"&key=192006250b4c09247ec02edce69f6a2d" //注:key為商戶平臺設定的金鑰key

sign=MD5(stringSignTemp).toUpperCase()="9A0A8659F005D6984697E2CA0A9CF3B7" //注:MD5簽名方式

sign=hash_hmac("sha256",stringSignTemp,key) //注:HMAC-SHA256簽名方式

兩種簽名方式任選,sign這就是我們需要的簽名

4.簡單地說:實現微信支付中的各種功能只需要3個大步驟:1.微信公眾號支付的各個介面。2.生成發起訂單等功能的XML字串。3.傳送http請求,輸出返回的結果

1.預支付訂單介面:https://api.mch.weixin.qq.com/pay/unifiedorder

預支付訂單的通知地址:http://www.weixin.qq.com/wxpay/pay.php(即發起訂單後的回撥介面),此介面不能攜帶引數

2.查詢預支付訂單的介面:https://api.mch.weixin.qq.com/pay/orderquery

查詢預支付訂單時需要一個引數:微信訂單號或者商戶訂單號任選一個,一般優先微信訂單號,商戶訂單號的詳細演算法地址:

3.關閉訂單介面:https://api.mch.weixin.qq.com/pay/closeorder

4.申請退款介面:https://api.mch.weixin.qq.com/secapi/pay/refund 此功能需要安全證書,自己去開發者中心下載

退款介面中需要的商戶訂單號與商戶退款訂單號是一致的,主要實現:

public static String getRandomStringByLength(int length) { String base = "0123456789"; 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(); } /** * @function 生成商戶訂單號/退款單號 * @date 2015-12-17 * @return String */ public static String getOrderNo(){ SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); Date date = new Date(); return sdf.format(date) + getRandomStringByLength(4); } 5.查詢退款介面:https://api.mch.weixin.qq.com/pay/refundquery

6.下載對賬單:https://api.mch.weixin.qq.com/pay/downloadbill

7.支付結果通知:https://pay.weixin.qq.com/wxpay/pay.action或者http://www.weixin.qq.com/wxpay/pay.php

8.獲取openid介面:https://api.weixin.qq.com/sns/oauth2/access_token需要部分引數,上面有例子