SpringBoot集成IJPay实现微信v3支付的示例代码

 更新时间:2023年07月24日 10:38:00   作者:保加利亚的风  
本文主要介绍了SpringBoot集成IJPay实现微信v3支付的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

前言

这篇文章主要实现一下通过IJPay来实现微信v3支付案例,本篇文章使用的是JSAPI即小程序支付

IJPay码云仓库:https://gitee.com/javen205/IJPay/tree/dev

IJPay官方文档:https://javen205.gitee.io/ijpay/

准备工作

导入依赖

   <dependency>
            <groupId>com.github.javen205</groupId>
            <artifactId>IJPay-WxPay</artifactId>
            <version>2.9.6</version>
        </dependency>
  • appId 由微信生成的应用ID,全局唯一。
  • mchId 直连商户的商户号,由微信支付生成并下发。
  • apiV3Key v3密钥
  • mchSerialNo 商户证书序列号

还需要三个证书文件

  • 通过微信官方指引下载证书并解压缩后得到的文件。apiclient_cert.pem称为商户证书apiclient_key.pem成为商户证书密钥
  • 通过IJPay的接口获取,称之为微信平台证书。(一般没有这个文件,所以暂时先不管,一会获取的时候会讲这个)

在这里我们给这三个文件起个别名,以便下方代码更容易区分。

  • apiclient_cert.pem:privateCertPath
  • apiclient_key.pem:privateKeyPath
  • wx_platform_cert.pem:platformCertPath

开始

1 首先将上面所有的参数配置到application.yml文件中,或者配置到nacos上。

  • wxJsapiUrl:是获取微信预支付参数的url路径
  • 最下面的三个是文件的绝对路径

2 读取配置文件的配置项,新建WxPayConfig

@Data
@Component
@ConfigurationProperties(prefix = "wx.pay")
public class WxPayConfig {
	/**
	 * appId
	 */
	private String appId;
	/**
	 * 商户号
	 */
	private String mchId;
	/**
	 * 商户证书序列号
	 */
	private String mchSerialNo;
	/**
	 * apiv3密钥
	 */
	private String apiV3Key;
	/**
	 * 支付回调地址
	 */
	private String notifyUrl;
	/**
	 * 微信支付请求url
	 */
	private String wxJsapiUrl;
	/**
	 * 私钥路径
	 */
	private String privateKeyPath;
	/**
	 * 商户证书路径
	 */
	private String privateCertPath;
	/**
	 * 微信平台证书路径
	 */
	private String platformCertPath;
}

3 首先获取到微信平台证书

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.mjfz.fc.weixin.WxPayConfig;
import com.ijpay.core.IJPayHttpResponse;
import com.ijpay.core.enums.RequestMethodEnum;
import com.ijpay.core.kit.AesUtil;
import com.ijpay.core.kit.PayKit;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.enums.WxDomainEnum;
import com.ijpay.wxpay.enums.v3.OtherApiEnum;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.FileWriter;
import java.nio.charset.StandardCharsets;
import java.security.cert.X509Certificate;
	@Resource
	private WxPayConfig wxPayConfig;
	public void v3Get() {
		// 获取平台证书列表
		try {
			IJPayHttpResponse response = WxPayApi.v3(
					RequestMethodEnum.GET,
					WxDomainEnum.CHINA.toString(),
					OtherApiEnum.GET_CERTIFICATES.toString(),
					wxPayConfig.getMchId(),
					wxPayConfig.getMchSerialNo(),
					null,
					wxPayConfig.getPrivateKeyPath(),
					""
			);
			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);
			if (status == 200) {
				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, wxPayConfig.getPlatformCertPath());
				log.info("平台证书序列号: {} serialNo: {}", platSerialNo, serialNo);
			}
			// 根据证书序列号查询对应的证书来验证签名结果
			boolean verifySignature = WxPayKit.verifySignature(response, wxPayConfig.getPlatformCertPath());
			System.out.println("verifySignature:" + verifySignature);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	private String savePlatformCert(String associatedData, String nonce, String cipherText, String certPath) {
		try {
			AesUtil aesUtil = new AesUtil(apiV3key.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);
			writer.close();
			// 获取平台证书序列号
			X509Certificate certificate = PayKit.getCertificate(new ByteArrayInputStream(publicKey.getBytes()));
			return certificate.getSerialNumber().toString(16).toUpperCase();
		} catch (Exception e) {
			e.printStackTrace();
			return e.getMessage();
		}
	}

4 支付和回调

//支付
	@RequestMapping("/jsApiPay")
	@ResponseBody
	public String jsApiPay(String openId) {
		try {
			String timeExpire = DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3);
			UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
					.setAppid(wxPayConfig.getAppId())
					.setMchid(wxPayConfig.getMchId())
					.setDescription("IJPay 让支付触手可及")
					.setOut_trade_no(PayKit.generateStr())
					.setTime_expire(timeExpire)
					.setAttach("微信系开发脚手架 https://gitee.com/javen205/TNWX")
					.setNotify_url(wxPayConfig.getNotifyUrl())
					.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(),
					wxPayConfig.getMchId(),
					wxPayConfig.getMchSerialNo(),
					null,
					wxPayConfig.getPrivateKeyPath(),
					JSONUtil.toJsonStr(unifiedOrderModel)
			);
			log.info("统一下单响应 {}", response);
			// 根据证书序列号查询对应的证书来验证签名结果
			boolean verifySignature = WxPayKit.verifySignature(response, wxPayConfig.getPlatformCertPath());
			log.info("verifySignature: {}", verifySignature);
			if (response.getStatus() == 200 && verifySignature) {
				String body = response.getBody();
				JSONObject jsonObject = JSONUtil.parseObj(body);
				String prepayId = jsonObject.getStr("prepay_id");
				Map<String, String> map = WxPayKit.jsApiCreateSign(wxPayConfig.getAppId(), prepayId, wxPayConfig.getPrivateKeyPath());
				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,
					wxPayConfig.getApiV3Key(), wxPayConfig.getPlatformCertPath());
			log.info("支付通知明文 {}", plainText);
			if (StrUtil.isNotEmpty(plainText)) {
				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();
		}
	}

总结

到此这篇关于SpringBoot集成IJPay实现微信v3支付的示例代码的文章就介绍到这了,更多相关SpringBoot IJPay微信v3支付内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java kafka如何实现自定义分区类和拦截器

    Java kafka如何实现自定义分区类和拦截器

    这篇文章主要介绍了Java kafka如何实现自定义分区类和拦截器,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-06-06
  • java多线程中断代码详解

    java多线程中断代码详解

    这篇文章主要介绍了java多线程中断代码详解,具有一定参考价值,需要的朋友可以了解下。
    2017-11-11
  • Java执行SQL脚本文件到数据库详解

    Java执行SQL脚本文件到数据库详解

    这篇文章主要为大家详细介绍了Java执行SQL脚本文件到数据库的相关方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-06-06
  • Java排序算法总结之插入排序

    Java排序算法总结之插入排序

    这篇文章主要介绍了Java排序算法总结之插入排序,较为详细的分析了插入排序的原理与java实现技巧,需要的朋友可以参考下
    2015-05-05
  • 详解Spring中Spel表达式和el表达式的区别

    详解Spring中Spel表达式和el表达式的区别

    在 Java 开发中,表达式语言是一种强大的工具,而SpEL 表达式与EL 表达式是我们常常遇到两种表达式语言,下面我们就来看看它们的具体使用与区别吧
    2023-07-07
  • SystemServer进程启动过程解析

    SystemServer进程启动过程解析

    这篇文章主要为大家介绍了SystemServer进程启动过程解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-07-07
  • 举例讲解Java设计模式编程中Decorator装饰者模式的运用

    举例讲解Java设计模式编程中Decorator装饰者模式的运用

    这篇文章主要介绍了Java设计模式编程中Decorator装饰者模式的运用,装饰者模式就是给一个对象动态的添加新的功能,装饰者和被装饰者实现同一个接口,装饰者持有被装饰者的实例,需要的朋友可以参考下
    2016-05-05
  • 使用Springboot注入带参数的构造函数实例

    使用Springboot注入带参数的构造函数实例

    这篇文章主要介绍了使用Springboot注入带参数的构造函数实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-04-04
  • springcloud+nacos实现灰度发布示例详解

    springcloud+nacos实现灰度发布示例详解

    这篇文章主要介绍了springcloud+nacos实现灰度发布,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-08-08
  • SpringMVC访问静态资源的三种方式小结

    SpringMVC访问静态资源的三种方式小结

    这篇文章主要介绍了SpringMVC访问静态资源的三种方式小结,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-02-02

最新评论