微信支付(微信支付密码设置)


这次呢是开发小程序的支付功能。因为没有做过微信支付,特此记录,做一个小总结,以便以后使用以及给小伙伴们提供一个像我一样的小白一个参考,我也是一点一点摸索过来的,此文只针对开发支付流程而言以及出现的问题,其它则会略过,只讲解实际动手开发过程 ,

名词和实际开发API看 开发文档

而我用的是普通模式

在这里插入图片描述

前期准备

1.开通微信支付平台 成为普通商户,上传商户所需信息(这个不用我多说)

2.配置小程序,获取appId (小程序项目也和支付无关,只需小程序的appId ,其它不表)

3.小程序appId 关联绑定商户支付平台 ,如图:

在这里插入图片描述

4.微信支付平台(简称平台)设置密钥,(密钥就是签名时要用的 key) 如图:

在这里插入图片描述

然后进入正题,首先服务器后端项目需要加入依赖:


	
		com.github.wxpay
		wxpay-sdk
		0.0.3
	

以上的依赖官方已经封装了支付的方法及工具,使用起来很是方便,完全不用从基础一步一步根据API 封装实现。省了我们不少麻烦和繁琐。

也可以从支付平台下载SDK和demo对比,查看具体的内容, 其内容和依赖是一样的。

如图:

在这里插入图片描述

现在开始看代码,虽然封装了一些方法,但是项目还是需要配置一下自己的东西,比如appid 、商户号以及key 的配置,

package com.xn.weixin.common;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import com.github.wxpay.sdk.WXPayConfig;
//  需要实现一下支付基本的配置,方便调用
	public class MyPayConfig implements WXPayConfig{
			private byte[] certData;
			public void MyConfig() throws Exception {
					//此处暂时用不到,这里是读取证书的地方
			}
		    public String getAppID() {
		        return "这里是你的appid";
		    }
		
		    public String getMchID() {
		    //申请普通商户时分配给你的商户号
		        return "这里是你的商户号";
		    }
		
		    public String getKey() {
		    //这里的key 就是你在支付平台设置的API密钥
		        return "这是就是你的Key了";
		    }
		
		    public InputStream getCertStream() {
		        ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
		        return certBis;
		    }
		
		    public int getHttpConnectTimeoutMs() {
		        return 8000;
		    }
		
		    public int getHttpReadTimeoutMs() {
		        return 10000;
		    }
}

接下来下一步,我们看API 文档中有下面几点:

商户系统和微信支付系统主要交互:

1、小程序内调用登录接口,获取到用户的openid,api参见公共api【小程序登录API】

2、商户server调用支付统一下单,api参见公共api【统一下单API】

3、商户server调用再次签名,api参见公共api【再次签名】

4、商户server接收支付通知,api参见公共api【支付结果通知API】

5、商户server查询支付结果,如未收到支付通知的情况,商户后台系统可调用【查询订单API】

按照这个顺序,我们的项目都准备好了,也就是第一步已经过了微信支付,我们现在正在从第二步开始,

小程序登录后 =openId 是必有的 所以登录后可以保存下获取的openId ,以方便以后 支付时使用;

在这里插入图片描述

注意:

appid必须为最后拉起收银台的小程序appid;

mch_id为和appid成对绑定的支付商户号,收款资金会进入该商户号;

trade_type请填写JSAPI;

openid为appid对应的用户标识,即使用wx.login接口获得的openid

登录后进入商品页面,选择商品后,点击支付button ,首先就是要统一下单或JSAPI 下单,完成这一步返回得到 prepay_id 参数值,后面调用支付API 要用到。

我们看一下我们需要用到哪些参数:

在这里插入图片描述

以下还有几个参数。大家可以自行看API ;

依赖中封装的就是这几个类;

在这里插入图片描述

微信支付 Java SDK

对微信支付开发者文档中给出的API进行了封装。

com.github.wxpay.sdk.WXPay类下提供了对应的方法:

方法名说明

microPay

刷卡支付

unifiedOrder

统一下单

orderQuery

查询订单

reverse

撤销订单

closeOrder

关闭订单

refund

申请退款

refundQuery

查询退款

downloadBill

下载对账单

report

交易保障

shortUrl

转换短链接

authCodeToOpenid

授权码查询openid

所以接下来上面配置好的config 就可以用到了

package com.xn.weixin.controller;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConstants.SignType;
import com.github.wxpay.sdk.WXPayUtil;
import com.xn.system.entity.User;
import com.xn.util.ResultObj;
import com.xn.weixin.common.MyPayConfig;
@RestController
@RequestMapping("/pay/")
public class PaymentController {
@RequestMapping("payment")
public Object getpayment(HttpServletRequest request,String totalfee,String tradeno) throws Exception {
//	获取到当前登录用户,因为这里我保存了openid , 方法大家可以自己处理,这里就不展示了
	User user = User.getCurrentUserInfo().getUser();
	//当前就是我们自己配置的支付配置。appid 商户号 key 什么的;
	MyPayConfig config = new MyPayConfig(); 
	//当前类是官方为我们封装的一些使用的方法
    WXPay wxpay = new WXPay(config);
    //获取到 IP 
    String clientIp = getIpAddress(request);
	System.err.println(clientIp);
	//封装请求参数 参数说明看API文档,当前就不进行讲解了
    Map data = new HashMap();
    data.put("body", "腾讯充值中心-QQ会员充值");
    data.put("out_trade_no", "2016090910595900000012");
    data.put("device_info", "12345679"); //此处设备或商品编号
    data.put("fee_type", "CNY");  // 货币类型  人民币
    
     // 支付中没有小数点,起步以分做为单们,当前为1 分钱,所以自行调整金额 ,这里可以做为传参,
     //选取商品金额传到后端来
     data.put("total_fee", "1"); 
     
    data.put("spbill_create_ip", "123.12.12.123");
    data.put("notify_url", "http://www.example.com/wxpay/notify");
    data.put("trade_type", "JSAPI");  // 此处指定JSAPI
    data.put("product_id", "12");
    data.put("openid", “这是是登录获取到的openId  必传”);
    //调用统一下单方法
    Map order = wxpay.unifiedOrder(data);
    //获取到需要的参数返回小程序
	return order;
	
}
// 获取 IP
public static String getIpAddress(HttpServletRequest request) {
	String ip = request.getHeader("x-forwarded-for");
	if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
		ip = request.getHeader("Proxy-Client-IP");
	}
	if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
		ip = request.getHeader("WL-Proxy-Client-IP");
	}
	if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
		ip = request.getHeader("HTTP_CLIENT_IP");
	}
	if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
		ip = request.getHeader("HTTP_X_FORWARDED_FOR");
	}
	if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
		ip = request.getRemoteAddr();
	}
	return ip;
}
}

大家可能要问了,为什么这里没有放入 appid 和 mchid 和 key,sign 签名

其实我们上面依赖中已经封装了,会自动获取到我们自己配置的 appid mchid 和key ,放入集合然后进行签名加密,下面看依赖中的方法:

在这里插入图片描述

我们找到这个方法看看具体内容:

/**
     * 作用:统一下单
* 场景:公共号支付、扫码支付、APP支付 * @param reqData 向wxpay post的请求数据 * @return API返回数据 * @throws Exception */ public Map unifiedOrder(Map reqData) throws Exception { return this.unifiedOrder(reqData, config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs()); } /** * 作用:统一下单
* 场景:公共号支付、扫码支付、APP支付 * @param reqData 向wxpay post的请求数据 * @param connectTimeoutMs 连接超时时间,单位是毫秒 * @param readTimeoutMs 读超时时间,单位是毫秒 * @return API返回数据 * @throws Exception */ public Map unifiedOrder(Map reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception { String url; if (this.useSandbox) { url = WXPayConstants.SANDBOX_UNIFIEDORDER_URL_SUFFIX; } else { url = WXPayConstants.UNIFIEDORDER_URL_SUFFIX; } if(this.notifyUrl != null) { reqData.put("notify_url", this.notifyUrl); } String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs); return this.processResponseXml(respXml); }

以上中最后第二行用到了这个方法 this.fillRequestData(reqData),其作用就是

向 Map 中添加 appid、mch_id、nonce_str、sign_type、sign ,

它自动为我们加密签名 发送请求,xml 转换map 等操作,我们只需要接收返回的数据再次调用小程序支付API 就可以了

	 /**
 * 向 Map 中添加 appid、mch_id、nonce_str、sign_type、sign 
* 该函数适用于商户适用于统一下单等接口,不适用于红包、代金券接口 * * @param reqData * @return * @throws Exception */ public Map fillRequestData(Map reqData) throws Exception { reqData.put("appid", config.getAppID()); reqData.put("mch_id", config.getMchID()); reqData.put("nonce_str", WXPayUtil.generateNonceStr()); if (SignType.MD5.equals(this.signType)) { reqData.put("sign_type", WXPayConstants.MD5); } else if (SignType.HMACSHA256.equals(this.signType)) { reqData.put("sign_type", WXPayConstants.HMACSHA256); } reqData.put("sign", WXPayUtil.generateSignature(reqData, config.getKey(), this.signType)); return reqData; }

当我们小程序接收到服务器返回的参数数据,我们就可以再次调用wx.requestPayment(Object)发起微信支付。

统一下单返回的参数:

在这里插入图片描述

var data = {
		变量:金额什么的参数
}
	//小程序封装的post请求 
	action.post("请求url",“data参数”,function( res){
	//支付请求 但是此处有大坑,一定要注意,
	
	wx.requestPayment(
		{
		"timeStamp":"",
		"nonceStr": "",
		"package": "",
		"signType": "MD5",
		"paySign": "",
		"success":function(res){},
		"fail":function(res){},
		"complete":function(res){}
	})
	})

但是此处有大坑,一定要注意,

//api上说是只有五个参数 实际上还有一个 appid 需要加上,api 中也有说起过,但是发起支付api 示例上没有,一不注意就容易忽略掉,如果没有appid 总是报支付问题,这个需要你们自己测试了,我就不多加演示了

至此基本算是完结了,但是我刚开始发起这一步的时候总是出现 支付签名验证失败,怎么也过不去,卡了两天,后来我虽然做出来了,但是我还没有深入理解,我现在只能把改动的内容告诉你们,原理就需要同志们自己研究啦,

下面是几个小方法,调用比较方便:

	// 时间戳
timeStamp:function () {
  return parseInt(new Date().getTime() / 1000) + ''
},
/* 随机数 */
randomString:function () {
  var chars = 'A2345678';    
  var maxPos = chars.length;
  var pwd = '';
  for (var i = 0; i < 32; i++) {
    pwd += chars.charAt(Math.floor(Math.random() * maxPos));
  }
  return pwd;
},
  // 调起支付签名    这里我不太明白,虽然前面加载签名和后面验证,但里面加了随机数为什么验证还能通过我没还转过	      弯来,希望大家能搞明白吧,到时候可不要吝啬留言讲解一下下
MixedencryMD5:function (data,randomString,timeStamp) {
  var pay =  "appId=" + config.appid + "&nonceStr=" + randomString + "&package=prepay_id=" + data.prepay_id + 		  "&signType=MD5" + "&timeStamp=" + timeStamp+ "&key=" + config.key;  
  console.log(md5.hexMD5(pay))
  return  md5.hexMD5(pay);
},

完整的调用小程序支付:

changePayment:function(){
  var that = this;
  var fee = that.data.inputValue*100;
  //小程序封装的post请求 
	action.post("请求url",“data参数”,function( res){
	//支付请求 但是此处有大坑,一定要注意,
	
    //随机数  
    var randomString = that.randomString();
    //当前时间
    var time = that.timeStamp();
    //签名
    var parSigns = that.MixedencryMD5(res.data,randomString,time);
      wx.requestPayment({ 
        appId:config.appid,
        timeStamp: time,
        nonceStr: randomString,
        package: "prepay_id="+res.data.prepay_id,
        signType: "MD5",
        paySign: parSigns,
        success (ress) {
          console.log(ress)
        },
        fail (ress) {
          console.log(ress)
        }
      })
    
  })

到此小程序支付我已经完成了,并且成功支付,挺开心。

下面我再放一下效果图,然后本文就结束了,请大拿多多指教,有问题就评论区见吧

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站不拥有所有权,不承担相关法律责任。如发现有侵权/违规的内容, 联系QQ3361245237,本站将立刻清除。