2023微信支付对接全流程

这篇具有很好参考价值的文章主要介绍了2023微信支付对接全流程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

简单说一下微信支付的几种类型的应用场景以及前提条件
官方文档:https://pay.weixin.qq.com/wiki/doc/apiv3/index.shtml

前提条件:

1.需要一个载体公众号或者小程序,公众号要是服务号不是订阅号。
2.小程序和公众号支付都要认证,要300rmb。
3.需要一个商户号,绑定公众号或者小程序。

1.jsapi支付:

就是在微信平台内,微信内置浏览器或者小程序唤起微信支付

对接流程:

在自己的后台请求微信接口下预订单,然后将下单参数各种加密传到前端,用微信浏览器内置对象方法唤起支付WeixinJSBridge.invoke,小程序用
wx.requestPayment唤起支付,用户支付成功后将回调给你在下单参数中的回调地址,你再根据订单号自己处理结果。注意,两个方法的参数名相同,但是小程序支付唤起参数requestPayment下单接口参数中的openid和appid必须用小程序的,微信浏览器的同理。

2.h5支付:

普通浏览器,或者app的webview里面访问下单接口返回的h5_url,可通过访问该url来拉起微信客户端,完成支付。

对接流程:

在自己的后台请求微信接口下预订单,然后接口返回h5_url,前端浏览器访问这个url即可唤起客户端。

3Native下单

生成二维码,用户扫码支付,这个比较适用于PC网站等非移动端。

对接流程:

在自己的后台请求微信接口下预订单,然后接口返回code_url,将这个code_url转换成二维码即可。

以上这几个几乎满足所有需求情况了,上点代码,研究全流程细节和坑点

开发示例

这里jspapi为例
1.申请个公众号 https://mp.weixin.qq.com,必须是服务号不然无法开通支付。
2.在后台通过微信认证,要不然商户号没办法绑定你的公众号
2023微信支付对接全流程
3.申请个商户号 https://pay.weixin.qq.com/
4.商户号绑定公众号,在商户号后台
2023微信支付对接全流程
5.这里开始看后台代码,接口参数缺的我们再找,首先微信支付的加密解密签名太复杂,而且也不是我们关注的点,已经有大佬写好了,IJPay,不仅微信,还封装了、支付宝支付、银联支付常用的支付方式以及各种常用的接口,源码及示例工程gitee :https://gitee.com/luozhizkang/IJPay
也可以引个maven,这里只引微信支付需要的

		<dependency>
            <groupId>com.github.javen205</groupId>
            <artifactId>IJPay-WxPay</artifactId>
            <version>2.9.4</version>
        </dependency>

6.参数准备类

@Component
@Data
public class WxPayV3Bean {
    @Value("${wxPay.appId}")
    private String appId ;//小程序appid
    @Value("${wxPay.keyPath}")
    private String keyPath;
    @Value("${wxPay.certPath}")
    private String certPath ;
    @Value("${wxPay.certP12Path}")
    private String certP12Path ;
    @Value("${wxPay.platformCertPath}")
    private String platformCertPath ;
    @Value("${wxPay.mchId}")
    private String mchId;//商户号mchId
    @Value("${wxPay.apiKey}")
    private String apiKey ;
    @Value("${wxPay.apiKey3}")
    private String apiKey3 ;
    @Value("${wxPay.domain}")
    private String domain;//支付成功回调地址
}

剩下这几个参数怎么获取呢?
2023微信支付对接全流程
在商户平台中按照指引“申请api证书”,会得到几个文件
2023微信支付对接全流程
keyPath就是 apiclient_key.pem的绝对路径,例如:D://xxx/apiclient_key.pem
certPath就是 apiclient_cert.pem的绝对路径
certP12Path就是 apiclient_cert.p12的绝对路径
platformCertPath 等会要根据上面的秘钥和证书生成一个文件名字叫platformCertPath.pem,你只需要将绝对路径写好在这就行了,后面程序启动再通过接口下载。例如:D://xxx/platformCertPath.pem
apiKey 可以不用填。
domain就是支付成功的回调地址,这个回调地址的域名要在商户平台配置。

建个controller

@RestController
@RequestMapping("/api/v3")
public class WxPayV3Controller {
	private final Logger log = LoggerFactory.getLogger(this.getClass());
	private final static int OK = 200;

	@Resource
	WxPayV3Bean wxPayV3Bean;

	String serialNo;
	String platSerialNo;

	@RequestMapping("/getSerialNumber")
	@ResponseBody
	public String serialNumber() {
		return getSerialNumber();
	}

	@RequestMapping("/getPlatSerialNumber")
	@ResponseBody
	public String platSerialNumber() {
		return getPlatSerialNumber();
	}

	private String getSerialNumber() {
		if (StrUtil.isEmpty(serialNo)) {
			// 获取证书序列号
			X509Certificate certificate = PayKit.getCertificate(wxPayV3Bean.getCertPath());
			if (null != certificate) {
				serialNo = certificate.getSerialNumber().toString(16).toUpperCase();
				// 提前两天检查证书是否有效
				boolean isValid = PayKit.checkCertificateIsValid(certificate, wxPayV3Bean.getMchId(), -2);
				log.info("证书是否可用 {} 证书有效期为 {}", isValid, DateUtil.format(certificate.getNotAfter(), DatePattern.NORM_DATETIME_PATTERN));
			}
//            System.out.println("输出证书信息:\n" + certificate.toString());
//            // 输出关键信息,截取部分并进行标记
//            System.out.println("证书序列号:" + certificate.getSerialNumber().toString(16));
//            System.out.println("版本号:" + certificate.getVersion());
//            System.out.println("签发者:" + certificate.getIssuerDN());
//            System.out.println("有效起始日期:" + certificate.getNotBefore());
//            System.out.println("有效终止日期:" + certificate.getNotAfter());
//            System.out.println("主体名:" + certificate.getSubjectDN());
//            System.out.println("签名算法:" + certificate.getSigAlgName());
//            System.out.println("签名:" + certificate.getSignature().toString());
		}
		System.out.println("serialNo:" + serialNo);
		return serialNo;
	}

	private String getPlatSerialNumber() {
		if (StrUtil.isEmpty(platSerialNo)) {
			// 获取平台证书序列号
			X509Certificate certificate = PayKit.getCertificate(FileUtil.getInputStream(wxPayV3Bean.getPlatformCertPath()));
			platSerialNo = certificate.getSerialNumber().toString(16).toUpperCase();
		}
		System.out.println("platSerialNo:" + platSerialNo);
		return platSerialNo;
	}

	private String savePlatformCert(String associatedData, String nonce, String cipherText, String certPath) {
		try {
			AesUtil aesUtil = new AesUtil(wxPayV3Bean.getApiKey3().getBytes(StandardCharsets.UTF_8));
			// 平台证书密文解密
			// encrypt_certificate 中的  associated_data nonce  ciphertext
			String publicKey = aesUtil.decryptToString(
				associatedData.getBytes(StandardCharsets.UTF_8),
				nonce.getBytes(StandardCharsets.UTF_8),
				cipherText
			);
			// 保存证书
			FileWriter writer = new FileWriter(certPath);
			writer.write(publicKey);
			// 获取平台证书序列号
			X509Certificate certificate = PayKit.getCertificate(new ByteArrayInputStream(publicKey.getBytes()));
			return certificate.getSerialNumber().toString(16).toUpperCase();
		} catch (Exception e) {
			e.printStackTrace();
			return e.getMessage();
		}
	}

	@RequestMapping("/get")
	@ResponseBody
	public String v3Get() {
		// 获取平台证书列表
		try {
			IJPayHttpResponse response = WxPayApi.v3(
				RequestMethodEnum.GET,
				WxDomainEnum.CHINA.toString(),
				OtherApiEnum.GET_CERTIFICATES.toString(),
				wxPayV3Bean.getMchId(),
				getSerialNumber(),
				null,
				wxPayV3Bean.getKeyPath(),
				""
			);

			String timestamp = response.getHeader("Wechatpay-Timestamp");
			String nonceStr = response.getHeader("Wechatpay-Nonce");
			String serialNumber = response.getHeader("Wechatpay-Serial");
			String signature = response.getHeader("Wechatpay-Signature");

			String body = response.getBody();
			int status = response.getStatus();

			log.info("serialNumber: {}", serialNumber);
			log.info("status: {}", status);
			log.info("body: {}", body);
			int isOk = 200;
			if (status == isOk) {
				JSONObject jsonObject = JSONUtil.parseObj(body);
				JSONArray dataArray = jsonObject.getJSONArray("data");
				// 默认认为只有一个平台证书
				JSONObject encryptObject = dataArray.getJSONObject(0);
				JSONObject encryptCertificate = encryptObject.getJSONObject("encrypt_certificate");
				String associatedData = encryptCertificate.getStr("associated_data");
				String cipherText = encryptCertificate.getStr("ciphertext");
				String nonce = encryptCertificate.getStr("nonce");
				String serialNo = encryptObject.getStr("serial_no");
				final String platSerialNo = savePlatformCert(associatedData, nonce, cipherText, wxPayV3Bean.getPlatformCertPath());
				log.info("平台证书序列号: {} serialNo: {}", platSerialNo, serialNo);
			}
			// 根据证书序列号查询对应的证书来验证签名结果
			boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
			System.out.println("verifySignature:" + verifySignature);
			return body;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	@RequestMapping("/nativePay")
	@ResponseBody
	public String nativePay() {
		try {
			String timeExpire = DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3);
			UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
				.setAppid(wxPayV3Bean.getAppId())
				.setMchid(wxPayV3Bean.getMchId())
				.setDescription("IJPay 让支付触手可及")
				.setOut_trade_no(PayKit.generateStr())
				.setTime_expire(timeExpire)
				.setAttach("微信系开发脚手架 https://gitee.com/javen205/TNWX")
				.setNotify_url(wxPayV3Bean.getDomain().concat("/v3/payNotify"))
				.setAmount(new Amount().setTotal(1));

			log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
			IJPayHttpResponse response = WxPayApi.v3(
				RequestMethodEnum.POST,
				WxDomainEnum.CHINA.toString(),
				BasePayApiEnum.NATIVE_PAY.toString(),
				wxPayV3Bean.getMchId(),
				getSerialNumber(),
				null,
				wxPayV3Bean.getKeyPath(),
				JSONUtil.toJsonStr(unifiedOrderModel)
			);
			log.info("统一下单响应 {}", response);
			// 根据证书序列号查询对应的证书来验证签名结果
			boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
			log.info("verifySignature: {}", verifySignature);
			return response.getBody();
		} catch (Exception e) {
			e.printStackTrace();
			return e.getMessage();
		}
	}

	@RequestMapping("/jsApiPay")
	@ResponseBody
	public String jsApiPay(@RequestParam(value = "openId", required = false, defaultValue = "o-_-itxuXeGW3O1cxJ7FXNmq8Wf8") String openId) {
		try {
			String timeExpire = DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3);
			UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
				.setAppid(wxPayV3Bean.getAppId())
				.setMchid(wxPayV3Bean.getMchId())
				.setDescription("IJPay 让支付触手可及")
				.setOut_trade_no(PayKit.generateStr())
				.setTime_expire(timeExpire)
				.setAttach("微信系开发脚手架 https://gitee.com/javen205/TNWX")
				.setNotify_url(wxPayV3Bean.getDomain().concat("/v3/payNotify"))
				.setAmount(new Amount().setTotal(1))
				.setPayer(new Payer().setOpenid(openId));

			log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
			IJPayHttpResponse response = WxPayApi.v3(
				RequestMethodEnum.POST,
				WxDomainEnum.CHINA.toString(),
				BasePayApiEnum.JS_API_PAY.toString(),
				wxPayV3Bean.getMchId(),
				getSerialNumber(),
				null,
				wxPayV3Bean.getKeyPath(),
				JSONUtil.toJsonStr(unifiedOrderModel)
			);
			log.info("统一下单响应 {}", response);
			// 根据证书序列号查询对应的证书来验证签名结果
			boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
			log.info("verifySignature: {}", verifySignature);
			if (response.getStatus() == OK && verifySignature) {
				String body = response.getBody();
				JSONObject jsonObject = JSONUtil.parseObj(body);
				String prepayId = jsonObject.getStr("prepay_id");
				//这些参数传到前端去,是小程序或者微信浏览器唤起支付的参数
				Map<String, String> map = WxPayKit.jsApiCreateSign(wxPayV3Bean.getAppId(), prepayId, wxPayV3Bean.getKeyPath());
				log.info("唤起支付参数:{}", map);
				return JSONUtil.toJsonStr(map);
			}
			return JSONUtil.toJsonStr(response);
		} catch (Exception e) {
			e.printStackTrace();
			return e.getMessage();
		}
	}
	
	//支付成功回调
	@RequestMapping(value = "/payNotify", method = {org.springframework.web.bind.annotation.RequestMethod.POST, org.springframework.web.bind.annotation.RequestMethod.GET})
	@ResponseBody
	public void payNotify(HttpServletRequest request, HttpServletResponse response) {
		Map<String, String> map = new HashMap<>(12);
		try {
			String timestamp = request.getHeader("Wechatpay-Timestamp");
			String nonce = request.getHeader("Wechatpay-Nonce");
			String serialNo = request.getHeader("Wechatpay-Serial");
			String signature = request.getHeader("Wechatpay-Signature");

			log.info("timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);
			String result = HttpKit.readData(request);
			log.info("支付通知密文 {}", result);

			// 需要通过证书序列号查找对应的证书,verifyNotify 中有验证证书的序列号
			String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
				wxPayV3Bean.getApiKey3(), wxPayV3Bean.getPlatformCertPath());

			log.info("支付通知明文 {}", plainText);

			if (StrUtil.isNotEmpty(plainText)) {
				//完成订单充值
				com.alibaba.fastjson.JSONObject plain = com.alibaba.fastjson.JSONObject.parseObject(plainText);
				orderService.updateOrderStatus(plain.getString("out_trade_no"));

				response.setStatus(200);
				map.put("code", "SUCCESS");
				map.put("message", "SUCCESS");
			} else {
				response.setStatus(500);
				map.put("code", "ERROR");
				map.put("message", "签名错误");
			}
			response.setHeader("Content-type", ContentType.JSON.toString());
			response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
			response.flushBuffer();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

上面的代码也是从IJPay的示例工程中copy来的,如果运行有什么问题直接去gitee去复制源码,我上面有贴gitee地址
启动成功后,调用 /get 接口下载 platformCertPath.pem
调用 /jsApiPay 接口生成微信预支付订单,并将参数传到前端,唤起支付,用户支付成功后会回调到 /payNotify 接口,但是回调地址的域名必须在商户后台配置过,在产品中心->开发配置 里面设置业务域名,如果是本地调试,可以用花生壳或者natapp伪装一个域名,建议用natapp。
前端唤起:
微信浏览器

//order是调用/jsApiPay接口返回的参数
WeixinJSBridge.invoke('getBrandWCPayRequest', order,
					function(res) {
						if (res.err_msg == "get_brand_wcpay_request:ok") {
							// 使用以上方式判断前端返回,微信团队郑重提示:
							//res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
							
						} else {
							
						}
					});

小程序

//order是调用/jsApiPay接口返回的参数
wx.requestPayment({
            'timeStamp':order.timeStamp,
            'nonceStr': order.nonceStr,
            'package': order.package,
            'signType': order.signType,
            'paySign': order.paySign,
            'success':function(res){
               
            },
            'fail':function(res){
             
            },
          })

这里一定要记得 /jsApiPay接口的 openid 如果是公众号的方式获取的,wxPayV3Bean.getAppId 也要是公众号的appid,小程序同理。
openid是微信的 相对于载体的用户唯一标识,公众号用户openid获取方式文档:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html
用户openid获取简单流程就是
1.引导用户访问
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
scope 为snsapi_base时只能获取appid ,scope为snsapi_userinfo 可以获取用户的具体信息,可以来做微信登录(其他参数自己文档里看)
用授权成功后候回调到 REDIRECT_URI 并带着参数code
2.拿这个code到后台
访问接口
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
获得用户的 appid

以上就是本人对接微信支付的过程记录,如果碰到什么问题欢迎大家留言讨论文章来源地址https://www.toymoban.com/news/detail-445744.html

到了这里,关于2023微信支付对接全流程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • java对接微信支付:JSAPI支付(微信公众号支付)

    本文是【微信JSAPI支付】文章,主要讲解商户对接微信支付,简洁版测试 文章目录 一、JSAPI支付接入前准备 二、代码片段 1.引入Maven依赖 2.后端业务请求接口 3.前端调起支付请求方法 总结 1、JSAPI支付首先需要注册、认证一个公众号(大概300块一年) 微信公众号注册 2、申请成为

    2024年02月08日
    浏览(62)
  • 对接微信支付接口

    https://pay.weixin.qq.com/wiki/doc/api/index.html 1.准备工作: 在微信上申请服务号类型的公众号,从公众号获取以下数据 appid:微信公众账号或开放平台APP的唯一标识 mch_id:商户号 (配置文件中的partner) partnerkey:商户密钥 2. 根据项目需求选择适合的支付方式,本例使用Native支付方式

    2024年02月13日
    浏览(60)
  • 微信建行支付对接

    建行微信支付 代码参考 java实现对接建行支付及其回调 参考链接一 微信小程序使用建行支付 参考链接二 微信小程序,调用建行支付 参开链接三 集成建行聚合支付踩过的坑,有些槽不吐不快 建行支付里三大步骤与坑 验签也有顺序 Java实现建行聚合支付对接及其回调 这里我

    2023年04月08日
    浏览(44)
  • java对接微信支付:JSAPI支付成功之“微信回调”

    承接上一篇微信支付,现在简单说一下 微信支付回调 目录 一、支付回调 二、微信回调地址问题 1.本地/上线测试 2.控制器调用接口(代码) 总结 当用户支付成功之后,支付平台会向我们指定的服务器接口发送请求传递订单支付状态数据 如果你是再本地进行测试,那就需要使用

    2024年02月12日
    浏览(41)
  • 微信小程序支付-java对接微信

     一共是两个方法: 一个方法后台生成预支付订单,得到预支付交易会话标识prepay_id,传给前端,让前端调起小程序支付; 一个是支付回调 目录 一、生成预支付订单  注意: 二、 支付回调         封装参数向微信发送生成预支付交易单请求,微信会返回一个prepay_id,再将

    2024年02月12日
    浏览(50)
  • 微信小程序对接微信支付详细教程

    小程序 微信支付官方文档 https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_11index=2 https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_8_0.shtml 前提 在进行对接微信支付之前,我们首先需要将以下几点准备好: 申请APPID 申请商户号 小程序开通微信支付,绑定已经申请好的商户号。

    2024年02月09日
    浏览(49)
  • SpringBoot对接小程序微信支付

    目录 前言 一、准备工作 2.1、企业微信小程序开通 2.1.1、获取开发者ID 2.1.2、开通支付功能 2.1.3、关联商户号 2.2、企业商户号的开通 2.2.1、获取商户号mch_id 2.2.2、获取商户API密钥mch_key 二、整体流程 三、后端项目搭建 3.1、统一下单 3.2、支付支付回调 3.3、问题排查 3.4、统一下

    2024年02月04日
    浏览(53)
  • SpringBoot对接微信小程序支付功能开发(二,支付回调功能)

    接着上一篇: SpringBoot对接微信小程序支付功能开发(一,下单功能) 在上一篇下单功能中我们有传支付结果回调地址。 下面是回调接口实现 根据官网给的参数进行业务处理 这就完成了,微信支付回调你的地址,并且把支付的信息传进来,剩下就要根据自己业务进行操作。

    2024年02月11日
    浏览(65)
  • 微信小程序对接微信支付所遇问题合集

    1. 后端使用微信官方sdk会简单很多,可以看看在第五个大标题上。 2. 相关文档汇总:         1、WxJava - MiniApp Java SDK 4.6.0 API         2、wechatpay-java/README.md at main · wechatpay-apiv3/wechatpay-java · GitHub         3、网络 | 微信开放文档         4、开发指引 - JSAPI支付 | 微信支付商

    2024年04月25日
    浏览(57)
  • Java对接微信支付(史上最详细)

    本文将介绍如何使用Java对接微信支付,包括获取支付参数、支付回调处理等步骤。本文适用于已经熟悉微信支付基本原理的读者。 JDK 1.8 Maven Spring Boot 2.x 微信支付开发文档 为了进行支付,我们需要先获取微信支付的参数信息,包括appid、商户id、支付密钥等。 配置文件 我们

    2024年02月15日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包