springboot实现微信支付V2,V3版本详解

目录

  • 开发环境
  • 商户开通JSAPI支付
  • JSAPI接口
    • 微信支付的统一流程
    • V2接口实现支付
    • 接口实现
    • V3接口实现支付
    • 接口实现

开发环境

java1.8
springboot 2.7.5

本文是以JSAPI支付为例子,其他支付完全可以以此参考
JSAPI支付适用于线下场所、公众号场景和PC网站场景。
商户已有H5商城网站,用户通过消息或扫描二维码在微信内打开网页时,可以调用微信支付完成下单购买的流程。

1、登陆已认证企业服务号,开通微信支付
springboot实现微信支付V2,V3版本详解_第1张图片springboot实现微信支付V2,V3版本详解_第2张图片

注册微信商户号请参考官方文档,参考地址如下:
https://pay.weixin.qq.com/index.php/apply/applyment_home/guide_normal#none

商户开通JSAPI支付

商户到公众平台开通JSAPI支付
springboot实现微信支付V2,V3版本详解_第3张图片
同时配置JSAPI回调域,授权目录为公网IP,本地测试要使用内网穿透
springboot实现微信支付V2,V3版本详解_第4张图片

JSAPI接口

JSAPI支付时必要传入openid

前提配置
springboot实现微信支付V2,V3版本详解_第5张图片
springboot实现微信支付V2,V3版本详解_第6张图片

openid获取是在微信登录授权时获取的,他和access_token一同获取到,分为两步。
相关文档参考:
https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html#0

  • 第一步:根据appid获取code()访问地址为:https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

  • 注意在公众号中配置回调接受code的地址:redirect_uri

  • 注意scope的类型

  • 第二步:根据code,appid,appsecret获取openid,访问地址为:https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

正确访问后返回结果
springboot实现微信支付V2,V3版本详解_第7张图片

微信支付的统一流程

1,后端向微信第三方发送预支付(其中包括支付详细信息),
2,将预支付的返回结果返回给前端,前端拉起支付界面
3,支付状态进入后端回调接口中,后端记录数据持久到数据库

V2接口实现支付

导入maven

 
 <dependency>
     <groupId>com.github.tedzhdzgroupId>
     <artifactId>wxpay-sdkartifactId>
     <version>3.0.10version>
 dependency>
 <dependency>
     <groupId>com.github.binarywanggroupId>
     <artifactId>weixin-java-payartifactId>
     <version>3.4.0version>
 dependency>

接口参考文档:
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
使用微信统一下单接口

  • 红色的是自己填写的
  • 蓝色是SDK生成的

springboot实现微信支付V2,V3版本详解_第8张图片

接口实现

@Controller
public class WxPayController {

    String appID = "xxxxxxx"; //公众号id
    String mchID = "xxxxxxx"; //商户号
    String appSecret = "xxxxxxx";//公众号idSecret
    String key = "xxxxxxx"; //商户key,用于sign验证
    //申请授权码地址
    String notify_url = "xxxxxxx/jsapiPayback";
    //授权回调地址
    String state="";

    //统一下单,接收openid
    @GetMapping("/wxjspay")
    public ModelAndView wxjspay(HttpServletRequest request,HttpServletResponse response) throws Exception {
        //创建sdk客户端
        WXPay wxPay = new WXPay(new WXPayConfigCustom());
        //构造请求的参数
        Map<String,String> requestParam = new HashMap<>();
        requestParam.put("out_trade_no","10029293889");//订单号
        requestParam.put("body", "iphone8");//订单描述
        requestParam.put("fee_type", "CNY");//人民币
        requestParam.put("total_fee", String.valueOf(1)); //金额
        requestParam.put("spbill_create_ip", "");//客户端ip
        requestParam.put("notify_url", "xxxxx/payback");//微信异步通知支付结果接口,
        requestParam.put("trade_type", "JSAPI");
        //从之前的步骤中拿到openid
        String openid = ;
        requestParam.put("openid",openid);
        //调用统一下单接口
        Map<String, String> resp = wxPay.unifiedOrder(requestParam);

        //准备h5网页需要的数据
        Map<String,String> jsapiPayParam = new HashMap<>();
        jsapiPayParam.put("appId",appID);
        jsapiPayParam.put("timeStamp",System.currentTimeMillis()/1000+"");
        jsapiPayParam.put("nonceStr", UUID.randomUUID().toString());//随机字符串
        jsapiPayParam.put("package","prepay_id="+resp.get("prepay_id"));
        jsapiPayParam.put("signType","HMAC-SHA256");
        jsapiPayParam.put("paySign", WXPayUtil.generateSignature(jsapiPayParam,key,WXPayConstants.SignType.HMACSHA256));
        //将h5网页响应给前端
        return new ModelAndView("wxpay",jsapiPayParam);
    }
        // 支付功能
    @GetMapping("xxxxxxx/jsapiPayback")
    public void h5payBack(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 读取回调数据
        InputStream inputStream = request.getInputStream();
        StringBuffer sb = new StringBuffer();
        String s;
        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
        while ((s = in.readLine()) != null) {
            sb.append(s);
        }
        in.close();
        inputStream.close();

        // 解析xml成map
        Map<String, Object> m = XmlUtil.xmlToMap(sb.toString());
        // 过滤空 设置 TreeMap
        SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
        Iterator<String> it = m.keySet().iterator();
        while (it.hasNext()) {
            String parameter = it.next();
            Object parameterValue = m.get(parameter);
            String v = "";
            if (null != parameterValue) {
                v = parameterValue.toString().trim();
            }
            packageParams.put(parameter, v);
        }
        System.out.println("packageParams=" + packageParams);

        // 微信支付的API密钥
        String key = environment.getProperty("wechat.pay.apiKey");
        // 判断签名是否正确
        if (WechatUtils.isTenpaySign(packageParams, key)) {
            String resXml = "";
            if ("SUCCESS".equals((String) packageParams.get("result_code"))) {
                log.info("已支付, packageParams:{}", packageParams.toString());
                //开始自己的逻辑

                }

                // 通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
                resXml = "" + ""
                        + "" + " ";

            } else {
                log.info("支付失败,错误信息:" + packageParams.get("err_code"));
                log.info("支付失败");
                resXml = "" + ""
                        + "" + " ";
            }
            response.getWriter().write(resXml);
        } else {
            log.info("通知签名验证失败");
        }
    }

V3接口实现支付

前置条件

  • Java 1.8+。
  • 成为微信支付商户。
  • 商户 API 证书:指由商户申请的,包含商户的商户号、公司名称、公钥信息的证书。
  • 商户 API 私钥:商户申请商户API证书时,会生成商户私钥,并保存在本地证书文件夹的文件 apiclient_key.pem 中。
  • APIv3密钥:为了保证安全性,微信支付在回调通知和平台证书下载接口中,对关键信息进行了 AES-256-GCM 加密。APIv3密钥是加密时使用的对称密钥。

导入maven,这个maven是官方推荐maven,里面很多需要填写的已经封装好,非常推荐

 
<dependency>
  <groupId>com.github.wechatpay-apiv3groupId>
  <artifactId>wechatpay-javaartifactId>
  <version>0.2.7version>
dependency>

v3接口文档参考
https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml

接口实现

   @GetMapping("/wxjspay")
    public ModelAndView wxjspay(HttpServletRequest request,HttpServletResponse response) throws Exception {
    /** 商户号 */
    public static String merchantId = "";
    /** 商户API私钥路径 */
    public static String privateKeyPath = "";
    /** 商户证书序列号 */
    public static String merchantSerialNumber = "";
    /** 商户APIV3密钥 */
    public static String apiV3key = "";
	    RSAConfig config =
	        new RSAConfig.Builder()
	            .merchantId(merchantId)
	            // 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
	            .privateKeyFromPath(privateKeyPath)
	            .merchantSerialNumber(merchantSerialNumber)
	            .wechatPayCertificatesFromPath(wechatPayCertificatePath)
	            .build();
	    // 初始化服务
	    service =
	        new JsapiServiceExtension.Builder()
	            .config(config)
	            .signType("RSA") // 不填默认为RSA
	            .build();
	    try {
	      // ... 调用接口
	      PrepayWithRequestPaymentResponse response = prepayWithRequestPayment();
	      System.out.println(response);
	      Map<String,String> jsapiPayParam = new HashMap<>();
          jsapiPayParam.put("appId",appID);
          jsapiPayParam.put("timeStamp",System.currentTimeMillis()/1000+"");
          jsapiPayParam.put("nonceStr", UUID.randomUUID().toString());//随机字符串
          jsapiPayParam.put("package","prepay_id="+resp.get("prepay_id"));
          jsapiPayParam.put("signType","HMAC-SHA256");
          jsapiPayParam.put("paySign", WXPayUtil.generateSignature(jsapiPayParam,key,WXPayConstants.SignType.HMACSHA256));
        //将h5网页响应给前端
        return new ModelAndView("wxpay",jsapiPayParam);
	
	    } catch (HttpException e) { // 发送HTTP请求失败
	      // 调用e.getHttpRequest()获取请求打印日志或上报监控,更多方法见HttpException定义
	    } catch (ServiceException e) { // 服务返回状态小于200或大于等于300,例如500
	      // 调用e.getResponseBody()获取返回体打印日志或上报监控,更多方法见ServiceException定义
	    } catch (MalformedMessageException e) { // 服务返回成功,返回体类型不合法,或者解析返回体失败
	      // 调用e.getMessage()获取信息打印日志或上报监控,更多方法见MalformedMessageException定义
	    }
	  }
	  /** 关闭订单 */
	  public static void closeOrder() {
	
	    CloseOrderRequest request = new CloseOrderRequest();
	    // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
	    // 调用接口
	    service.closeOrder(request);
	  }
	  /** JSAPI支付下单,并返回JSAPI调起支付数据 */
	  public static PrepayWithRequestPaymentResponse prepayWithRequestPayment() {
	    PrepayRequest request = new PrepayRequest();
	    // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
	    // 调用接口
	    return service.prepayWithRequestPayment(request);
	  }
	  /** 微信支付订单号查询订单 */
	  public static Transaction queryOrderById() {
	
	    QueryOrderByIdRequest request = new QueryOrderByIdRequest();
	    // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
	    // 调用接口
	    return service.queryOrderById(request);
	  }
	  /** 商户订单号查询订单 */
	  public static Transaction queryOrderByOutTradeNo() {
	
	    QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
	    // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
	    // 调用接口
	    return service.queryOrderByOutTradeNo(request);
	  }
  }

回调处理见v2后面的**“xxxxxxx/jsapiPayback”**接口,v3与其一致
此文章包含部分参考

原文链接:https://blog.csdn.net/weixin_45865428/article/details/117807648

你可能感兴趣的:(微信,spring,boot,后端)