zoukankan      html  css  js  c++  java
  • 微信Native支付

    微信Native支付对接(扫码)

    由于有业务需求对接了微信和paypal支付,这边做个记录

    微信支付开发文档:https://pay.weixin.qq.com/wiki/doc/api/index.html

    一、支付方式

    这边有个坑,微信h5支付和Native支付都是微信外部使用的支付方式,但是h5支付适用于移动端,因为支付时是从外部唤醒本地移动端的微信app进行支付;而Native支付则是在pc端生成订单后,用户使用移动端的微信app扫码完成支付

    1. 付款码支付:需要用户有扫码枪.如:肯德基,麦当劳的支付
    2. JSAPI支付: 主要服务于微信内部调用的支付接口
    3. Native支付:扫码支付
    4. h5支付:手机浏览器调用的支付

    二、支付流程介绍

    用户:客户

    前端:ui界面,客户端

    后端:java写的服务端

    微信系统:包括生产订单的接口等
    流程:

    1. 用户点击前端的支付按钮
    2. 前端将对应的订单信息发送给后端
    3. 后端预处理订单的信息(如在数据库中生成对应的记录),然后调用微信支付系统生成订单的接口
    4. 微信支付系统返回对应订单的支付地址给后端
    5. 后端将该订单地址返还给前端,前端调用QRCode工具生成二维码
    6. 用户打开手机微信app扫码完成支付(由于和我们业务并没有直接的相关性,这个过程没有直接在上图中表现出来)
    7. 微信系统异步(有延时)收到微信支付成功的回调,回调函数中应该包括对于验证订单的有效性(如果被人攻破就麻烦了),存储数据库(确认订单已结算),回复微信系统(否则微信会在一天之内多次发送回调信息)等步骤
    8. 后端可以通知前端订单完成,以便后续的操作(具体的做法可以是从订单生成之后,前端可以以一定的时间间隔询问订单的状态)

    注:其它支付手段的流程应该也是大致相同的

    三、准备工作

    首先必然是下载sdk(software development kit).值的注意的一点是,对比于网上的许多旧的微信博客,可以发现微信的api有了极大的改进,我们只要调用少许的接口即可完成开发.同时api的命名目前也是比较统一的

    1. 申请一个商机号

      注:商家号的申请是需要相关的营业执照的

    2. 上微信商户号中开通Native支付的服务

    3. 准备调用订单支付接口相关的参数(这里只展示一下必填项)

      字段名 变量名 描述
      公众账号ID appid 微信支付分配的公众账号ID
      商户号 mch_id 微信支付分配的商户号
      随机字符串 nonce_str 由内置的随机数生成算法生成
      签名 sign 由内置的签名算法生成
      商品描述 body 商品的简单描述
      商品订单号 out_trade_no 可以直接用订单id
      标价金额 total_fee 单位为分(CNY)
      终端IP spbill_creat 服务器IP
      通知地址 notify_url 异步回调的地址(回调不能在本地测试)
      交易类型 trade_type NATIVE -Native支付
      商品ID product_id 商品id,Native必填
      密匙 key 商家自行设置的密匙
      • 微信商户号后台获得appid,mch_id,设置key
      • out_trade_no必须大于10,不能重复
      • total_fee不能有小数点(正常情况也不应该有小数点)
      • nonce_str变量用于提高生成的sign不确定
      • sign的算法是先将所有的参数进行排序,然后按key=value的形式拼接为字符串,最后加上key.最后,对拼接后字符串进行加密,加密方式一种是用MD5,一种使用HMAC-SHA256.具体的过程可以查看sdk原码,实际使用只要传入参数map给相关的api即可,但是了解一下有助于调试,另外附加一个微信官方的签名校验工具
      • key是保证整个支付过程加密以及回调地址不被攻破的关键!
      • 可以用额外的attach附加参数,如订单id
    4. sdk下载地址(maven的相关地址大家可以自己去找找):https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=11_1

    四、开发工作

    这里主要说明一下后端接口的调用

    1. 调用接口生成订单

          public String getWxQrCode(HashMap<String,Object> paraMap) throws Exception {
              /*数据库操作*/
              Integer maxId = userMapper.getMaxUserId();
              Integer id = maxId==null?1:maxId+1;
              paraMap.put("user_id",id);
              userMapper.addUser(paraMap);
              /*获得code_url*/
              Map<String, String> map = new HashMap<>();
              map.put("appid",wxPayConfigBean.getAppID());
              map.put("mch_id",wxPayConfigBean.getMchID());
              map.put("body",wxPayConfigBean.getBody());
              map.put("out_trade_no",id.toString());
              map.put("total_fee",paraMap.get("order_amount").toString());
              map.put("spbill_create_ip",paraMap.get("ip").toString());
              map.put("notify_url",wxPayConfigBean.getNotifyUrl());
              map.put("trade_type",wxPayConfigBean.getTradeType());
              map.put("attach",id.toString());
              //Native必传
              map.put("product_id",paraMap.get("order_productid").toString());
              //获得sign
              WXPay wxPay = new WXPay(wxPayConfigBean);
              Map<String, String> backMap = wxPay.unifiedOrder(map);
              HashMap<String, Object> resMap = new HashMap<>();
              resMap.put("url",backMap.get("code_url"));
              resMap.put("id",id);
              return JsonUtil.toJsonString(resMap);
          }
      
    2. 回调

          public void wxNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
      
              //拿到微信回调信息(以字节流的方式)
              InputStream inputStream = request.getInputStream();
              BufferedReader in = new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));
              //String是字符串变量,StringBuffer是字符串变量
              StringBuffer sb = new StringBuffer();
              //将字节流转换为字符串
              String line;
              while ((line = in.readLine()) != null){
                  //每次用line读取一行的字节流,如果这一行不为空就扩展到sb上
                  sb.append(line);
              }
              System.out.println("*****************************sb**************************");
              System.out.println(sb);
              System.out.println("*****************************sb**************************");
              //关闭
              in.close();
              inputStream.close();
              String strXml = sb.toString();
              Map<String, String> toMap = WXPayUtil.xmlToMap(strXml);
              System.out.println(toMap);
      
              //获取业务信息
              String outTradeNo = toMap.get("out_trade_no");
              String totalFee = toMap.get("total_fee");
              String appId = toMap.get("appId");
              String mchId = toMap.get("mch_id");
              String resultCode = toMap.get("result_code");
              String attach = toMap.get("attach");  //附加数据
      
              //该对象用于通知微信
              PrintWriter writer = response.getWriter();
      
              //验签
              String res = null;
              Map<String,String> paraMap = WXPayUtil.xmlToMap(strXml);
              boolean signatureValid = WXPayUtil.isSignatureValid(paraMap, wxPayConfigBean.getKey(), WXPayConstants.SignType.HMACSHA256);  //注:注意返回时有nonce_str
              if (signatureValid){
                  System.out.println("验证成功~");
                  if ("SUCCESS".equals(toMap.get("result_code"))){
                      System.out.println("返回的是SUCCESS");
                      /*自己的业务逻辑*/
                      }
                      //返回值——仍然有问题,不断刷回复
                      String noticeStr = setXML("SUCCESS","");
                      writer.write(noticeStr);
                      writer.flush();  //情况缓存区,并完成文件写入操作
                  }
              }else{
                  System.out.println("验证失败");
                  String noticeStr = setXML("FATL","");
                  writer.write(noticeStr);
                  writer.flush();
              };
          }
        private static String setXML(String return_code, String return_msg) {
              return "<xml><return_code><![CDATA[" + return_code + "]]></return_code><return_msg><![CDATA[" + return_msg + "]]></return_msg></xml>";
          }
      

    注:

    • 有时候回调好像没有正确地返还个微信支付系统,对java的输入输出不太了解,麻烦有大佬知道问题的请留言
    • 在最开始尝试对接微信支付时查阅了较多的博客,代码,在这里表示感谢.但因为实在太过庞杂,就不一一列出了.
  • 相关阅读:
    洛谷模板汇总
    BZOJ1787【AHOI2008】Meet紧急集合 <LCA>
    HDU3068 最长回文 <Manacher>
    UVa12345 Dynamic len(set(a[L:R])) <带修莫队>
    BZOJ2038 小Z的袜子 <莫队>
    BZOJ1103【POI2007】大都市meg <树上差分+树状数组>
    BZOJ3226【SDOI2008】校门外的区间
    BZOJ1012【JSOI2008】最大数 <线段树>
    20170918~24周总结
    BZOJ1934【SHOI2007】善意的投票 <网络流>
  • 原文地址:https://www.cnblogs.com/Arno-vc/p/13735914.html
Copyright © 2011-2022 走看看