微信h5支付,微信外浏览器支付实现

微信h5支付,微信外浏览器支付实现2021-02-07修改看一下官方文档还是很必要的,知道必不可少的参数是什么:https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_20&index=1下面按步骤跟着我做首先需要APPID,微信支付商户号mch_id,API密钥key,Appsecret(secret),说明在这里https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=3_1 然后设置支付域名,设置路径:商户平

大家好,又见面了,我是你们的朋友全栈君。

对接第三方比较重要的点都有什么?

1.按规则

2.单独封装

3.做好出入参

2021-02-07修改

看一下官方文档还是很必要的,知道必不可少的参数是什么:https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_20&index=1

前期步骤及注意事项

下面按步骤跟着我做

  1. 首先需要APPID,微信支付商户号mch_id,API密钥key,Appsecret(secret),说明在这里https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=3_1
  2. 然后设置支付域名,设置路径:商户平台–>产品中心–>开发配置中设置域名,
  3. 如果是公众号支付就设置对应的,要注意的是公众号支付授权域名为请求的前一级,比如你要请求http://xxx/wx/abc,那么你就设置http://xxx/wx即可
  4. h5支付设置h5域名就行,不用后缀,直接写你要设置的域名(这个一般在申请开通的时候就可以填上去,后设置也行,域名需要备案,可设置为顶级域名,子域名都可访问(在代码中写死此域名,调起支付只能是这个域名之下的网站,比如电商网站域名等而非后端请求域名,证明是在此域名下安全支付的)
  5. partnerkey需要在API中设置,需要安装证书,这个根据提示安装即可,自行设置32位partnerkey

微信h5支付,微信外浏览器支付实现

 

 

我用的是插件IJPay的springboot版,其实说到底就是封装请求,解析请求,有做得好的可以拿过来用,用好了就是自己的

主要用的的是封装的jar,现在maven库中已经有了

 

具体代码

着手代码,一般支付模块的设计都用策略模式,大家可以了解一下

初始化账号信息

WxPayApiConfig build = WxPayApiConfig.builder()
                .appId(wxPayBean.getAppId())
                .mchId(wxPayBean.getMchId())
                .partnerKey(wxPayBean.getPartnerKey())
                .domain(wxPayBean.getDomain())
                .build();

        WxPayApiConfigKit.setThreadLocalWxPayApiConfig(build);
        log.info("wx config 初始化完成");

封装支付方式

/**
     * 微信h5支付
     */
    public Result wxH5Pay(PayCoreDTO payCoreDTO) {
        String ip = payCoreDTO.getIp();
        if (StrUtil.isBlank(ip)) {
            ip = "127.0.0.1";
        }
        H5SceneInfo.H5 h5_info = new H5SceneInfo.H5();
        h5_info.setType("Wap");
        //TODO 此域名必须在商户平台--"产品中心"--"开发配置"中添加
        h5_info.setWap_url(permitUrl);
        h5_info.setWap_name(payCoreDTO.getPayDesc());
        H5SceneInfo sceneInfo = new H5SceneInfo();
        sceneInfo.setH5Info(h5_info);

        WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();
       //此处可以设置支付白名单
//        PayWhite white = payWhiteMapper.getWhite(payCoreDTO.getMid());
        Map<String, String> params = UnifiedOrderModel
                .builder()
                .appid(wxPayApiConfig.getAppId())
                .mch_id(wxPayApiConfig.getMchId())
                .nonce_str(WxPayKit.generateStr())
                .body(payCoreDTO.getPayDesc())
                .attach(payCoreDTO.getAttach())
                .out_trade_no(payCoreDTO.getOutTradeNo())
//                .total_fee(white == null ? payCoreDTO.getTotalAmount().toString() : BigDecimalUtil.mulRoundDown(white.getPayDollar(), 100).toString())
                .total_fee(payCoreDTO.getTotalAmount().toString())
                .spbill_create_ip(ip)
                .notify_url(wxPayBean.getDomain())
                .trade_type(TradeType.MWEB.getTradeType())
                .scene_info(JSON.toJSONString(sceneInfo))
                .build()
                .createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);

        String xmlResult = WxPayApi.pushOrder(false, params);
        Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
        log.info("wx解析xml:{}", result);
        String return_code = result.get("return_code");
        String return_msg = result.get("return_msg");
        if (!WxPayKit.codeIsOk(return_code)) {
            throw new RuntimeException(return_msg);
        }
        String result_code = result.get("result_code");
        if (!WxPayKit.codeIsOk(result_code)) {
            throw new RuntimeException(return_msg);
        }
        // 以下字段在return_code 和result_code都为SUCCESS的时候有返回
        String prepayId = result.get("prepay_id");
        String webUrl = result.get("mweb_url") + "&redirect_url=" + payCoreDTO.getReturnUrl();
//        String webUrl = result.get("mweb_url");
        log.info("wx pay prepay_id:" + prepayId + " mweb_url:" + webUrl);
        return Result.success(webUrl);
    }

先给出H5ScencInfo

package com.mtgg.entity;
import com.jfinal.kit.JsonKit;
/**
 * @author Javen
 */
public class H5ScencInfo {
	private H5 h5_info;
	
	public H5 getH5_info() {
		return h5_info;
	}
	public void setH5_info(H5 h5_info) {
		this.h5_info = h5_info;
	}
	@Override
	public String toString() {
		return JsonKit.toJson(h5_info);
	}
	public static class H5{
		private String type;
		private String app_name;
		private String bundle_id;
		private String package_name;
		private String wap_url;
		private String wap_name;
		public String getType() {
			return type;
		}
		public void setType(String type) {
			this.type = type;
		}
		public String getApp_name() {
			return app_name;
		}
		public void setApp_name(String app_name) {
			this.app_name = app_name;
		}
		public String getBundle_id() {
			return bundle_id;
		}
		public void setBundle_id(String bundle_id) {
			this.bundle_id = bundle_id;
		}
		public String getPackage_name() {
			return package_name;
		}
		public void setPackage_name(String package_name) {
			this.package_name = package_name;
		}
		public String getWap_url() {
			return wap_url;
		}
		public void setWap_url(String wap_url) {
			this.wap_url = wap_url;
		}
		public String getWap_name() {
			return wap_name;
		}
		public void setWap_name(String wap_name) {
			this.wap_name = wap_name;
		}
	}
}


支付回调处理

注意notify_url要保证能够访问,用域名访问,本地是不行的,要么就用内网穿透工具,网上一搜就出来,注意用外浏览器打开

最后发送mweb_url就可以打开微信进行支付了

给出支付成功的返回(这里把退款回调的代码放一起了,不同接口处理也好)

public CallbackBizDTO notifyDeal(Map<String, String> map){
        String returnCode = map.get("return_code");
        CallbackBizDTO callbackBizDTO = new CallbackBizDTO();
        String reqInfo = map.get("req_info");
        if (StrUtil.isNotEmpty(reqInfo)) {
            //退款回调 
            // 注意重复通知的情况,同一订单号可能收到多次通知,请注意一定先判断订单状态
            if (WxPayKit.codeIsOk(returnCode)) {
                String decryptData = WxPayKit.decryptData(reqInfo, WxPayApiConfigKit.getWxPayApiConfig().getPartnerKey());
                Map<String, String> xmlToMap = WxPayKit.xmlToMap(decryptData);
                log.info("wx退款通知解密后的数据=" + xmlToMap);
                callbackBizDTO.setOutTradeNo(xmlToMap.get("out_trade_no"));
                callbackBizDTO.setTradeNo(xmlToMap.get("transaction_id"));
                callbackBizDTO.setTotalAmount(Long.valueOf(xmlToMap.get("total_fee")));
                callbackBizDTO.setMchId(map.get("mch_id"));
                callbackBizDTO.setAppid(map.get("appid"));
                callbackBizDTO.setTradeStatus(returnCode);
//                callbackBizDTO.setPassbackParams(xmlToMap.get("attach"));
                callbackBizDTO.setRefundFee(Long.parseLong(xmlToMap.get("refund_fee")));
                callbackBizDTO.setRefundNo(xmlToMap.get("out_refund_no"));
                callbackBizDTO.setGmtRefund(xmlToMap.get("success_time") + ".000");
                Map<String, String> xml = new HashMap<String, String>(2);
                xml.put("return_code", "SUCCESS");
                xml.put("return_msg", "OK");
                callbackBizDTO.setReturnStr(WxPayKit.toXml(xml));
                return callbackBizDTO;
            }
            log.error("验签失败:{}", returnCode);
            return null;
        } else {
            // 注意重复通知的情况,同一订单号可能收到多次通知,请注意一定先判断订单状态
            // 注意此处签名方式需与统一下单的签名类型一致
            if (WxPayKit.verifyNotify(map, WxPayApiConfigKit.getWxPayApiConfig().getPartnerKey(), SignType.HMACSHA256)) {
                if (WxPayKit.codeIsOk(returnCode)) {
                    String appid = map.get("appid");
                    String mchId = map.get("mch_id");
//                String totalFee = map.get("total_fee");
                    String cashFee = map.get("cash_fee");
                    String transactionId = map.get("transaction_id");
                    String outTradeNo = map.get("out_trade_no");
                    String attach = map.get("attach");
                    String timeEnd = map.get("time_end");

                    callbackBizDTO.setOutTradeNo(outTradeNo);
                    callbackBizDTO.setTradeNo(transactionId);
                    callbackBizDTO.setTotalAmount(Long.valueOf(cashFee));
                    callbackBizDTO.setPassbackParams(attach);
                    callbackBizDTO.setTradeStatus(returnCode);
                    callbackBizDTO.setAppid(appid);
                    callbackBizDTO.setMchId(mchId);
                    // 更新订单信息 发送通知等
                    Map<String, String> xml = new HashMap<String, String>(2);
                    xml.put("return_code", "SUCCESS");
                    xml.put("return_msg", "OK");
                    callbackBizDTO.setReturnStr(WxPayKit.toXml(xml));
                    return callbackBizDTO;
                }
            }
            log.error("wx回调验签失败::{}", map);
            return null;
        }
    }

最后封装需要返回的参数

这里需要注意最后的xml.put(),return PaymentKit.toXml(xml)一定要返回给微信,SUCCESS表示商户接收通知成功并校验成功,这样微信才会知道商户支付成功,否则会不断通知,这样就会重复处理数据,这个错误是致命的

上面回调我改了一下,可以做到闭嘴,不会重复通知

示例

下面就是测试调起微信支付

微信h5支付,微信外浏览器支付实现微信h5支付,微信外浏览器支付实现

微信h5支付,微信外浏览器支付实现微信h5支付,微信外浏览器支付实现

常见错误及注意事项:

1、网络环境未能通过安全验证,请稍后再试(IP改变导致的) 
2、商家参数格式有误,请联系商家解决(H5支付的referer为空导致) 
3、商家存在未配置的参数,请联系商家解决(H5支付的域名问题) 
4、支付请求已失效,请重新发起支付(有效期为5分钟) 

5、请在微信外打开订单,进行支付(H5支付不能直接在微信客户端内调起)

6.已经调起微信支付了,但是点击立即支付的时候报商家参数配置错误:有一种情况就是 调起支付参数比较严谨,需要填写真实IP,否则会报缺少参数,其次支付描述需要为当前业务描述

 

支付完成跳转

支付完成前端如果要跳转,可以设置微信下单返回的mweb_url+”&redirect_url=” + returnUrl;这样就能够跳转到指定地址,这个官方文档也有提到

 

 

支付说到底就是封装,安全调用,微信都是返回预支付id,要细心

 

支付服务代码设计(策略模式,可扩展,接入方便): https://blog.csdn.net/Goligory/article/details/106740171

 

需要项目源码的私我(源码包括设计)

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/135039.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 什么是云服务器ECS?云服务器ECS详解

    什么是云服务器ECS?云服务器ECS详解什么是云服务器ECS?云服务器ECS详解一、前言二、云服务器ECS详解为什么选择云服务器ECS?产品架构产品定价管理工具部署建议相关服务三、写在后面的话叮嘟!这里是小啊呜的学习课程资料整理。好记性不如烂笔头,今天也是努力进步的一天。一起加油进阶吧!一、前言云服务器ecs有什么作用?现在越来越多的企业都开始将服务器迁移至云端,云技术的应用十分广泛,其中之一就体现在云服务器的使用上,凭借更加简单的操作与便利等优势,云服务器可谓深受众多企业青睐二、云服务器ECS详解云服务器(ElasticComp

    2022年5月23日
    31
  • roboguide安装失败异常代码_ros安装教程unbuntu18.04

    roboguide安装失败异常代码_ros安装教程unbuntu18.04安装ROS时,报错:GPGerror:******isnotavailable:NO_PUBKEY******问题分析图片里的第三行提示信息:W:GPGerror:http://packages.ros.org/ros/ubuntuxenialInRelease:Thefollowingsignaturescouldn’tbeverifiedbeca…

    2022年10月10日
    4
  • 使用KNN识别MNIST手写数据集(手写,不使用KNeighborsClassifier)

    KNN识别MNIST手写数据集(32*32维),根据KNN原理一步步实现。

    2022年4月6日
    40
  • 关于ie下阻止ActiveX控件

    关于ie下阻止ActiveX控件
    最近,公司的项目上有个部分要用到ActiveX控件。可是在访问的时候,就会弹出”Internetexplorer已经阻止站点用不安全方式使用ActiveX控件”一句。查了好多资料,除了更改ie的安全设置,没有其他方法。
    更改ie安全设置,需要更改的几个地方:
    首先,Internet选项–>安全
    1.选中Internet –“自定义级别”– “ActiveX控件和插件 “–“对未标记为可安全执行脚本的ActiveX控件初始化并执行脚本”(启用

    2022年5月14日
    46
  • matlab as(assert dominance)

    目录一.语法1.输入参数二.说明三.示例1.值在预期范围之内2.期望的数据类型3.预期的代码执行情况assert是条件为false时引发错误。一.语法assert(cond)assert(cond,msg)assert(cond,msg,A1,…,An)assert(cond,errID,msg)assert(cond,errID,msg,A1,…,An)1.输入参数cond-断言条件MATLAB表达式..

    2022年4月15日
    41
  • phpstrom2021激活码(在线激活)

    phpstrom2021激活码(在线激活),https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月14日
    62

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号