1. 程序開發(fā)前的準(zhǔn)備工作,獲取微信支付相關(guān)的參數(shù)
- appId:小程序appid
- appSecret:小程序的secret
- mchId:商戶號
- keyPath:商戶私鑰路徑(apiclient_key.pem)
- certPath:證書路徑(apiclient_cert.pem)
- platFormPath:平臺證書(cert.pem)
注 : 需要通過寫程序生成平臺證書(見v3Get()方法) - apiKey3:apiv3密鑰
- serialnumber:商戶證書序列號
- notifyUrl:回調(diào)地址
注 : 回調(diào)地址需要是線上能訪問到的地址,本地的地址是無效的
1.1 在application.yml文件中填寫配置信息
# 微信支付
pay:
wechat:
appId: xxx
appSecret: xxx
mchId: xxx
# 商戶私鑰路徑
keyPath: D:\xx\xx\WxPay\apiclient_key.pem
# 證書路徑
certPath: D:\xx\xx\\WxPay\apiclient_cert.pem
platFormPath: D:\xx\xx\\WxPay\cert.pem # 后續(xù)生成的平臺證書路徑
# apiv3秘鑰
apiKey3: xxx
# 商戶證書序列號
serialnumber: xxx
# 回調(diào)地址
notifyUrl: http://xxx:xx/wx/pay/payNotify # 線上地址
1.2 獲取配置文件中的參數(shù)
/**微信小程序appid**/
@Value("${pay.wechat.appId}")
String appid;
/**微信小程序secretId**/
@Value("${pay.wechat.appSecret}")
String secret;
/**商戶號**/
@Value("${pay.wechat.mchId}")
String mchid;
/**商戶密鑰**/
@Value("${pay.wechat.apiKey3}")
String mchKey;
/**回調(diào)地址**/
@Value("${pay.wechat.notifyUrl}")
String notifyUrl;
/**證書地址**/
@Value("${pay.wechat.certPath}")
String certPath;
/**證書密鑰地址**/
@Value("${pay.wechat.keyPath}")
String certKeyPath;
/**微信平臺證書**/
@Value("${pay.wechat.platFormPath}")
String platFormPath;
/**證書序列號**/
@Value("${pay.wechat.serialnumber}")
String serialNumber;
2. 在pom.xml中引入相關(guān)依賴
<!-- https://mvnrepository.com/artifact/com.github.javen205/IJPay-WxPay -->
<dependency>
<groupId>com.github.javen205</groupId>
<artifactId>IJPay-WxPay</artifactId>
<version>2.7.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-core -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
<version>5.8.16</version>
</dependency>
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-apache-httpclient</artifactId>
<version>0.4.7</version>
</dependency>
3. 實現(xiàn)微信支付相關(guān)方法
3.1 獲取平臺證書
public String v3Get() {
// 獲取平臺證書列表
try {
IJPayHttpResponse response = WxPayApi.v3(
RequestMethod.GET,
WxDomain.CHINA.toString(),
WxApiType.GET_CERTIFICATES.toString(),
mchid,
serialNumber,
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);
}
// 根據(jù)證書序列號查詢對應(yīng)的證書來驗證簽名結(jié)果
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();
}
}
3.2 微信支付
public String wxPay(String openId, String payId, int amount) {
//商戶訂單號(隨機字符串)
// String orderSn = PayKit.generateStr();
try {
String timeExpire = DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3);
UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
// APPID
.setAppid(appid)
// 商戶號
.setMchid(mchid)
.setDescription("門票賬單支付")
.setOut_trade_no(payId)
.setTime_expire(timeExpire)
.setNotify_url(notifyUrl)
.setAmount(new Amount().setTotal(amount))
.setPayer(new Payer().setOpenid(openId));
log.info("統(tǒng)一下單參數(shù) {}", JSONUtil.toJsonStr(unifiedOrderModel));
IJPayHttpResponse response = WxPayApi.v3(
RequestMethod.POST,
WxDomain.CHINA.toString(),
WxApiType.JS_API_PAY.toString(),
mchid,
serialNumber,
null,
certKeyPath,
JSONUtil.toJsonStr(unifiedOrderModel)
);
log.info("統(tǒng)一下單響應(yīng) {}", response);
// 根據(jù)證書序列號查詢對應(yīng)的證書來驗證簽名結(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);
String jsonStr = JSONUtil.toJsonStr(map);
return jsonStr;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
3.3 微信支付回調(diào)
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);
// 需要通過證書序列號查找對應(yīng)的證書,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();
}
}
3.4 微信退款
public String payRefund(int amount, int qty, String outTradeNo, String outRefundNo) {
log.info("進入退款接口------>" );
log.info("執(zhí)行操作的 原支付交易對應(yīng)的商戶訂單號:{}", outTradeNo );
try {
// String outRefundNo = PayKit.generateStr();
log.info("商戶退款單號: {}", outRefundNo);
List<RefundGoodsDetail> list = new ArrayList<>();
RefundGoodsDetail refundGoodsDetail = new RefundGoodsDetail()
.setMerchant_goods_id(outRefundNo)
.setGoods_name("取消訂單")
.setUnit_price(amount) //金額,單位為分
.setRefund_amount(amount)
.setRefund_quantity(qty);
list.add(refundGoodsDetail);
RefundModel refundModel = new RefundModel()
.setOut_refund_no(outRefundNo)
.setReason("取消訂單")
//.setNotify_url(wechatPayV3Bean.getDomain().concat("/wechat/operation/pay/refundNotify")) //退款異步回調(diào)通知
.setAmount(new RefundAmount().setRefund(1).setTotal(1).setCurrency("CNY"))
.setGoods_detail(list);
if (outTradeNo != null && !outTradeNo.equals("")) {
refundModel.setOut_trade_no( outTradeNo );
}
log.info("退款參數(shù): {}", JSONUtil.toJsonStr(refundModel));
IJPayHttpResponse response = WxPayApi.v3(
RequestMethod.POST,
WxDomain.CHINA.toString(),
WxApiType.DOMESTIC_REFUNDS.toString(),
mchid,
serialNumber,
null,
certKeyPath,
JSONUtil.toJsonStr(refundModel)
);
log.info("退款響應(yīng) {}", response);
// 根據(jù)證書序列號查詢對應(yīng)的證書來驗證簽名結(jié)果
boolean verifySignature = WxPayKit.verifySignature(response, platFormPath);
log.info("verifySignature: {}", verifySignature);
String body = response.getBody();
JSONObject jsonObject = JSONUtil.parseObj(body); //轉(zhuǎn)換為JSON
log.info("響應(yīng)數(shù)據(jù):" + body);
if(response.getStatus()==200){ //退款成功,處理業(yè)務(wù)邏輯
System.out.println("==================================");
System.out.println("退款成功!");
}
if (verifySignature) {
return response.getBody();
}
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
}
return null;
}
3.5 訂單查詢
public String queryPayResult(String payId) throws Exception{
WechatPayHttpClientBuilder builder = getWechatPayHttpClientBuilder();
CloseableHttpClient httpClient = builder.build();
String result = "";
try {
URIBuilder uriBuilder = new URIBuilder("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/"+ payId +"?mchid=" + mchid);
HttpGet httpGet = new HttpGet(uriBuilder.build());
httpGet.addHeader("Accept", "application/json");
CloseableHttpResponse response = httpClient.execute(httpGet);
result = EntityUtils.toString(response.getEntity());
log.info("支付信息:" + result);
JSONObject jsonObject = JSONUtil.parseObj(result);
String code = jsonObject.getStr("trade_state");
log.info("支付結(jié)果:" + code);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
private WechatPayHttpClientBuilder getWechatPayHttpClientBuilder() throws Exception{
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(
new FileInputStream(certKeyPath));
// 獲取證書管理器實例
CertificatesManager certificatesManager = CertificatesManager.getInstance();
// 向證書管理器增加需要自動更新平臺證書的商戶信息
certificatesManager.putMerchant(mchid, new WechatPay2Credentials(mchid,
new PrivateKeySigner(serialNumber, merchantPrivateKey)), mchKey.getBytes(StandardCharsets.UTF_8));
// ... 若有多個商戶號,可繼續(xù)調(diào)用putMerchant添加商戶信息
// 從證書管理器中獲取verifier
Verifier verifier = certificatesManager.getVerifier(mchid);
X509Certificate certificate = verifier.getValidCertificate();
List<X509Certificate> certificates = new ArrayList<>();
certificates.add(certificate);
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
.withMerchant(mchid, serialNumber, merchantPrivateKey)
.withWechatPay(certificates);
// 通過WechatPayHttpClientBuilder構(gòu)造的HttpClient,會自動的處理簽名和驗簽
return builder;
}
文章來源地址http://www.zghlxwxcb.cn/news/detail-662821.html
文章來源:http://www.zghlxwxcb.cn/news/detail-662821.html
到了這里,關(guān)于springboot實現(xiàn)微信小程序V3微信支付功能的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!