1. 程式人生 > >微信小程式支付開發筆記2--生成簽名-統一下單-二次簽名

微信小程式支付開發筆記2--生成簽名-統一下單-二次簽名

使用者選擇商品發起購買請求,後端接收到請求後,先生成本地訂單,以得到一個本地訂單的商戶訂單號。同時從表中讀取該使用者的openID。

我是用一個物件pay來存統一下單需要傳的引數,pay的欄位如下(部分引數並非必填引數,可傳可不傳):

注:notify_url是必填引數,是微信支付成功後需要呼叫的回撥方法,系統支付成功需要做的業務處理都是在這方法裡面執行的。


進行統一下單之前,我們需要根據請求引數進行第一次簽名,簽名演算法可以參考微信支付開發文件,這裡提幾點注意事項:

1、訂單金額需要轉換成以分為單位;

2、引數區分大小寫,且值為空的引數不參與簽名

3、引數需按ASCII碼從小到大排序

簽名方法舉例:

/**

    * 生成sign用於請求微信

    * @param key祕鑰

    * @param parameters引數map

    * @return

    */

   publicstatic StringcreateSign(Stringkey,Map<Object, Object>parameters) {

      StringBuffersb =new StringBuffer();

      if (!(parametersinstanceof SortedMap<?,?>)) {

        parameters = new

TreeMap<Object,Object>(parameters);

      }

      Set<?>es =parameters.entrySet();//所有參與傳參的引數按照accsii排序(升序),sign引數不參與簽名

      Iterator<?>it =es.iterator();

      while (it.hasNext()) {

        Map.Entryentry= (Map.Entry)it.next();

        Stringk = (String)entry.getKey();

        Objectv

=entry.getValue();

        if (null !=v && !"".equals(v) && !"sign".equals(k)

              &&!"key".equals(k)) {

           sb.append(k +"=" +v +"&");

        }

      }

      sb.append("key=" +key);

      Stringsign=md5Util.getMD5ofStr(sb.toString()).toUpperCase();

      returnsign;

   }

簽名成功後,得到sign並賦值pay.setSign(sign) ;接下來就是將pay物件轉換成xml,呼叫統一下單介面進行統一支付,並將統一支付返回的xml轉換成bean,這裡使用的是WechatPayResult物件,WechatPayResult的欄位如下圖; 


統一下單成功會返回微信預支付訂單號prepay_id,我們需要根據這個prepay_id進行二次簽名,二次簽名所用引數如下(不包括paySign):


其中,預支付訂單號prepay_id儲存在package欄位中。

二次簽名成功後,即可將參與簽名引數及簽名paySign一併傳到小程式端,小程式端在接受到這些引數後,即可呼叫方法調起支付,調起程式碼如下:

wx.requestPayment({

           'timeStamp': pay.timeStamp,

           'nonceStr': pay.nonceStr,

           'package': pay.package,

           'signType': pay.signType,

           'paySign': pay.paySign,

           'success':function (res) {

              console.log("支付成功")

              callback();

           },

           'fail':function (res) {

           }

         });


支付成功後,微信伺服器將會呼叫我們在呼叫統一下單時傳過去的回撥方法路徑notify_url,在這個方法裡是本地系統在支付成功後需要做的一些業務操作。

需要注意的是,商戶系統對於支付結果通知的內容一定要做簽名驗證,並校驗返回的訂單金額是否與商戶側的訂單金額一致,防止資料洩漏導致出現“假通知”,造成資金損失。其次就是在業務處理完成後,需要向微信伺服器返回一個成功的資訊,否則微信將按一定的策略定期重新發起通知,這樣會頻繁請求本地伺服器的,所以本地系統必須能夠正確處理重複的通知,並在處理完成後一定要向微信端傳送成功的訊息。

推薦的做法是,當收到通知進行處理時,首先檢查對應業務資料的狀態,判斷該通知是否已經處理過,如果沒有處理過再進行處理,如果處理過直接返回結果成功。在對業務資料進行狀態檢查和處理之前,要採用資料鎖進行併發控制,以避免函式重入造成的資料混亂。

附:

物件轉換成xml的方法如下:

publicstaticStringmyBeanToXML(Objectmodel,StringrootName){

      StringBuildersb =new StringBuilder();

      sb.append("<" +rootName +">");

      if (model !=null) {

        Field[]field=model.getClass().getDeclaredFields();//獲取實體類的所有屬性,返回Field陣列

        for (intj = 0;j <field.length;j++) {// 遍歷所有屬性

           field[j].setAccessible(true);

           Stringname=field[j].getName();//獲取屬性的名字

           Objectvalue=null;

           try {

              value = field[j].get(model);

           }catch(IllegalArgumentExceptione) {

              e.printStackTrace();

           }catch(IllegalAccessExceptione) {

              e.printStackTrace();

           }

           if (value !=null) {

              sb.append("<" +name +">");

              if(!"total_fee".equals(name)){

                 sb.append("<![CDATA["+value.toString()+"]]>");

              }else{

                 sb.append(value.toString());

              }

              sb.append("</"+name+">");

           }

        }

      }

      sb.append("</"+rootName+">");

      returnsb.toString();

   }