SpringBoot集成IJPay實(shí)現(xiàn)微信v3支付的示例代碼
前言
這篇文章主要實(shí)現(xiàn)一下通過(guò)IJPay
來(lái)實(shí)現(xiàn)微信v3支付案例,本篇文章使用的是JSAPI
即小程序支付
IJPay碼云倉(cāng)庫(kù):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è)證書文件
- 通過(guò)微信官方指引下載證書并解壓縮后得到的文件。
apiclient_cert.pem
稱為商戶證書,apiclient_key.pem
成為商戶證書密鑰 - 通過(guò)IJPay的接口獲取,稱之為微信平臺(tái)證書。(一般沒(méi)有這個(gè)文件,所以暫時(shí)先不管,一會(huì)獲取的時(shí)候會(huì)講這個(gè))
在這里我們給這三個(gè)文件起個(gè)別名,以便下方代碼更容易區(qū)分。
- apiclient_cert.pem:privateCertPath
- apiclient_key.pem:privateKeyPath
- wx_platform_cert.pem:platformCertPath
開(kāi)始
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)的證書來(lái)驗(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("微信系開(kāi)發(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)的證書來(lái)驗(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); // 需要通過(guò)證書序列號(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過(guò)程解析
- 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整合微信支付(訂單過(guò)期取消及商戶主動(dòng)查單)
- SpringBoot對(duì)接小程序微信支付的實(shí)現(xiàn)
相關(guān)文章
Apache DolphinScheduler實(shí)現(xiàn)自動(dòng)化打包單機(jī)/集群部署詳解
這篇文章主要為大家介紹了Apache DolphinScheduler實(shí)現(xiàn)自動(dòng)化打包單機(jī)/集群部署詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09springboot使用maven實(shí)現(xiàn)多環(huán)境運(yùn)行和打包問(wèn)題
這篇文章主要介紹了springboot使用maven實(shí)現(xiàn)多環(huán)境運(yùn)行和打包問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07Java利用OSHI實(shí)現(xiàn)獲取機(jī)器的硬件信息
OSHI(Operating System and Hardware Information)是一個(gè)開(kāi)源的Java庫(kù),用于獲取操作系統(tǒng)和硬件的詳細(xì)信息,下面我們就來(lái)看看他的具體使用吧2024-11-11通過(guò)java備份恢復(fù)mysql數(shù)據(jù)庫(kù)的實(shí)現(xiàn)代碼
這篇文章主要介紹了如何通過(guò)java備份恢復(fù)mysql數(shù)據(jù)庫(kù),其實(shí)一般情況下通過(guò)bat或sh就可以,這里主要是介紹了java的實(shí)現(xiàn)思路,喜歡的朋友可以參考下2013-09-09java 學(xué)習(xí)筆記(入門篇)_java的安裝與配置
學(xué)習(xí)Java已經(jīng)很長(zhǎng)時(shí)間了,由于基礎(chǔ)不好遇到問(wèn)題就無(wú)從下手,所以,打算寫Java的隨手筆記來(lái)鞏固基礎(chǔ),加強(qiáng)學(xué)習(xí),接下來(lái)講解java的安裝,配置等,感興趣的朋友可以參考下2013-01-01Java輕松使用工具類實(shí)現(xiàn)獲取MP3音頻時(shí)長(zhǎng)
在Java中,工具類定義了一組公共方法,這篇文章將介紹Java中使用工具類來(lái)獲取一個(gè)MP3音頻文件的時(shí)間長(zhǎng)度,感興趣的同學(xué)繼續(xù)往下閱讀吧2021-10-10一文搞懂Java MD5算法的原理及實(shí)現(xiàn)
MD5信息摘要算法,一種被廣泛使用的密碼散列函數(shù),可以產(chǎn)生出一個(gè)128位(16字節(jié))的散列值(hash value),用于確保信息傳輸完整一致。本文將詳解MD5算法的原理及實(shí)現(xiàn),感興趣的可以了解一下2022-06-06