前言
微信支付適用于許多場(chǎng)合,如小程序、網(wǎng)頁(yè)支付、但微信支付相對(duì)于其他支付方式略顯麻煩,我們使用IJpay框架進(jìn)行整合

一、IJpay是什么?
JPay 讓支付觸手可及,封裝了微信支付、支付寶支付、銀聯(lián)支付常用的支付方式以及各種常用的接口。不依賴任何第三方 mvc 框架,僅僅作為工具使用簡(jiǎn)單快速完成支付模塊的開(kāi)發(fā),可輕松嵌入到任何系統(tǒng)里。
二、使用步驟
1.準(zhǔn)備小程序必要信息
1.1 要在小程序端關(guān)聯(lián)商戶號(hào)

1.2在application.yml文件中配置相關(guān)信息

這是微信平臺(tái)下載的證書

1.3導(dǎo)入IJpay依賴
<dependency>
<groupId>com.github.javen205</groupId>
<artifactId>IJPay-WxPay</artifactId>
<version>2.9.6</version>
</dependency>
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;
/**
* @Author: Scoot
* @Date: 2023/3/16 15:52
* @Description: 微信支付控制器
*/
@Slf4j
@Api(tags = "微信支付控制器")
@RestController
@RequestMapping("/api/wx/pay/v1")
@Scope("prototype")
public class WxPayApiController {
/**微信小程序appid**/
@Value("${wechat.ma.appId}")
String appid;
/**微信小程序secretId**/
@Value("${wechat.ma.secret}")
String secret;
/**商戶號(hào)**/
@Value("${wechat.ma.mchid}")
String mchid;
/**商戶密鑰**/
@Value("${wechat.ma.mchKey}")
String mchKey;
/**回調(diào)地址**/
@Value("${wechat.ma.notifyUrl}")
String notifyUrl;
/**證書地址**/
@Value("${wechat.ma.certPath}")
String certPath;
/**證書密鑰地址**/
@Value("${wechat.ma.certKeyPath}")
String certKeyPath;
/**微信平臺(tái)證書**/
@Value("${wechat.ma.platFormPath}")
String platFormPath;
/**
* 微信支付
* @param openId 用戶openId
* @return
*/
@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)
// 商戶號(hào)
.setMchid(mchid)
.setDescription("IJPay 讓支付觸手可及")
.setOut_trade_no(PayKit.generateStr())
.setTime_expire(timeExpire)
.setAttach("微信系開(kāi)發(fā)腳手架 https://gitee.com/javen205/TNWX")
.setNotify_url(notifyUrl)
.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(),
mchid,
getSerialNumber(),
null,
certKeyPath,
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, 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<String, String> map = WxPayKit.jsApiCreateSign(appid, prepayId, certKeyPath);
log.info("喚起支付參數(shù):{}", map);
return JsonResult.success("獲取成功",JSONUtil.toJsonStr(map));
}
} catch (Exception e) {
e.printStackTrace();
}
return JsonResult.error("喚起失敗");
}
/**
* 微信支付回調(diào)
* @param request
* @param response
*/
@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<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,
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", "簽名錯(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();
}
}
private String getSerialNumber() {
// 獲取證書序列號(hào)
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() {
// 獲取平臺(tái)證書列表
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");
// 默認(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, platFormPath);
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, platFormPath);
System.out.println("verifySignature:" + verifySignature);
return body;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 保存平臺(tái)證書
* @param associatedData associated_data
* @param nonce nonce
* @param cipherText cipherText
* @param certPath 證書保存路徑
* @return
*/
private String savePlatformCert(String associatedData, String nonce, String cipherText, String certPath) {
try {
AesUtil aesUtil = new AesUtil(mchKey.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
);
// 保存證書
cn.hutool.core.io.file.FileWriter writer = new FileWriter(certPath);
writer.write(publicKey);
// 獲取平臺(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();
}
}
}
2.3下載平臺(tái)證書platForm.pem
調(diào)用上面get方法下載證書下載完成后會(huì)在yml配置的路徑生成platForm.pem證書

2.4啟動(dòng)測(cè)試
接口傳入openID(后續(xù)可換其他方式),返回如下json字符串表示成功

2.5小程序喚起微信支付
2.5.1uniapp代碼
<template>
<view class="content">
<button @click="pay">支付</button>
</view>
</template>
<script>
export default {
data() {
return {
title: 'Hello',
sign :{}
}
},
onLoad() {
},
methods: {
pay(){
uni.request({
// 獲取微信支付簽名地址
url:"http://192.168.0.231:8087/api/wx/pay/v1/jsApiPay?openId=oEmg75RAQX-7uRqGUkSy0tGcfzpI",
// 成功回調(diào)
success: (res) => {
let sign =JSON.parse(res.data.data);
// 僅作為示例,非真實(shí)參數(shù)信息。
uni.requestPayment({
provider: 'wxpay',
timeStamp: sign.timeStamp,
nonceStr: sign.nonceStr,
package: sign.package,
signType: sign.signType,
paySign: sign.paySign,
success: function (res) {
console.log('success:' + JSON.stringify(res));
},
fail: function (err) {
console.log('fail:' + JSON.stringify(err));
}
});
}
})
}
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.logo {
height: 200rpx;
width: 200rpx;
margin-top: 200rpx;
margin-left: auto;
margin-right: auto;
margin-bottom: 50rpx;
}
.text-area {
display: flex;
justify-content: center;
}
.title {
font-size: 36rpx;
color: #8f8f94;
}
</style>

2.6異步回調(diào)
在yml配置的異步回調(diào)地址(需要外網(wǎng)訪問(wèn))文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-433791.html

總結(jié)
以上就是今天要講的內(nèi)容,本文僅僅簡(jiǎn)單介紹了springboot整合IJpay進(jìn)行微信支付的使用,關(guān)于調(diào)用支付jspi缺少參數(shù):total_fee主要是因?yàn)?.金額為空 2.訂單號(hào)重復(fù) 3.訂單號(hào)為空文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-433791.html
到了這里,關(guān)于springboot整合IJPay實(shí)現(xiàn)微信支付-V3---微信小程序的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!