微信小程序支付开发笔记2--生成签名-统一下单-二次签名

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_22158021/article/details/78667122

用户选择商品发起购买请求,后端接收到请求后,先生成本地订单,以得到一个本地订单的商户订单号。同时从表中读取该用户的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();

   }


没有更多推荐了,返回首页