微信支付开发流程_清晰_易懂_有源码

2024-05-28 01:32

本文主要是介绍微信支付开发流程_清晰_易懂_有源码,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转自 https://blog.csdn.net/weixin_41497737/article/details/80547243

     最近因为公司需求开始开始做微信支付的开发,在网上参考来了很多文章,大多都说微信支付的开发文档真坑怎样怎样,做完之后感觉没那么坑,都是自己看的不仔细才回导致出了问题。这里我以JSAPI公众号支付为例。测试环境使用花生壳的内网穿透来搭建的,还开始担心壳域名没有备案,后来发现也是可以的,用花生壳的可以放心使用..

    主要分一下几个大步骤:

    一。下载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位的!后来尝试用支付成功后返回的微信系统订单来查询订单,发现还是不行的.

这篇关于微信支付开发流程_清晰_易懂_有源码的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1009165

相关文章

问题:第一次世界大战的起止时间是 #其他#学习方法#微信

问题:第一次世界大战的起止时间是 A.1913 ~1918 年 B.1913 ~1918 年 C.1914 ~1918 年 D.1914 ~1919 年 参考答案如图所示

[职场] 护理专业简历怎么写 #经验分享#微信

护理专业简历怎么写   很多想成为一名护理方面的从业者,但是又不知道应该怎么制作一份简历,现在这里分享了一份护理方面的简历模板供大家参考。   蓝山山   年龄:24   号码:12345678910   地址:上海市 邮箱:jianli@jianli.com   教育背景   时间:2011-09到2015-06   学校:蓝山大学   专业:护理学   学历:本科

大学湖北中医药大学法医学试题及答案,分享几个实用搜题和学习工具 #微信#学习方法#职场发展

今天分享拥有拍照搜题、文字搜题、语音搜题、多重搜题等搜题模式,可以快速查找问题解析,加深对题目答案的理解。 1.快练题 这是一个网站 找题的网站海量题库,在线搜题,快速刷题~为您提供百万优质题库,直接搜索题库名称,支持多种刷题模式:顺序练习、语音听题、本地搜题、顺序阅读、模拟考试、组卷考试、赶快下载吧! 2.彩虹搜题 这是个老公众号了 支持手写输入,截图搜题,详细步骤,解题必备

uniapp接入微信小程序原生代码配置方案(优化版)

uniapp项目需要把微信小程序原生语法的功能代码嵌套过来,无需把原生代码转换为uniapp,可以配置拷贝的方式集成过来 1、拷贝代码包到src目录 2、vue.config.js中配置原生代码包直接拷贝到编译目录中 3、pages.json中配置分包目录,原生入口组件的路径 4、manifest.json中配置分包,使用原生组件 5、需要把原生代码包里的页面修改成组件的方

笔记本电脑屏幕模糊?6招恢复屏幕清晰!

在数字化时代的浪潮中,笔记本电脑已成为我们生活、学习和工作中不可或缺的一部分。然而,当那曾经清晰明亮的屏幕逐渐变得模糊不清时,无疑给我们的使用体验蒙上了一层阴影。屏幕模糊不仅影响视觉舒适度,更可能对我们的工作效率和眼睛健康构成威胁。 遇到笔记本电脑屏幕模糊的情况时我们应该如何解决?本文将与大家分享6个简单易懂的解决方法。 方法一:调整Windows分辨率 电脑屏幕模糊显示不清晰怎

工作流Activiti初体验—流程撤回【二】

已经玩工作流了,打算还是研究一下撤回的功能。但是流程图里面并不带撤回的组件,所以需要自己动态改造一下,还是延续上一个流程继续试验撤回功能。《工作流Activiti初体验【一】》 完整流程图 我们研究一下分发任务撤回到发起任务,其他环节的撤回类似 撤回的原理大概如下: 将分发任务后面的方向清空,把发起任务拼接到原来的判断网关,然后结束分发任务,这样流程就到发起任务了 此时的流程如上图,

ROS话题通信流程自定义数据格式

ROS话题通信流程自定义数据格式 需求流程实现步骤定义msg文件编辑配置文件编译 在 ROS 通信协议中,数据载体是一个较为重要组成部分,ROS 中通过 std_msgs 封装了一些原生的数据类型,比如:String、Int32、Int64、Char、Bool、Empty… 但是,这些数据一般只包含一个 data 字段,结构的单一意味着功能上的局限性,当传输一些复杂的数据,比如:

Eclipse+ADT与Android Studio开发的区别

下文的EA指Eclipse+ADT,AS就是指Android Studio。 就编写界面布局来说AS可以边开发边预览(所见即所得,以及多个屏幕预览),这个优势比较大。AS运行时占的内存比EA的要小。AS创建项目时要创建gradle项目框架,so,创建项目时AS比较慢。android studio基于gradle构建项目,你无法同时集中管理和维护多个项目的源码,而eclipse ADT可以同时打开

springboot家政服务管理平台 LW +PPT+源码+讲解

3系统的可行性研究及需求分析 3.1可行性研究 3.1.1技术可行性分析 经过大学四年的学习,已经掌握了JAVA、Mysql数据库等方面的编程技巧和方法,对于这些技术该有的软硬件配置也是齐全的,能够满足开发的需要。 本家政服务管理平台采用的是Mysql作为数据库,可以绝对地保证用户数据的安全;可以与Mysql数据库进行无缝连接。 所以,家政服务管理平台在技术上是可以实施的。 3.1

Python应用开发——30天学习Streamlit Python包进行APP的构建(9)

st.area_chart 显示区域图。 这是围绕 st.altair_chart 的语法糖。主要区别在于该命令使用数据自身的列和指数来计算图表的 Altair 规格。因此,在许多 "只需绘制此图 "的情况下,该命令更易于使用,但可定制性较差。 如果 st.area_chart 无法正确猜测数据规格,请尝试使用 st.altair_chart 指定所需的图表。 Function signa