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支付内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
SpringMVC MethodArgumentResolver的作用与实现
这篇文章主要介绍了SpringMVC MethodArgumentResolver的作用与实现,MethodArgumentResolver采用一种策略模式,在Handler的方法被调用前,Spring MVC会自动将HTTP请求中的参数转换成方法参数2023-04-04VSCode中开发JavaWeb项目的详细过程(Maven+Tomcat+热部署)
这篇文章主要介绍了VSCode中开发JavaWeb项目(Maven+Tomcat+热部署),本文分步骤通过图文并茂的形式给大家介绍的非常详细,需要的朋友可以参考下2022-09-09Java concurrency之AtomicReference原子类_动力节点Java学院整理
AtomicReference是作用是对"对象"进行原子操作。这篇文章主要介绍了Java concurrency之AtomicReference原子类,需要的朋友可以参考下2017-06-06
最新评论