前言
微信支付适用于许多场合,如小程序、网页支付、但微信支付相对于其他支付方式略显麻烦,我们使用IJpay框架进行整合
一、IJpay是什么?
JPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。
二、使用步骤
1.准备小程序必要信息
1.1 要在小程序端关联商户号
1.2在application.yml文件中配置相关信息
这是微信平台下载的证书
1.3导入IJpay依赖
com.github.javen205 IJPay-WxPay 2.9.6
2.具体操作
2.1新建控制器WxPayApiContoller
2.2控制器代码:
package cn.cnvp.web.api.wechart;import cn.cnvp.web.token.message.JsonResult;import cn.cnvp.web.utils.WxUtils;import cn.hutool.core.date.DatePattern;import cn.hutool.core.date.DateUtil;import cn.hutool.core.io.file.FileWriter;import cn.hutool.core.util.StrUtil;import cn.hutool.http.ContentType;import cn.hutool.http.HttpStatus;import cn.hutool.json.JSONArray;import cn.hutool.json.JSONObject;import cn.hutool.json.JSONUtil;import com.ijpay.core.IJPayHttpResponse;import com.ijpay.core.enums.RequestMethodEnum;import com.ijpay.core.kit.AesUtil;import com.ijpay.core.kit.HttpKit;import com.ijpay.core.kit.PayKit;import com.ijpay.core.kit.WxPayKit;import com.ijpay.core.utils.DateTimeZoneUtil;import com.ijpay.wxpay.WxPayApi;import com.ijpay.wxpay.enums.WxDomainEnum;import com.ijpay.wxpay.enums.v3.BasePayApiEnum;import com.ijpay.wxpay.enums.v3.OtherApiEnum;import com.ijpay.wxpay.model.v3.Amount;import com.ijpay.wxpay.model.v3.Payer;import com.ijpay.wxpay.model.v3.UnifiedOrderModel;import io.swagger.annotations.Api;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Scope;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.ByteArrayInputStream;import java.nio.charset.StandardCharsets;import java.security.cert.X509Certificate;import java.util.HashMap;import java.util.Map;@Slf4j@Api(tags = "微信支付控制器")@RestController@RequestMapping("/api/wx/pay/v1")@Scope("prototype")public class WxPayApiController { @Value("${wechat.ma.appId}") String appid; @Value("${wechat.ma.secret}") String secret; @Value("${wechat.ma.mchid}") String mchid; @Value("${wechat.ma.mchKey}") String mchKey; @Value("${wechat.ma.notifyUrl}") String notifyUrl; @Value("${wechat.ma.certPath}") String certPath; @Value("${wechat.ma.certKeyPath}") String certKeyPath; @Value("${wechat.ma.platFormPath}") String platFormPath; @RequestMapping("/jsApiPay") @ResponseBody public JsonResult 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() // APPID .setAppid(appid) // 商户号 .setMchid(mchid) .setDescription("IJPay 让支付触手可及") .setOut_trade_no(PayKit.generateStr()) .setTime_expire(timeExpire) .setAttach("微信系开发脚手架 https://gitee.com/javen205/TNWX") .setNotify_url(notifyUrl) .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(), mchid, getSerialNumber(), null, certKeyPath, JSONUtil.toJsonStr(unifiedOrderModel) ); log.info("统一下单响应 {}", response); // 根据证书序列号查询对应的证书来验证签名结果 boolean verifySignature = WxPayKit.verifySignature(response, platFormPath); log.info("verifySignature: {}", verifySignature); if (response.getStatus() == HttpStatus.HTTP_OK && verifySignature) { String body = response.getBody(); JSONObject jsonObject = JSONUtil.parseObj(body); String prepayId = jsonObject.getStr("prepay_id"); Map map = WxPayKit.jsApiCreateSign(appid, prepayId, certKeyPath); log.info("唤起支付参数:{}", map); return JsonResult.success("获取成功",JSONUtil.toJsonStr(map)); } } catch (Exception e) { e.printStackTrace(); } return JsonResult.error("唤起失败"); } @RequestMapping(value = "/payNotify", method = {org.springframework.web.bind.annotation.RequestMethod.POST, org.springframework.web.bind.annotation.RequestMethod.GET}) public void payNotify(HttpServletRequest request, HttpServletResponse response) { Map 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, mchKey, platFormPath); 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(); } } private String getSerialNumber() { // 获取证书序列号 X509Certificate certificate = PayKit.getCertificate(certPath); if (null != certificate) { String serialNo = certificate.getSerialNumber().toString(16).toUpperCase(); // 提前两天检查证书是否有效 boolean isValid = PayKit.checkCertificateIsValid(certificate, mchid, -2); log.info("证书是否可用 {} 证书有效期为 {}", isValid, DateUtil.format(certificate.getNotAfter(), DatePattern.NORM_DATETIME_PATTERN)); System.out.println("serialNo:" + serialNo); return serialNo; } return null; } @RequestMapping("/get") @ResponseBody public String v3Get() { // 获取平台证书列表 try { IJPayHttpResponse response = WxPayApi.v3( RequestMethodEnum.GET, WxDomainEnum.CHINA.toString(), OtherApiEnum.GET_CERTIFICATES.toString(), mchid, getSerialNumber(), null, certKeyPath, "" ); String serialNumber = response.getHeader("Wechatpay-Serial"); 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, platFormPath); log.info("平台证书序列号: {} serialNo: {}", platSerialNo, serialNo); } // 根据证书序列号查询对应的证书来验证签名结果 boolean verifySignature = WxPayKit.verifySignature(response, platFormPath); System.out.println("verifySignature:" + verifySignature); return body; } catch (Exception e) { e.printStackTrace(); return null; } } private String savePlatformCert(String associatedData, String nonce, String cipherText, String certPath) { try { AesUtil aesUtil = new AesUtil(mchKey.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 ); // 保存证书 cn.hutool.core.io.file.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(); } }}
2.3下载平台证书platForm.pem
调用上面get方法下载证书下载完成后会在yml配置的路径生成platForm.pem证书
2.4启动测试
接口传入openID(后续可换其他方式),返回如下json字符串表示成功
2.5小程序唤起微信支付
2.5.1uniapp代码
2.6异步回调
在yml配置的异步回调地址(需要外网访问)
总结
以上就是今天要讲的内容,本文仅仅简单介绍了springboot整合IJpay进行微信支付的使用,关于调用支付jspi缺少参数:total_fee主要是因为1.金额为空 2.订单号重复 3.订单号为空
来源地址:https://blog.csdn.net/qq_37612049/article/details/129589510