微信支付--JSAPI和Native

/ java / 没有评论 / 344浏览

微信支付

支付方式

alt

流程

alt

登录微信公众平台, 开通微信支付功能

alt

登录微信商户平台

alt alt

下载sdk

alt

JSAPI

配置微信sdk配置类

这里配置的是小程序的appid

public class MiniProgramPayConfig extends WXPayConfig {

    private byte[] certData;

    public MiniProgramPayConfig() throws Exception {
        Resource resource = new ClassPathResource("cert/apiclient_cert.p12");
        InputStream certStream = resource.getInputStream();
        this.certData = IOUtils.toByteArray(certStream);
        certStream.close();
    }

    /**
     * appid
     * @return
     */
    @Override
    public String getAppID() {
        return WXLoginConfig.getAppId();
    }

    /**
     * 商户id
     * @return
     */
    @Override
    public String getMchID() {
        return WxPayConfig.getMchId();
    }

    /**
     * 商户api安全key
     * @return
     */
    @Override
    public String getKey() {
        return WxPayConfig.getApiKey();
    }

    @Override
    public InputStream getCertStream() {
        ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
        return certBis;
    }

    @Override
    public IWXPayDomain getWXPayDomain() {
        return new IWXPayDomain() {
            @Override
            public void report(String domain, long elapsedTimeMillis, Exception ex) {
            }

            @Override
            public DomainInfo getDomain(WXPayConfig config) {
                return new DomainInfo("api.mch.weixin.qq.com", false);
            }
        };
    }
}

后端统一下单接口

controller

/**
     * 微信小程序支付
     * @param form
     * @return
     * @throws Exception
     */
    @PostMapping("/payData")
    public ResponseResult<Map<String, String>> payDataTest(@RequestBody PayFromVO form) throws Exception {
        return ResponseResultUtil.createSuccesResult(payService.payData());
    }

service

   public Map<String, String> payData() throws Exception {

        MiniProgramPayConfig config = new MiniProgramPayConfig();
        WXPay wxpay = new WXPay(config);
        Map<String, String> data = new HashMap<>();
        //appid 是小程序的appid(微信公众平台获取)
        //data.put("appid", config.getAppID());// 小程序ID
        //商户id(微信商户平台申请)
        //data.put("mch_id", config.getMchID());// 商户号
        //随机字符串,微信推荐长度要求在32位以内。
        //data.put("nonce_str", WXPayUtil.generateNonceStr());// 随机字符串
        //商品描述
        data.put("body", "测试");// 商品描述
        //商户订单号可以根据这个订单查询账单
        data.put("out_trade_no", WXPayUtil.generateNonceStr());// 商户订单号
        //支付金额 微信支付是按分为单位的 是int类型 1就是1分 10就是一角
        data.put("total_fee", "1");// 标价金额 ,单位为分
        //获取客户端的ip地址
        data.put("spbill_create_ip", IpUtils.getAddrIp());// 终端IP
        //微信支付回调地址 也就是用户支付成功改状态的地方
        data.put("notify_url", WxPayConfig.getNotifyUrl());// 通知地址
        //如果是微信小小程序和公众号这是一个固定值,统一调用JSAPI
        data.put("trade_type", "NATIVE");// 交易类型
        //openid
        //data.put("openid", openId);
        //封装签名的格式 md5
        //data.put("sign_type", "MD5");
        // 生成签名
        //String sign = WXPayUtil.generateSignature(data, config.getKey());
        //封装签名
        //data.put("sign",sign);
        //统一下单,调用官方接口
        Map<String, String> resp = wxpay.unifiedOrder(data);
        if ("SUCCESS".equals(resp.get("return_code"))) {
            //再次签名
            Map<String, String> reData = new HashMap<>();
            //appid
            reData.put("appId", config.getAppID());
            //随机字符串
            reData.put("nonceStr", WXPayUtil.generateNonceStr());
            //当前时间戳
            reData.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
            //预订单id 上一次请求返回的id
            String newPackage = "prepay_id=" + resp.get("prepay_id");
            reData.put("package", newPackage);
            //签名加密方式
            reData.put("signType","MD5");
            String newSign = WXPayUtil.generateSignature(reData, config.getKey());
            //签名
            reData.put("paySign", newSign);
            return reData;
        }
        return null;
    }

坑点

官方的sdk有个bug,沙盒模式才是MD5加密 修改sdk的WXPay文件 alt

支付回调通知


/**
     * 支付回调通知
     *
     * @param response
     * @param notityXml
     * @throws IOException
     */
    @Transactional(rollbackFor = Exception.class)
    public void wxPayNotify(HttpServletResponse response, String notityXml) throws IOException {
        PrintWriter writer = response.getWriter();
        try {
            logger.info("微信支付结果通知接口请求数据xml:" + notityXml);
            Map<String, String> map = WXPayUtil.xmlToMap(notityXml);
            Map<String, String> res = new HashMap<>();
            logger.debug("微信支付结果通知接口请求数据map:" + map);
            if ("SUCCESS".equalsIgnoreCase(map.get("result_code"))) {
                if (WXPayUtil.isSignatureValid(notityXml, WxPayConfig.getApiKey())) {
                    //业务逻辑
                }
            } else {
                res.put("return_code", "FAIL");
                res.put("return_msg", "报文为空");
            }
            writer.write(WXPayUtil.mapToXml(res));
            writer.flush();
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("微信支付结果通知接口服务端异常,异常信息---" + e.getMessage(), e);
        } finally {
            writer.close();
        }
    }

Native

配置微信sdk配置类

这里配置的是公众服务号的appid

public class WebPayConfig extends WXPayConfig {

    private byte[] certData;

    public WebPayConfig() throws Exception {
        Resource resource = new ClassPathResource("cert/apiclient_cert.p12");
        InputStream certStream = resource.getInputStream();
        this.certData = IOUtils.toByteArray(certStream);
        certStream.close();
    }

    /**
     * appid
     * @return
     */
    @Override
    public String getAppID() {
        return WXLoginConfig.getAppIdOffice();
    }

    /**
     * 商户id
     * @return
     */
    @Override
    public String getMchID() {
        return WxPayConfig.getMchId();
    }

    /**
     * 商户api安全key
     * @return
     */
    @Override
    public String getKey() {
        return WxPayConfig.getApiKey();
    }

    @Override
    public InputStream getCertStream() {
        ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
        return certBis;
    }

    @Override
    public IWXPayDomain getWXPayDomain() {
        return new IWXPayDomain() {
            @Override
            public void report(String domain, long elapsedTimeMillis, Exception ex) {
            }

            @Override
            public DomainInfo getDomain(WXPayConfig config) {
                return new DomainInfo("api.mch.weixin.qq.com", false);
            }
        };
    }
}

后端统一下单接口

返回二维码链接给前端生成二维码

 /**
     * 微信网页扫码支付
     * @param form
     * @return
     * @throws Exception
     */
    @PostMapping("/payDataWeb")
    public ResponseResult<Map<String, String>> payDataWeb(@RequestBody PayFromVO form) throws Exception {
        return ResponseResultUtil.createSuccesResult(payService.payDataWeb(this.getTokenUser(), form));
    }

service

   public Map<String, String> payData() throws Exception {

        MiniProgramPayConfig config = new MiniProgramPayConfig();
        WXPay wxpay = new WXPay(config);
        Map<String, String> data = new HashMap<>();
        //appid 是小程序的appid(微信公众平台获取)
        //data.put("appid", config.getAppID());// 小程序ID
        //商户id(微信商户平台申请)
        //data.put("mch_id", config.getMchID());// 商户号
        //随机字符串,微信推荐长度要求在32位以内。
        //data.put("nonce_str", WXPayUtil.generateNonceStr());// 随机字符串
        //商品描述
        data.put("body", "测试");// 商品描述
        //商户订单号可以根据这个订单查询账单
        data.put("out_trade_no", WXPayUtil.generateNonceStr());// 商户订单号
        //支付金额 微信支付是按分为单位的 是int类型 1就是1分 10就是一角
        data.put("total_fee", "1");// 标价金额 ,单位为分
        //获取客户端的ip地址
        data.put("spbill_create_ip", IpUtils.getAddrIp());// 终端IP
        //微信支付回调地址 也就是用户支付成功改状态的地方
        data.put("notify_url", WxPayConfig.getNotifyUrl());// 通知地址
        //如果是微信小小程序和公众号这是一个固定值,统一调用JSAPI
        data.put("trade_type", "NATIVE");// 交易类型
        //openid
        //data.put("openid", openId);
        //封装签名的格式 md5
        //data.put("sign_type", "MD5");
        // 生成签名
        //String sign = WXPayUtil.generateSignature(data, config.getKey());
        //封装签名
        //data.put("sign",sign);
        //统一下单,调用官方接口
        Map<String, String> resp = wxpay.unifiedOrder(data);
        if ("SUCCESS".equals(resp.get("return_code"))) {
            Map<String, String> reData = new HashMap<>();
            reData.put("codeUrl", resp.get("code_url"));
            return reData;
        }
        return null;
    }