@@ -4,14 +4,13 @@ import me.chanjar.weixin.common.bean.WxAccessToken; | |||
import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder; | |||
import javax.net.ssl.SSLContext; | |||
import java.io.File; | |||
import java.util.concurrent.locks.Lock; | |||
/** | |||
* 微信客户端配置存储 | |||
* @author chanjarster | |||
* | |||
* @author chanjarster | |||
*/ | |||
public interface WxMpConfigStorage { | |||
@@ -28,13 +27,15 @@ public interface WxMpConfigStorage { | |||
/** | |||
* 应该是线程安全的 | |||
* | |||
* @param accessToken 要更新的WxAccessToken对象 | |||
*/ | |||
void updateAccessToken(WxAccessToken accessToken); | |||
/** | |||
* 应该是线程安全的 | |||
* @param accessToken 新的accessToken值 | |||
* | |||
* @param accessToken 新的accessToken值 | |||
* @param expiresInSeconds 过期时间,以秒为单位 | |||
*/ | |||
void updateAccessToken(String accessToken, int expiresInSeconds); | |||
@@ -52,7 +53,8 @@ public interface WxMpConfigStorage { | |||
/** | |||
* 应该是线程安全的 | |||
* @param jsapiTicket 新的jsapi ticket值 | |||
* | |||
* @param jsapiTicket 新的jsapi ticket值 | |||
* @param expiresInSeconds 过期时间,以秒为单位 | |||
*/ | |||
void updateJsapiTicket(String jsapiTicket, int expiresInSeconds); | |||
@@ -70,7 +72,8 @@ public interface WxMpConfigStorage { | |||
/** | |||
* 应该是线程安全的 | |||
* @param cardApiTicket 新的cardApi ticket值 | |||
* | |||
* @param cardApiTicket 新的cardApi ticket值 | |||
* @param expiresInSeconds 过期时间,以秒为单位 | |||
*/ | |||
void updateCardApiTicket(String cardApiTicket, int expiresInSeconds); | |||
@@ -82,21 +85,23 @@ public interface WxMpConfigStorage { | |||
String getPartnerId(); | |||
String getPartnerKey(); | |||
/** | |||
* 微信支付异步回掉地址,通知url必须为直接可访问的url,不能携带参数。 | |||
* @since 2.5.0 | |||
* | |||
* @return | |||
* @since 2.5.0 | |||
*/ | |||
String getNotifyURL(); | |||
/** | |||
* 交易类型 | |||
* <pre> | |||
* JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付 | |||
* </pre> | |||
* @since 2.5.0 | |||
* | |||
* @return | |||
* @since 2.5.0 | |||
*/ | |||
String getTradeType(); | |||
@@ -118,23 +123,20 @@ public interface WxMpConfigStorage { | |||
File getTmpDirFile(); | |||
@Deprecated | |||
SSLContext getSSLContext(); | |||
SSLContext getSslContext(); | |||
void setSslContext(SSLContext sslContext); | |||
/** | |||
* 在此之前,必须将partnerId进行赋值 | |||
* | |||
* @param filePath | |||
* apiclient_cert.p12的文件的绝对路径 | |||
*/ | |||
void setSslContextFilePath(String filePath) throws Exception; | |||
/** | |||
* 在此之前,必须将partnerId进行赋值 | |||
* | |||
* @param filePath apiclient_cert.p12的文件的绝对路径 | |||
*/ | |||
void setSslContextFilePath(String filePath) throws Exception; | |||
/** | |||
* http client builder | |||
* | |||
* @return ApacheHttpClientBuilder | |||
*/ | |||
ApacheHttpClientBuilder getApacheHttpClientBuilder(); | |||
@@ -143,5 +145,5 @@ public interface WxMpConfigStorage { | |||
* 是否自动刷新token | |||
*/ | |||
boolean autoRefreshToken(); | |||
} |
@@ -1,23 +1,21 @@ | |||
package me.chanjar.weixin.mp.api; | |||
import me.chanjar.weixin.common.bean.WxAccessToken; | |||
import me.chanjar.weixin.common.util.ToStringUtils; | |||
import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder; | |||
import org.apache.http.ssl.SSLContexts; | |||
import javax.net.ssl.SSLContext; | |||
import java.io.File; | |||
import java.io.FileInputStream; | |||
import java.security.KeyStore; | |||
import java.util.concurrent.locks.Lock; | |||
import java.util.concurrent.locks.ReentrantLock; | |||
import javax.net.ssl.SSLContext; | |||
import org.apache.http.ssl.SSLContexts; | |||
import me.chanjar.weixin.common.bean.WxAccessToken; | |||
import me.chanjar.weixin.common.util.ToStringUtils; | |||
import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder; | |||
/** | |||
* 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化 | |||
* @author chanjarster | |||
* | |||
* @author chanjarster | |||
*/ | |||
public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { | |||
@@ -63,6 +61,10 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { | |||
return this.accessToken; | |||
} | |||
public void setAccessToken(String accessToken) { | |||
this.accessToken = accessToken; | |||
} | |||
@Override | |||
public Lock getAccessTokenLock() { | |||
return this.accessTokenLock; | |||
@@ -94,15 +96,15 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { | |||
return this.jsapiTicket; | |||
} | |||
public void setJsapiTicket(String jsapiTicket) { | |||
this.jsapiTicket = jsapiTicket; | |||
} | |||
@Override | |||
public Lock getJsapiTicketLock() { | |||
return this.jsapiTicketLock; | |||
} | |||
public void setJsapiTicket(String jsapiTicket) { | |||
this.jsapiTicket = jsapiTicket; | |||
} | |||
public long getJsapiTicketExpiresTime() { | |||
return this.jsapiTicketExpiresTime; | |||
} | |||
@@ -163,31 +165,35 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { | |||
return this.appId; | |||
} | |||
public void setAppId(String appId) { | |||
this.appId = appId; | |||
} | |||
@Override | |||
public String getSecret() { | |||
return this.secret; | |||
} | |||
public void setSecret(String secret) { | |||
this.secret = secret; | |||
} | |||
@Override | |||
public String getToken() { | |||
return this.token; | |||
} | |||
public void setToken(String token) { | |||
this.token = token; | |||
} | |||
@Override | |||
public long getExpiresTime() { | |||
return this.expiresTime; | |||
} | |||
public void setAppId(String appId) { | |||
this.appId = appId; | |||
} | |||
public void setSecret(String secret) { | |||
this.secret = secret; | |||
} | |||
public void setToken(String token) { | |||
this.token = token; | |||
public void setExpiresTime(long expiresTime) { | |||
this.expiresTime = expiresTime; | |||
} | |||
@Override | |||
@@ -199,14 +205,6 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { | |||
this.aesKey = aesKey; | |||
} | |||
public void setAccessToken(String accessToken) { | |||
this.accessToken = accessToken; | |||
} | |||
public void setExpiresTime(long expiresTime) { | |||
this.expiresTime = expiresTime; | |||
} | |||
@Override | |||
public String getOauth2redirectUri() { | |||
return this.oauth2redirectUri; | |||
@@ -259,40 +257,40 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { | |||
@Override | |||
public String getPartnerId() { | |||
return this.partnerId; | |||
return this.partnerId; | |||
} | |||
public void setPartnerId(String partnerId) { | |||
this.partnerId = partnerId; | |||
this.partnerId = partnerId; | |||
} | |||
@Override | |||
public String getPartnerKey() { | |||
return this.partnerKey; | |||
return this.partnerKey; | |||
} | |||
public void setPartnerKey(String partnerKey) { | |||
this.partnerKey = partnerKey; | |||
this.partnerKey = partnerKey; | |||
} | |||
public String getNotifyURL() { | |||
return notifyURL; | |||
} | |||
public String getNotifyURL() { | |||
return notifyURL; | |||
} | |||
public void setNotifyURL(String notifyURL) { | |||
this.notifyURL = notifyURL; | |||
} | |||
public void setNotifyURL(String notifyURL) { | |||
this.notifyURL = notifyURL; | |||
} | |||
public String getTradeType() { | |||
return tradeType; | |||
} | |||
public String getTradeType() { | |||
return tradeType; | |||
} | |||
public void setTradeType(String tradeType) { | |||
this.tradeType = tradeType; | |||
} | |||
public void setTradeType(String tradeType) { | |||
this.tradeType = tradeType; | |||
} | |||
@Override | |||
@Override | |||
public File getTmpDirFile() { | |||
return this.tmpDirFile; | |||
} | |||
@@ -302,47 +300,43 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { | |||
} | |||
@Override | |||
public SSLContext getSSLContext() { | |||
public SSLContext getSslContext() { | |||
return this.sslContext; | |||
} | |||
@Override | |||
public SSLContext getSslContext() { | |||
return this.sslContext; | |||
} | |||
@Override | |||
public void setSslContextFilePath(String filePath) throws Exception { | |||
if (null == partnerId) { | |||
throw new Exception("请先将partnerId进行赋值"); | |||
} | |||
File file = new File(filePath); | |||
if (!file.exists()) { | |||
throw new RuntimeException(file.getPath() + ":文件不存在!在设置SSLContext的时候"); | |||
} | |||
FileInputStream inputStream = new FileInputStream(file); | |||
KeyStore keystore = KeyStore.getInstance("PKCS12"); | |||
char[] partnerId2charArray = partnerId.toCharArray(); | |||
keystore.load(inputStream, partnerId2charArray); | |||
this.sslContext = SSLContexts.custom().loadKeyMaterial(keystore, partnerId2charArray).build(); | |||
} | |||
@Override | |||
public void setSslContext(SSLContext context) { | |||
this.sslContext = context; | |||
} | |||
public void setSslContext(SSLContext context) { | |||
this.sslContext = context; | |||
} | |||
@Override | |||
public ApacheHttpClientBuilder getApacheHttpClientBuilder() { | |||
return this.apacheHttpClientBuilder; | |||
public void setSslContextFilePath(String filePath) throws Exception { | |||
if (null == partnerId) { | |||
throw new Exception("请先将partnerId进行赋值"); | |||
} | |||
File file = new File(filePath); | |||
if (!file.exists()) { | |||
throw new RuntimeException(file.getPath() + ":文件不存在!在设置SSLContext的时候"); | |||
} | |||
FileInputStream inputStream = new FileInputStream(file); | |||
KeyStore keystore = KeyStore.getInstance("PKCS12"); | |||
char[] partnerId2charArray = partnerId.toCharArray(); | |||
keystore.load(inputStream, partnerId2charArray); | |||
this.sslContext = SSLContexts.custom().loadKeyMaterial(keystore, partnerId2charArray).build(); | |||
} | |||
@Override | |||
public boolean autoRefreshToken() { | |||
return true; | |||
public ApacheHttpClientBuilder getApacheHttpClientBuilder() { | |||
return this.apacheHttpClientBuilder; | |||
} | |||
public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) { | |||
this.apacheHttpClientBuilder = apacheHttpClientBuilder; | |||
} | |||
@Override | |||
public boolean autoRefreshToken() { | |||
return true; | |||
} | |||
} |
@@ -7,7 +7,6 @@ import me.chanjar.weixin.mp.bean.pay.request.WxPaySendRedpackRequest; | |||
import me.chanjar.weixin.mp.bean.pay.request.WxPayUnifiedOrderRequest; | |||
import me.chanjar.weixin.mp.bean.pay.result.*; | |||
import java.io.File; | |||
import java.util.Map; | |||
/** | |||
@@ -76,10 +75,9 @@ public interface WxMpPayService { | |||
* </pre> | |||
* | |||
* @param request 请求对象 | |||
* @param keyFile 证书文件对象(即apiclient_cert.p12 商户证书文件,详细参考https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3) | |||
* @return 退款操作结果 | |||
*/ | |||
WxPayRefundResult refund(WxPayRefundRequest request, File keyFile) throws WxErrorException; | |||
WxPayRefundResult refund(WxPayRefundRequest request) throws WxErrorException; | |||
/** | |||
* <pre> | |||
@@ -128,7 +126,7 @@ public interface WxMpPayService { | |||
/** | |||
* 微信公众号支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3) | |||
* | |||
* @param prams 参数信息,默认使用配置中的PartnerKey进行签名 | |||
* @param prams 参数信息,默认使用配置中的PartnerKey进行签名 | |||
* @return 签名字符串 | |||
* @see #createSign(Map, String) | |||
*/ | |||
@@ -176,7 +174,7 @@ public interface WxMpPayService { | |||
/** | |||
* 校验签名是否正确 | |||
* | |||
* @param params 需要校验的参数Map | |||
* @param params 需要校验的参数Map | |||
* @param signKey 校验的签名Key | |||
* @return true - 签名校验成功,false - 签名校验失败 | |||
* @see #checkSign(Map, String) | |||
@@ -195,41 +193,9 @@ public interface WxMpPayService { | |||
* </pre> | |||
* | |||
* @param request 请求对象 | |||
* @param keyFile 证书文件对象(即apiclient_cert.p12 商户证书文件,详细参考https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3) | |||
*/ | |||
@Deprecated | |||
WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request, File keyFile) throws WxErrorException; | |||
/** | |||
* 发送微信红包给个人用户 | |||
* <pre> | |||
* 文档详见: | |||
* 发送普通红包 https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_4&index=3 | |||
* 接口地址:https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack | |||
* 发送裂变红包 https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_5&index=4 | |||
* 接口地址:https://api.mch.weixin.qq.com/mmpaymkttransfers/sendgroupredpack | |||
* </pre> | |||
* | |||
* @param request 请求对象 | |||
* @param keyFile 证书文件对象(即apiclient_cert.p12 商户证书文件,详细参考https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3) | |||
*/ | |||
WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) throws WxErrorException; | |||
/** | |||
* <pre> | |||
* 查询红包记录 | |||
* 用于商户对已发放的红包进行查询红包的具体信息,可支持普通红包和裂变包。 | |||
* 请求Url https://api.mch.weixin.qq.com/mmpaymkttransfers/gethbinfo | |||
* 是否需要证书 是(证书及使用说明详见商户证书) | |||
* 请求方式 POST | |||
* </pre> | |||
* | |||
* @param mchBillNo 商户发放红包的商户订单号,比如10000098201411111234567890 | |||
* @param keyFile 证书文件对象(即apiclient_cert.p12 商户证书文件,详细参考https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3) | |||
*/ | |||
@Deprecated | |||
WxPayRedpackQueryResult queryRedpack(String mchBillNo, File keyFile) throws WxErrorException; | |||
/** | |||
* <pre> | |||
* 查询红包记录 | |||
@@ -240,7 +206,6 @@ public interface WxMpPayService { | |||
* </pre> | |||
* | |||
* @param mchBillNo 商户发放红包的商户订单号,比如10000098201411111234567890 | |||
* @param keyFile 证书文件对象(即apiclient_cert.p12 商户证书文件,详细参考https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3) | |||
*/ | |||
WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxErrorException; | |||
@@ -255,9 +220,8 @@ public interface WxMpPayService { | |||
* </pre> | |||
* | |||
* @param request 请求对象 | |||
* @param keyFile 证书文件对象(即apiclient_cert.p12 商户证书文件,详细参考https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3) | |||
*/ | |||
WxEntPayResult entPay(WxEntPayRequest request, File keyFile) throws WxErrorException; | |||
WxEntPayResult entPay(WxEntPayRequest request) throws WxErrorException; | |||
/** | |||
* <pre> | |||
@@ -268,8 +232,7 @@ public interface WxMpPayService { | |||
* </pre> | |||
* | |||
* @param partnerTradeNo 商户订单号 | |||
* @param keyFile 证书文件对象(即apiclient_cert.p12 商户证书文件,详细参考https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3) | |||
*/ | |||
WxEntPayQueryResult queryEntPay(String partnerTradeNo, File keyFile) throws WxErrorException; | |||
WxEntPayQueryResult queryEntPay(String partnerTradeNo) throws WxErrorException; | |||
} |
@@ -23,16 +23,12 @@ import org.apache.http.conn.ssl.SSLConnectionSocketFactory; | |||
import org.apache.http.entity.StringEntity; | |||
import org.apache.http.impl.client.CloseableHttpClient; | |||
import org.apache.http.impl.client.HttpClients; | |||
import org.apache.http.ssl.SSLContexts; | |||
import org.apache.http.util.EntityUtils; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import javax.net.ssl.SSLContext; | |||
import java.io.File; | |||
import java.io.FileInputStream; | |||
import java.io.IOException; | |||
import java.security.KeyStore; | |||
import java.util.*; | |||
/** | |||
@@ -44,7 +40,7 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
private static final String PAY_BASE_URL = "https://api.mch.weixin.qq.com"; | |||
private static final String[] TRADE_TYPES = new String[]{"JSAPI", "NATIVE", "APP"}; | |||
private static final String[] REFUND_ACCOUNT = new String[]{"REFUND_SOURCE_RECHARGE_FUNDS","REFUND_SOURCE_UNSETTLED_FUNDS"}; | |||
private static final String[] REFUND_ACCOUNT = new String[]{"REFUND_SOURCE_RECHARGE_FUNDS", "REFUND_SOURCE_UNSETTLED_FUNDS"}; | |||
private final Logger log = LoggerFactory.getLogger(this.getClass()); | |||
private WxMpService wxMpService; | |||
@@ -57,20 +53,20 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
} | |||
@Override | |||
public WxPayRefundResult refund(WxPayRefundRequest request, File keyFile) throws WxErrorException { | |||
public WxPayRefundResult refund(WxPayRefundRequest request) throws WxErrorException { | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.processAnnotations(WxPayRefundRequest.class); | |||
xstream.processAnnotations(WxPayRefundResult.class); | |||
initRequest(request); | |||
if(StringUtils.isBlank(request.getOpUserId())){ | |||
if (StringUtils.isBlank(request.getOpUserId())) { | |||
request.setOpUserId(getConfig().getPartnerId()); | |||
} | |||
checkParameters(request); | |||
request.setSign(this.createSign(request)); | |||
String url = PAY_BASE_URL + "/secapi/pay/refund"; | |||
String responseContent = this.executeRequestWithKeyFile(url, keyFile, xstream.toXML(request), request.getMchId()); | |||
String responseContent = this.executeRequestWithKeyFile(url, xstream.toXML(request)); | |||
WxPayRefundResult result = (WxPayRefundResult) xstream.fromXML(responseContent); | |||
this.checkResult(result); | |||
return result; | |||
@@ -158,10 +154,8 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
} | |||
} | |||
@Override | |||
@Deprecated | |||
public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request, File keyFile) | |||
public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) | |||
throws WxErrorException { | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.processAnnotations(WxPaySendRedpackRequest.class); | |||
@@ -175,36 +169,14 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
//裂变红包 | |||
url = PAY_BASE_URL + "/mmpaymkttransfers/sendgroupredpack"; | |||
} | |||
String responseContent = this.executeRequestWithKeyFile(url, keyFile, xstream.toXML(request), request.getMchId()); | |||
String responseContent = this.executeRequestWithKeyFile(url, xstream.toXML(request)); | |||
WxPaySendRedpackResult result = (WxPaySendRedpackResult) xstream.fromXML(responseContent); | |||
this.checkResult(result); | |||
return result; | |||
} | |||
@Override | |||
public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) | |||
throws WxErrorException { | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.processAnnotations(WxPaySendRedpackRequest.class); | |||
xstream.processAnnotations(WxPaySendRedpackResult.class); | |||
initRequest(request); | |||
request.setSign(this.createSign(request)); | |||
String url = PAY_BASE_URL + "/mmpaymkttransfers/sendredpack"; | |||
if (request.getAmtType() != null) { | |||
//裂变红包 | |||
url = PAY_BASE_URL + "/mmpaymkttransfers/sendgroupredpack"; | |||
} | |||
String responseContent = this.executeRequestWithKeyFile(url, xstream.toXML(request)); | |||
WxPaySendRedpackResult result = (WxPaySendRedpackResult) xstream.fromXML(responseContent); | |||
this.checkResult(result); | |||
return result; | |||
} | |||
@Override | |||
@Deprecated | |||
public WxPayRedpackQueryResult queryRedpack(String mchBillNo, File keyFile) throws WxErrorException { | |||
public WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxErrorException { | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.processAnnotations(WxPayRedpackQueryRequest.class); | |||
xstream.processAnnotations(WxPayRedpackQueryResult.class); | |||
@@ -216,30 +188,11 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
request.setSign(this.createSign(request)); | |||
String url = PAY_BASE_URL + "/mmpaymkttransfers/gethbinfo"; | |||
String responseContent = this.executeRequestWithKeyFile(url, keyFile, xstream.toXML(request), request.getMchId()); | |||
String responseContent = this.executeRequestWithKeyFile(url, xstream.toXML(request)); | |||
WxPayRedpackQueryResult result = (WxPayRedpackQueryResult) xstream.fromXML(responseContent); | |||
this.checkResult(result); | |||
return result; | |||
} | |||
@Override | |||
public WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxErrorException { | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.processAnnotations(WxPayRedpackQueryRequest.class); | |||
xstream.processAnnotations(WxPayRedpackQueryResult.class); | |||
WxPayRedpackQueryRequest request = new WxPayRedpackQueryRequest(); | |||
request.setMchBillNo(mchBillNo); | |||
request.setBillType("MCHT"); | |||
initRequest(request); | |||
request.setSign(this.createSign(request)); | |||
String url = PAY_BASE_URL + "/mmpaymkttransfers/gethbinfo"; | |||
String responseContent = this.executeRequestWithKeyFile(url, xstream.toXML(request)); | |||
WxPayRedpackQueryResult result = (WxPayRedpackQueryResult) xstream.fromXML(responseContent); | |||
this.checkResult(result); | |||
return result; | |||
} | |||
@Override | |||
public WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxErrorException { | |||
@@ -296,17 +249,17 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.processAnnotations(WxPayUnifiedOrderRequest.class); | |||
xstream.processAnnotations(WxPayUnifiedOrderResult.class); | |||
initRequest(request); | |||
if(StringUtils.isBlank(request.getNotifyURL())){ | |||
if (StringUtils.isBlank(request.getNotifyURL())) { | |||
request.setNotifyURL(getConfig().getNotifyURL()); | |||
} | |||
if(StringUtils.isBlank(request.getTradeType())){ | |||
if (StringUtils.isBlank(request.getTradeType())) { | |||
request.setTradeType(getConfig().getTradeType()); | |||
} | |||
checkParameters(request);//校验参数 | |||
request.setSign(this.createSign(request)); | |||
String url = PAY_BASE_URL + "/pay/unifiedorder"; | |||
String xmlParam = xstream.toXML(request); | |||
log.debug("微信统一下单接口,URL:{},参数:{}", url, xmlParam); | |||
@@ -317,15 +270,15 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
this.checkResult(result); | |||
return result; | |||
} | |||
private void initRequest(WxPayBaseRequest request){ | |||
if(StringUtils.isBlank(request.getAppid())){ | |||
private void initRequest(WxPayBaseRequest request) { | |||
if (StringUtils.isBlank(request.getAppid())) { | |||
request.setAppid(getConfig().getAppId()); | |||
} | |||
if(StringUtils.isBlank(request.getMchId())){ | |||
if (StringUtils.isBlank(request.getMchId())) { | |||
request.setMchId(getConfig().getPartnerId()); | |||
} | |||
if(StringUtils.isBlank(request.getNonceStr())){ | |||
if (StringUtils.isBlank(request.getNonceStr())) { | |||
request.setNonceStr(String.valueOf(System.currentTimeMillis())); | |||
} | |||
} | |||
@@ -370,25 +323,25 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
} | |||
@Override | |||
public WxEntPayResult entPay(WxEntPayRequest request, File keyFile) throws WxErrorException { | |||
public WxEntPayResult entPay(WxEntPayRequest request) throws WxErrorException { | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.processAnnotations(WxEntPayRequest.class); | |||
xstream.processAnnotations(WxEntPayResult.class); | |||
initRequest(request); | |||
BeanUtils.checkRequiredFields(request); | |||
request.setSign(this.createSign(request)); | |||
String url = PAY_BASE_URL + "/mmpaymkttransfers/promotion/transfers"; | |||
String responseContent = this.executeRequestWithKeyFile(url, keyFile, xstream.toXML(request), request.getMchId()); | |||
String responseContent = this.executeRequestWithKeyFile(url, xstream.toXML(request)); | |||
WxEntPayResult result = (WxEntPayResult) xstream.fromXML(responseContent); | |||
this.checkResult(result); | |||
return result; | |||
} | |||
@Override | |||
public WxEntPayQueryResult queryEntPay(String partnerTradeNo, File keyFile) throws WxErrorException { | |||
public WxEntPayQueryResult queryEntPay(String partnerTradeNo) throws WxErrorException { | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.processAnnotations(WxEntPayQueryRequest.class); | |||
xstream.processAnnotations(WxEntPayQueryResult.class); | |||
@@ -398,7 +351,7 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
request.setSign(this.createSign(request)); | |||
String url = PAY_BASE_URL + "/mmpaymkttransfers/gettransferinfo"; | |||
String responseContent = this.executeRequestWithKeyFile(url, keyFile, xstream.toXML(request), request.getMchId()); | |||
String responseContent = this.executeRequestWithKeyFile(url, xstream.toXML(request)); | |||
WxEntPayQueryResult result = (WxEntPayQueryResult) xstream.fromXML(responseContent); | |||
this.checkResult(result); | |||
return result; | |||
@@ -425,15 +378,15 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
httpPost.releaseConnection(); | |||
} | |||
} | |||
@Deprecated | |||
private String executeRequestWithKeyFile(String url, File keyFile, String requestStr, String mchId) throws WxErrorException { | |||
try (FileInputStream inputStream = new FileInputStream(keyFile)) { | |||
KeyStore keyStore = KeyStore.getInstance("PKCS12"); | |||
keyStore.load(inputStream, mchId.toCharArray()); | |||
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mchId.toCharArray()).build(); | |||
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, | |||
private String executeRequestWithKeyFile(String url, String requestStr) throws WxErrorException { | |||
try { | |||
SSLContext sslContext = getConfig().getSslContext(); | |||
if (null == sslContext) { | |||
throw new Exception("请将配置类(即WxMpConfigStorage的实现类)中的SSLContext初始化"); | |||
} | |||
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, new String[]{"TLSv1"}, null, | |||
new DefaultHostnameVerifier()); | |||
HttpPost httpPost = new HttpPost(url); | |||
@@ -456,38 +409,7 @@ public class WxMpPayServiceImpl implements WxMpPayService { | |||
throw new WxErrorException(WxError.newBuilder().setErrorCode(-1).setErrorMsg(e.getMessage()).build(), e); | |||
} | |||
} | |||
private String executeRequestWithKeyFile(String url, String requestStr) throws WxErrorException { | |||
try { | |||
SSLContext sslcontext = getConfig().getSSLContext(); | |||
if(null==sslcontext){ | |||
throw new Exception("请将配置类(WxMpInMemoryConfigStorage)中的SSLContext初始化"); | |||
} | |||
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, | |||
new DefaultHostnameVerifier()); | |||
HttpPost httpPost = new HttpPost(url); | |||
if (this.wxMpService.getHttpProxy() != null) { | |||
httpPost.setConfig(RequestConfig.custom().setProxy(this.wxMpService.getHttpProxy()).build()); | |||
} | |||
try (CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build()) { | |||
httpPost.setEntity(new StringEntity(new String(requestStr.getBytes("UTF-8"), "ISO-8859-1"))); | |||
try (CloseableHttpResponse response = httpclient.execute(httpPost)) { | |||
String result = EntityUtils.toString(response.getEntity(), Consts.UTF_8); | |||
this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", url, requestStr, result); | |||
return result; | |||
} | |||
} finally { | |||
httpPost.releaseConnection(); | |||
} | |||
} catch (Exception e) { | |||
this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", url, requestStr, e.getMessage()); | |||
throw new WxErrorException(WxError.newBuilder().setErrorCode(-1).setErrorMsg(e.getMessage()).build(), e); | |||
} | |||
} | |||
@Override | |||
public String createSign(Object xmlBean) { | |||
return createSign(BeanUtils.xmlBean2Map(xmlBean), getConfig().getPartnerKey()); | |||
@@ -20,8 +20,6 @@ import org.apache.http.HttpHost; | |||
import org.apache.http.client.config.RequestConfig; | |||
import org.apache.http.client.methods.CloseableHttpResponse; | |||
import org.apache.http.client.methods.HttpGet; | |||
//import org.apache.http.conn.ssl.DefaultHostnameVerifier; | |||
//import org.apache.http.conn.ssl.SSLConnectionSocketFactory; | |||
import org.apache.http.impl.client.BasicResponseHandler; | |||
import org.apache.http.impl.client.CloseableHttpClient; | |||
import org.slf4j.Logger; | |||
@@ -30,55 +28,39 @@ import org.slf4j.LoggerFactory; | |||
import java.io.IOException; | |||
import java.util.concurrent.locks.Lock; | |||
//import org.apache.http.conn.ssl.DefaultHostnameVerifier; | |||
//import org.apache.http.conn.ssl.SSLConnectionSocketFactory; | |||
public class WxMpServiceImpl implements WxMpService { | |||
private static final JsonParser JSON_PARSER = new JsonParser(); | |||
protected final Logger log = LoggerFactory.getLogger(this.getClass()); | |||
protected final Logger log = LoggerFactory.getLogger(this.getClass()); | |||
protected WxSessionManager sessionManager = new StandardSessionManager(); | |||
private WxMpConfigStorage configStorage; | |||
private WxMpKefuService kefuService = new WxMpKefuServiceImpl(this); | |||
private WxMpMaterialService materialService = new WxMpMaterialServiceImpl(this); | |||
private WxMpMenuService menuService = new WxMpMenuServiceImpl(this); | |||
private WxMpUserService userService = new WxMpUserServiceImpl(this); | |||
private WxMpUserTagService tagService = new WxMpUserTagServiceImpl(this); | |||
private WxMpQrcodeService qrCodeService = new WxMpQrcodeServiceImpl(this); | |||
private WxMpCardService cardService = new WxMpCardServiceImpl(this); | |||
private WxMpPayService payService = new WxMpPayServiceImpl(this); | |||
private WxMpStoreService storeService = new WxMpStoreServiceImpl(this); | |||
private WxMpDataCubeService dataCubeService = new WxMpDataCubeServiceImpl(this); | |||
private WxMpUserBlacklistService blackListService = new WxMpUserBlacklistServiceImpl(this); | |||
private WxMpTemplateMsgService templateMsgService = new WxMpTemplateMsgServiceImpl(this); | |||
private WxMpDeviceService deviceService = new WxMpDeviceServiceImpl(this); | |||
private CloseableHttpClient httpClient; | |||
private HttpHost httpProxy; | |||
private int retrySleepMillis = 1000; | |||
private int maxRetryTimes = 5; | |||
protected WxSessionManager sessionManager = new StandardSessionManager(); | |||
@Override | |||
public boolean checkSignature(String timestamp, String nonce, String signature) { | |||
try { | |||
return SHA1.gen(this.configStorage.getToken(), timestamp, nonce) | |||
.equals(signature); | |||
.equals(signature); | |||
} catch (Exception e) { | |||
return false; | |||
} | |||
@@ -101,8 +83,8 @@ public class WxMpServiceImpl implements WxMpService { | |||
if (this.configStorage.isAccessTokenExpired()) { | |||
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" + | |||
"&appid=" + this.configStorage.getAppId() + "&secret=" | |||
+ this.configStorage.getSecret(); | |||
"&appid=" + this.configStorage.getAppId() + "&secret=" | |||
+ this.configStorage.getSecret(); | |||
try { | |||
HttpGet httpGet = new HttpGet(url); | |||
if (this.httpProxy != null) { | |||
@@ -117,8 +99,8 @@ public class WxMpServiceImpl implements WxMpService { | |||
} | |||
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent); | |||
this.configStorage.updateAccessToken(accessToken.getAccessToken(), | |||
accessToken.getExpiresIn()); | |||
}finally { | |||
accessToken.getExpiresIn()); | |||
} finally { | |||
httpGet.releaseConnection(); | |||
} | |||
} catch (IOException e) { | |||
@@ -167,7 +149,7 @@ public class WxMpServiceImpl implements WxMpService { | |||
String noncestr = RandomUtils.getRandomStr(); | |||
String jsapiTicket = getJsapiTicket(false); | |||
String signature = SHA1.genWithAmple("jsapi_ticket=" + jsapiTicket, | |||
"noncestr=" + noncestr, "timestamp=" + timestamp, "url=" + url); | |||
"noncestr=" + noncestr, "timestamp=" + timestamp, "url=" + url); | |||
WxJsapiSignature jsapiSignature = new WxJsapiSignature(); | |||
jsapiSignature.setAppid(this.configStorage.getAppId()); | |||
jsapiSignature.setTimestamp(timestamp); | |||
@@ -247,7 +229,7 @@ public class WxMpServiceImpl implements WxMpService { | |||
@Override | |||
public String buildQrConnectUrl(String redirectURI, String scope, | |||
String state) { | |||
String state) { | |||
StringBuilder url = new StringBuilder(); | |||
url.append("https://open.weixin.qq.com/connect/qrconnect?"); | |||
url.append("appid=").append(this.configStorage.getAppId()); | |||
@@ -366,7 +348,7 @@ public class WxMpServiceImpl implements WxMpService { | |||
do { | |||
try { | |||
T result = executeInternal(executor, uri, data); | |||
this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}",uri, data, result); | |||
this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", uri, data, result); | |||
return result; | |||
} catch (WxErrorException e) { | |||
if (retryTimes + 1 > this.maxRetryTimes) { | |||
@@ -416,7 +398,7 @@ public class WxMpServiceImpl implements WxMpService { | |||
if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001) { | |||
// 强制设置wxMpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token | |||
this.configStorage.expireAccessToken(); | |||
if(this.configStorage.autoRefreshToken()){ | |||
if (this.configStorage.autoRefreshToken()) { | |||
return this.execute(executor, uri, data); | |||
} | |||
} | |||
@@ -441,30 +423,24 @@ public class WxMpServiceImpl implements WxMpService { | |||
return this.httpClient; | |||
} | |||
@Override | |||
public void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider) { | |||
this.configStorage = wxConfigProvider; | |||
this.initHttpClient(); | |||
} | |||
private void initHttpClient() { | |||
ApacheHttpClientBuilder apacheHttpClientBuilder = this.configStorage | |||
.getApacheHttpClientBuilder(); | |||
.getApacheHttpClientBuilder(); | |||
if (null == apacheHttpClientBuilder) { | |||
apacheHttpClientBuilder = DefaultApacheHttpClientBuilder.get(); | |||
} | |||
apacheHttpClientBuilder.httpProxyHost(this.configStorage.getHttpProxyHost()) | |||
.httpProxyPort(this.configStorage.getHttpProxyPort()) | |||
.httpProxyUsername(this.configStorage.getHttpProxyUsername()) | |||
.httpProxyPassword(this.configStorage.getHttpProxyPassword()); | |||
.httpProxyPort(this.configStorage.getHttpProxyPort()) | |||
.httpProxyUsername(this.configStorage.getHttpProxyUsername()) | |||
.httpProxyPassword(this.configStorage.getHttpProxyPassword()); | |||
// if (this.configStorage.getSSLContext() != null) { | |||
// SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( | |||
// this.configStorage.getSSLContext(), new String[] { "TLSv1" }, null, | |||
// new DefaultHostnameVerifier()); | |||
// apacheHttpClientBuilder.sslConnectionSocketFactory(sslsf); | |||
// } | |||
// if (this.configStorage.getSSLContext() != null) { | |||
// SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( | |||
// this.configStorage.getSSLContext(), new String[] { "TLSv1" }, null, | |||
// new DefaultHostnameVerifier()); | |||
// apacheHttpClientBuilder.sslConnectionSocketFactory(sslsf); | |||
// } | |||
if (this.configStorage.getHttpProxyHost() != null && this.configStorage.getHttpProxyPort() > 0) { | |||
this.httpProxy = new HttpHost(this.configStorage.getHttpProxyHost(), this.configStorage.getHttpProxyPort()); | |||
@@ -478,6 +454,12 @@ public class WxMpServiceImpl implements WxMpService { | |||
return this.configStorage; | |||
} | |||
@Override | |||
public void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider) { | |||
this.configStorage = wxConfigProvider; | |||
this.initHttpClient(); | |||
} | |||
@Override | |||
public void setRetrySleepMillis(int retrySleepMillis) { | |||
this.retrySleepMillis = retrySleepMillis; | |||
@@ -34,7 +34,7 @@ public class WxMpPayServiceImplTest { | |||
} | |||
/** | |||
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#refund(WxPayRefundRequest, File)} . | |||
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#refund(WxPayRefundRequest)} . | |||
*/ | |||
@Test | |||
public void testRefund() throws Exception { | |||
@@ -43,8 +43,7 @@ public class WxMpPayServiceImplTest { | |||
request.setOutTradeNo("1111"); | |||
request.setTotalFee(1222); | |||
request.setRefundFee(111); | |||
File keyFile = new File("E:\\dlt.p12"); | |||
WxPayRefundResult result = this.wxService.getPayService().refund(request, keyFile); | |||
WxPayRefundResult result = this.wxService.getPayService().refund(request); | |||
System.err.println(result); | |||
} | |||
@@ -72,7 +71,7 @@ public class WxMpPayServiceImplTest { | |||
} | |||
/** | |||
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#sendRedpack(WxPaySendRedpackRequest, File)} . | |||
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#sendRedpack(WxPaySendRedpackRequest)} . | |||
*/ | |||
@Test | |||
public void testSendRedpack() throws Exception { | |||
@@ -82,18 +81,17 @@ public class WxMpPayServiceImplTest { | |||
request.setMchBillNo("aaaa"); | |||
request | |||
.setReOpenid(((WxXmlMpInMemoryConfigStorage) this.wxService.getWxMpConfigStorage()).getOpenid()); | |||
File keyFile = new File("E:\\dlt.p12"); | |||
WxPaySendRedpackResult redpackResult = this.wxService.getPayService().sendRedpack(request, keyFile); | |||
WxPaySendRedpackResult redpackResult = this.wxService.getPayService().sendRedpack(request); | |||
System.err.println(redpackResult); | |||
} | |||
/** | |||
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#queryRedpack(String, File)}. | |||
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#queryRedpack(String)}. | |||
*/ | |||
@Test | |||
public void testQueryRedpack() throws Exception { | |||
File keyFile = new File("E:\\dlt.p12"); | |||
WxPayRedpackQueryResult redpackResult = this.wxService.getPayService().queryRedpack("aaaa", keyFile); | |||
WxPayRedpackQueryResult redpackResult = this.wxService.getPayService().queryRedpack("aaaa"); | |||
System.err.println(redpackResult); | |||
} | |||
@@ -128,21 +126,19 @@ public class WxMpPayServiceImplTest { | |||
} | |||
/** | |||
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#entPay(WxEntPayRequest, File)}. | |||
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#entPay(WxEntPayRequest)}. | |||
*/ | |||
@Test | |||
public final void testEntPay() throws WxErrorException { | |||
File keyFile = new File("E:\\dlt.p12"); | |||
WxEntPayRequest request = new WxEntPayRequest(); | |||
System.err.println(this.wxService.getPayService().entPay(request, keyFile)); | |||
System.err.println(this.wxService.getPayService().entPay(request)); | |||
} | |||
/** | |||
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#queryEntPay(String, File)}. | |||
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#queryEntPay(String)}. | |||
*/ | |||
@Test | |||
public final void testQueryEntPay() throws WxErrorException { | |||
File keyFile = new File("E:\\dlt.p12"); | |||
System.err.println(this.wxService.getPayService().queryEntPay("11212121", keyFile)); | |||
System.err.println(this.wxService.getPayService().queryEntPay("11212121")); | |||
} | |||
} |