SpringBoot集成IJPay實(shí)現(xiàn)微信v3支付的示例代碼
前言
這篇文章主要實(shí)現(xiàn)一下通過IJPay來實(shí)現(xiàn)微信v3支付案例,本篇文章使用的是JSAPI即小程序支付
IJPay碼云倉庫:https://gitee.com/javen205/IJPay/tree/dev
IJPay官方文檔:https://javen205.gitee.io/ijpay/
準(zhǔn)備工作
導(dǎo)入依賴
<dependency>
<groupId>com.github.javen205</groupId>
<artifactId>IJPay-WxPay</artifactId>
<version>2.9.6</version>
</dependency>- appId 由微信生成的應(yīng)用ID,全局唯一。
- mchId 直連商戶的商戶號(hào),由微信支付生成并下發(fā)。
- apiV3Key v3密鑰
- mchSerialNo 商戶證書序列號(hào)
還需要三個(gè)證書文件

- 通過微信官方指引下載證書并解壓縮后得到的文件。
apiclient_cert.pem稱為商戶證書,apiclient_key.pem成為商戶證書密鑰 - 通過IJPay的接口獲取,稱之為微信平臺(tái)證書。(一般沒有這個(gè)文件,所以暫時(shí)先不管,一會(huì)獲取的時(shí)候會(huì)講這個(gè))
在這里我們給這三個(gè)文件起個(gè)別名,以便下方代碼更容易區(qū)分。
- apiclient_cert.pem:privateCertPath
- apiclient_key.pem:privateKeyPath
- wx_platform_cert.pem:platformCertPath
開始
1 首先將上面所有的參數(shù)配置到application.yml文件中,或者配置到nacos上。

- wxJsapiUrl:是獲取微信預(yù)支付參數(shù)的url路徑
- 最下面的三個(gè)是文件的絕對(duì)路徑
2 讀取配置文件的配置項(xiàng),新建WxPayConfig
@Data
@Component
@ConfigurationProperties(prefix = "wx.pay")
public class WxPayConfig {
/**
* appId
*/
private String appId;
/**
* 商戶號(hào)
*/
private String mchId;
/**
* 商戶證書序列號(hào)
*/
private String mchSerialNo;
/**
* apiv3密鑰
*/
private String apiV3Key;
/**
* 支付回調(diào)地址
*/
private String notifyUrl;
/**
* 微信支付請(qǐng)求url
*/
private String wxJsapiUrl;
/**
* 私鑰路徑
*/
private String privateKeyPath;
/**
* 商戶證書路徑
*/
private String privateCertPath;
/**
* 微信平臺(tái)證書路徑
*/
private String platformCertPath;
}3 首先獲取到微信平臺(tái)證書
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() {
// 獲取平臺(tái)證書列表
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");
// 默認(rèn)認(rèn)為只有一個(gè)平臺(tái)證書
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("平臺(tái)證書序列號(hào): {} serialNo: {}", platSerialNo, serialNo);
}
// 根據(jù)證書序列號(hào)查詢對(duì)應(yīng)的證書來驗(yàn)證簽名結(jié)果
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));
// 平臺(tái)證書密文解密
// 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();
// 獲取平臺(tái)證書序列號(hào)
X509Certificate certificate = PayKit.getCertificate(new ByteArrayInputStream(publicKey.getBytes()));
return certificate.getSerialNumber().toString(16).toUpperCase();
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
}
}4 支付和回調(diào)
//支付
@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("微信系開發(fā)腳手架 https://gitee.com/javen205/TNWX")
.setNotify_url(wxPayConfig.getNotifyUrl())
.setAmount(new Amount().setTotal(1))
.setPayer(new Payer().setOpenid(openId));
log.info("統(tǒng)一下單參數(shù) {}", 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("統(tǒng)一下單響應(yīng) {}", response);
// 根據(jù)證書序列號(hào)查詢對(duì)應(yīng)的證書來驗(yàn)證簽名結(jié)果
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("喚起支付參數(shù):{}", 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);
// 需要通過證書序列號(hào)查找對(duì)應(yīng)的證書,verifyNotify 中有驗(yàn)證證書的序列號(hào)
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", "簽名錯(cuò)誤");
}
response.setHeader("Content-type", ContentType.JSON.toString());
response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
response.flushBuffer();
} catch (Exception e) {
e.printStackTrace();
}
}總結(jié)
到此這篇關(guān)于SpringBoot集成IJPay實(shí)現(xiàn)微信v3支付的示例代碼的文章就介紹到這了,更多相關(guān)SpringBoot IJPay微信v3支付內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- springboot整合微信支付sdk過程解析
- Springboot集成第三方j(luò)ar快速實(shí)現(xiàn)微信、支付寶等支付場(chǎng)景
- SpringBoot微信掃碼支付的實(shí)現(xiàn)示例
- springboot接入微信app支付的方法
- springboot對(duì)接微信支付的完整流程(附前后端代碼)
- SpringBoot實(shí)現(xiàn)整合微信支付方法詳解
- SpringBoot整合Vue實(shí)現(xiàn)微信掃碼支付以及微信退款功能詳解
- Springboot整合微信支付(訂單過期取消及商戶主動(dòng)查單)
- SpringBoot對(duì)接小程序微信支付的實(shí)現(xiàn)
相關(guān)文章
Mybatis的xml中使用if/else標(biāo)簽的具體使用
本文主要介紹了Mybatis的xml中使用if/else標(biāo)簽的具體使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05
java實(shí)現(xiàn)給圖片加鋪滿的網(wǎng)格式文字水印
這篇文章主要給大家介紹了關(guān)于java實(shí)現(xiàn)給圖片加鋪滿的網(wǎng)格式文字水印的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
解決Idea項(xiàng)目結(jié)構(gòu)顯示不全問題
文章描述了在使用IntelliJ IDEA時(shí)遇到的問題,并提出了解決方法:關(guān)閉IDEA、刪除項(xiàng)目中的.idea文件夾,然后重新打開IDEA導(dǎo)入項(xiàng)目2024-11-11
SpringBoot集成Access?DB實(shí)現(xiàn)數(shù)據(jù)導(dǎo)入和解析
microsoft?office?access是由微軟發(fā)布的關(guān)聯(lián)式數(shù)據(jù)庫管理系統(tǒng),它結(jié)合了?microsoft?jet?database?engine?和?圖形用戶界面兩項(xiàng)特點(diǎn),是一種關(guān)系數(shù)據(jù)庫工具,本文給大家介紹了SpringBoot集成Access?DB實(shí)現(xiàn)數(shù)據(jù)導(dǎo)入和解析,需要的朋友可以參考下2024-11-11

