前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >微信H5支付

微信H5支付

作者头像
二十三年蝉
发布2022-03-10 16:48:32
1.3K0
发布2022-03-10 16:48:32
举报
文章被收录于专栏:闻道于事闻道于事

微信支付分很多种,其中微信H5支付是给在手机浏览器上使用,在手机上发起付款,自动跳转到微信并付款

微信支付开发文档:https://pay.weixin.qq.com/wiki/doc/api/index.html

微信H5支付文档:https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_1

微信统一下单接口:https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_1

微信H5支付流程:

1、用户在商户侧完成下单,使用微信支付进行支付

2、由商户后台向微信支付发起下单请求(调用统一下单接口)注:交易类型trade_type=MWEB

3、统一下单接口返回支付相关参数给商户后台,如支付跳转url(参数名“mweb_url”),商户通过mweb_url调起微信支付中间页

4、中间页进行H5权限的校验,安全性检查(此处常见错误请见下文)

5、如支付成功,商户后台会接收到微信侧的异步通知

6、用户在微信支付收银台完成支付或取消支付,返回商户页面(默认为返回支付发起页面)

7、商户在展示页面,引导用户主动发起支付结果的查询

8,9、商户后台判断是否接到收微信侧的支付结果通知,如没有,后台调用我们的订单查询接口确认订单状态

10、展示最终的订单支付结果给用户

支付部分代码:

代码语言:javascript
复制
   /**
     * 微信H5支付2号方案
     */
    @RequestMapping("/wapPay")
    @ResponseBody
    public net.sf.json.JSONObject pay(HttpServletRequest  request, HttpServletResponse response, Integer userid, Double money, Integer num)
            throws ServletException, IOException {

        request.setCharacterEncoding("UTF-8");
        net.sf.json.JSONObject json = new net.sf.json.JSONObject();

        String ip = null;

        //以下代码为获取请求的公网IP
        //X-Forwarded-For:Squid 服务代理
        String ipAddresses = request.getHeader("X-Forwarded-For");

        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            //Proxy-Client-IP:apache 服务代理
            ipAddresses = request.getHeader("Proxy-Client-IP");
        }

        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            //WL-Proxy-Client-IP:weblogic 服务代理
            ipAddresses = request.getHeader("WL-Proxy-Client-IP");
        }

        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            //HTTP_CLIENT_IP:有些代理服务器
            ipAddresses = request.getHeader("HTTP_CLIENT_IP");
        }

        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            //X-Real-IP:nginx服务代理
            ipAddresses = request.getHeader("X-Real-IP");
        }

        //有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP
        if (ipAddresses != null && ipAddresses.length() != 0) {
            ip = ipAddresses.split(",")[0];
        }

        //还是不能获取到,最后再通过request.getRemoteAddr();获取
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            ip = request.getRemoteAddr();
        }
        if (StrKit.isBlank(ip)) {
            ip = "127.0.0.1";
        }

        int intMoney =(int)(money * 100);
        //商户相关资料
        String appid = "***";//公众号appid
        String appsecret = "***";//公众号秘钥
        String partner = "***";//商户号
        String partnerkey = "***";//商户API秘钥

        //用于获取随机数
        String currTime = TenpayUtil.getCurrTime();//获取当前时间
        String strTime = currTime.substring(8, currTime.length());//8位日期
        String strRandom = TenpayUtil.buildRandom(4) + "";//四位随机数
        String strReq = strTime + strRandom;//10位序列号,可以自行调整

        String orderNo=appid+userid+ Sha1Util.getTimeStamp();//随机生成了一个订单号

        //商户号
        String mch_id = partner;

        //设备号   非必输
        String device_info="WEB";

        //随机数
        String nonce_str = strReq;

        //商品描述
        String body = "号码筛选充值";

        //附加数据
        String attach = "shengyu";

        //商户订单号
        String out_trade_no = orderNo;

        //总金额以分为单位,不带小数点
        int total_fee = intMoney;

//        String spbill_create_ip = request.getRemoteAddr();
        String spbill_create_ip = ip;

        String trade_type = "MWEB";//H5支付方式

        SortedMap<String, String> packageParams = new TreeMap<String, String>();
        packageParams.put("appid", appid);
        packageParams.put("mch_id", mch_id);
        packageParams.put("nonce_str", nonce_str);
        packageParams.put("body", body);
        packageParams.put("attach", attach);
        packageParams.put("out_trade_no", out_trade_no);
        packageParams.put("total_fee", String.valueOf((intMoney)));
        packageParams.put("spbill_create_ip", spbill_create_ip);
        packageParams.put("notify_url", notify_url);
        packageParams.put("trade_type", trade_type);
        RequestHandler reqHandler = new RequestHandler(request, response);
        reqHandler.init(appid, appsecret, partnerkey);

        //获取签名
        String sign = reqHandler.createSign(packageParams);

        String xml="<xml>"+
                "<appid>"+appid+"</appid>"+
                "<mch_id>"+mch_id+"</mch_id>"+
                "<nonce_str>"+nonce_str+"</nonce_str>"+
                "<sign>"+sign+"</sign>"+
                "<body>"+body+"</body>"+
                "<attach>"+attach+"</attach>"+
                "<out_trade_no>"+out_trade_no+"</out_trade_no>"+
                "<total_fee>"+total_fee+"</total_fee>"+
                "<spbill_create_ip>"+spbill_create_ip+"</spbill_create_ip>"+
                "<notify_url>"+notify_url+"</notify_url>"+
                "<out_trade_no>"+ orderNo+"</out_trade_no>"+
                "<trade_type>"+trade_type+"</trade_type>"+
                "</xml>";

        String allParameters = "";//没用
        try {
            allParameters =  reqHandler.genPackage(packageParams);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        //请求微信统一下单接口,成功后返回预支付交易会话标识prepay_id
        String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        String prepay_id = "";
        String mweb_url="";
        try {
            Map<String ,String> returnmap= new GetWxOrderno().getPayNo(createOrderURL, xml);
            prepay_id=returnmap.get("prepay_id");
            mweb_url=returnmap.get("mweb_url");
            if(prepay_id.equals("")){
                json.put("msg","统一支付接口获取预支付订单出错");
                return json;
            }
            //这里可以放增加订单信息

        } catch (Exception e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

        //生成H5调起微信支付API相关参数(前端页面js的配置参数)
        SortedMap<String, String> finalpackage = new TreeMap<String, String>();
        String timestamp = Sha1Util.getTimeStamp();//当前时间的时间戳
        String packages = "prepay_id="+prepay_id;;//订单详情扩展字符串
        finalpackage.put("appId", appid);//公众号appid
        finalpackage.put("timeStamp", timestamp);
        finalpackage.put("nonceStr", strReq); //随机数
        finalpackage.put("package", packages);
        finalpackage.put("signType", "MD5");//签名方式
        String finalsign = reqHandler.createSign(finalpackage);//签名

        String returnurl_1="";
        try {
            returnurl_1=returnurl;
            // 将普通字符创转换成application/x-www-from-urlencoded字符串
            returnurl_1 = URLEncoder.encode(returnurl, "GBK"); 
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        json.put("appId", appid);
        json.put("timeStamp", timestamp);
        json.put("nonceStr", strReq);
        json.put("packages", packages);
        json.put("sign", finalsign);
        json.put("mweb_url", mweb_url+"&redirect_url="+returnurl);//+"&redirect_url=wap%2frechargeSuccess.html"
        return json;
    }

    /**
     * 支付完成的回调,修改订单状态等
     * @return
     */
    @ResponseBody
    @RequestMapping("/trueOrder")
    public String notify(HttpServletRequest request, HttpServletResponse response)
            throws Exception {

        BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream) request.getInputStream()));
        String line = null;
        StringBuilder sb = new StringBuilder();
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }

        StringBuilder jsonStr = sb;
        Map<String, Object> dataMap = new HashMap<String, Object>();

        Map map = doXMLParse(jsonStr.toString());
        String out_trade_no  = (String) map.get("out_trade_no");//获取订单号
        //下面是根据订单号修改订单状态、账户余额等

        //返回,如果不加可能会请求多次
        return  "<xml>" +
                "<return_code><![CDATA[SUCCESS]]></return_code>" +
                "<return_msg><![CDATA[支付成功]]></return_msg>" +
                "</xml>";
    }
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-05-30 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
弹性公网 IP
弹性公网 IP(Elastic IP,EIP)是可以独立购买和持有,且在某个地域下固定不变的公网 IP 地址,可以与 CVM、NAT 网关、弹性网卡和高可用虚拟 IP 等云资源绑定,提供访问公网和被公网访问能力;还可与云资源的生命周期解耦合,单独进行操作;同时提供多种计费模式,您可以根据业务特点灵活选择,以降低公网成本。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档