java微信支付接口源码_java微信支付源码(WxPayAPI_JAVA_v3)

本文档详细介绍了使用Java实现微信支付接口的源码,包括初始化配置、签名验证、不同支付场景的接口调用方法,如统一下单、查询订单、退款、对账单下载等。同时,源码中包含了沙箱环境的处理和异常处理机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【实例简介】

【实例截图】

【核心代码】

package com.github.wxpay.sdk;

import java.util.HashMap;

import java.util.Map;

import com.github.wxpay.sdk.WXPayConstants.SignType;

public class WXPay {

private WXPayConfig config;

private SignType signType;

private boolean autoReport;

private boolean useSandbox;

private String notifyUrl;

private WXPayRequest wxPayRequest;

public WXPay(final WXPayConfig config) throws Exception {

this(config, null, true, false);

}

public WXPay(final WXPayConfig config, final boolean autoReport) throws Exception {

this(config, null, autoReport, false);

}

public WXPay(final WXPayConfig config, final boolean autoReport, final boolean useSandbox) throws Exception{

this(config, null, autoReport, useSandbox);

}

public WXPay(final WXPayConfig config, final String notifyUrl) throws Exception {

this(config, notifyUrl, true, false);

}

public WXPay(final WXPayConfig config, final String notifyUrl, final boolean autoReport) throws Exception {

this(config, notifyUrl, autoReport, false);

}

public WXPay(final WXPayConfig config, final String notifyUrl, final boolean autoReport, final boolean useSandbox) throws Exception {

this.config = config;

this.notifyUrl = notifyUrl;

this.autoReport = autoReport;

this.useSandbox = useSandbox;

if (useSandbox) {

this.signType = SignType.MD5; // 沙箱环境

}

else {

this.signType = SignType.HMACSHA256;

}

this.wxPayRequest = new WXPayRequest(config);

}

private void checkWXPayConfig() throws Exception {

if (this.config == null) {

throw new Exception("config is null");

}

if (this.config.getAppID() == null || this.config.getAppID().trim().length() == 0) {

throw new Exception("appid in config is empty");

}

if (this.config.getMchID() == null || this.config.getMchID().trim().length() == 0) {

throw new Exception("appid in config is empty");

}

if (this.config.getCertStream() == null) {

throw new Exception("cert stream in config is empty");

}

// if (this.config.getPrimaryDomain() == null || this.config.getPrimaryDomain().trim().length() == 0) {

// throw new Exception("primary domain in config is empty");

// }

//

// // todo 海外就填两个相同的? 下面的逻辑待考虑

// if (this.config.getAlternateDomain() == null || this.config.getAlternateDomain().trim().length() == 0) {

// throw new Exception("alternate domain in config is empty");

// }

if (this.config.getWXPayDomain() == null){

throw new Exception("config.getWXPayDomain() is null");

}

if (this.config.getHttpConnectTimeoutMs() < 10) {

throw new Exception("http connect timeout is too small");

}

if (this.config.getHttpReadTimeoutMs() < 10) {

throw new Exception("http read timeout is too small");

}

}

/**

* 向 Map 中添加 appid、mch_id、nonce_str、sign_type、sign

* 该函数适用于商户适用于统一下单等接口,不适用于红包、代金券接口

*

* @param reqData

* @return

* @throws Exception

*/

public Map fillRequestData(Map reqData) throws Exception {

reqData.put("appid", config.getAppID());

reqData.put("mch_id", config.getMchID());

reqData.put("nonce_str", WXPayUtil.generateUUID());

if (SignType.MD5.equals(this.signType)) {

reqData.put("sign_type", WXPayConstants.MD5);

}

else if (SignType.HMACSHA256.equals(this.signType)) {

reqData.put("sign_type", WXPayConstants.HMACSHA256);

}

reqData.put("sign", WXPayUtil.generateSignature(reqData, config.getKey(), this.signType));

return reqData;

}

/**

* 判断xml数据的sign是否有效,必须包含sign字段,否则返回false。

*

* @param reqData 向wxpay post的请求数据

* @return 签名是否有效

* @throws Exception

*/

public boolean isResponseSignatureValid(Map reqData) throws Exception {

// 返回数据的签名方式和请求中给定的签名方式是一致的

return WXPayUtil.isSignatureValid(reqData, this.config.getKey(), this.signType);

}

/**

* 判断支付结果通知中的sign是否有效

*

* @param reqData 向wxpay post的请求数据

* @return 签名是否有效

* @throws Exception

*/

public boolean isPayResultNotifySignatureValid(Map reqData) throws Exception {

String signTypeInData = reqData.get(WXPayConstants.FIELD_SIGN_TYPE);

SignType signType;

if (signTypeInData == null) {

signType = SignType.MD5;

}

else {

signTypeInData = signTypeInData.trim();

if (signTypeInData.length() == 0) {

signType = SignType.MD5;

}

else if (WXPayConstants.MD5.equals(signTypeInData)) {

signType = SignType.MD5;

}

else if (WXPayConstants.HMACSHA256.equals(signTypeInData)) {

signType = SignType.HMACSHA256;

}

else {

throw new Exception(String.format("Unsupported sign_type: %s", signTypeInData));

}

}

return WXPayUtil.isSignatureValid(reqData, this.config.getKey(), signType);

}

/**

* 不需要证书的请求

* @param urlSuffix String

* @param reqData 向wxpay post的请求数据

* @param connectTimeoutMs 超时时间,单位是毫秒

* @param readTimeoutMs 超时时间,单位是毫秒

* @return API返回数据

* @throws Exception

*/

public String requestWithoutCert(String urlSuffix, Map reqData,

int connectTimeoutMs, int readTimeoutMs) throws Exception {

String msgUUID = reqData.get("nonce_str");

String reqBody = WXPayUtil.mapToXml(reqData);

String resp = this.wxPayRequest.requestWithoutCert(urlSuffix, msgUUID, reqBody, connectTimeoutMs, readTimeoutMs, autoReport);

return resp;

}

/**

* 需要证书的请求

* @param urlSuffix String

* @param reqData 向wxpay post的请求数据 Map

* @param connectTimeoutMs 超时时间,单位是毫秒

* @param readTimeoutMs 超时时间,单位是毫秒

* @return API返回数据

* @throws Exception

*/

public String requestWithCert(String urlSuffix, Map reqData,

int connectTimeoutMs, int readTimeoutMs) throws Exception {

String msgUUID= reqData.get("nonce_str");

String reqBody = WXPayUtil.mapToXml(reqData);

String resp = this.wxPayRequest.requestWithCert(urlSuffix, msgUUID, reqBody, connectTimeoutMs, readTimeoutMs, this.autoReport);

return resp;

}

/**

* 处理 HTTPS API返回数据,转换成Map对象。return_code为SUCCESS时,验证签名。

* @param xmlStr API返回的XML格式数据

* @return Map类型数据

* @throws Exception

*/

public Map processResponseXml(String xmlStr) throws Exception {

String RETURN_CODE = "return_code";

String return_code;

Map respData = WXPayUtil.xmlToMap(xmlStr);

if (respData.containsKey(RETURN_CODE)) {

return_code = respData.get(RETURN_CODE);

}

else {

throw new Exception(String.format("No `return_code` in XML: %s", xmlStr));

}

if (return_code.equals(WXPayConstants.FAIL)) {

return respData;

}

else if (return_code.equals(WXPayConstants.SUCCESS)) {

if (this.isResponseSignatureValid(respData)) {

return respData;

}

else {

throw new Exception(String.format("Invalid sign value in XML: %s", xmlStr));

}

}

else {

throw new Exception(String.format("return_code value %s is invalid in XML: %s", return_code, xmlStr));

}

}

/**

* 作用:提交刷卡支付

* 场景:刷卡支付

* @param reqData 向wxpay post的请求数据

* @return API返回数据

* @throws Exception

*/

public Map microPay(Map reqData) throws Exception {

return this.microPay(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());

}

/**

* 作用:提交刷卡支付

* 场景:刷卡支付

* @param reqData 向wxpay post的请求数据

* @param connectTimeoutMs 连接超时时间,单位是毫秒

* @param readTimeoutMs 读超时时间,单位是毫秒

* @return API返回数据

* @throws Exception

*/

public Map microPay(Map reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {

String url;

if (this.useSandbox) {

url = WXPayConstants.SANDBOX_MICROPAY_URL_SUFFIX;

}

else {

url = WXPayConstants.MICROPAY_URL_SUFFIX;

}

String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);

return this.processResponseXml(respXml);

}

/**

* 提交刷卡支付,针对软POS,尽可能做成功

* 内置重试机制,最多60s

* @param reqData

* @return

* @throws Exception

*/

public Map microPayWithPos(Map reqData) throws Exception {

return this.microPayWithPos(reqData, this.config.getHttpConnectTimeoutMs());

}

/**

* 提交刷卡支付,针对软POS,尽可能做成功

* 内置重试机制,最多60s

* @param reqData

* @param connectTimeoutMs

* @return

* @throws Exception

*/

public Map microPayWithPos(Map reqData, int connectTimeoutMs) throws Exception {

int remainingTimeMs = 60*1000;

long startTimestampMs = 0;

Map lastResult = null;

Exception lastException = null;

while (true) {

startTimestampMs = WXPayUtil.getCurrentTimestampMs();

int readTimeoutMs = remainingTimeMs - connectTimeoutMs;

if (readTimeoutMs > 1000) {

try {

lastResult = this.microPay(reqData, connectTimeoutMs, readTimeoutMs);

String returnCode = lastResult.get("return_code");

if (returnCode.equals("SUCCESS")) {

String resultCode = lastResult.get("result_code");

String errCode = lastResult.get("err_code");

if (resultCode.equals("SUCCESS")) {

break;

}

else {

// 看错误码,若支付结果未知,则重试提交刷卡支付

if (errCode.equals("SYSTEMERROR") || errCode.equals("BANKERROR") || errCode.equals("USERPAYING")) {

remainingTimeMs = remainingTimeMs - (int)(WXPayUtil.getCurrentTimestampMs() - startTimestampMs);

if (remainingTimeMs <= 100) {

break;

}

else {

WXPayUtil.getLogger().info("microPayWithPos: try micropay again");

if (remainingTimeMs > 5*1000) {

Thread.sleep(5*1000);

}

else {

Thread.sleep(1*1000);

}

continue;

}

}

else {

break;

}

}

}

else {

break;

}

}

catch (Exception ex) {

lastResult = null;

lastException = ex;

}

}

else {

break;

}

}

if (lastResult == null) {

throw lastException;

}

else {

return lastResult;

}

}

/**

* 作用:统一下单

* 场景:公共号支付、扫码支付、APP支付

* @param reqData 向wxpay post的请求数据

* @return API返回数据

* @throws Exception

*/

public Map unifiedOrder(Map reqData) throws Exception {

return this.unifiedOrder(reqData, config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());

}

/**

* 作用:统一下单

* 场景:公共号支付、扫码支付、APP支付

* @param reqData 向wxpay post的请求数据

* @param connectTimeoutMs 连接超时时间,单位是毫秒

* @param readTimeoutMs 读超时时间,单位是毫秒

* @return API返回数据

* @throws Exception

*/

public Map unifiedOrder(Map reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {

String url;

if (this.useSandbox) {

url = WXPayConstants.SANDBOX_UNIFIEDORDER_URL_SUFFIX;

}

else {

url = WXPayConstants.UNIFIEDORDER_URL_SUFFIX;

}

if(this.notifyUrl != null) {

reqData.put("notify_url", this.notifyUrl);

}

String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);

return this.processResponseXml(respXml);

}

/**

* 作用:查询订单

* 场景:刷卡支付、公共号支付、扫码支付、APP支付

* @param reqData 向wxpay post的请求数据

* @return API返回数据

* @throws Exception

*/

public Map orderQuery(Map reqData) throws Exception {

return this.orderQuery(reqData, config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());

}

/**

* 作用:查询订单

* 场景:刷卡支付、公共号支付、扫码支付、APP支付

* @param reqData 向wxpay post的请求数据 int

* @param connectTimeoutMs 连接超时时间,单位是毫秒

* @param readTimeoutMs 读超时时间,单位是毫秒

* @return API返回数据

* @throws Exception

*/

public Map orderQuery(Map reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {

String url;

if (this.useSandbox) {

url = WXPayConstants.SANDBOX_ORDERQUERY_URL_SUFFIX;

}

else {

url = WXPayConstants.ORDERQUERY_URL_SUFFIX;

}

String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);

return this.processResponseXml(respXml);

}

/**

* 作用:撤销订单

* 场景:刷卡支付

* @param reqData 向wxpay post的请求数据

* @return API返回数据

* @throws Exception

*/

public Map reverse(Map reqData) throws Exception {

return this.reverse(reqData, config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());

}

/**

* 作用:撤销订单

* 场景:刷卡支付

* 其他:需要证书

* @param reqData 向wxpay post的请求数据

* @param connectTimeoutMs 连接超时时间,单位是毫秒

* @param readTimeoutMs 读超时时间,单位是毫秒

* @return API返回数据

* @throws Exception

*/

public Map reverse(Map reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {

String url;

if (this.useSandbox) {

url = WXPayConstants.SANDBOX_REVERSE_URL_SUFFIX;

}

else {

url = WXPayConstants.REVERSE_URL_SUFFIX;

}

String respXml = this.requestWithCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);

return this.processResponseXml(respXml);

}

/**

* 作用:关闭订单

* 场景:公共号支付、扫码支付、APP支付

* @param reqData 向wxpay post的请求数据

* @return API返回数据

* @throws Exception

*/

public Map closeOrder(Map reqData) throws Exception {

return this.closeOrder(reqData, config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());

}

/**

* 作用:关闭订单

* 场景:公共号支付、扫码支付、APP支付

* @param reqData 向wxpay post的请求数据

* @param connectTimeoutMs 连接超时时间,单位是毫秒

* @param readTimeoutMs 读超时时间,单位是毫秒

* @return API返回数据

* @throws Exception

*/

public Map closeOrder(Map reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {

String url;

if (this.useSandbox) {

url = WXPayConstants.SANDBOX_CLOSEORDER_URL_SUFFIX;

}

else {

url = WXPayConstants.CLOSEORDER_URL_SUFFIX;

}

String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);

return this.processResponseXml(respXml);

}

/**

* 作用:申请退款

* 场景:刷卡支付、公共号支付、扫码支付、APP支付

* @param reqData 向wxpay post的请求数据

* @return API返回数据

* @throws Exception

*/

public Map refund(Map reqData) throws Exception {

return this.refund(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());

}

/**

* 作用:申请退款

* 场景:刷卡支付、公共号支付、扫码支付、APP支付

* 其他:需要证书

* @param reqData 向wxpay post的请求数据

* @param connectTimeoutMs 连接超时时间,单位是毫秒

* @param readTimeoutMs 读超时时间,单位是毫秒

* @return API返回数据

* @throws Exception

*/

public Map refund(Map reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {

String url;

if (this.useSandbox) {

url = WXPayConstants.SANDBOX_REFUND_URL_SUFFIX;

}

else {

url = WXPayConstants.REFUND_URL_SUFFIX;

}

String respXml = this.requestWithCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);

return this.processResponseXml(respXml);

}

/**

* 作用:退款查询

* 场景:刷卡支付、公共号支付、扫码支付、APP支付

* @param reqData 向wxpay post的请求数据

* @return API返回数据

* @throws Exception

*/

public Map refundQuery(Map reqData) throws Exception {

return this.refundQuery(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());

}

/**

* 作用:退款查询

* 场景:刷卡支付、公共号支付、扫码支付、APP支付

* @param reqData 向wxpay post的请求数据

* @param connectTimeoutMs 连接超时时间,单位是毫秒

* @param readTimeoutMs 读超时时间,单位是毫秒

* @return API返回数据

* @throws Exception

*/

public Map refundQuery(Map reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {

String url;

if (this.useSandbox) {

url = WXPayConstants.SANDBOX_REFUNDQUERY_URL_SUFFIX;

}

else {

url = WXPayConstants.REFUNDQUERY_URL_SUFFIX;

}

String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);

return this.processResponseXml(respXml);

}

/**

* 作用:对账单下载(成功时返回对账单数据,失败时返回XML格式数据)

* 场景:刷卡支付、公共号支付、扫码支付、APP支付

* @param reqData 向wxpay post的请求数据

* @return API返回数据

* @throws Exception

*/

public Map downloadBill(Map reqData) throws Exception {

return this.downloadBill(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());

}

/**

* 作用:对账单下载

* 场景:刷卡支付、公共号支付、扫码支付、APP支付

* 其他:无论是否成功都返回Map。若成功,返回的Map中含有return_code、return_msg、data,

* 其中return_code为`SUCCESS`,data为对账单数据。

* @param reqData 向wxpay post的请求数据

* @param connectTimeoutMs 连接超时时间,单位是毫秒

* @param readTimeoutMs 读超时时间,单位是毫秒

* @return 经过封装的API返回数据

* @throws Exception

*/

public Map downloadBill(Map reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {

String url;

if (this.useSandbox) {

url = WXPayConstants.SANDBOX_DOWNLOADBILL_URL_SUFFIX;

}

else {

url = WXPayConstants.DOWNLOADBILL_URL_SUFFIX;

}

String respStr = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs).trim();

Map ret;

// 出现错误,返回XML数据

if (respStr.indexOf("

ret = WXPayUtil.xmlToMap(respStr);

}

else {

// 正常返回csv数据

ret = new HashMap();

ret.put("return_code", WXPayConstants.SUCCESS);

ret.put("return_msg", "ok");

ret.put("data", respStr);

}

return ret;

}

/**

* 作用:交易保障

* 场景:刷卡支付、公共号支付、扫码支付、APP支付

* @param reqData 向wxpay post的请求数据

* @return API返回数据

* @throws Exception

*/

public Map report(Map reqData) throws Exception {

return this.report(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());

}

/**

* 作用:交易保障

* 场景:刷卡支付、公共号支付、扫码支付、APP支付

* @param reqData 向wxpay post的请求数据

* @param connectTimeoutMs 连接超时时间,单位是毫秒

* @param readTimeoutMs 读超时时间,单位是毫秒

* @return API返回数据

* @throws Exception

*/

public Map report(Map reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {

String url;

if (this.useSandbox) {

url = WXPayConstants.SANDBOX_REPORT_URL_SUFFIX;

}

else {

url = WXPayConstants.REPORT_URL_SUFFIX;

}

String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);

return WXPayUtil.xmlToMap(respXml);

}

/**

* 作用:转换短链接

* 场景:刷卡支付、扫码支付

* @param reqData 向wxpay post的请求数据

* @return API返回数据

* @throws Exception

*/

public Map shortUrl(Map reqData) throws Exception {

return this.shortUrl(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());

}

/**

* 作用:转换短链接

* 场景:刷卡支付、扫码支付

* @param reqData 向wxpay post的请求数据

* @return API返回数据

* @throws Exception

*/

public Map shortUrl(Map reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {

String url;

if (this.useSandbox) {

url = WXPayConstants.SANDBOX_SHORTURL_URL_SUFFIX;

}

else {

url = WXPayConstants.SHORTURL_URL_SUFFIX;

}

String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);

return this.processResponseXml(respXml);

}

/**

* 作用:授权码查询OPENID接口

* 场景:刷卡支付

* @param reqData 向wxpay post的请求数据

* @return API返回数据

* @throws Exception

*/

public Map authCodeToOpenid(Map reqData) throws Exception {

return this.authCodeToOpenid(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());

}

/**

* 作用:授权码查询OPENID接口

* 场景:刷卡支付

* @param reqData 向wxpay post的请求数据

* @param connectTimeoutMs 连接超时时间,单位是毫秒

* @param readTimeoutMs 读超时时间,单位是毫秒

* @return API返回数据

* @throws Exception

*/

public Map authCodeToOpenid(Map reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {

String url;

if (this.useSandbox) {

url = WXPayConstants.SANDBOX_AUTHCODETOOPENID_URL_SUFFIX;

}

else {

url = WXPayConstants.AUTHCODETOOPENID_URL_SUFFIX;

}

String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);

return this.processResponseXml(respXml);

}

} // end class

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值