日期:2023-08-02访问量:0类型:小程序制作资讯
这次是开发小程序的支付功能。 因为之前没有做过,所以特此记录一下,做个小总结,以备以后使用,也为像我这样的朋友提供参考。 我也一点一点摸索着。 本文仅针对支付流程的开发。 语言以及出现的问题,其他的就略过,只讲解实际的动手开发过程。
名词和实际开发API参见开发文档
而且我用的是普通模式
准备
1.打开微信支付平台成为普通商户,上传商户所需信息(这个不用我多说了)
2、配置小程序并获取appId(小程序项目与支付无关,只需要小程序的appId,其他的就不列出来了)
3、小程序appId与商户支付平台关联,如图:
4、微信支付平台(简称平台)设置密钥,(密钥为签名时要使用的密钥)如图:
然后进入主题。 首先,服务器后端项目需要添加依赖:
com.github.wxpay
wxpay-sdk
0.0.3
上面的依赖已经官方封装了支付方式和工具,使用起来非常方便,不需要按照API封装从基础一步步实现。 为我们省去了很多麻烦和麻烦。
您也可以从支付平台下载SDK并与demo对比查看具体内容。 内容和依赖关系是相同的。
如图所示:
现在开始看代码。 虽然封装了一些方法,但是项目还是需要配置自己的东西,比如appid、商户号、按键配置等。
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.小程序中调用登录接口获取用户的api,参见公共api【小程序登录API】
2、商户统一调用支付下单。 api请参考公共api【统一订单API】
3.商户调用重签,api参见公共api【重签】
4.商户收到支付通知,api见公共api【支付结果通知API】
5、商户查看支付结果。 若未收到支付通知,商户后台系统可调用【查询订单API】
按照这个顺序,我们的项目就准备好了,也就是第一步已经过去了,现在我们从第二步开始,
小程序登录后=是必须的,所以登录后可以保存获得的,以便以后支付时使用;
注意:
appid必须是最后拉出收银的小程序的appid;
是与appid配对的支付商户账户,收到的资金将进入商户账户;
请填写JSAPI;
是appid对应的用户ID,通过wx.login接口获取
登录后,进入商品页面,选择商品,点击支付。 第一步是下订单或者JSAPI订单。 完成此步骤后,返回获取参数值,用于后续调用支付接口。
让我们看看我们需要使用哪些参数:
下面还有几个参数。 你可以自己看API;
这些类被封装在依赖项中;
微信支付Java SDK
封装了微信支付开发者文档中给出的API。
com..wxpay.sdk.WXPay类提供了相应的方法:
方法名称说明
信用卡付款
统一订单
检查订单
取消订单
关闭订单
要求退款
询问退款事宜
下载声明
交易保护
转换短链接
授权码查询
那么接下来就可以使用上面的配置了
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.()方法,其作用是
添加appid,,,,标志到地图,
它会自动发送请求进行我们的加密签名、xml转换图等操作,我们只需接收返回的数据并再次调用小程序支付接口即可
/**
* 向 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.()来发起微信支付。
统一订单返回的参数:
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示例中没有。 如果不注意很容易被忽视。 问题,这个需要自己测试,我就不多演示了
至此,基本上就结束了,但是当我第一次发起这一步的时候,支付签名的验证总是失败。 我给大家讲一下改动的内容,原理需要同志们研究一下,
下面介绍几个小方法,调用起来比较方便:
// 时间戳
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)
}
})
})
至此,我已经完成了小程序支付,并且支付成功,很开心。
接下来我再把效果图放上来,然后这篇文章就结束了,请大家多多指教,有问题评论区见
TAG标签:微信小程序
日期:2024-11-10 浏览量:95
日期:2024-11-09 浏览量:82
日期:2024-11-07 浏览量:86
日期:2024-11-05 浏览量:70
日期:2024-11-03 浏览量:74
日期:2024-10-30 浏览量:59
日期:2024-10-26 浏览量:59
日期:2024-10-19 浏览量:84
日期:2024-09-25 浏览量:66