微信JSAPI支付,微信浏览器内支付,解决微信H5支付只能在微信外浏览器支付的问题

一、设置支付目录

请确保实际支付时的请求目录与后台配置的目录一致(现在已经支持配置根目录,配置后有一定的生效时间,一般5分钟内生效),否则将无法成功唤起微信支付。

在微信商户平台(pay.weixin.qq.com)设置您的JSAPI支付支付目录,设置路径:商户平台–>产品中心–>开发配置,如图7.7所示。JSAPI支付在请求支付的时候会校验请求来源是否有在商户平台做了配置,所以必须确保支付目录已经正确的被配置,否则将验证失败,请求支付不成功。

微信JSAPI支付,微信浏览器内支付,解决微信H5支付只能在微信外浏览器支付的问题_第1张图片

二、设置授权域名

开发JSAPI支付时,在统一下单接口中要求必传用户openid,而获取openid则需要您在公众平台设置获取openid的域名,只有被设置过的域名才是一个有效的获取openid的域名,否则将获取失败。具体界面如图7.8所示:
微信JSAPI支付,微信浏览器内支付,解决微信H5支付只能在微信外浏览器支付的问题_第2张图片
微信JSAPI支付,微信浏览器内支付,解决微信H5支付只能在微信外浏览器支付的问题_第3张图片

三.将支付页面的连接编码后替换连接中的redirect-url参数,获取code

参考链接(请在微信客户端中打开此链接体验)
Scope为snsapi_base ,此连接为静默获取用户授权

https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx520c15f417810387&redirect_uri=http%3A%2F%2Fchong.qq.com%2Fphp%2Findex.php%3Fd%3D%26c%3DwxAdapter%26m%3DmobileDeal%26showwxpaytitle%3D1%26vb2ctag%3D4_2030_5_1194_60&response_type=code&scope=snsapi_base&state=123#wechat_redirect

四.通过code获取openid,有openid后就可以调用统一下单接口了,此时secret不能忽略,在微信公众平台获取

https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

五.调用统一下单接口,AppID等敏感信息我封装到实体类中了

 /**
     * 微信内浏览器支付
     *
     * @return
     */
    @PostMapping("/createJSAPI")
    @ApiOperation("微信内支付,orderId订单ID,openId用户唯一识别ID")
    public DzResult createJSAPI(String orderId, String openId) throws Exception {
        if (StringUtils.isBlank(orderId) || StringUtils.isBlank(openId)) {
            System.out.println("微信内支付空订单号-------------------->");
            return new DzResult().error(OrderCode.ERROR_PARAMS, "参数错误");
        }
        // 获取当前用户
        Claims claims = (Claims) request.getAttribute("authInfo");
        if (claims == null) {
            return new DzResult().error(OrderCode.NOT_LEGAL, "非法操作");
        }
        // 调用业务层查询订单信息
        CyOrder order = weixinPayService.findOrderByOrderId(orderId);
        if (order == null) {
            return new DzResult().error(OrderCode.ORDER_NOT_EXIST, "订单不存在");
        }
        if (!claims.getId().equals(order.getFrontUserId())) {
            return new DzResult().error(OrderCode.NOT_BELONG, "订单不属于当前用户");
        }
        // 商户订单号(用下划线后面数字为标识1:支付定金 2:支付尾款)
        BigDecimal totalAmount;
        // 将数据库价格去分
        BigDecimal mun = BigDecimal.valueOf(100);
        // 名称
        String subject;
        //设置商品详情参数
        HashMap attach = new HashMap<>(16);
        // 订单号
        String outTradeNo = orderId;
        //订单号
        attach.put("outTradeNo", outTradeNo);
        //自定义参数
        String attachStr;
        //全款
        //微信是按分为单位,此处*100去分:
        totalAmount = order.getPayMoney().multiply(mun);
        subject = "呈衣全款支付";
        attach.put("subject", subject);
        //去掉小数点后的零
        attach.put("totalAmount", totalAmount.stripTrailingZeros().toPlainString());
        attachStr = JSONUtils.toJSONString(attach);
        Map map = weixinPayService.createJSAPI(outTradeNo, totalAmount.stripTrailingZeros().toPlainString(), attachStr, openId);
        if (map == null) {
            return new DzResult().error(OrderCode.ORDER_WECAT_ERROR, "微信支付异常");
        }
        if ("FAIL".equals(map.get("return_code"))) {
            System.out.println("通讯异常");
            Object errorMsg = map.get("return_msg");
            return new DzResult().error(OrderCode.ORDER_WECAT_ERROR, errorMsg + "");
        }
        if ("FAIL".equals(map.get("result_code"))) {
            System.out.println("支付错误");
            Object errCode = map.get("err_code");
            Object errCodeDes = map.get("err_code_des");
            String errorMsg = errCode + "  :  " + errCodeDes;
            return new DzResult().error(OrderCode.ORDER_WECAT_ERROR, errorMsg + "");
        }
        System.out.println("调统一下单接口返回的结果都OK...............");
        boolean haveMwebUrl = map.containsKey("mweb_url");
        System.out.println("是否有拉起微信APP的路径:" + haveMwebUrl);
        boolean havePrepay_id = map.containsKey("prepay_id");
        System.out.println("是否有,预支付交易会话标识:" + havePrepay_id);
        //新建一个map集合
        Map resMap = new HashMap<>(16);
        //appID
        resMap.put("appId", WeChatPayConfig.app_id);
        System.out.println("appId:-->" + resMap.get("appId").toString());
        //时间戳
        resMap.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
        System.out.println("timeStamp:-->" + resMap.get("timeStamp").toString());
        //随机字符串
        resMap.put("nonceStr", WXPayUtil.generateNonceStr());
        System.out.println("nonceStr:-->" + resMap.get("nonceStr").toString());
        //订单详情扩展字段
        resMap.put("package", "prepay_id="+map.get("prepay_id").toString());
        System.out.println("package:-->" + map.get("prepay_id").toString());
        //签名方式
        resMap.put("signType", "MD5");
        String paySign = WXPayUtil.generateSignature(resMap, WeChatPayConfig.partner_key);
        //签名
        resMap.put("paySign", paySign);
        System.out.println("paySign:-->" + resMap.get("paySign").toString());
        //返回给前端
        map.put("WCPayRequest", resMap);
        return new DzResult().success(map);

实现层代码,调统一下单接口代码

/**
     * 微信浏览器内调用JSAPI支付
     *
     * @param outTradeNo
     * @param totalFee
     * @param attachStr
     * @param openID
     * @return
     */
    @Override
    public Map createJSAPI(String outTradeNo, String totalFee, String attachStr, String openID) {
        System.out.println("进入微信内浏览器支付方法");
        System.out.println("传过来的订单号:"+outTradeNo);
        System.out.println("传过来的金额:"+totalFee);
        System.out.println("传过来的自定义参数:"+attachStr);
        System.out.println("传过来的openid:"+openID);
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        //设置失效时间5分钟
        String expireTime = getOrderExpireTime(300 * 1000L);
        //1.创建参数
        HashMap param = new HashMap<>(16);
        //公账号
        param.put("appid", WeChatPayConfig.app_id);
        //自定义参数(attach)
        param.put("attach", attachStr);
        //商品描述:商品名字
        param.put("body", "呈衣定制");
        //商户号
        param.put("mch_id", WeChatPayConfig.partner);
        //随机字符串
        param.put("nonce_str", WXPayUtil.generateNonceStr());
        //回调地址
        param.put("notify_url", WeChatPayConfig.notify_url);
        //用户的openID,JSAPI支付必填
        param.put("openid", openID);
        //订单号
        param.put("out_trade_no", outTradeNo);
        //ip,
        param.put("spbill_create_ip", getIpAddr(request));
        //设置失效时间5分钟
        param.put("time_expire", expireTime);
        //总金额(分)
        param.put("total_fee", totalFee);
        //交易类型
        param.put("trade_type", "JSAPI");

        System.out.println("appid"+param.get("appid").toString());
        System.out.println("attach"+param.get("attach").toString());
        System.out.println("body"+param.get("body").toString());
        System.out.println("mch_id"+param.get("mch_id").toString());
        System.out.println("nonce_str"+param.get("nonce_str").toString());
        System.out.println("notify_url"+param.get("notify_url").toString());
        System.out.println("openid"+param.get("openid").toString());
        System.out.println("out_trade_no"+param.get("out_trade_no").toString());
        System.out.println("spbill_create_ip"+param.get("spbill_create_ip").toString());
        System.out.println("time_expire"+param.get("time_expire").toString());
        System.out.println("total_fee"+param.get("total_fee").toString());
        System.out.println("trade_type"+param.get("trade_type").toString());
        System.out.println("partner_key"+WeChatPayConfig.partner_key);
        try {
            //2.生成要发送的xml,方法中传入签名
            String xmlParam = WXPayUtil.generateSignedXml(param, WeChatPayConfig.partner_key);
            System.out.println("调用微信统一下单接口,请求的参数" + xmlParam);
            //请求的url地址
            HttpClient httpclient = new HttpClient(WeChatPayConfig.request_url);
            //是否是https协议
            httpclient.setHttps(true);
            //发送的xml数据
            httpclient.setXmlParam(xmlParam);
            //执行的请求方法
            httpclient.post();
            Map returnMap = WXPayUtil.xmlToMap(httpclient.getContent());
            //订单号
            returnMap.put("out_trade_no", outTradeNo);
            //自定义参数,交易信息
            returnMap.put("attach", attachStr);
            System.out.println("调用统一下单接口正常");
            return returnMap;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

六. 前台支付页面里放入微信示例的JS代码就可以拉起微信支付了

在微信浏览器里面打开H5网页中执行JS调起支付。接口输入输出数据格式为JSON。

注意:WeixinJSBridge内置对象在其他浏览器中无效。

getBrandWCPayRequest参数以及返回值定义:

1、网页端接口请求参数列表(参数需要重新进行签名计算,参与签名的参数为:appId、timeStamp、nonceStr、package、signType,参数区分大小写。)

名称 变量名 必填 类型 示例值 描述
公众号id appId 是 String(16) wx8888888888888888 商户注册具有支付权限的公众号成功后即可获得
时间戳 timeStamp 是 String(32) 1414561699 当前的时间,其他详见时间戳规则
随机字符串 nonceStr 是 String(32) 5K8264ILTKCH16CQ2502SI8ZNMTM67VS 随机字符串,不长于32位。推荐随机数生成算法
订单详情扩展字符串 package 是 String(128) prepay_id=123456789 统一下单接口返回的prepay_id参数值,提交格式如:prepay_id=***
签名方式 signType 是 String(32) MD5 签名类型,默认为MD5,支持HMAC-SHA256和MD5。注意此处需与统一下单的签名类型一致
签名 paySign 是 String(64) C380BEC2BFD727A4B6845133519F3AD6 签名,详见签名生成算法
2、返回结果值说明

返回值 描述
get_brand_wcpay_request:ok 支付成功
get_brand_wcpay_request:cancel 支付过程中用户取消
get_brand_wcpay_request:fail 支付失败
调用支付JSAPI缺少参数:total_fee
1、请检查预支付会话标识prepay_id是否已失效

2、请求的appid与下单接口的appid是否一致

注:JS API的返回结果get_brand_wcpay_request:ok仅在用户成功完成支付时返回。由于前端交互复杂,get_brand_wcpay_request:cancel或者get_brand_wcpay_request:fail可以统一处理为用户遇到错误或者主动放弃,不必细化区分。

示例代码如下:

function onBridgeReady(){
   WeixinJSBridge.invoke(
      'getBrandWCPayRequest', {
         "appId":"wx2421b1c4370ec43b",     //公众号名称,由商户传入     
         "timeStamp":"1395712654",         //时间戳,自1970年以来的秒数     
         "nonceStr":"e61463f8efa94090b1f366cccfbbb444", //随机串     
         "package":"prepay_id=u802345jgfjsdfgsdg888",     
         "signType":"MD5",         //微信签名方式:     
         "paySign":"70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名 
      },
      function(res){
      if(res.err_msg == "get_brand_wcpay_request:ok" ){
      // 使用以上方式判断前端返回,微信团队郑重提示:
            //res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
      } 
   }); 
}
if (typeof WeixinJSBridge == "undefined"){
   if( document.addEventListener ){
       document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
   }else if (document.attachEvent){
       document.attachEvent('WeixinJSBridgeReady', onBridgeReady); 
       document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
   }
}else{
   onBridgeReady();
}

注意:

签名的时候package字段一定要拼接prepay_id后再进行签名,不然前台拉起微信支付时会报支付验证签名失败
微信JSAPI支付,微信浏览器内支付,解决微信H5支付只能在微信外浏览器支付的问题_第4张图片

你可能感兴趣的:(笔记)