一。下載sdk 。其實這個sdk就已經把微信支付的功能封裝在里面了,已經算是一個成形的代碼級應用了.sdk已經把要做的工作都做了,剩下的就是你去調用了,就這么簡單。
先看一下這幾個接口和類大概是干嘛的(不了解也絲毫不影響開發):
可以對照自己的SDK來看。
1.IWXPayDomain.java
實現域名管理的,不需要我們做工作。
這個抽象接口,測試包中已經幫助我們實現了,我們可以拿過來直接用。復制粘貼改個名字。
2.WXPayConstants
微信支付常量類,這其中的常量很多,但是也都很好理解,內部類枚舉,限定了簽名方式只能是MD5或者HMACSHA256。這里要注意的是,簽名也是有SDK內部實現的,只有在使用到沙箱環境時,才用MD5簽名。最后兩
部分主要是請求后綴,只不過前者是生產環境,后邊的帶有的SANbox的是沙箱測試環境。為了直觀,我把他們都標注出來了。主要分六部分:
你可以把你們公司的名字MD5加密一下做加密或者直接加密的方式,MD5加密。這么做的好處是,加密源好記,可以防止丟失。
3.WXPayConfig.java
這是一個抽象類,里邊是一些微信支付的基本配置。是需要你自己繼承並完善的。但是這個實現在SDK自帶的測試包中已經實現了,直接把他復制過來。把自己的配置搞進去。
這一步主要的就是下載證書,在商戶平台下載證書后,生產環境或者測試的電腦主機才可以調用微信支付下載證書后,放到指定位置,在配置一下路徑,很簡單,例如我的:
這樣配置的實現類就完成了。
4.WXPay.java
看名字你就應該知道,這是最重要的類。就是這個類中已經封裝好了所有方法,我們只需要在創建一個類,來調用其中的方法就可以了。
5.WXPayUtil.java
工具類,里邊包含了要用到的方法,很全面。
微信支付接口傳輸數據是通過XML字符串來傳輸的,然后再兩端再分別解析成映射結合。這是封裝在內部的我們了解一下就可以了。還包括符號的生成,你看,簽名都給你寫好了。
當然,你也可以根據自己的需求在放一些其他的工具方法。
6.request和report我沒怎么看。看到這里就足夠了。
二。創建工具類WXPayTool.java
這里我就直接復制了。排版有點亂,但方便大家。這是測試用,大家可以在改一下。在這里我還新創建了一個類,也就是OrderData類。在傳參的時候還要多寫一些代碼,為什么我要創建這個類呢?我看了微信簽名的生成規則,如果字符串為空或者空字符串。那么簽名時會自動過濾掉,不參與簽名。這么做的好處就是,易於擴展,如果以后公司在需要什么其他的支付方法,也比較方便,在調用一個wxpay中的方法,並傳進對應的參數就可以了。我把WXPayTool和OrderData.java的實體類粘貼出來。
公共類WXPayTool {
私人WXPay wxpay;
私人WXPayConfigImpl配置;
公共WXPayTool()拋出異常{
config = WXPayConfigImpl.getInstance();
wxpay =新的WXPay(config,false,false);
}
/ **
*公眾號支付
*發起支付后--- >>通信代碼,必然返回。請求是否成功代碼。如果成功則不返回或者。
*得到預付單編號
* /
public Map <String,String> doUnifiedOrder(OrderData orderData){
Map <String,String> data = new HashMap <String,String>();
data.put(“body”,orderData.getBody());
data.put(“out_trade_no”,orderData.getout_trade_no());
data.put(“total_fee”,orderData.getTotal_fee());
data.put(“spbill_create_ip”,orderData.getSpbill_create_ip());
data.put(“time_start”,orderData.getTime_start());
data.put(“time_expire”,orderData.getTime_expire());
data.put(“notify_url”,orderData.getNotify_url());
data.put(“trade_type”,orderData.getTrade_type());
data.put(“product_id”,orderData.getProduct_id());
data.put(“openid”,orderData.getOpenid());
嘗試{
Map <String,String> r = wxpay.unifiedOrder(data,1000,1000);
的System.out.println(R);
返回r;
catch(Exception e){
e.printStackTrace();
返回null;
}
}
/ **
*關閉訂單
* @param out_trade_no預付單
* @返回
* /
public Map <String,String> doOrderClose(String out_trade_no){
的System.out.println( “關閉訂單”);
HashMap <String,String> data = new HashMap <String,String>();
data.put(“out_trade_no”,out_trade_no);
嘗試{
Map <String,String> r = wxpay.closeOrder(data);
的System.out.println(R);
返回r;
catch(Exception e){
e.printStackTrace();
返回null;
}
}
public Map <String,String> doOrderQuery(String out_trade_no){
的System.out.println( “查詢訂單”);
HashMap <String,String> data = new HashMap <String,String>();
data.put(“out_trade_no”,out_trade_no);
// data.put(“transaction_id”,“4008852001201608221962061594”);
嘗試{
Map <String,String> r = wxpay.orderQuery(data,1000,1000);
的System.out.println(R);
返回r;
catch(Exception e){
e.printStackTrace();
返回null;
}
}
/ **
*退款
*已測試
* @返回
* /
public Map <String,String> doRefund(String out_trade_no,String total_fee){
HashMap <String,String> data = new HashMap <String,String>();
data.put(“out_trade_no”,out_trade_no);
data.put(“out_refund_no”,out_trade_no);
data.put(“total_fee”,total_fee);
data.put(“refund_fee”,total_fee);
data.put(“refund_fee_type”,“CNY”);
//data.put(“op_user_id”,config.getMchID());
嘗試{
Map <String,String> r = wxpay.refund(data);
的System.out.println(R);
返回r;
catch(Exception e){
e.printStackTrace();
返回null;
}
}
/ **
*查詢退款
*已經測試
* @返回
* /
public Map <String,String> doRefundQuery(String out_trade_no){
HashMap <String,String> data = new HashMap <String,String>();
data.put(“out_refund_no”,out_trade_no);
嘗試{
Map <String,String> r = wxpay.refundQuery(data);
的System.out.println(R);
返回r;
catch(Exception e){
e.printStackTrace();
返回null;
}
}
/ **
*對賬單下載
*已測試
* @返回
* /
public Map <String,String> doDownloadBill(long time){
HashMap <String,String> data = new HashMap <String,String>();
data.put(“bill_date”,WXPayUtil.generateBillDateStrByLong(time));
data.put(“bill_type”,“ALL”);
嘗試{
Map <String,String> r = wxpay.downloadBill(data);
的System.out.println(R);
返回r;
catch(Exception e){
e.printStackTrace();
返回null;
}
}
}
/ **
*微信支付統一下單,所用到的參數,全部為String
* /
公共類OrderData擴展BaseEntity實現Serializable {
/ *參數說明---->
* 1。這里包含的參數,是出去的配置中的其他參數,配置中包含了
* APPID,mchid,標志,signtype,nonce_str
* 2。余下的是下面這些,***標記的為必填項
* 3。參數的初始值都是“”空字符串
* 因為在微信支付官方的SDK中,實現了參數為空不參與簽名
* 4。把所有參數都實現的目的是,易於擴展
* 5。由於我們的使用場景,是JSAPI微信公眾號支付,我們把要選擇參數標記一下用###來標識
* /
private String device_info =“”; //設備號
private String body =“”; //商品簡單描述維康動力 - 醫療###
private String detail =“”; //商品詳情
私人字符串附加=“”; //附加數據,在查詢時,原樣返回待定
private String out_trade_no =“”; //訂單號***
private String fee_type =“”; //類型,不傳,默認為CNY
private String total_fee =“”; //總計多少錢***
private String spbill_create_ip =“”; //用戶端ip,必傳***
private String time_start =“”; // ###訂單生成時間--->這里指的是預付單生成時間###
private String time_expire =“”; // ###訂單失效時間--->預付單失效后,如果用戶還要提交支付,需要發起重新請求訂單接口,獲得新的預付單ID ###
private String goods_tag =“”; //訂單優惠說明待定
私人字符串notify_url =“”; //回調地址***
private String trade_type =“”; // JSAPI ***
私人字符串product_id =“”; //商品ID,###
private String limit_pay =“”; //非信用卡支付
private String openid =“”; //用戶的OpenID ***
private String scene_info =“”; //場景信息
三。具體流程
上一張圖,這是我測試用的前端頁面,這樣看起來也比較清楚。
第一個接口,也就是統一下單接口。這一步相當於用戶選中了一個商品,並生成了訂單,而這個訂單就是預付單。這里有幾個需要注意的地方
1)spbill_create_ip的填寫文檔中指的是客戶端的IP,使用了SDK提供的方法WXPayUtil.getCustomerIp(請求)。但是貌似沒有什么效果,直接用的127.0.0.1也沒問題。微信支付系統雖然要求傳這個參數,但貌似對這個參數沒有多大的處理。
下面的開始時間和結束時間,微信支付是有要求的,格式為YYYYMMDDHHMMSS,下面的兩個方法是我封裝的方法。
2)在統一下單提交的數據中要添加notify_url。這是在用戶支付成功之后,微信支付系統返回給系統的數據。以XML字符串數據流在HTTP實體中傳過來。這是很重要的,在這個過程中,我們需要把返回的數據與平台內數據做對比,查看信息是否准確。並且校驗之后要把信息返回給微信支付系統的。如果配置了過濾器過濾器,別忘了放了這個方法。
這個接口主要獲得的就是prepay_id預付單ID,有了預付單號之后就可以進行下一步,在JS中調起微信支付控件了。
大概是這樣的:
3)在調用返回的數據是Map集合,這樣傳到前端解析時有問題的,所以使用JSON.fromObject(map)解析成net.json,再傳到前端就不會有問題了,后續的接口這些也是需要注意的。
第二步,已經有了訂單,用戶決定要不要支付。在JS中調起控件,發起支付。點擊發起支付,輸入密碼付款成功。這里需要注意的是
1)package參數,packge參數的內部是prepay_id ='prepay_id'。在這一步測試時,最好用iphone測試,我在使用安卓時,出錯了但是沒有任何提示。在使用蘋果測試時,彈出了錯誤信息,total_fee參數錯誤,但是在我們傳的簽名參數中根本就沒有total_fee這個參數。這就比較奇怪了,再次查看文檔,發現還是自己看的不仔細。
主要檢查了下prepay_id,我傳參數的時候格式不對,pacakge是js中的關鍵字,我把prepay_id傳到了后台,拼接出鍵值對:package:'prepay_id = xxxxxx',在前端取值時就出了問題。所以我直接把prepay_id設置為js的全局變量。在js傳參時直接把這個參數傳進去。
2)在這里我引入了一個獲取JS調用的參數的方法,這個方法也很簡單,直接把prepay_id傳入后端,用SDK生成簽名。這里要注意的是signType不是MD5.MD5是沙箱測試才會使用簽名方式。
第三步查詢訂單。,查詢訂單是可以根據微信生成的訂單號或者平台自己的訂單號來查詢當前訂單的狀態的這里要注意的是:
1)要先分清幾個單號的概念。預付單ID,商戶訂單ID,微信系統訂單ID。商戶訂單,這里商戶訂單是平台自己的自己生成的,在平台中標識,並且也傳到微信系統中。預付單,在把商品信息提交后產生的預付款的單號,只是在微信系統中生成了訂單,但是還沒有支付。而微信系統訂單則是已經支付完成之后的單號。
開始的時候,我是用預付單查詢訂單,但是報錯為參數長度有誤。開發文檔中寫的是微信系統訂單和商戶訂單二選一,並且長度都是32位的。后來我做了一個騷操作,數了一下預付單ID的長度,的確的確,它是31位的!后來嘗試用支付成功后返回的微信系統訂單來查詢訂單,發現還是不行的.