14 9 2021

因为之前有开发微信的经验,所以少走很多弯路,但是不得不提,微信有很多坑,我现在一个一个帮你们填上,让你们不用走弯路,一路畅通无阻,有任何问题,可以 邮箱我:wh_djj@163.com

1.开通微信支付功能

2.安装证书、设置微信支付秘钥

2.1.此秘钥是自己生成,密码随机生成器,选择32位:链接地址:
https://suijimimashengcheng.51240.com/

安装证书、设置微信支付秘钥

3.添加支付配置

3.1 一定要注意,支付授权目录,一定是详细一点,
如:支付页面是,http://baidu.com/pay/wxpay/wxpay.aspx
支付授权目录应该设置成:http://baidu.com/pay/wxpay/ 最后以"/"结尾

在这里插入图片描述

4.设置js安全域名,授权域名

4.1 应该设置已经备案过得域名,并把 txt 文件放在根目录 即可

在这里插入图片描述

5.获取用户授权码:code

5.1 获取用户授权,得到 code
在微信公众号测试菜单中,添加地址:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxd59849ba4991d63b&redirect_uri=xxxxxx&response_type=code&scope=snsapi_userinfo&state=STATE%23wechat_redirect&connect_redirect=1#wechat_redirect

5.2 上面的链接地址中的:xxxxxx 改为,微信调试地址,并经过urlencode编码一次,如:
编码前:http://wx.baidu.com
编码后:http%3a%2f%2fwx.baidu.com 传入编码后的地址即可

5.3 此链接是用户授权认证,有了此链接,可以获取到用户的:oauth_code

在这里插入图片描述

5.4

在这里插入图片描述

5.5

在这里插入图片描述

6.通过code,获取用户唯一码:openid

6.1

在这里插入图片描述

6.2.设置当前域名所在的Ip地址在微信白名单中

6.3 代码块

6.3.1 准备类:CodeResponse,6.3.2 会用到

/**
     * 网页授权接口调用凭证
     */
    private String accessToken;

    /**
     * 接口调用凭证超时时间,单位(秒)
     */
    private String expiresIn;

    /**
     * 用户刷新access_token
     */
    private String refreshToken;

    /**
     * 用户唯一标识
     */
    private String openid;

    /**
     * 用户授权的作用域
     */
    private String scope;

    /**
     * 错误码
     */
    private String errcode;

    /**
     * 错误信息
     */
    private String errmsg;

 

6.3.2 CodeResponse 中的 openid 已经拿到了想得到的 用户唯一码:openid

String appId = "微信公众号的appId";
			String secret = "微信公众号的秘钥";
			String code = "前台传的code,不懂的可以看 5.5 的那张图";
            Map<String, String> map = new HashMap();
            String url = "https://api.weixin.qq.com/sns/oauth2/access_token?";
            map.put("appid", appId);
            map.put("secret", secret);
            map.put("code", code);
            map.put("grant_type", "authorization_code");
            try {
               //不要纠结这个doQueryString方法,就是一个get请求,网上搜索 java  get请求,一大推
                String tokenStr = WebUtils.doQueryString(url, map);
                CodeResponse codeResponse = JSON.parseObject(tokenStr, CodeResponse.class);
                if (StringUtils.isEmpty(codeResponse.getErrcode())) {//判断返回的json中有没有 errcode,如果没有说明获取成功,否则查看原因
                    return codeResponse ;//最上面用  CodeResponse   接收即可
                } else {
                   //这里是随意写的,你们直接用肯定会报错,意思是,返回错误码和错误信息,好查找错误原因
                    return codeResponse.getErrmsg(), codeResponse.getErrcode()
                }
            } catch (Exception ext) {
                return null;
            }

 

6.3.3 用户基本信息类 UserInfoResponse

 /**
     * 用户的唯一标识
     */
    private String openid;

    /**
     * 用户昵称
     */
    private String nickname;

    /**
     * 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
     */
    private String sex;

    /**
     * 省份
     */
    private String province;

    /**
     * 城市
     */
    private String city;

    /**
     * 国家
     */
    private String country;

    /**
     * 用户头像
     */
    private String headimgurl;

    /**
     * 用户特权信息
     */
    private String privilege;

    /**
     * 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段
     */
    private String unionid;

    /**
     * 错误码
     */
    private String errcode;

    /**
     * 错误信息
     */
    private String errmsg;

6.3.4 附加:通过 openid获取用户基本信息

   Map<String, String> infoMap = new HashMap();
            String infoUrl = "https://api.weixin.qq.com/sns/userinfo?";
            infoMap.put("access_token", codeResponse.getData().getAccessToken());
            infoMap.put("openid", codeResponse.getData().getOpenid());
            infoMap.put("lang", "zh_CN");
            String infoStr = WebUtils.doQueryString(infoUrl, infoMap);
            UserInfoResponse userInfoResponse = JSON.parseObject(infoStr, UserInfoResponse.class);

            if (StringUtils.isEmpty(userInfoResponse.getErrcode())) {
                return userInfoResponse;
            } else {
                return null;
            }

 

7.微信支付,前面的都是为了打基础,真正的好戏,现在才开始

7.1. 帮助类

 /**
     * 用户输入的是 元,需要  分,不能填写 点 ,  提供精确的乘法运算。
     *
     * @param v1 被乘数
     * @param v2 乘数
     * @return 两个参数的积
     */
    public static String Mul2(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return getDoubleStr2(b1.multiply(b2).doubleValue());
    }

 public static String replaceBlank(String str) {
        String dest = "";
        if (str!=null) {
            dest =  str.replace("\\n","").replace("\n","").replace("\\r","").replace("\r","").replace("  ","").trim();
        }
        return dest;
    }
public static String MapToJson(Map map) {
        String json = StringUtils.replaceBlank(JSONObject.toJSONString(map));
        return json;
    }


    public static <T> T MapToObjcet(Map map, Class<T> zclass) {
        String json = MapToJson(map);
        return JSONObject.parseObject(json, zclass);
    }

7.2 下面缺少的方法,sdk中有,我就不写了

 String mch_id = "商户号";
        String key = "商户密钥";//key是商户密钥.本文章 2.1 中已经提到
        String appId = "微信appid";
        String fee = "0.01";
        String ip = "当前请求微信支付的服务器ip地址";
        Map<String, String> params = MapToJsonUtils.objectToMap(payRequest);
        String key = setting.getPayKey();
        String nonceStr = WXPayUtil.generateNonceStr();
        String openid = "用户的openid";
        params.put("nonce_str", nonceStr);
        params.put("openid", openid);
        params.put("body", "商品123");
        params.put("mch_id", mch_id);
        params.put("appid", appId);
        params.put("sign_type", WXPayConstants.MD5);
        Double feeDouble = Double.valueOf(fee);
        String feeStr = DoubleUtil.Mul2(feeDouble, 100);//用户输入的是 元,需要  分,不能填写 点
        params.put("total_fee", feeStr);
        params.put("trade_type", "JSAPI");
        params.put("spbill_create_ip", ip);
        //下面这个方法可能需要改造一下,最好是把 key也 传进去 计算 7.3的图片中会有
        String signature = WXPayUtil.generateSignature(params, key, WXPayConstants.MD5);   //TODO  key是商户密钥
        params.put("sign", signature);
        WxPayConfigImpl instance = WxPayConfigImpl.getInstance();
        WXPay wxPay = new WXPay(instance);
         //下面这个方法可能需要改造一下,最好是把 key也 传进去 计算 7.3的图片中会有
        Map returnMap = wxPay.unifiedOrder(params, key);
        PayResponse payResponse = MapToJsonUtils.MapToObjcet(returnMap, PayResponse.class);
        if (payResponse.getReturnCode().equals("SUCCESS") && payResponse.getResultCode().equals("SUCCESS")) {
           //第二次验签、这一步非常重要,在很多别的博客中都没有这句话,造成了 前台返回签名错误
           //这里是一个大坑,必须要签名两次的
            Map<String, String> chooseWXPayMap = new HashMap<>();
            chooseWXPayMap.put("appId", payResponse.getAppid());
            chooseWXPayMap.put("timeStamp", WXPayUtil.getCurrentTimestamp();
            chooseWXPayMap.put("nonceStr", payResponse.getNonceStr());
            chooseWXPayMap.put("package", "prepay_id=" + payResponse.getPrepayId());//这个很关键,需要
            chooseWXPayMap.put("signType", WXPayConstants.MD5);

            WXPayUtil.getLogger().info("wxPay.chooseWXPayMap:" + chooseWXPayMap.toString());

            // 生成支付签名
            String paySign = WXPayUtil.generateSignature(chooseWXPayMap, key, WXPayConstants.MD5);
            chooseWXPayMap.put("paySign", paySign);

payResponse.setPaySign(paySign);
            return payResponse;
        } else {
            return null;
        }

 

7.3 这些都是 微信支付提供的sdk原生的代码,我们需要改造一番,适合自己的才最好,因为你的所有的配置,不可能写在代码中,所以最好是在数据库,或者配置文件中配置

在这里插入图片描述

在这里插入图片描述

7.4.上面所有的准备,代码,已经完毕,现在开始,前台的调用

8.前台 jsapi调用微信支付

8.1 我使用 java 写接口,c# 写调用api,然后呈现
rlskOpenWechatData
rlskWechatPayResponse
rlskWechatUserInfo

这三个,在后台的方法中,已经拿到具体数据了,现在呈现即可

 

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="default.aspx.cs" Inherits="WxTest._default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
    <script src="/js/jquery-1.7.2.min.js"></script>
    <script type="text/javascript" src="http://res2.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
    <script>
        wx.config({
            debug: false,   //是否调试,true,会弹窗
            appId: '<%=rlskOpenWechatData.app_id%>', //得到这个东西,首先必须有一个公众号,或者企业号,如果已经拥有了,你可以就知道AppId在哪里了。
            timestamp: <%=rlskOpenWechatData.timestamp%>,//生成签名的时间戳,随机数,之后会用这个生成一个签名
            nonceStr: '<%=rlskOpenWechatData.nonce_str%>',//生成签名的随机串,随机串,之后会用这个生成一个签名
            signature: '<%=rlskOpenWechatData.signature%>',//这个就是签名了,在步骤4,我会详细讲解
            jsApiList: [
                'scanQRCode',//开启扫一扫功能,这里还可以添加更多的功能,比如微信支付
                'chooseWXPay'
            ]
        });
        wx.ready(function () {
            //点击按钮,出现扫描界面
            document.querySelector('#sm').onclick = function () {
                wx.scanQRCode({
                    desc: 'scanQRCode desc',
                    needResult: 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
                    scanType: ["qrCode", "barCode"], // 可以指定扫二维码还是一维码,默认二者都有
                    success: function (res) {
                        var url = res.resultStr;
                        var tempArray = url.split(',');
                        var tempNum = tempArray[1];//这个就是扫描后返回值扫描值
                        alert(url);
                    }
                });
            };
            var appId = "<%=rlskWechatPayResponse.appid %>";
            var timeStamp = "<%=rlskWechatPayResponse.time_stamp %>";
            var nonceStr = "<%=rlskWechatPayResponse.nonce_str %>";
            var prepay_id = "prepay_id=<%=rlskWechatPayResponse.prepay_id %>";
            var paySign = "<%=rlskWechatPayResponse.pay_sign %>";
            var signType = "<%=rlskWechatPayResponse.sign_type %>";
            document.querySelector('#pay').onclick = function () {
                wx.chooseWXPay({
                    timestamp: timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
                    nonceStr: nonceStr, // 支付签名随机串,不长于 32 位
                    package: prepay_id, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*)
                    signType: signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
                    paySign:paySign, // 支付签名
                    success: function (res) {
                        alert("成功");
                        // 支付成功后的回调函数
                    }
                });
            };




        });

    </script>
</head>
<body>
    <form id="form1" runat="server">
        <div style="margin-top: 300px;">
            用户基本信息:<br />
            1.唯一标识:<%=rlskWechatUserInfo.openid %><br />
            2.昵称:<%=rlskWechatUserInfo.nickname %><br />
            3.头像:<img src="<%=rlskWechatUserInfo.headimgurl %>" height="50" width="50" /><br />
            4.性别:<%=rlskWechatUserInfo.sex %><br />
            6.国家:<%=rlskWechatUserInfo.country %><br />
            6.省份:<%=rlskWechatUserInfo.province %><br />
            7.城市:<%=rlskWechatUserInfo.city %><br />
            8.用户特权信息:<%=rlskWechatUserInfo.privilege %><br />
            9.unionid:<%=rlskWechatUserInfo.unionid %><br />
            10.ip:<%=ip %><br />

            <a href="javascript:;" id="sm" style="margin-left: 200px; font-size: 100px;">1.开启扫一扫</a><br />
            <br />
            <br />

            <a href="/pay/wxpay.aspx?openid=<%=openid %>" style="margin-left: 200px; font-size: 100px;">2.微信支付</a><br />


            <a href="javascript:;" id="pay" style="margin-left: 200px; font-size: 100px;">3.微信支付</a><br />
            <br />
            <br />


        </div>
    </form>
</body>
</html>

 

备注:微信中遇到的坑不少,但是你不要怀疑微信有问题,因为不只你一人调用过,别人怎么不说有问题,就你有问题?所以,文档看详细点,不要一目十行。如有问题,随时邮件沟通 !

 wh_djj@163.com

延伸阅读
  1. (详解)钉钉接口,PC端微应用,免登录及获取当前用户信息