微信支付采坑记录(java后端 一:微信支付调用从哪一步开始)

普通商户模式微信支付之APP支付统一下单:

前言:

最近项目开发到微信支付的模块,经过一周的不懈努力,虽然微信支付流程跑通了,但当时的那些坑是真的烦,为了避免自己以后犯同样的错误,当然还有各位新接触微信支付的同仁们闭坑,所以自我觉得还是有必要写个博客记录记录,顺便提高一下自己的总结能力以及表达能力。

为了更加详细的记录微信支付的整个流程,我还是从微信支付的开发文档说起:
微信支付开发文档地址(我这里使用的微信支付V2版本开发文档):https://pay.weixin.qq.com/wiki/doc/api/index.html

打开链接会进入如下图的页面:
在这里插入图片描述
可以看到页面的上部分分别有 普通商户版 服务商版 和 银行服务商版 三个版本的文档 分类

还是要说一下区别:(自我理解的)

普通商户版:就是在微信商户平台使用企业公司资质等信息申请开通的微信普通商户,开通完成后会微信会分配一个商户号(mch_id)商户密钥(mch_secret),是在调用支付接口时使用的重要参数。

服务商版:大致和普通商户的申请规则一样,只不过可能会多一些申请资料之类的,经过微信审核通过,则成为微信支付服务商,服务商下面可以邀请多个子商户进入,服务商相当于就是一个管理员可以管理这些子商户,我们把这些子商户称为特约商户,同样微信支付也会给服务商商户分配 服务商商户号和服务商商户密钥 用于 提供其相关支付能力。

银行服务商版:暂时没有接触到,但大致原理都一样,需要银行资质申请,但其中支付产品较少。

在这里我先说一说普通商户版文档里面的APP支付这一支付产品

点击进入看到如下页面:侧边栏的文档说明,术语,支付账户,接口规则,运营规范这些等等都可以自己去看,可以仔细研究研究,因为可能很多支付遇到的细节性问题里面都能找到答案。我这里就不具体一一介绍了,直接进入正题,API列表

在这里插入图片描述
点击进入API列表:如下图,可以看到许多微信支付提供的对外接口,如统一下单,申请退款等。具体要查看哪一个文档,点击进入就行了。
在这里插入图片描述

在这里要先说一下自己理解的APP支付这一支付产品的支付流程:

1、前端选择商品提交订单,跳转到支付页面选择支付方式;
2、选择微信支付后,请求java后端根据微信app支付文档写好的的统一下单接口;
3、这个统一下单的接口在请求微信那边过后会返给前端一些重要的参数,用于唤醒手机app里的微信支付;
4、在统一下单接口中我们会给微信服务器那边一个回调地址路径,用户微信服务回调我们自己系统的通知接口,用于响应微信服务订单是否支付成功;

在写代码之前要做好微信支付的一些准备:

1、java项目中的配置文件配置好微信支付需要的相关参数,如你 应用 appid,应用 appsecret,商户号 mch_id,商户密钥
mch_secret 回调地址接口路径 2、要将应用 appid 和你的商户 产生绑定关系,这个可以在微信公众平台去绑定
3、要有切实可行的运行环境,保证微信回调可以成功。
4、有些微信API接口还需要商户证书文件,需要去商户平台下载并放置到你的项目中的resources文件夹下

准备工作完成之后就可以安心写代码了,不多说了,直接上代码:

统一下单接口:

 @RequestMapping("/wxAppPay")
    public ResBean<Object> wxAppPay(@RequestBody ReqWxPayBean reqWxPayBean, HttpServletRequest request){
    
    	// 响应数据体
        ResBean<Object> resBean = new ResBean<>();
        
        //根据订单号去数据库拿出对应订单的价格(如果是前端传值价格的话可能会有风险,所以后端从数据库获取订单价格,单位为分)
        Long price = orderTooler.fetchPrice(reqWxPayBean.getPayOutTradeNo(), reqWxPayBean.getSessionId());
        
        //添加app唤醒支付所需支付信息的参数
        LinkedHashMap<String, String> params = new LinkedHashMap<>();
        params.put("appid", appId);//如果是app支付则为应用appid
        params.put("attach", reqWxPayBean.getSessionId());
        params.put("body", reqWxPayBean.getPayBody());
        params.put("mch_id", mchId);//商户的商户号
        params.put("nonce_str", Long.toString(System.currentTimeMillis() / 1000));// 随机字符串
        params.put("notify_url", couponNoticeUrl);  // 支付成功回调地址
        params.put("out_trade_no", reqWxPayBean.getPayOutTradeNo());   // 自己系统生成的订单号
        params.put("spbill_create_ip", PayUtils.getIp(request));   // ip
        params.put("total_fee", String.valueOf(price));   // 订单总价,单位为分
        params.put("trade_type", String.valueOf(WxPayApi.TradeType.APP));  // 指定支付方式,为app支付
        params.put("sign", PayUtils.getSign(params, mchSecret));   // 构造签名,这里的构造签名的方式的代码在后面说明

        //提交到微信服务器,这里的这个HttpUtils.post(“统一下单接口路径”,“xml格式的请求参数”),是微信提供的sdk里面的方法
        //package com.jfinal.weixin.sdk.utils;
        // PaymentKit来源于(package com.jpay.ext.kit;)
        String post = HttpUtils.post("https://api.mch.weixin.qq.com/pay/unifiedorder", PaymentKit.toXml(params));
        //4、解析xml格式的数据为map集合
        Map<String, String> result = PaymentKit.xmlToMap(post);

        //5、获得返回状态码
        String return_code = result.get("return_code");
        String result_code = result.get("result_code");
        String err_code = result.get("err_code");
        String err_code_des = result.get("err_code_des");
        String return_msg = result.get("return_msg");

        if (PaymentKit.codeIsOK(return_code)) {
            if (PaymentKit.codeIsOK(result_code)) {
            // 成功之后将一下参数返回给前端人员用于唤醒app支付
                Map<String, String> parameterMap = new LinkedHashMap<>();
                //非空参数值的参数按照参数名ASCII码从小到大排序(字典序)
                parameterMap.put("appid",appId);//服务商申请的公众号或移动应用appid。
                parameterMap.put("mch_id",result.get("mch_id"));  // 商户号
                parameterMap.put("nonce_str",String.valueOf(result.get("nonce_str")));  // 随机字符串
                parameterMap.put("packageValue", "Sign=WXPay");  // 默认为Sign=WXPay
                parameterMap.put("prepay_id", String.valueOf(result.get("prepay_id")));// 调用微信接口之后生成的预支付id最重要的参数
                parameterMap.put("timestamp", Long.toString(System.currentTimeMillis() / 1000));//时间戳
                Map<String, String> map = new LinkedHashMap<>();
                map.put("appid", appId);
                map.put("noncestr", String.valueOf(result.get("nonce_str")));
                map.put("package", "Sign=WXPay");
                map.put("partnerid", result.get("sub_mch_id"));
                map.put("prepayid", String.valueOf(result.get("prepay_id")));
                map.put("timestamp", Long.toString(System.currentTimeMillis() / 1000));//时间戳
                parameterMap.put("sign",PayUtils.getSign(map,serverMchSecret));

                resBean.setRes_code("0000");
                resBean.setRes_desc(result_code);
                resBean.setRes_content(parameterMap);
            } else {
                resBean.setRes_code("9999");
                resBean.setRes_desc(err_code_des);
                resBean.setRes_content(err_code);
            }
        } else {
            resBean.setRes_code("9999");
            resBean.setRes_desc(return_msg);
            resBean.setRes_content(err_code);
        }
        return resBean;
    }

辅助工具方法:

// PayUtils.getSign(params, mchSecret)  params:参与签名的参数,mchSecret:商户密钥
 public static String getSign(Map<String, String> params, String paternerKey){
        return MD5Utils.MD5Encode(createSign(params, false) + "&key=" + paternerKey,"utf-8").toUpperCase();
    }

//MD5Utils.MD5Encode(createSign(params, false) + "&key=" + paternerKey,"utf-8")  md5加密
public static String MD5Encode(String origin, String charsetname) {
		String resultString = null;
		try {
			resultString = new String(origin);
			MessageDigest md = MessageDigest.getInstance("MD5");
			if (charsetname == null || "".equals(charsetname))
				resultString = byteArrayToHexString(md.digest(resultString
						.getBytes()));
			else
				resultString = byteArrayToHexString(md.digest(resultString
						.getBytes(charsetname)));
		} catch (Exception exception) {
		}
		return resultString;
	}

这里仅仅只是微信支付里面普通商户模式的app统一下单一个模块的记录,后面还会继续更新其他微信支付相关的采坑记录。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值