微信小程序支付_微信小程序 微信支付 支付类型 - CSDN
精华内容
参与话题
  • 学习微信小程序已经半个多月了,终于接触到小程序中一个很重要的功能——微信支付。接下来就给大家详细讲解一下微信支付功能的调用。一想到微信支付,大家一定会去看微信小程序的API文档,没错,作为一个菜鸟我也看...

    学习微信小程序已经半个多月了,终于接触到小程序中一个很重要的功能——微信支付。接下来就给大家详细讲解一下微信支付功能的调用。

    一想到微信支付,大家一定会去看微信小程序的API文档,没错,作为一个菜鸟我也看过,当然我第一次看的时候脑袋也有点晕,因为其中所需要的参数有点多,而且很多东西我们都不知道怎样去获得。没关系,下面我一步一步给各位讲解,怎么去实现微信支付这一功能的调用。

    首先大家需要去下载一个公众号支付的sdk,下面是网址
    https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1
    我的服务器后台选用的是php,所以我下载的是php的sdk。

    话不多说,接下来开始我们的正题。我们下载完sdk以后会发现这就是一个支付的demo,微信团队已经把所有的代码帮我们写好了,但是请注意,这是公众号支付的demo,因此我们需要修改一下其中的部分内容。

    1.首先我们打开WxpayAPI_php_v3.0.1目录下的cert目录,我们可以看到cert目录放的就是我们的证书文件,我们需要把原有的证书文件删除,替换成我们微信商户平台中的证书文件。所谓证书文件,就是当你注册成功一个微信商户号后,在“账户中心—API安全”下我们可以下载我们的证书,微信团队需要在支付时确认商家身份,所以需要这一环节,如下图
    原始文件

    替换后的文件

    2.配置完证书以后,我们就该配置我们的小程序信息和商家信息了。在文件夹lib目录下的WxPay.Config.php文件中,我们可以看到一些参数的信息,因此我们需要把它修改成我们自己的信息。如下图。
    这里写图片描述

    3.修改example目录下的WxPay.JsApiPay.php文件。如下图。
    原始代码

    途中参数code指的是获取到的用户的code,但是在开发文档中code变量为js_code,因此我们需要将202行中的code->js_code。还有第205行,我们需要的接口应该为wx.login中的接口,因为我们需要把这些参数传上去,因此修改后的代码为下图。
    修改后的代码

    3.在example目录下的jsapi.php文件中,我们可以修改以下信息。
    这里写图片描述

    其中的参数信息我们可以在微信文档中了解,部分的参数我们无需修改,大家想了解参数可以进入下面链接。
    https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1
    最后29行是我手动加上去的,给我们的前台返回统一下单的这些参数,以便我们传递给微信支付API。然后我们还需要把这个文件中的H5代码注释掉或者删掉,因为小程序不会显示这些代码。注释掉下图中的全部H5代码
    这里写图片描述

    当我们做完以上几步以后,我们就可以开始我们的微信小程序的开发了。首先我们创建一个项目,添加我们的APPID。

    首先在app.js中我们需要调用wx.login方法来获取用户的code

    //app.js
    App({
      code: null,
      onLaunch: function () {
        var that=this;
        wx.login({
          success: function (res) {
            if (res.code) {
              that.code=res.code;
            } else {
              console.log('获取用户登录态失败!' + res.errMsg)
            }
          }
        });
      },
    
    })

    然后我们创建一个page,命名为pay,我们在pay.wxml中创建一个按钮,并且给它绑定事件,我们希望点击按钮实现支付功能。

    <view>
    <button bindtap='wxpay' class='css'>发起支付</button>
    </view>

    接下来是pay.js代码

    // pages/pay/pay.js
    var app=getApp();
    Page({
      wxpay: function(){
        var code=app.code;
        wx.request({
          //我把文件夹名改为了wxpayapi,SERVER_PATH为服务器的域名
          url: SERVER_PATH+'wxpayapi/example/jsapi.php', 
          data: {
            code: code
          },
          header: {
            'content-type': 'application/json' // 默认值
          },
          success: function (res) {
            console.log(res.data);
            var data=res.data;
            wx.requestPayment({
              'timeStamp': data.timeStamp,
              'nonceStr': data.nonceStr,
              'package': data.package,
              'signType': 'MD5',
              'paySign': data.paySign,
              'success': function (res) {
                console.log("支付成功!")
              },
              'fail': function (res) {
              }
            })
          }
        })
      }
    })

    这里写图片描述
    当我们获取到code后就把code发送给jsapi.php文件,然后我们把结果给log出来,我们可以看到我们统一下单api给我们返回的参数,而这些参数正是wx.requestPayment所需要的参数,因此我们直接传给wx.requestPayment方法,然后就可以支付了。
    这里写图片描述

    接下来还有一个很重要的环节,就是我在调用微信支付功能的工程中所遇到的一些bug,可能有些人也会遇到同样的问题,于是我就给大家说明一下。

    1.发送请求失败。我们调用wx.request给服务器发送请求的时候必须在微信小程序的后台给我们的服务器域名设置白名单。在“设置->开发设置”。
    这里写图片描述
    需要注意的一点是我们发起请求的是域名,而且是HTTPS的域名,因此如果请求的地址是IP或者是HTTP,编译器会报错。

    2.

    Notice: “Undefined property: JsApiPay::$curl_timeout in C:\xampp\htdocs\www\curtain\public\WxPay414\WxPay.JsApiPay.php on line 100”

    这里写图片描述
    这里写图片描述
    在此处改为30,指30s。

    3.证书问题。

    Fatal error: Uncaught WxPayException: curl出错,错误码:60 in C:\xampp\htdocs\www\curtain\public\WxPay414\lib\WxPay.Api.php:564
    Stack trace:
    解决方法:http://blog.csdn.net/qq_34755805/article/details/51221932

    4.<b>Notice</b>: Undefined index: access_token in <b>C:\phpStudy\PHPTutorial\WWW\wxpayapi\example\WxPay.JsApiPay.php</b> on line <b>156</b><br />

    解决方法,注释掉第156行。
    这里写图片描述


    展开全文
  • 博主,之前做微信支付,在网上很少找到支付...2.微信小程序处理 .wxml .js 3 后台处理部分(博主使用php为例子)【其他语言参照修改就可以了】 以下参数不懂,可通过这个查看,微信文档查看参数的名称 https:/...

    博主,之前做微信支付,在网上很少找到支付的文章,所以就抽空把微信支付流程给整理出来,方便各位刚刚接触微信支付的用户,参考,如有不好之处,欢迎评论指出

    1、必须开通支付,并且有备案的域名 和 配置 https

    2.微信小程序处理

    .wxml

    .js

    3 后台处理部分(博主使用php为例子)【其他语言参照修改就可以了】

    以下参数不懂,可通过这个查看,微信文档查看参数的名称

    https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1

    下面是实现的代码:


    //微信支付
    public function Pay(){
        $fee = 0.01;//举例充值0.01
        $appid =        '微信小程序的appid【自己填写】';//如果是公众号 就是公众号的appid
        $body =         '蜗牛充值【自己填写】';
        $mch_id =       '你的商户号【自己填写】';
        $nonce_str =    $this->nonce_str();//随机字符串
        $notify_url =   '回调的url【自己填写】';
        $openid =       '用户的openid【自己填写】';
        $out_trade_no = $this->order_number();//商户订单号
        $spbill_create_ip = '服务器的ip【自己填写】';
        $total_fee =    $fee*100;//因为充值金额最小是1 而且单位为分 如果是充值1元所以这里需要*100
        $trade_type = 'JSAPI';//交易类型 默认

        //这里是按照顺序的 因为下面的签名是按照顺序 排序错误 肯定出错
        $post['appid'] = $appid;
        $post['body'] = $body;
        $post['mch_id'] = $mch_id;
        $post['nonce_str'] = $nonce_str;//随机字符串
        $post['notify_url'] = $notify_url;
        $post['openid'] = $openid;
        $post['out_trade_no'] = $out_trade_no;
        $post['spbill_create_ip'] = $spbill_create_ip;//终端的ip
        $post['total_fee'] = $total_fee;//总金额 最低为一块钱 必须是整数
        $post['trade_type'] = $trade_type;
        $sign = $this->sign($post);//签名
        $post_xml = '<xml>
               <appid>'.$appid.'</appid>
               <body>'.$body.'</body>
               <mch_id>'.$mch_id.'</mch_id>
               <nonce_str>'.$nonce_str.'</nonce_str>
               <notify_url>'.$notify_url.'</notify_url>
               <openid>'.$openid.'</openid>
               <out_trade_no>'.$out_trade_no.'</out_trade_no>
               <spbill_create_ip>'.$spbill_create_ip.'</spbill_create_ip>
               <total_fee>'.$total_fee.'</total_fee>
               <trade_type>'.$trade_type.'</trade_type>
               <sign>'.$sign.'</sign>
            </xml> ';
        //统一接口prepay_id
        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        $xml = $this->http_request($url,$post_xml);
        $array = $this->xml($xml);//全要大写
        if($array['RETURN_CODE'] == 'SUCCESS' && $array['RESULT_CODE'] == 'SUCCESS'){
            $time = time();
            $tmp='';//临时数组用于签名
            $tmp['appId'] = $appid;
            $tmp['nonceStr'] = $nonce_str;
            $tmp['package'] = 'prepay_id='.$array['PREPAY_ID'];
            $tmp['signType'] = 'MD5';
            $tmp['timeStamp'] = "$time";

            $data['state'] = 1;
            $data['timeStamp'] = "$time";//时间戳
            $data['nonceStr'] = $nonce_str;//随机字符串
            $data['signType'] = 'MD5';//签名算法,暂支持 MD5
            $data['package'] = 'prepay_id='.$array['PREPAY_ID'];//统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=*
            $data['paySign'] = $this->sign($tmp);//签名,具体签名方案参见微信公众号支付帮助文档;
            $data['out_trade_no'] = $out_trade_no;

        }else{
            $data['state'] = 0;
            $data['text'] = "错误";
            $data['RETURN_CODE'] = $array['RETURN_CODE'];
            $data['RETURN_MSG'] = $array['RETURN_MSG'];
        }
        echo json_encode($data);
    }


    //随机32位字符串
    private function nonce_str(){
        $result = '';
        $str = 'QWERTYUIOPASDFGHJKLZXVBNMqwertyuioplkjhgfdsamnbvcxz';
        for ($i=0;$i<32;$i++){
            $result .= $str[rand(0,48)];
        }
        return $result;
    }


    //生成订单号
    private function order_number($openid){
        //date('Ymd',time()).time().rand(10,99);//18位
        return md5($openid.time().rand(10,99));//32位
    }


    //签名 $data要先排好顺序
    private function sign($data){
        $stringA = '';
        foreach ($data as $key=>$value){
            if(!$value) continue;
            if($stringA) $stringA .= '&'.$key."=".$value;
            else $stringA = $key."=".$value;
        }
        $wx_key = '';//申请支付后有给予一个商户账号和密码,登陆后自己设置key
    $stringSignTemp = $stringA.'&key='.$wx_key;//申请支付后有给予一个商户账号和密码,登陆后自己设置key return strtoupper(md5($stringSignTemp));}

    //curl请求啊
    function http_request($url,$data = null,$headers=array())
    {
        $curl = curl_init();
        if( count($headers) >= 1 ){
            curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        }
        curl_setopt($curl, CURLOPT_URL, $url);

        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);

        if (!empty($data)){
            curl_setopt($curl, CURLOPT_POST, 1);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        }
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($curl);
        curl_close($curl);
        return $output;
    }

    //获取xml
    private function xml($xml){
        $p = xml_parser_create();
        xml_parse_into_struct($p, $xml, $vals, $index);
        xml_parser_free($p);
        $data = "";
        foreach ($index as $key=>$value) {
            if($key == 'xml' || $key == 'XML') continue;
            $tag = $vals[$value[0]]['tag'];
            $value = $vals[$value[0]]['value'];
            $data[$tag] = $value;
        }
        return $data;
    }


    这里就实现微信支付了,看效果,在真机上面测试,才行

    --------------------- 
    作者:CSDN蜗牛 
    来源:CSDN 
    原文:https://blog.csdn.net/xieshunhai/article/details/72829232?utm_source=copy 
    版权声明:本文为博主原创文章,转载请附上博文链接!

    展开全文
  • 微信小程序支付详解:

    千次阅读 2018-09-12 18:50:02
    前段时间在公司的开发了一个微信小程序的项目,今天来说一说微信小程序的支付,有很多优秀的文章都说了小程序支付的 开发流程步骤,这里我们推荐一个博主以前就是看他的开发小程序支付:...

    前段时间在公司的开发了一个微信小程序的项目,今天来说一说微信小程序的支付,有很多优秀的文章都说了小程序支付的
    开发流程步骤,这里我们推荐一个博主以前就是看他的开发小程序支付:https://github.com/1913045515/weixin
    现在来说说我对小程序支付的理解,首先我们在开发文档中找到小程序支付流程,

    这里写图片描述
    上面的图是我们支付的流程图,下面是开发要调用接口的顺序,
    首先第一步我们获取openid,因为在统一下单接口中的交易类型是JSAPI,是必须要填openid
    第二步就是下单了,把我们要下单参数拼接成xml的形式去发送接口,这里主要是签名很重要
    签名:
    1.签名算法
    签名生成的通用步骤如下:

    第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。

    特别注意以下重要规则:

     ◆ 参数名ASCII码从小到大排序(字典序);
     ◆ 如果参数的值为空不参与签名;
     ◆ 参数名区分大小写;
     ◆ 验证调用返回或微信主动通知签名时,传送的sign参数不参与签名,将生成的签名与该sign值作校验。
     ◆ 微信接口可能增加字段,验证签名时必须支持增加的扩展字段
    第二步,在stringA最后拼接上key=(API密钥的值)得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。
    假设传送的参数如下:

    appid: wxd930ea5d5a258f4f

    mch_id: 10000100

    device_info: 1000

    body: test

    nonce_str: ibuaiVcKdpRxkhJA

    第一步:对参数按照key=value的格式,并按照参数名ASCII字典序排序如下:

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

    第二步:拼接API密钥:

    stringSignTemp=”stringA&key=192006250b4c09247ec02edce69f6a2d”

    sign=MD5(stringSignTemp).toUpperCase()=”9A0A8659F005D6984697E2CA0A9CF3B7”

    网友的整理:
    这里写图片描述
    这样我们就得到了签名
    我们下单成功后微信会给我们预支付交易会话标识 这个很主要,拿这个在进行一次签名加密,
    因为我们调用支付的接口中需要一个签名,支付成功后就会调用我们下单时所传的回调地址,我们在回调方法中判断用户是否支付成功,进行业务处理

    代码实例:
    OrderController.java

        /**
         * 下单:
         * @param openid 用户openid
         * @param money 金额
         * @return map
         */
        @RequestMapping("/createOrder")
        @ResponseBody
        public Map<String,String>createOrder(String openid,int money){
            logger.info("用户的openid:-------->"+openid+"下单的金额:-------------->"+money);
    
            String mch_id= WeChatTool.mch_id; //商户号
    
            String today = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
            String WXPay= WXPayUtil.createCode(8);
            String out_trade_no=mch_id+today+WXPay;//生成订单号
        Map<String,String> result=new HashMap<String,String>();
        //去Service层中去生成签名,用户openid out_trade_no订单号  money支付的金额
            String formData=orderService.getopenid(openid,out_trade_no,money);
        //在servlet层中生成签名成功后,把下单所要的参数以xml的格式拼接,发送下单接口
            String httpResult = HttpUtils.httpXMLPost(WeChatTool.createOrderUrl,formData);
            try {
        //xml转换成Map对象或者值
                Map<String, String> resultMap = WXPayUtil.xmlToMap(httpResult);
                result.put("package", "prepay_id=" + resultMap.get("prepay_id")); //这里是拿下单成功的微信交易号去拼接,因为在下面的接口中必须要这个样子
                result.put("nonceStr",resultMap.get("nonce_str")); //随机字符串
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            String times= WXPayUtil.getCurrentTimestamp()+""; //获取当前时间
            result.put("timeStamp",times); //当前时间戳
        //生成调用支付接口要的签名
            Map<String, String> packageParams = new HashMap<String ,String>();
            packageParams.put("appId", WeChatTool.wxspAppid);
            packageParams.put("signType", WeChatTool.sign_type);
            packageParams.put("nonceStr",result.get("nonceStr")+"");
            packageParams.put("timeStamp",times);
            packageParams.put("package", result.get("package")+"");//商户订单号
            String sign="";
            try {
                sign= WXPayUtil.generateSignature(packageParams, WeChatTool.sercet_key); //生成签名:
            } catch (Exception e) {
                e.printStackTrace();
            }
            result.put("paySign",sign);
            logger.info("签名成功----->"+result.get("paySign"));
            return result; //所有的参数放进map中保存发送到小程序页面中,去调用微信支付接口
        }
    

    OrderServiceImpl.java:

    /**
         * 统一下单
         * @param openid 用户标识
         * @param out_trade_no 订单号
         * @param total_fee 金额
         * @return String
         */
        @Override
        public String getopenid(String openid,String out_trade_no,int total_fee) {
    
            //下单的金额,因为在微信支付中默认是分所以要这样处理
            Integer total_fees=total_fee*100;
            微信下单的金额是String类型的所以要转换类型
            String money=total_fees.toString();
            String nonceStr=WXPayUtil.generateUUID(); //设置UUID作为随机字符串
    
            Map<String ,String> map = new HashMap<String ,String>();
            map.put("appid",WeChatTool.wxspAppid); //商户appid
            map.put("mch_id", WeChatTool.mch_id);//商户号
            map.put("nonce_str",nonceStr); //随机数
            map.put("body","大米");//商户名称
            map.put("out_trade_no",out_trade_no);//商户订单号
            map.put("total_fee",money);//下单金额
            map.put("spbill_create_ip", "127.0.0.1");//终端IP
                map.put("notify_url",https://xxxx/xxxxx/notify.do);//回调地址 这里的接口必须是在线上用户支付成功才能收到微信发送的信息
            map.put("trade_type","JSAPI");//交易类型
                map.put("openid",openid+"");//用户openid
                map.put("sign_type","MD5");//加密类型
            String sign="";
            try {
            sign= WXPayUtil.generateSignature(map, WeChatTool.sercet_key); //生成sign签名WeChatTool.sercet_key是商户的支付秘钥
            } catch (Exception e) {
                e.printStackTrace();
            }
            //拼接成xml的格式,这里的参数必须要和上面的一致,并且每次下单的订单号不能一致
            String formData="<xml>";
    
            formData += "<appid>"+ WeChatTool.wxspAppid+"</appid>"; 
            formData += "<mch_id>"+ WeChatTool.mch_id+"</mch_id>"; 
            formData += "<nonce_str>"+nonceStr+"</nonce_str>";
            formData += "<body>"+WeChatTool.month+"</body>";
            formData += "<out_trade_no>"+out_trade_no +"</out_trade_no>"; 
            formData += "<total_fee>"+money+"</total_fee>"; 
            formData += "<spbill_create_ip>"+"127.0.0.1"+"</spbill_create_ip>"; 
            formData += "<notify_url>"+WeChatTool.notify_url+"</notify_url>"; 
            formData += "<trade_type>"+WeChatTool.trade_type+"</trade_type>";
            formData += "<openid>"+openid+"</openid>"; //appid
            formData += "<sign_type>"+WeChatTool.sign_type+"</sign_type>";
            formData += "<sign>"+sign+"</sign>"; //签名算法
            formData += "</xml>";
            return formData;
        }

    工具类:
    WXPayUtil.java:

    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.w3c.dom.Node;
    import org.w3c.dom.NodeList;
    import com.youquan.utli.WXPayConstants.SignType;
    import javax.crypto.Mac;
    import javax.crypto.spec.SecretKeySpec;
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    import javax.xml.transform.OutputKeys;
    import javax.xml.transform.Transformer;
    import javax.xml.transform.TransformerFactory;
    import javax.xml.transform.dom.DOMSource;
    import javax.xml.transform.stream.StreamResult;
    import java.io.ByteArrayInputStream;
    import java.io.InputStream;
    import java.io.StringWriter;
    import java.security.MessageDigest;
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.*;
    /**
     * <p>User: qrn
     * <p>Date: 14-1-28
     * <p>Version: 1.0
     * 描述: 工具类
     */
    public class WXPayUtil {
    
        /**
         *  XML格式字符串转换为Map
         * @param strXML XML字符串
         * @return  Map XML数据转换后的Map
         * @see Exception
         */
        public static Map<String, String> xmlToMap(String strXML) throws Exception {
            try {
                Map<String, String> data = new HashMap<String, String>();
                DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
                DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
                InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
                org.w3c.dom.Document doc = documentBuilder.parse(stream);
                doc.getDocumentElement().normalize();
                NodeList nodeList = doc.getDocumentElement().getChildNodes();
                for (int idx = 0; idx < nodeList.getLength(); ++idx) {
                    Node node = nodeList.item(idx);
                    if (node.getNodeType() == Node.ELEMENT_NODE) {
                        org.w3c.dom.Element element = (org.w3c.dom.Element) node;
                        data.put(element.getNodeName(), element.getTextContent());
                    }
                }
                try {
                    stream.close();
                } catch (Exception ex) {
                    // do nothing
                }
                return data;
            } catch (Exception ex) {
                WXPayUtil.getLogger().warn("Invalid XML, can not convert to map. Error message: {}. XML content: {}", ex.getMessage(), strXML);
                throw ex;
            }
    
        }
        /**
         * 将Map转换为XML格式的字符串
         * @param data Map类型数据
         * @return   XML格式的字符串
         * @see Exception
         */
        public static String mapToXml(Map<String, String> data) throws Exception {
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();
            org.w3c.dom.Document document = documentBuilder.newDocument();
            org.w3c.dom.Element root = document.createElement("xml");
            document.appendChild(root);
            for (String key: data.keySet()) {
                String value = data.get(key);
                if (value == null) {
                    value = "";
                }
                value = value.trim();
                org.w3c.dom.Element filed = document.createElement(key);
                filed.appendChild(document.createTextNode(value));
                root.appendChild(filed);
            }
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer transformer = tf.newTransformer();
            DOMSource source = new DOMSource(document);
            transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            StringWriter writer = new StringWriter();
            StreamResult result = new StreamResult(writer);
            transformer.transform(source, result);
            String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");
            try {
                writer.close();
            }
            catch (Exception ex) {
            }
            return output;
        }
    
    
        /**
         * 生成6位或10位随机数 param codeLength(多少位)
         * @param codeLength 参数
         * @return  String
    
         */
        public static String createCode(int codeLength) {
            String code = "";
            for (int i = 0; i < codeLength; i++) {
                code += (int) (Math.random() * 9);
            }
            return code;
        }
        /**
         * 生成带有 sign 的 XML 格式字符串
         * @param data Map类型数据
         * @param key API密钥
         * @see Exception
         * @return String 含有sign字段的XML
         */
        public static String generateSignedXml(final Map<String, String> data, String key) throws Exception {
            return generateSignedXml(data, key, SignType.MD5);
        }
    
        /**
         * 生成带有 sign 的 XML 格式字符串
         *
         * @param data Map类型数据
         * @param key API密钥
         * @param signType 签名类型
         * @see Exception
         * @return 含有sign字段的XML
         */
        public static String generateSignedXml(final Map<String, String> data, String key, SignType signType) throws Exception {
            String sign = generateSignature(data, key, signType);
            data.put(WXPayConstants.FIELD_SIGN, sign);
            return mapToXml(data);
        }
    
        /**
         * 判断签名是否正确
         * @param xmlStr XML格式数据
         * @param key  API密钥
         * @return  boolean 签名是否正确
         * @see Exception
         */
        public static boolean isSignatureValid(String xmlStr, String key) throws Exception {
            Map<String, String> data = xmlToMap(xmlStr);
            if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) {
                return false;
            }
            String sign = data.get(WXPayConstants.FIELD_SIGN);
            return generateSignature(data, key).equals(sign);
        }
    
        /**
         * 判断签名是否正确,必须包含sign字段,否则返回false。使用MD5签名。
         * @param data Map类型数据
         * @param key API密钥
         * @return  boolean 签名是否正确
         * @see Exception
         */
        public static boolean isSignatureValid(Map<String, String> data, String key) throws Exception {
            return isSignatureValid(data, key, SignType.MD5);
        }
    
        /**
         * 判断签名是否正确,必须包含sign字段,否则返回false。
         *
         * @param data Map类型数据
         * @param key API密钥
         * @param signType 签名方式
         * @return boolean 签名是否正确
         * @exception Exception
         */
        public static boolean isSignatureValid(Map<String, String> data, String key, SignType signType) throws Exception {
            if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) {
                return false;
            }
            String sign = data.get(WXPayConstants.FIELD_SIGN);
            return generateSignature(data, key, signType).equals(sign);
        }
    
        /**
         * 生成签名
         * @param data  待签名数据
         * @param key  API密钥
         * @return String
         * @see Exception
         */
        public static String generateSignature(final Map<String, String> data, String key) throws Exception {
            return generateSignature(data, key, SignType.MD5);
        }
    
        /**
         * 生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。
         *
         * @param data 待签名数据
         * @param key API密钥
         * @param signType 签名方式
         * @return  String 签名
         * @see Exception
         */
        public static String generateSignature(final Map<String, String> data, String key, SignType signType) throws Exception {
            Set<String> keySet = data.keySet();
            String[] keyArray = keySet.toArray(new String[keySet.size()]);
            Arrays.sort(keyArray);
            StringBuilder sb = new StringBuilder();
            for (String k : keyArray) {
                if (k.equals(WXPayConstants.FIELD_SIGN)) {
                    continue;
                }
                if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名
                    sb.append(k).append("=").append(data.get(k).trim()).append("&");
            }
            sb.append("key=").append(key);
            if (SignType.MD5.equals(signType)) {
                return MD5(sb.toString()).toUpperCase();
            }
            else if (SignType.HMACSHA256.equals(signType)) {
                return HMACSHA256(sb.toString(), key);
            }
            else {
                throw new Exception(String.format("Invalid sign_type: %s", signType));
            }
        }
    
    
        /**
         * 获取随机字符串 Nonce Str
         *
         * @return String 随机字符串
         */
        public static String generateNonceStr() {
            return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
        }
    
    
        /**
         *
         *
         * @param data 待处理数据
         * @return String MD5结果
         * @see Exception
         */
        public static String MD5(String data) throws Exception {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] array = md.digest(data.getBytes("UTF-8"));
            StringBuilder sb = new StringBuilder();
            for (byte item : array) {
                sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
            }
            return sb.toString().toUpperCase();
        }
    
        /**
         * 生成 HMACSHA256
         * @param data 待处理数据
         * @param key 密钥
         * @return String 加密结果
         * @see  Exception
         */
        public static String HMACSHA256(String data, String key) throws Exception {
            Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
            SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
            sha256_HMAC.init(secret_key);
            byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));
            StringBuilder sb = new StringBuilder();
            for (byte item : array) {
                sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
            }
            return sb.toString().toUpperCase();
        }
    
        /**
         * 日志
         * @return Logger
         */
        public static Logger getLogger() {
            Logger logger = LoggerFactory.getLogger("wxpay java sdk");
            return logger;
        }
    
        /**
         * 获取当前时间戳,单位秒
         * @return long
         */
        public static long getCurrentTimestamp() {
            return System.currentTimeMillis()/1000;
        }
    
        /**
         * 当前时间的下一个月:
         * @return String
         */
        public static String getcuentime() {
              Calendar cal = Calendar.getInstance();
                cal.add(cal.MONTH, 1);
                SimpleDateFormat dft = new SimpleDateFormat("yyyy-MM-dd-HH-mm");
                String preMonth = dft.format(cal.getTime());
                System.out.println(preMonth);
    
                return preMonth;
        }
    
        /**
         * 给时间在加上一个月:
         * @param cur 时间参数
         * @return Date
         */
        public Date getNewDate(Date cur) {  
            Calendar c = Calendar.getInstance();  
            c.setTime(cur);   //设置时间
            c.add(Calendar.MINUTE, 1); //日期分钟加1,Calendar.DATE(天),Calendar.HOUR(小时)  
            Date date = c.getTime(); //结果  
           return date;
        }
    
    
    
        /**
         * 获取当前时间戳,单位毫秒
         * @return long
         */
        public static long getCurrentTimestampMs() {
            return System.currentTimeMillis();
        }
    
        /**
         * 生成 uuid, 即用来标识一笔单,也用做 nonce_str
         * @return String
         */
        public static String generateUUID() {
            return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
        }
    
    
    
    
    
    
    
        /**
         * map 转换为
         * @param map
         * @return
         */
        public  static String sunx(Map<String, String> map) {
            String  xmlResult="";
              StringBuffer sb = new StringBuffer();
              sb.append("<xml>");
              for (String key : map.keySet()) {
                  sb.append("<" + key + ">" + map.get(key) + "</" + key + ">");
                  System.out.println();
              }
              sb.append("</xml>");
              xmlResult = sb.toString();
              return xmlResult;
        }
    
    
    }

    HttpUtils.java:

    package com.youquan.utli;
    
    import com.alibaba.fastjson.JSONObject;
    import org.apache.http.HttpResponse;
    import org.apache.http.HttpStatus;
    import org.apache.http.client.HttpClient;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.util.EntityUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.io.IOException;
    import java.net.URLDecoder;
    /**
     * <p>User: qrn
     * <p>Date: 14-1-28
     * <p>Version: 1.0
     * 描述: http请求的工具类
     */
    public class HttpUtils {
        private static Logger logger = LoggerFactory.getLogger(HttpUtils.class);    //日志记录
    
        /**
         * httpPost
         *
         * @param url       路径
         * @param jsonParam 参数
         * @return JSONObject
         */
        public static JSONObject httpPost(String url, String jsonParam) {
            return httpPost(url, jsonParam, false);
        }
    
        /**
         * post请求
         *
         * @param url            url地址
         * @param param      参数
         * @param noNeedResponse 不需要返回结果
         * @return JSONObject
         */
        public static JSONObject httpPost(String url, String param, boolean noNeedResponse) {
            //post请求返回结果
            HttpClient httpClient = HttpClients.createDefault();
            JSONObject jsonResult = null;
            HttpPost method = new HttpPost(url);
            try {
                if (null != param) {
                    //解决中文乱码问题
                    StringEntity entity = new StringEntity(param, "utf-8");
                    entity.setContentEncoding("UTF-8");
                    entity.setContentType("application/json");
                    method.setEntity(entity);
                }
                HttpResponse result = httpClient.execute(method);
                url = URLDecoder.decode(url, "UTF-8");
                /**请求发送成功,并得到响应**/
                if (result.getStatusLine().getStatusCode() == 200) {
                    String str = "";
                    try {
                        /**读取服务器返回过来的json字符串数据**/
                        str = EntityUtils.toString(result.getEntity());
                        System.out.println(str);
                        if (noNeedResponse) {
                            return null;
                        }
                        /**把json字符串转换成json对象**/
                        jsonResult = JSONObject.parseObject(str);
                    } catch (Exception e) {
                        logger.error("post请求提交失败:" + url, e);
                    }
                }
            } catch (IOException e) {
                logger.error("post请求提交失败:" + url, e);
            }
            return jsonResult;
        }
    
        /**
         * post请求
         *
         * @param url            url地址
         * @param param      参数
         * @return String
         */
        public static String httpXMLPost(String url, String param) {
            //post请求返回结果
            HttpClient httpClient = HttpClients.createDefault();
            String xmlResult = null;
            HttpPost method = new HttpPost(url);
            try {
                if (null != param) {
                    //解决中文乱码问题
                    StringEntity entity = new StringEntity(param, "utf-8");
                    entity.setContentEncoding("utf-8");
                    entity.setContentType("text/xml");
                    method.setEntity(entity);
                }
                HttpResponse result = httpClient.execute(method);
                url = URLDecoder.decode(url, "utf-8");
                /**请求发送成功,并得到响应**/
                if (result.getStatusLine().getStatusCode() == 200) {
                    try {
                        /**读取服务器返回过来的json字符串数据**/
                        xmlResult = EntityUtils.toString(result.getEntity(),"utf-8");
                    } catch (Exception e) {
                        logger.error("post请求提交失败:" + url, e);
                    }
                }
            } catch (IOException e) {
                logger.error("post请求提交失败:" + url, e);
            }
            return xmlResult;
        }
    
        /**
         * 发送get请求
         * @param url    路径
         * @return  JSONObject
         */
        public static JSONObject httpGet(String url){
            //get请求返回结果
            JSONObject jsonResult = null;
            try {
                HttpClient client = HttpClients.createDefault();
                //发送get请求
                HttpGet request = new HttpGet(url);
                HttpResponse response = client.execute(request);
    
                /**请求发送成功,并得到响应**/
                if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                    /**读取服务器返回过来的json字符串数据**/
                    String strResult = EntityUtils.toString(response.getEntity());
                    /**把json字符串转换成json对象**/
                    jsonResult = JSONObject.parseObject(strResult);
                    url = URLDecoder.decode(url, "UTF-8");
                } else {
                    logger.error("get请求提交失败:" + url);
                }
            } catch (IOException e) {
                logger.error("get请求提交失败:" + url, e);
            }
            return jsonResult;
        }
    
    
    }
    

    好了支付的代码就到这里了,拿到参数在前端使用小程序

    wx.requestPayment(
    {
    'timeStamp': '',
    'nonceStr': '',
    'package': '',
    'signType': 'MD5',
    'paySign': '',
    'success':function(res){},
    'fail':function(res){},
    'complete':function(res){}
    })

    把上面的参数填充就可以调用支付了,如果没有问题那么支付就成功了

    展开全文
  • 详解微信小程序支付流程

    万次阅读 多人点赞 2018-07-02 18:29:54
    花了几天把小程序的支付模块接口写了一下...微信小程序的商户系统一般是以接口的形式开发的,小程序通过调用与后端约定好的接口进行参数的传递以及数据的接收。在小程序支付这块,还需要跟微信服务器进行交互。过程...

      花了几天把小程序的支付模块接口写了一下,可能有着公众号开发的一点经验,没有入太多的坑,在此我想记录一下整个流程。

    首先先把小程序微信支付的图搬过来:


    相信会来查百度的同学们基本都是对文档的说明不是很理解。我下面大概总结一下整个业务逻辑的过程。

    微信小程序的商户系统一般是以接口的形式开发的,小程序通过调用与后端约定好的接口进行参数的传递以及数据的接收。在小程序支付这块,还需要跟微信服务器进行交互。过程大致是这样的:

    一.小程序调用登录接口获取code,传递给商户服务器用来获取用户的openID

     我们知道在微信平台中,同一个公众号的openID都是不同的,它是用户身份识别的id,也就是说,我们通过openID来区分不同的用户,这个有微信开发基础的应该都很熟悉。为了知道谁在支付,我们需要先获取当前用户的openid,那么openID应该怎么获取呢?看下图:


    1. 小程序调用wx.login() 获取 临时登录凭证code ,并回传到开发者服务器。

    2. 开发者服务器以code换取 用户唯一标识openid 和 会话密钥session_key

    看不懂吗?不急,听我慢慢解释,这个业务流程大致就是首先你得先在小程序的代码中调用wx.login()来向微信获取到code,拿到了之后把code通过request传给商户服务器,再由商户服务器通过骚操作来跟微信服务器要session_key和openID。

    伪代码如下(小程序端):

    getToken: function () {
        //调用登录接口
        wx.login({
          success: function (res) {
            var code = res.code;
            wx.request({
              url: 商户服务器接口地址, 
              data: {
                code: code
              },
              method: 'POST', 
              success: function (res) { 
                wx.setStorageSync('token', res.data.token); //存在小程序缓存中
              },
              fail: function (res) {
                console.log(res.data);
              }
            })
          }
        })
      }

    调用这几行代码就可以向跟微信服务器要code,并且将code传到商户服务器中,记住这里最好使用post发送请求,安全性的东西我应该不用讲了,因为避免其他人滥用接口,于是我们使用token来进行验证。并将商户服务器返回的token存在小程序缓存中。

    那么服务器端应该怎么做呢?

    我门通过小程序提交的code,和小程序的APPID以及APPSECRET和拼接下列的url,并用curl进行get请求。

    https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code

    返回的数据是一个json对象,我门通过使用json_decode(JSON,true)解析为数组,数据包括用户的openID以及session_key,获取到了后我们应该将openID存入数据库中,它代表着用户的身份,那么令牌应该怎么生成呢。

    二.token的生成以及缓存

    我们根据一个用户表将id和openid联系起来,对应openID的id则是用户的uid,我们可以这么封装

    //要缓存的数据数组
    $cacheValue = $result;   //包含openID和session_key
    $cacheValue['uid'] =$uid;   //用户id
    
    $cacheValue['scope'] =ScopeEnum::User;   //用户权限级别

    缓存的方式我们可以选择redis,memcache, 文件缓存等等,采用键值对(key-value)的方式进行存储,记得设置好过期时间。这里的key我们用token来赋值,token可以通过这样的方式进行生成:

    //获取32位随机字符串
    $str = getRandChar(32);   //自定义方法生成32位随机串
    //三组字符串进行md5加密
    $timeStamp =$_SERVER['REQUEST_TIME_FLOAT'];
    //salt
    $salt = config('secure.token_salt'); //随机字符串
    //返回token
    
    return md5($str.$timeStamp.$salt);

    这种算法基本保障了token的唯一性。因为值是我们获取到的openID和session_key所在的数组,所以需要将数组转成json才能存进去。以后的代码当我们需要openID或者uid等时可以直接通过取缓存的方式来取。

    三,调用统一下单接口,获取prepay_id,再次签名

     在你写完了订单操作后,如何让用户支付订单费用呢?这里就是重点了,我一步一步来说:

    1.下载微信JS-SDK:

    (https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1)

    解压打开进入lib文件夹中:


    我们需要将lib中的文件放到我们的框架中,例如我使用的是tp5,就放到extend下,最好是在extend下建个子文件夹。其中WxPay.Api.php是入口,WxPay.Config.php是配置文件。下好后需要改动一些地方。在WxPay.Config.php中修改下列的东西改成你的。


    然后在WxPay.Api.php中require一下WxPay.Notify.php,如图:

    在某个控制器或者服务层的代码先是用Loader::import()引入WxPay.Api.php,相当于五个都引入了。

    2.调用统一下单api

    这里要啰嗦的是,如何你写的是有关商品买卖的小程序,那么需要在支付前再次检测一下库存量,因为用户下完订单后不一定马上就会付款,如果在付款的期间库存量没了便会出现问题。业务逻辑我就不说太多了,这取决于你写代码的严谨性。

    在我们引入了上面那个文件后,先实例化这个类WxPayUnifiedOrder,把需要的参数通过调用对应的方法传入。

    伪代码如下:

     //调用微信支付统一下单接口
            $wxOrderData = new \WxPayUnifiedOrder();
            //设置相关参数
            $wxOrderData->SetOut_trade_no($this->orderNO);
            $wxOrderData->SetTrade_type('JSAPI');
            $wxOrderData->SetTotal_fee($totalPrice * 100); //这里的价格单位是分
            $wxOrderData->SetBody('Mc');
            $wxOrderData->SetOpenid($openid);
            $wxOrderData->SetNotify_url(config('secure.pay_back_url'));//支付回调

    其中第一个是你的订单号,订单号的生成方法可以自定义,第二个是死参数,第三个是总订单价格,第四个是名称如果是中文的话要转码,第四个是openID,这个这时候就可以从缓存中取了。最后一个是支付回调,就是支付成功后微信要访问的地址。必须是公网能访问的,或者你使用ngrok来进行反向代理转发本地的服务器。

    参数设置好了之后,就直接调用SDK的方法了

     $wxOrder = \WxPayApi::unifiedOrder($wxOrderData);
    如果参数没有错误的话,返回的数据中会含有prepay_id,这个是我们需要的参数。


    3.再次签名
    //  提交JSAPI输入对象
            $jsApiPayData = new \WxPayJsApiPay();
            //设置appid
            $jsApiPayData->SetAppid(config('wx.app_id'));
            //timeStamp
            $jsApiPayData->SetTimeStamp((string)time());
            //随机串
            $randStr = md5(time().mt_rand(0,1000));
            $jsApiPayData->SetNonceStr($randStr);
            //数据报
            $jsApiPayData->SetPackage('prepay_id='.$wxOrder['prepay_id']);
            //类型
            $jsApiPayData->SetSignType('MD5');
            //生成签名
            $sign  = $jsApiPayData->MakeSign();
            //获得签名数组
            $signData = $jsApiPayData->GetValues();
            //增加字段paySign
            $signData['paySign']=$sign;
            //删除signData中的app_Id字段
            unset($signData['appId']);
            return $signData;

    再次签名完成后,就把五个参数返回给小程序。

    四,小程序获取五个参数后,鉴权调起支付

    伪代码(小程序端)

      pay: function () {
        var token = wx.getStorageSync('token');
        var that = this;
      
        wx.request({
          url: baseUrl + '/order',
          header: {
            token: token
          },
          data: {   //产品的数据
            products:
            [
              {
                product_id: 1, count: 1
              },
              
              {
                product_id: 2, count: 1
              }
            ]
          },
          method: 'POST',
          success: function (res) {
            console.log(res.data);
            if (res.data.pass) {
              wx.setStorageSync('order_id', res.data.order_id);
              that.getPreOrder(token, res.data.order_id); //调用getPreOrder
            }
            else {
              console.log('订单未创建成功');
            }
          }
        })
      },
    
      getPreOrder: function (token, orderID) {
        if (token) {
          wx.request({
            url: baseUrl + '/pay/pre_order',
            method: 'POST',
            header: {
              token: token
            },
            data: {
              id: orderID
            },
            success: function (res) {
              var preData = res.data;
              console.log(preData);
              
              wx.requestPayment({    //请求支付
                timeStamp: preData.timeStamp.toString(),
                nonceStr: preData.nonceStr,
                package: preData.package,
                signType: preData.signType,
                paySign: preData.paySign,
                success: function (res) {
                  console.log(res.data);     
                },
                fail: function (error) {
                  console.log(error);
                }
              })
            }
          })
        }
      },

    如果一切正常的话,在微信开发者工具就会显示这个二维码,


    如果在真机上测试的话,就会直接弹出支付页面。小程序会直接显示支付成功或者失败的页面,然后微信服务器就会开始访问我们之前设置的支付回调地址来推送支付结果,根据结果可以来更新订单的状态。这里我就不写业务逻辑了,大概讲一下就好。

    五,支付回调

    实际上我们需要重写WxPayNotify类的NotifyProcess方法,这里记得Loader::impor()引入那个入口类。

    /**
    	 * 
    	 * 回调方法入口,子类可重写该方法
    	 * 注意:
    	 * 1、微信回调超时时间为2s,建议用户使用异步处理流程,确认成功之后立刻回复微信服务器
    	 * 2、微信服务器在调用失败或者接到回包为非确认包的时候,会发起重试,需确保你的回调是可以重入
    	 * @param array $data 回调解释出的参数
    	 * @param string $msg 如果回调处理失败,可以将错误信息输出到该方法
    	 * @return true 回调出来完成不需要继续回调,false回调处理未完成需要继续回调
    	 */
    	public function NotifyProcess($data, &$msg)
    	{
    		//TODO 用户基础该类之后需要重写该方法,成功的时候返回true,失败返回false
    		return true;
    	}

      也就是说你需要写个新类继承WxPayNotify,再重写NotifyProcess方法,根据检查$data['result_code']是否为SUCCESS可以判断成功与否,成功的话你可以根据业务需求写业务逻辑,最后return true 即可。这时候会想,我重写了这个方法后微信怎么调用呢,其实这里微信不是要直接调用这个方法,你应该在微信支付回调的方法中实例化这个新类,然后根据获得的对象去调用Handle()方法。$obj = new 新类(),$obj->Handle()。


    展开全文
  • 初级开发微信小程序支付实战

    千人学习 2018-10-22 21:38:06
    介绍微信小程序支付的接入,统一下单接口,支付接口,注意事项,微信支付回调。
  • 微信小程序调用微信支付接口

    万次阅读 多人点赞 2018-12-05 15:17:12
    前言:应项目要求,需要使用微信小程序支付,写完后告知手续费太高方案不予通过(宝宝心里苦,但宝宝不说)。此次开发在因站在巨人的肩膀上顺利完成。 微信支付文档传送门:...
  • 小程序如何开通微信支付

    万次阅读 2018-05-14 18:24:54
    目前开通微信小程序支付功能有两种方式,一个是你已经有微信商户号的情况下直接绑定一下商户号就可以了,另一个就是需要新申请一个微信支付的商户号。第一种:绑定已有微信支付商户号如果您开通过微信支付商户,绑定...
  • 小程序微信支付 实例配置详解

    万次阅读 热门讨论 2019-07-05 12:24:01
    近期进行小程序的开发,毕竟是商城项目的开发,最后牵扯到的微信支付是必要的个人开发过程中也是遇到各种问题。在此,进行代码的详细配置,以方便小程序新手的快速操作 使用语言:PHP 框架:ThinkPHP 3.2 整理时间...
  • 前面给大家讲过一个借助小程序云开发实现微信支付的,但是那个操作稍微有点繁琐,并且还会经常出现问题,今天就给大家讲一个简单的,并且借助官方支付api实现小程序支付功能。 传送门 借助小程序云开发实现小程序...
  • 微信小程序调用支付接口支付

    万次阅读 多人点赞 2019-03-17 13:07:45
    我前段时间做微信支付,遇到了很多坑,网上也没有讲解的特别明白的,通过借鉴各路人才的经验,最后也完成了,网上有很多讲解,我在这只讲一些注意点和解决的方法。我就讲讲我从完全懵到完成的过程吧。 在微信提供的...
  • 小程序微信支付功能开发

    千次阅读 2019-03-19 08:44:38
    关于小程序内唤起微信支付功能,不同人有不同的思路,有嵌套H5页面的,也有跳转第三方链接网站的,也有放收钱码等图片的。 今天讲一下微信原生的微信支付功能基础版块,支付页面和支付逻辑。 先上个效果图: 页面...
  • 这里我直接上代码,附有注释,直接把我的代码粘贴一下就可以用了,也是自己走了好多的弯路。。,写在博客里做个记录 直接把里面的参数替换成你的就可以了,...//小程序端代码: pay:function(){ var that=this...
  • 微信小程序 支付Demo

    2020-07-26 23:33:55
    该代码资源包,用于进行配置微信小程序支付功能,包括前后端核心代码。需要根据文章:https://blog.csdn.net/u011415782/article/details/80944832 进行参考配置。欢迎指摘,谢谢...
  • 微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付微信刷卡支付,异步处理支付结果等等...
  • 微信小程序 调用支付jsapi时缺少参数:total_fee
  • 微信小程序如何接入微信支付

    万次阅读 2018-02-28 16:18:54
    本文阐述如何从零开始接入小程序支付,尤其适合没有微信支付接入经验的开发者。1. 申请微信支付小程序认证以后,可以在小程序后台,微信支付菜单栏,申请微信支付。填写企业信息和对公账户,微信支付会打一笔随机...
  • 如果微信用户没有实名认证,微信零钱支付单笔限额1000元,每日限额1000元,每月限额2000元; 如果已经完成了实名认证,每日限额10000元。每年累计限额是20W。 手机银行限额 ...
  • 一个大客户的
  • 微信小程序支付报 签名错误

    万次阅读 2018-05-31 20:50:27
    今天在开发小程序支付时,将之前的公众号appId改为了小程序的appId,将appKey改为了小程序的appSecret。再次进行支付时,报出了签名错误的问题!问题原因:微信支付时,需要几个参数:appId,appKey,mchId这三个...
  • tp5实现微信小程序支付

    千次阅读 2018-02-27 17:05:07
    思路:后台调用第三方接口,获取小程序端所需要的五个参数;1.小程序wxml:传递订单号、订单id、订单金额、openid到js中;2.调用后台PHP接口,获取发起支付所需要的参数:3.tp5开发后台接口类:主要方法有:传递第一...
1 2 3 4 5 ... 20
收藏数 36,770
精华内容 14,708
关键字:

微信小程序支付