以上是官網文檔說明:java
下面是根據文檔 梳理下思路:git
/**
關於簽名的算法,api提供的原文是:
1.簽名算法
簽名生成的通用步驟以下:
第一步,設全部發送或者接收到的數據爲集合M,將集合M內非空參數值的參數按照參數名ASCII碼從小到大排序(字典序),使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串stringA。
特別注意如下重要規則:
參數名ASCII碼從小到大排序(字典序);
若是參數的值爲空不參與簽名;
參數名區分大小寫;
驗證調用返回或微信主動通知簽名時,傳送的sign參數不參與簽名,將生成的簽名與該sign值做校驗。
微信接口可能增長字段,驗證簽名時必須支持增長的擴展字段
第二步,在stringA最後拼接上key=(API密鑰的值)獲得stringSignTemp字符串,並對stringSignTemp進行MD5運算,再將獲得的字符串全部字符轉換爲大寫,獲得sign值signValue。
舉例:
假設傳送的參數以下:
appid: wx8888888888888888
mch_id: 1900000109
device_info: 013467007045764
body: test
nonce_str: 5K8264ILTKCH16CQ2502SI8ZNMTM67VS
第一步:對參數按照key=value的格式,並按照參數名ASCII字典序排序以下:
stringA="appid=wx8888888888888888&body=test&device_info=013467007045764&mch_id=1900000109&nonce_str=5K8264ILTKCH16CQ2502SI8ZNMTM67VS";
第二步:拼接API密鑰:
stringSignTemp="stringA&key=332F17B766FC787203EBE9D6E40457A1"
sign=MD5(stringSignTemp).toUpperCase()="332F17B766FC787203EBE9D6E40457A1"
*/
微信支付簽名算法sign:算法
String keywx = "9e4b63793722c61a555696be897d61f8";
/**
* 微信支付簽名算法sign
* 建立md5摘要,規則是:按參數名稱a-z排序,遇到空值的參數不參加簽名。
建立簽名 簽名 sign
*/
protected void createSign(SortedMap<Object,Object> parameters) {
StringBuffer sb = new StringBuffer();
//parameters 參數集合值
Set es = parameters.entrySet();//全部參與傳參的參數按照accsii排序(升序)
Iterator it = es.iterator();
while(it.hasNext()) {
Map.Entry entry = (Map.Entry)it.next();
String k = (String)entry.getKey();
Object v = entry.getValue();
if(null != v && !"".equals(v)
&& !"sign".equals(k) && !"key".equals(k)) {
sb.append(k + "=" + v+ "&" );
}
}
//key就是微信支付帳戶密鑰
sb.append("key=" + keywx);
//sb.append("key=" + this.getKey());
System.out.println("字符串拼接後是:"+sb.toString());
//字體編碼 生成MD5的時候,須要統一編碼,這裏微信api要求是UTF-8
String enc = getCharacterEncoding(this.request, this.response);
//生成MD5簽名驗證 注意轉換成大寫 在此是小寫
String sign = MD5Util.MD5Encode(sb.toString(), enc).toUpperCase();
this.setParameter("sign", sign);
//debug信息
this.setDebugInfo(sb.toString() + " => sign:" + sign);
return ;
}
/**
*設置debug信息
*/
protected void setDebugInfo(String debugInfo) {
this.debugInfo = debugInfo;
}
/**
* 設置參數值
* @param parameter 參數名稱
* @param parameterValue 參數值
*/
public void setParameter(String parameter, String parameterValue) {
String v = "";
if(null != parameterValue) {
v = parameterValue.trim();
}
this.parameters.put(parameter, v);
}
/**
* 獲取編碼字符集
* @param request
* @param response
* @return String
*/
public static String getCharacterEncoding(HttpServletRequest request,
HttpServletResponse response) {
if(null == request || null == response) {
return "gbk";
}
String enc = request.getCharacterEncoding();
if(null == enc || "".equals(enc)) {
enc = response.getCharacterEncoding();
}
if(null == enc || "".equals(enc)) {
enc = "gbk";
}
return enc;
}
MD5Util方法:數據庫
public class MD5Util { private static String byteArrayToHexString(byte b[]) { StringBuffer resultSb = new StringBuffer(); for (int i = 0; i < b.length; i++) resultSb.append(byteToHexString(b[i])); return resultSb.toString(); } private static String byteToHexString(byte b) { int n = b; if (n < 0) n += 256; int d1 = n / 16; int d2 = n % 16; return hexDigits[d1] + hexDigits[d2]; } public static String MD5Encode(String origin, String charsetname) { String resultString = null; try { resultString = new String(origin); MessageDigest md = MessageDigest.getInstance("MD5"); if (charsetname == null || "".equals(charsetname)) resultString = byteArrayToHexString(md.digest(resultString .getBytes())); else resultString = byteArrayToHexString(md.digest(resultString .getBytes(charsetname))); } catch (Exception exception) { } return resultString; } private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" }; }
參數包裝成XML格式丟給微信:api
/**
* 參數包裝成XML格式丟給微信
* */
public String GetpayXmlRequest(String appid,String spid,String getNonce_str,String sign, String trans_time, String bill_type)
{
/*
<xml>
<appid>wx8888888888888888</appid>
<bill_date>20160426</bill_date>
<bill_type>ALL</bill_type>
<mch_id>1900000109</mch_id>
<nonce_str>21df7dc9cd8616b56919f20d9f679233</nonce_str>
<sign>E8778F1C4C953C0BF37AA45C3BC379D0</sign>
</xml>
*/
StringBuffer sb = new StringBuffer();
sb.append("<xml>");
sb.append("<appid><![CDATA[");
sb.append(appid);
sb.append("]]></appid>");
sb.append("<mch_id><![CDATA[");
sb.append(spid);
sb.append("]]></mch_id>");
sb.append("<nonce_str><![CDATA[");
sb.append(getNonce_str);
sb.append("]]></nonce_str>");
sb.append("<sign><![CDATA[");
sb.append(sign);
sb.append("]]></sign>");
sb.append("<bill_date><![CDATA[");
sb.append(trans_time);
sb.append("]]></bill_date>");
sb.append("<bill_type><![CDATA[");
sb.append(bill_type);
sb.append("]]></bill_type>");
sb.append("</xml>");
return sb.toString();
/*
sb.append("<appid>");
sb.append(appid);
sb.append("</appid>");
sb.append("<bill_date>");
sb.append(trans_time);
sb.append("</bill_date>");
sb.append("<bill_type>");
sb.append(bill_type);
sb.append("</bill_type>");
sb.append("<mch_id>");
sb.append(spid);
sb.append("</mch_id>");
sb.append("<nonce_str>");
sb.append(stamp);
sb.append("</nonce_str>");
sb.append("<sign>");
sb.append(sign);
sb.append("</sign>");
sb.append("</xml>");
return sb.toString();
*/
}
post發送請求數據:服務器
/** 請求的參數 */
protected SortedMap parameters;
protected HttpServletRequest request;
protected HttpServletResponse response;
/** 密鑰 */
protected String key;
/** debug信息 */
protected String debugInfo;
/**
*獲取密鑰
*/
public String getKey() {
return key;
}
/**
*設置密鑰
*/
public void setKey(String key) {
this.key = key;
}
/**
* post發送請求數據
* @param urlStr
*/
public void testPost(String urlStr) {
BufferedReader br= null;
HttpURLConnection con=null;
OutputStreamWriter out=null;
try {
URL url = new URL(urlStr);
// URLConnection con = url.openConnection();
con = (HttpURLConnection) url.openConnection();
// 發送POST請求必須設置以下兩行
con.setDoOutput(true); // POST方式
con.setDoInput(true);
con.setUseCaches(false);
con.setRequestMethod("POST");
// 設置通用的請求屬性
con.setRequestProperty("accept", "*/*");
con.setRequestProperty("connection", "Keep-Alive");
con.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// con.setRequestProperty("Pragma:", "no-cache");
// con.setRequestProperty("Cache-Control", "no-cache");
// con.setRequestProperty("Content-Type", "text/xml");
// 輸出流,寫數據
out = new OutputStreamWriter(con
.getOutputStream(),"UTF-8");
// 發送請求參數
String xmlInfo = GetpayXmlRequest("wx8888888888888888","1900000109","1462240367309","56B106AFDDF1802B12DF8634C2E73B92","20160623","ALL");
System.out.println("urlStr=" + urlStr);
System.out.println("xmlInfo=" + xmlInfo);
out.write(new String(xmlInfo.getBytes("UTF-8")));
// flush輸出流的緩衝
out.flush();
// out.close();
//讀取服務器的響應內容並顯示 定義BufferedReader輸入流來讀取URL的響應
br = new BufferedReader(new InputStreamReader(con
.getInputStream(),"UTF-8"));
String line = "";
StringBuffer buffer = new StringBuffer();
// for (line = br.readLine(); line != null; line = br.readLine()) {
// System.out.println(line);
// buffer.append(line);// 將讀到的內容添加到 buffer 中
// buffer.append("\n"); // 添加換行符
//
// }
while ((line = br.readLine()) != null)
{
buffer.append(line); // 將讀到的內容添加到 buffer 中
buffer.append("\n"); // 添加換行符
System.out.println(line);
}
//con.getOutputStream().close();
}
catch (MalformedURLException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
// 使用finally塊來關閉輸入流
finally {
try {
if(out!=null){
out.close();
}
if (br != null)
{
br.close();
con.disconnect();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String url = "https://api.mch.weixin.qq.com/pay/downloadbill";
new HttpPostTest().testPost(url);
//微信api提供的參數 賦值
String appid="wx8888888888888888";
String spid="1900000109";// 1221024001
String getNonce_str="1462240367309";//1462240367309 ibuaiVcKdpRxkhJA
String trans_time="20160623";
String bill_type="ALL";
String sign ="";
// 獲取值
SortedMap<Object,Object> sparameters = new TreeMap<Object,Object>();
sparameters.put("appid", appid);
sparameters.put("mch_id", spid);
sparameters.put("nonce_str", getNonce_str);
sparameters.put("bill_date", trans_time);
sparameters.put("bill_type", bill_type);
// new HttpPostTest().createSign(sparameters);
}
注意 以上單元測試時要先 建立生成簽名後,再把簽名的值傳到參數中去,而後進行httppost請求便可。微信
這裏商戶號 必定都要改爲本身申請的appid 和 mch_id 這樣就會有微信返回結果數據顯示了,結果實例就不在這裏展示出來。app
獲取到對帳信息後就是後續的業務處理了,根據不一樣的需求進行不一樣的業務處理了,主要就是解析數據格式,生成文檔,保存到本地以及導入到數據庫的邏輯操做了。post