微信小程序支付流程(Java后端)

微信小程序支付(Java后端)

一、小程序支付的交互图如下

wxa-7-2

按住ctrl点击 微信支付平台开发文档

二、准备工作

  • 第一步:在pom文件中导入微信支付SDK

    • 有可能自动下载不了,可以到微信支付平台下载手动导入maven仓库
    • SDK下载地址:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=11_1
  • 第二步:创造一个配置类,填入必要信息,如图

    • 微信参数配置类
    • 支付成功后的回调url必须是公网可以访问的
  • 第三步:创建包结构com.github.wxpay.sdk,然后创建一个类继承WXPayConfig

    • 实现抽象类中的方法,将配置类中的小程序ID、商户号、商户秘钥一一填入,getWXPayDomain()为固定写法
    • 如图:20-07-01_21-11-28
  • 第四步:在启动类中注入上一步的配置类和RestTemplate,RestTemplate是用来发送请求的

    • 20-07-01_21-15-16
  • 第五步:添加转换工具类,作用:将输入流转换为xml字符串

    • /**
       * 转换工具类
       */
      public class ConvertUtils {
          /**
           * 输入流转换为xml字符串
           * @param inputStream
           * @return
           */
          public static String convertToString(InputStream inputStream) throws IOException {
              ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
              byte[] buffer = new byte[1024];
              int len = 0;
              while ((len = inputStream.read(buffer)) != -1) {
                  outSteam.write(buffer, 0, len);
              }
              outSteam.close();
              inputStream.close();
              String result  = new String(outSteam.toByteArray(), "utf-8");
              return result;
          }
      }
      

三、实现小程序支付步骤

  • 第一步:获取openid

    • 登录流程图api-login.2fcc9f35
    • 在微信小程序登录时,调用登录API获取登录凭证(code),通过code获取用户登录信息,包含用户的唯一标识(openid)和本次登录的会话秘钥(session key),将openid存入缓存
    • 小程序端:
    //在登录方法内
    wx.login({
      success (res) {
        if (res.code) {
          //拿到登录凭证code
          //将code作为参数调用后台接口
          wx.request({
            //此处url是后台获取openid的接口
            url: 'https://localhost:9091/wx/login/' + res.code,//
            success: function(res) {
                if(res.data.openid){
                    //如果响应结果包含openid,将其存入缓存
                    wx.setStorage({
                      key:"openid",
                      data: res.data.openid
                    })
    				//提示框
                    wx.showToast({
                        title: '登录成功',
                        icon: 'success',
                        duration: 2000
                    });
                }					
    		}
          })
        } else {
          console.log('登录失败!' + res.errMsg)
        }
      }
    })
    
    • 后台:
    //在controller层
    @RequestMapping("/wx")
    @RestController
    public class WXPayController {
        @Autowired
        private RestTemplate restTemplate;
    
        @PostMapping("/login/{code}")
        public String wxLogin(@PathVariable("code") String code) {
            //接收到登录凭证,拼接url
            String url = MyWxPayConfig.get_openid_url  //获取openid接口
                    + "?appid=" + MyWxPayConfig.appid   //小程序ID
                    + "&secret=" + MyWxPayConfig.appSecret   //小程序秘钥
                    + "&js_code=" + code
                    + "&grant_type=authorization_code";
    
            //发送请求,将响应数据返回给前端
            String jsonData = this.restTemplate.getForObject(url, String.class);
            return jsonData;
        }
    }    
    
  • 第二步:生成商户订单

    • 在点击支付后,调用后台的新增订单接口,返回订单的编号(代码略…)
  • 第三步:

    • 生成商户订单,获取订单编号后,将订单编号和金额作为参数,传入小程序端的支付方法wxPay(),wxPay是自定义的方法

    • 小程序端:

    //参数:订单编号,付款金额
    wxPay(orderNo,totalMoney) {
      	console.log("统一下单接口开始执行")
        	//从缓存中取出openid
        	wx.getStorage({
      		key: 'openid',
      		success (res) {
                  wx.request({
                      //此处url是后台统一下单的接口
                      url: 'https://localhost:9091/wx/pay',
                      data: {
                          openid: res.data,
                          orderNO: orderNo,
                          totalMoney: tatalmoney
                      },
                      header: {
                          'content-type': 'application/x-www-form-urlencoded'
                      },
                      success: function(res) {
                          //根据响应数据判断是否执行成功
                          if(res.data.status_code == '00000'){
                              //发起微信支付
                              wx.requestPayment({
                                  provider: 'wxpay',
                                  timeStamp: res.data.object.timeStamp,
    	                            nonceStr: res.data.object.nonceStr,
                                  package: res.data.object.package,
    	                            signType: res.data.object.signType,
                                  paySign: res.data.object.paySign,
                                  success: function (res) {
                                      //执行成功,打印
                                      console.log('success:' + JSON.stringify(res));
                                  },
                                  fail: function (err) {
                                      //执行失败,打印
                                      console.log('fail:' + JSON.stringify(err));
                                  }
                              })
                          }else{
                              //失败,提示框
                              wx.showToast({
                                  title: res.data.msg,
                                  icon: 'none',
                              });
                          }				
                      }
                  })
              }	
      	})
       
      			
      			
      		}
    
    • 后台:

    • //controller层
      //后台统一下单接口
      @GetMapping("/pay")
      @ResponseBody
      public Result pay(HttpServletRequest request,@RequestParam String openid, @RequestParam String orderNo, @RequestParam Double totalMoney) throws Exception {
          // 获取真实请求ip地址,避免获取代理ip
          String ip = request.getHeader("x-forwarded-for");
          if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
              ip = request.getHeader("Proxy-Client-IP");
          }
          if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
              ip = request.getHeader("WL-Proxy-Client-IP");
          }
          if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
              ip = request.getRemoteAddr();
          }
          if (ip.indexOf(",") != -1) {
              String[] ips = ip.split(",");
              ip = ips[0].trim();
          }
          return wxPayService.wxPay(openid, orderNo, totalMoney, ip);
      }
      
    • //service层
      @Override
      public Result wxPay(String openid, String orderNo, Double totalMoney, String ip) {
          try {
              // 1. 拼接统⼀下单地址参数
              Map<String, String> paraMap = new HashMap<String, String>();
              paraMap.put("openid",openid);//用户标识
              paraMap.put("body", "*****"); // 商品描述
              paraMap.put("out_trade_no", orderNo);// 订单号
              //金额转换
              BigDecimal payMoney = new BigDecimal("0.01");//正式使用时传入totalMoney
              BigDecimal fen = payMoney.multiply(new BigDecimal("100")); //1.00
              fen = fen.setScale(0, BigDecimal.ROUND_UP); 
              paraMap.put("total_fee", fen); // ⽀付⾦额,单位分,即0.01元
              paraMap.put("spbill_create_ip", ip);//终端ip
              paraMap.put("notify_url","http://zq32586844.qicp.vip/wx/notify");//支付结果通知地址
              paraMap.put("trade_type", "JSAPI"); // 交易类型
      
              //2.发送post请求"统⼀下单接⼝", 返回预⽀付id:prepay_id
              Map<String, String> map = wxPay.unifiedOrder(paraMap);
              String prepayId = (String) map.get("prepay_id");
      
              //3.将数据组合,再次签名
              Map<String, String> payMap = new HashMap<String, String>();
              payMap.put("appId", MyWxPayConfig.appid);
              payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp() + "");
              payMap.put("nonceStr", WXPayUtil.generateNonceStr());
              payMap.put("signType", WXPayConstants.HMACSHA256);
              payMap.put("package", "prepay_id=" + prepayId);
              //通过appId, timeStamp, nonceStr, signType, package及商户密钥进⾏key=value形式拼接并加密
              String paySign = WXPayUtil.generateSignature(payMap, MyWxPayConfig.key,WXPayConstants.SignType.HMACSHA256);
              payMap.put("paySign", paySign);
      
              //4.将参数传给前端
              return ResultGenerator.genSuccessResult("调用统一下单接口,成功!", payMap);
          } catch (Exception e) {
              e.printStackTrace();
              return ResultGenerator.genFailResult("调用统一下单接口,失败!");
          }
      }
      
    • 这样就可以正常支付了

  • 第四步:接收微信推送的支付结果通知

    • 请求路径为,在配置类中留的支付成功回调url

    • @RequestMapping("/notify")
      public void notifyLogic(HttpServletRequest request, HttpServletResponse response) {
          try {
              //1.输入流转换为字符串
              String xml = ConvertUtils.convertToString(request.getInputStream());
              
              //2.基于微信发送的通知内容,完成后续的业务逻辑处理
              //使用微信支付sdk中的工具类,将xml转换成map
              Map<String, String> map = WXPayUtil.xmlToMap(xml);
              if ("SUCCESS".equals(map.get("result_code"))) {
                  //支付成功回调
                  //给微信一个结果通知
                  response.setContentType("text/xml");
                  String data="<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
                  response.getWriter().write(data);
                  
                  //执行支付成功后的业务逻辑
                  //例如:修改订单的支付状态为已支付
              }
          } catch (Exception e) {
              e.printStackTrace();
          }
      }
      
  • 5
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值