|
@@ -5,14 +5,12 @@ import com.github.binarywang.wxpay.bean.request.*; |
|
|
import com.github.binarywang.wxpay.bean.result.*; |
|
|
import com.github.binarywang.wxpay.bean.result.*; |
|
|
import com.github.binarywang.wxpay.config.WxPayConfig; |
|
|
import com.github.binarywang.wxpay.config.WxPayConfig; |
|
|
import com.github.binarywang.wxpay.service.WxPayService; |
|
|
import com.github.binarywang.wxpay.service.WxPayService; |
|
|
|
|
|
import com.github.binarywang.wxpay.util.SignUtils; |
|
|
import com.google.common.collect.Maps; |
|
|
import com.google.common.collect.Maps; |
|
|
import jodd.http.HttpRequest; |
|
|
import jodd.http.HttpRequest; |
|
|
import jodd.http.HttpResponse; |
|
|
import jodd.http.HttpResponse; |
|
|
import me.chanjar.weixin.common.bean.result.WxError; |
|
|
import me.chanjar.weixin.common.bean.result.WxError; |
|
|
import me.chanjar.weixin.common.exception.WxErrorException; |
|
|
import me.chanjar.weixin.common.exception.WxErrorException; |
|
|
import me.chanjar.weixin.common.util.BeanUtils; |
|
|
|
|
|
import org.apache.commons.codec.digest.DigestUtils; |
|
|
|
|
|
import org.apache.commons.lang3.ArrayUtils; |
|
|
|
|
|
import org.apache.commons.lang3.CharEncoding; |
|
|
import org.apache.commons.lang3.CharEncoding; |
|
|
import org.apache.commons.lang3.StringUtils; |
|
|
import org.apache.commons.lang3.StringUtils; |
|
|
import org.apache.http.Consts; |
|
|
import org.apache.http.Consts; |
|
@@ -30,7 +28,8 @@ import org.slf4j.LoggerFactory; |
|
|
import javax.net.ssl.SSLContext; |
|
|
import javax.net.ssl.SSLContext; |
|
|
import java.io.File; |
|
|
import java.io.File; |
|
|
import java.io.UnsupportedEncodingException; |
|
|
import java.io.UnsupportedEncodingException; |
|
|
import java.util.*; |
|
|
|
|
|
|
|
|
import java.util.HashMap; |
|
|
|
|
|
import java.util.Map; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Created by Binary Wang on 2016/7/28. |
|
|
* Created by Binary Wang on 2016/7/28. |
|
@@ -38,12 +37,7 @@ import java.util.*; |
|
|
* @author binarywang (https://github.com/binarywang) |
|
|
* @author binarywang (https://github.com/binarywang) |
|
|
*/ |
|
|
*/ |
|
|
public class WxPayServiceImpl implements WxPayService { |
|
|
public class WxPayServiceImpl implements WxPayService { |
|
|
|
|
|
|
|
|
private static final String PAY_BASE_URL = "https://api.mch.weixin.qq.com"; |
|
|
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[] BILL_TYPE = new String[]{"ALL", "REFUND", "SUCCESS"}; |
|
|
|
|
|
|
|
|
|
|
|
private final Logger log = LoggerFactory.getLogger(this.getClass()); |
|
|
private final Logger log = LoggerFactory.getLogger(this.getClass()); |
|
|
|
|
|
|
|
|
private WxPayConfig config; |
|
|
private WxPayConfig config; |
|
@@ -62,126 +56,47 @@ public class WxPayServiceImpl implements WxPayService { |
|
|
if (this.getConfig().useSandboxForWxPay()) { |
|
|
if (this.getConfig().useSandboxForWxPay()) { |
|
|
return PAY_BASE_URL + "/sandboxnew"; |
|
|
return PAY_BASE_URL + "/sandboxnew"; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return PAY_BASE_URL; |
|
|
return PAY_BASE_URL; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
public WxPayRefundResult refund(WxPayRefundRequest request) throws WxErrorException { |
|
|
public WxPayRefundResult refund(WxPayRefundRequest request) throws WxErrorException { |
|
|
this.initRequest(request); |
|
|
|
|
|
if (StringUtils.isBlank(request.getOpUserId())) { |
|
|
|
|
|
request.setOpUserId(this.getConfig().getMchId()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
this.checkParameters(request); |
|
|
|
|
|
request.setSign(this.createSign(request)); |
|
|
|
|
|
|
|
|
request.checkAndSign(this.getConfig()); |
|
|
|
|
|
|
|
|
String url = this.getPayBaseUrl() + "/secapi/pay/refund"; |
|
|
String url = this.getPayBaseUrl() + "/secapi/pay/refund"; |
|
|
String responseContent = this.postWithKey(url, request.toXML()); |
|
|
String responseContent = this.postWithKey(url, request.toXML()); |
|
|
WxPayRefundResult result = WxPayRefundResult.fromXML(responseContent, WxPayRefundResult.class); |
|
|
|
|
|
this.checkResult(result); |
|
|
|
|
|
|
|
|
WxPayRefundResult result = WxPayBaseResult.fromXML(responseContent, WxPayRefundResult.class); |
|
|
|
|
|
result.checkResult(this); |
|
|
return result; |
|
|
return result; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
public WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, |
|
|
|
|
|
String outRefundNo, String refundId) |
|
|
|
|
|
|
|
|
public WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, String outRefundNo, String refundId) |
|
|
throws WxErrorException { |
|
|
throws WxErrorException { |
|
|
if ((StringUtils.isBlank(transactionId) && StringUtils.isBlank(outTradeNo) |
|
|
|
|
|
&& StringUtils.isBlank(outRefundNo) && StringUtils.isBlank(refundId)) || |
|
|
|
|
|
(StringUtils.isNotBlank(transactionId) && StringUtils.isNotBlank(outTradeNo) |
|
|
|
|
|
&& StringUtils.isNotBlank(outRefundNo) && StringUtils.isNotBlank(refundId))) { |
|
|
|
|
|
throw new IllegalArgumentException("transaction_id , out_trade_no,out_refund_no, refund_id 必须四选一"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
WxPayRefundQueryRequest request = new WxPayRefundQueryRequest(); |
|
|
WxPayRefundQueryRequest request = new WxPayRefundQueryRequest(); |
|
|
this.initRequest(request); |
|
|
|
|
|
request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); |
|
|
request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); |
|
|
request.setTransactionId(StringUtils.trimToNull(transactionId)); |
|
|
request.setTransactionId(StringUtils.trimToNull(transactionId)); |
|
|
request.setOutRefundNo(StringUtils.trimToNull(outRefundNo)); |
|
|
request.setOutRefundNo(StringUtils.trimToNull(outRefundNo)); |
|
|
request.setRefundId(StringUtils.trimToNull(refundId)); |
|
|
request.setRefundId(StringUtils.trimToNull(refundId)); |
|
|
request.setSign(this.createSign(request)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
request.checkAndSign(this.getConfig()); |
|
|
|
|
|
|
|
|
String url = this.getPayBaseUrl() + "/pay/refundquery"; |
|
|
String url = this.getPayBaseUrl() + "/pay/refundquery"; |
|
|
String responseContent = this.post(url, request.toXML()); |
|
|
String responseContent = this.post(url, request.toXML()); |
|
|
WxPayRefundQueryResult result = WxPayRefundQueryResult.fromXML(responseContent, WxPayRefundQueryResult.class); |
|
|
|
|
|
|
|
|
WxPayRefundQueryResult result = WxPayBaseResult.fromXML(responseContent, WxPayRefundQueryResult.class); |
|
|
result.composeRefundRecords(); |
|
|
result.composeRefundRecords(); |
|
|
this.checkResult(result); |
|
|
|
|
|
|
|
|
result.checkResult(this); |
|
|
return result; |
|
|
return result; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private void checkResult(WxPayBaseResult result) throws WxErrorException { |
|
|
|
|
|
//校验返回结果签名 |
|
|
|
|
|
Map<String, String> map = result.toMap(); |
|
|
|
|
|
if (result.getSign() != null && !this.checkSign(map)) { |
|
|
|
|
|
log.debug("校验结果签名失败,参数:{}", map); |
|
|
|
|
|
throw new WxErrorException(WxError.newBuilder().setErrorCode(-1).setErrorMsg("参数格式校验错误!").build()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//校验结果是否成功 |
|
|
|
|
|
if (!"SUCCESS".equalsIgnoreCase(result.getReturnCode()) |
|
|
|
|
|
|| !"SUCCESS".equalsIgnoreCase(result.getResultCode())) { |
|
|
|
|
|
StringBuilder errorMsg = new StringBuilder(); |
|
|
|
|
|
if (result.getReturnCode() != null) { |
|
|
|
|
|
errorMsg.append("返回代码:").append(result.getReturnCode()); |
|
|
|
|
|
} |
|
|
|
|
|
if (result.getReturnMsg() != null) { |
|
|
|
|
|
errorMsg.append(",返回信息:").append(result.getReturnMsg()); |
|
|
|
|
|
} |
|
|
|
|
|
if (result.getResultCode() != null) { |
|
|
|
|
|
errorMsg.append(",结果代码:").append(result.getResultCode()); |
|
|
|
|
|
} |
|
|
|
|
|
if (result.getErrCode() != null) { |
|
|
|
|
|
errorMsg.append(",错误代码:").append(result.getErrCode()); |
|
|
|
|
|
} |
|
|
|
|
|
if (result.getErrCodeDes() != null) { |
|
|
|
|
|
errorMsg.append(",错误详情:").append(result.getErrCodeDes()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
WxError error = WxError.newBuilder() |
|
|
|
|
|
.setErrorCode(-1) |
|
|
|
|
|
.setErrorMsg(errorMsg.toString()) |
|
|
|
|
|
.build(); |
|
|
|
|
|
log.error("\n结果业务代码异常,返回結果:{},\n{}", map, error); |
|
|
|
|
|
throw new WxErrorException(error); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private void checkParameters(WxPayDownloadBillRequest request) throws WxErrorException { |
|
|
|
|
|
BeanUtils.checkRequiredFields(request); |
|
|
|
|
|
|
|
|
|
|
|
if (StringUtils.isNotBlank(request.getTarType()) && !"GZIP".equals(request.getTarType())) { |
|
|
|
|
|
throw new IllegalArgumentException("tar_type值如果存在,只能为GZIP"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (!ArrayUtils.contains(BILL_TYPE, request.getBillType())) { |
|
|
|
|
|
throw new IllegalArgumentException("bill_tpye目前必须为" + Arrays.toString(BILL_TYPE) |
|
|
|
|
|
+ "其中之一,实际值:" + request.getBillType()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private void checkParameters(WxPayRefundRequest request) throws WxErrorException { |
|
|
|
|
|
BeanUtils.checkRequiredFields(request); |
|
|
|
|
|
|
|
|
|
|
|
if (StringUtils.isNotBlank(request.getRefundAccount())) { |
|
|
|
|
|
if (!ArrayUtils.contains(REFUND_ACCOUNT, request.getRefundAccount())) { |
|
|
|
|
|
throw new IllegalArgumentException("refund_account目前必须为" + Arrays.toString(REFUND_ACCOUNT) |
|
|
|
|
|
+ "其中之一,实际值:" + request.getRefundAccount()); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (StringUtils.isBlank(request.getOutTradeNo()) && StringUtils.isBlank(request.getTransactionId())) { |
|
|
|
|
|
throw new IllegalArgumentException("transaction_id 和 out_trade_no 不能同时为空,必须提供一个"); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
public WxPayOrderNotifyResult getOrderNotifyResult(String xmlData) throws WxErrorException { |
|
|
public WxPayOrderNotifyResult getOrderNotifyResult(String xmlData) throws WxErrorException { |
|
|
try { |
|
|
try { |
|
|
log.debug("微信支付回调参数详细:{}", xmlData); |
|
|
log.debug("微信支付回调参数详细:{}", xmlData); |
|
|
WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlData); |
|
|
WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlData); |
|
|
log.debug("微信支付回调结果对象:{}", result); |
|
|
log.debug("微信支付回调结果对象:{}", result); |
|
|
this.checkResult(result); |
|
|
|
|
|
|
|
|
result.checkResult(this); |
|
|
return result; |
|
|
return result; |
|
|
} catch (WxErrorException e) { |
|
|
} catch (WxErrorException e) { |
|
|
log.error(e.getMessage(), e); |
|
|
log.error(e.getMessage(), e); |
|
@@ -193,18 +108,17 @@ public class WxPayServiceImpl implements WxPayService { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) |
|
|
|
|
|
throws WxErrorException { |
|
|
|
|
|
this.initRequest(request); |
|
|
|
|
|
request.setSign(this.createSign(request)); |
|
|
|
|
|
|
|
|
public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) throws WxErrorException { |
|
|
|
|
|
request.checkAndSign(this.getConfig()); |
|
|
|
|
|
|
|
|
String url = this.getPayBaseUrl() + "/mmpaymkttransfers/sendredpack"; |
|
|
String url = this.getPayBaseUrl() + "/mmpaymkttransfers/sendredpack"; |
|
|
if (request.getAmtType() != null) { |
|
|
if (request.getAmtType() != null) { |
|
|
//裂变红包 |
|
|
//裂变红包 |
|
|
url = this.getPayBaseUrl() + "/mmpaymkttransfers/sendgroupredpack"; |
|
|
url = this.getPayBaseUrl() + "/mmpaymkttransfers/sendgroupredpack"; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
String responseContent = this.postWithKey(url, request.toXML()); |
|
|
String responseContent = this.postWithKey(url, request.toXML()); |
|
|
WxPaySendRedpackResult result = WxPaySendRedpackResult.fromXML(responseContent, WxPaySendRedpackResult.class); |
|
|
|
|
|
|
|
|
WxPaySendRedpackResult result = WxPayBaseResult.fromXML(responseContent, WxPaySendRedpackResult.class); |
|
|
//毋须校验,因为没有返回签名信息 |
|
|
//毋须校验,因为没有返回签名信息 |
|
|
// this.checkResult(result); |
|
|
// this.checkResult(result); |
|
|
return result; |
|
|
return result; |
|
@@ -215,28 +129,21 @@ public class WxPayServiceImpl implements WxPayService { |
|
|
WxPayRedpackQueryRequest request = new WxPayRedpackQueryRequest(); |
|
|
WxPayRedpackQueryRequest request = new WxPayRedpackQueryRequest(); |
|
|
request.setMchBillNo(mchBillNo); |
|
|
request.setMchBillNo(mchBillNo); |
|
|
request.setBillType("MCHT"); |
|
|
request.setBillType("MCHT"); |
|
|
initRequest(request); |
|
|
|
|
|
request.setSign(this.createSign(request)); |
|
|
|
|
|
|
|
|
request.checkAndSign(this.getConfig()); |
|
|
|
|
|
|
|
|
String url = this.getPayBaseUrl() + "/mmpaymkttransfers/gethbinfo"; |
|
|
String url = this.getPayBaseUrl() + "/mmpaymkttransfers/gethbinfo"; |
|
|
String responseContent = this.postWithKey(url, request.toXML()); |
|
|
String responseContent = this.postWithKey(url, request.toXML()); |
|
|
WxPayRedpackQueryResult result = WxPayRedpackQueryResult.fromXML(responseContent, WxPayRedpackQueryResult.class); |
|
|
|
|
|
this.checkResult(result); |
|
|
|
|
|
|
|
|
WxPayRedpackQueryResult result = WxPayBaseResult.fromXML(responseContent, WxPayRedpackQueryResult.class); |
|
|
|
|
|
result.checkResult(this); |
|
|
return result; |
|
|
return result; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
public WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxErrorException { |
|
|
public WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxErrorException { |
|
|
if ((StringUtils.isBlank(transactionId) && StringUtils.isBlank(outTradeNo)) || |
|
|
|
|
|
(StringUtils.isNotBlank(transactionId) && StringUtils.isNotBlank(outTradeNo))) { |
|
|
|
|
|
throw new IllegalArgumentException("transaction_id 和 out_trade_no 不能同时存在或同时为空,必须二选一"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
WxPayOrderQueryRequest request = new WxPayOrderQueryRequest(); |
|
|
WxPayOrderQueryRequest request = new WxPayOrderQueryRequest(); |
|
|
request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); |
|
|
request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); |
|
|
request.setTransactionId(StringUtils.trimToNull(transactionId)); |
|
|
request.setTransactionId(StringUtils.trimToNull(transactionId)); |
|
|
initRequest(request); |
|
|
|
|
|
request.setSign(this.createSign(request)); |
|
|
|
|
|
|
|
|
request.checkAndSign(this.getConfig()); |
|
|
|
|
|
|
|
|
String url = this.getPayBaseUrl() + "/pay/orderquery"; |
|
|
String url = this.getPayBaseUrl() + "/pay/orderquery"; |
|
|
String responseContent = this.post(url, request.toXML()); |
|
|
String responseContent = this.post(url, request.toXML()); |
|
@@ -244,9 +151,9 @@ public class WxPayServiceImpl implements WxPayService { |
|
|
throw new WxErrorException(WxError.newBuilder().setErrorMsg("无响应结果").build()); |
|
|
throw new WxErrorException(WxError.newBuilder().setErrorMsg("无响应结果").build()); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
WxPayOrderQueryResult result = WxPayOrderQueryResult.fromXML(responseContent, WxPayOrderQueryResult.class); |
|
|
|
|
|
|
|
|
WxPayOrderQueryResult result = WxPayBaseResult.fromXML(responseContent, WxPayOrderQueryResult.class); |
|
|
result.composeCoupons(); |
|
|
result.composeCoupons(); |
|
|
this.checkResult(result); |
|
|
|
|
|
|
|
|
result.checkResult(this); |
|
|
return result; |
|
|
return result; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@@ -258,77 +165,27 @@ public class WxPayServiceImpl implements WxPayService { |
|
|
|
|
|
|
|
|
WxPayOrderCloseRequest request = new WxPayOrderCloseRequest(); |
|
|
WxPayOrderCloseRequest request = new WxPayOrderCloseRequest(); |
|
|
request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); |
|
|
request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); |
|
|
this.initRequest(request); |
|
|
|
|
|
request.setSign(this.createSign(request)); |
|
|
|
|
|
|
|
|
request.checkAndSign(this.getConfig()); |
|
|
|
|
|
|
|
|
String url = this.getPayBaseUrl() + "/pay/closeorder"; |
|
|
String url = this.getPayBaseUrl() + "/pay/closeorder"; |
|
|
String responseContent = this.post(url, request.toXML()); |
|
|
String responseContent = this.post(url, request.toXML()); |
|
|
WxPayOrderCloseResult result = WxPayBaseResult.fromXML(responseContent, WxPayOrderCloseResult.class); |
|
|
WxPayOrderCloseResult result = WxPayBaseResult.fromXML(responseContent, WxPayOrderCloseResult.class); |
|
|
this.checkResult(result); |
|
|
|
|
|
|
|
|
result.checkResult(this); |
|
|
|
|
|
|
|
|
return result; |
|
|
return result; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) |
|
|
|
|
|
throws WxErrorException { |
|
|
|
|
|
this.initRequest(request); |
|
|
|
|
|
if (StringUtils.isBlank(request.getNotifyURL())) { |
|
|
|
|
|
request.setNotifyURL(getConfig().getNotifyUrl()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (StringUtils.isBlank(request.getTradeType())) { |
|
|
|
|
|
request.setTradeType(getConfig().getTradeType()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
this.checkParameters(request);//校验参数 |
|
|
|
|
|
request.setSign(this.createSign(request)); |
|
|
|
|
|
|
|
|
public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) throws WxErrorException { |
|
|
|
|
|
request.checkAndSign(this.getConfig()); |
|
|
|
|
|
|
|
|
String url = this.getPayBaseUrl() + "/pay/unifiedorder"; |
|
|
String url = this.getPayBaseUrl() + "/pay/unifiedorder"; |
|
|
String responseContent = this.post(url, request.toXML()); |
|
|
String responseContent = this.post(url, request.toXML()); |
|
|
WxPayUnifiedOrderResult result = WxPayUnifiedOrderResult.fromXML(responseContent, WxPayUnifiedOrderResult.class); |
|
|
|
|
|
this.checkResult(result); |
|
|
|
|
|
|
|
|
WxPayUnifiedOrderResult result = WxPayBaseResult.fromXML(responseContent, WxPayUnifiedOrderResult.class); |
|
|
|
|
|
result.checkResult(this); |
|
|
return result; |
|
|
return result; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private void initRequest(WxPayBaseRequest request) { |
|
|
|
|
|
if (StringUtils.isBlank(request.getAppid())) { |
|
|
|
|
|
request.setAppid(this.getConfig().getAppId()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (StringUtils.isBlank(request.getMchId())) { |
|
|
|
|
|
request.setMchId(this.getConfig().getMchId()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (StringUtils.isBlank(request.getSubAppId())) { |
|
|
|
|
|
request.setSubAppId(this.getConfig().getSubAppId()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (StringUtils.isBlank(request.getSubMchId())) { |
|
|
|
|
|
request.setSubMchId(this.getConfig().getSubMchId()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (StringUtils.isBlank(request.getNonceStr())) { |
|
|
|
|
|
request.setNonceStr(String.valueOf(System.currentTimeMillis())); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private void checkParameters(WxPayUnifiedOrderRequest request) throws WxErrorException { |
|
|
|
|
|
BeanUtils.checkRequiredFields(request); |
|
|
|
|
|
|
|
|
|
|
|
if (!ArrayUtils.contains(TRADE_TYPES, request.getTradeType())) { |
|
|
|
|
|
throw new IllegalArgumentException("trade_type目前必须为" + Arrays.toString(TRADE_TYPES) + "其中之一,实际值:" + request.getTradeType()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if ("JSAPI".equals(request.getTradeType()) && request.getOpenid() == null) { |
|
|
|
|
|
throw new IllegalArgumentException("当 trade_type是'JSAPI'时未指定openid"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if ("NATIVE".equals(request.getTradeType()) && request.getProductId() == null) { |
|
|
|
|
|
throw new IllegalArgumentException("当 trade_type是'NATIVE'时未指定product_id"); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
public Map<String, String> getPayInfo(WxPayUnifiedOrderRequest request) throws WxErrorException { |
|
|
public Map<String, String> getPayInfo(WxPayUnifiedOrderRequest request) throws WxErrorException { |
|
|
WxPayUnifiedOrderResult unifiedOrderResult = this.unifiedOrder(request); |
|
|
WxPayUnifiedOrderResult unifiedOrderResult = this.unifiedOrder(request); |
|
@@ -349,21 +206,18 @@ public class WxPayServiceImpl implements WxPayService { |
|
|
if ("NATIVE".equals(request.getTradeType())) { |
|
|
if ("NATIVE".equals(request.getTradeType())) { |
|
|
payInfo.put("codeUrl", unifiedOrderResult.getCodeURL()); |
|
|
payInfo.put("codeUrl", unifiedOrderResult.getCodeURL()); |
|
|
} |
|
|
} |
|
|
payInfo.put("paySign", this.createSign(payInfo)); |
|
|
|
|
|
|
|
|
payInfo.put("paySign", SignUtils.createSign(payInfo, this.getConfig().getMchKey())); |
|
|
return payInfo; |
|
|
return payInfo; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
public WxEntPayResult entPay(WxEntPayRequest request) throws WxErrorException { |
|
|
public WxEntPayResult entPay(WxEntPayRequest request) throws WxErrorException { |
|
|
this.initRequest(request); |
|
|
|
|
|
BeanUtils.checkRequiredFields(request); |
|
|
|
|
|
request.setSign(this.createSign(request)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
request.checkAndSign(this.getConfig()); |
|
|
String url = this.getPayBaseUrl() + "/mmpaymkttransfers/promotion/transfers"; |
|
|
String url = this.getPayBaseUrl() + "/mmpaymkttransfers/promotion/transfers"; |
|
|
|
|
|
|
|
|
String responseContent = this.postWithKey(url, request.toXML()); |
|
|
String responseContent = this.postWithKey(url, request.toXML()); |
|
|
WxEntPayResult result = WxEntPayResult.fromXML(responseContent, WxEntPayResult.class); |
|
|
|
|
|
this.checkResult(result); |
|
|
|
|
|
|
|
|
WxEntPayResult result = WxPayBaseResult.fromXML(responseContent, WxEntPayResult.class); |
|
|
|
|
|
result.checkResult(this); |
|
|
return result; |
|
|
return result; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@@ -371,25 +225,24 @@ public class WxPayServiceImpl implements WxPayService { |
|
|
public WxEntPayQueryResult queryEntPay(String partnerTradeNo) throws WxErrorException { |
|
|
public WxEntPayQueryResult queryEntPay(String partnerTradeNo) throws WxErrorException { |
|
|
WxEntPayQueryRequest request = new WxEntPayQueryRequest(); |
|
|
WxEntPayQueryRequest request = new WxEntPayQueryRequest(); |
|
|
request.setPartnerTradeNo(partnerTradeNo); |
|
|
request.setPartnerTradeNo(partnerTradeNo); |
|
|
this.initRequest(request); |
|
|
|
|
|
request.setSign(this.createSign(request)); |
|
|
|
|
|
|
|
|
request.checkAndSign(this.getConfig()); |
|
|
|
|
|
|
|
|
String url = this.getPayBaseUrl() + "/mmpaymkttransfers/gettransferinfo"; |
|
|
String url = this.getPayBaseUrl() + "/mmpaymkttransfers/gettransferinfo"; |
|
|
String responseContent = this.postWithKey(url, request.toXML()); |
|
|
String responseContent = this.postWithKey(url, request.toXML()); |
|
|
WxEntPayQueryResult result = WxEntPayQueryResult.fromXML(responseContent, WxEntPayQueryResult.class); |
|
|
|
|
|
this.checkResult(result); |
|
|
|
|
|
|
|
|
WxEntPayQueryResult result = WxPayBaseResult.fromXML(responseContent, WxEntPayQueryResult.class); |
|
|
|
|
|
result.checkResult(this); |
|
|
return result; |
|
|
return result; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
public byte[] createScanPayQrcodeMode1(String productId, File logoFile, Integer sideLength) { |
|
|
public byte[] createScanPayQrcodeMode1(String productId, File logoFile, Integer sideLength) { |
|
|
String content = createScanPayQrcodeMode1(productId); |
|
|
|
|
|
return createQrcode(content, logoFile, sideLength); |
|
|
|
|
|
|
|
|
String content = this.createScanPayQrcodeMode1(productId); |
|
|
|
|
|
return this.createQrcode(content, logoFile, sideLength); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
public String createScanPayQrcodeMode1(String productId){ |
|
|
|
|
|
//weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXXX&time_stamp=XXXXXX&nonce_str=XXXXX |
|
|
|
|
|
|
|
|
public String createScanPayQrcodeMode1(String productId) { |
|
|
|
|
|
//weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXXX&time_stamp=XXXXXX&nonce_str=XXXXX |
|
|
StringBuilder codeUrl = new StringBuilder("weixin://wxpay/bizpayurl?"); |
|
|
StringBuilder codeUrl = new StringBuilder("weixin://wxpay/bizpayurl?"); |
|
|
Map<String, String> params = Maps.newHashMap(); |
|
|
Map<String, String> params = Maps.newHashMap(); |
|
|
params.put("appid", this.getConfig().getAppId()); |
|
|
params.put("appid", this.getConfig().getAppId()); |
|
@@ -398,7 +251,7 @@ public class WxPayServiceImpl implements WxPayService { |
|
|
params.put("time_stamp", String.valueOf(System.currentTimeMillis() / 1000));//这里需要秒,10位数字 |
|
|
params.put("time_stamp", String.valueOf(System.currentTimeMillis() / 1000));//这里需要秒,10位数字 |
|
|
params.put("nonce_str", String.valueOf(System.currentTimeMillis())); |
|
|
params.put("nonce_str", String.valueOf(System.currentTimeMillis())); |
|
|
|
|
|
|
|
|
String sign = this.createSign(params); |
|
|
|
|
|
|
|
|
String sign = SignUtils.createSign(params, this.getConfig().getMchKey()); |
|
|
params.put("sign", sign); |
|
|
params.put("sign", sign); |
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -407,72 +260,80 @@ public class WxPayServiceImpl implements WxPayService { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
String content = codeUrl.toString().substring(0, codeUrl.length() - 1); |
|
|
String content = codeUrl.toString().substring(0, codeUrl.length() - 1); |
|
|
log.debug("扫码支付模式一生成二维码的URL:{}",content); |
|
|
|
|
|
return content; |
|
|
|
|
|
|
|
|
log.debug("扫码支付模式一生成二维码的URL:{}", content); |
|
|
|
|
|
return content; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
public byte[] createScanPayQrcodeMode2(String codeUrl, File logoFile, Integer sideLength) { |
|
|
public byte[] createScanPayQrcodeMode2(String codeUrl, File logoFile, Integer sideLength) { |
|
|
return createQrcode(codeUrl, logoFile, sideLength); |
|
|
|
|
|
|
|
|
return this.createQrcode(codeUrl, logoFile, sideLength); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private byte[] createQrcode(String content, File logoFile, Integer sideLength) { |
|
|
private byte[] createQrcode(String content, File logoFile, Integer sideLength) { |
|
|
if (sideLength == null || sideLength < 1) { |
|
|
|
|
|
|
|
|
if (sideLength == null || sideLength < 1) { |
|
|
return QrcodeUtils.createQrcode(content, logoFile); |
|
|
return QrcodeUtils.createQrcode(content, logoFile); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return QrcodeUtils.createQrcode(content, sideLength, logoFile); |
|
|
return QrcodeUtils.createQrcode(content, sideLength, logoFile); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public void report(WxPayReportRequest request) throws WxErrorException { |
|
|
public void report(WxPayReportRequest request) throws WxErrorException { |
|
|
BeanUtils.checkRequiredFields(request); |
|
|
|
|
|
this.initRequest(request); |
|
|
|
|
|
request.setSign(this.createSign(request)); |
|
|
|
|
|
|
|
|
request.checkAndSign(this.getConfig()); |
|
|
|
|
|
|
|
|
String url = this.getPayBaseUrl() + "/payitil/report"; |
|
|
String url = this.getPayBaseUrl() + "/payitil/report"; |
|
|
String responseContent = this.post(url, request.toXML()); |
|
|
String responseContent = this.post(url, request.toXML()); |
|
|
WxPayCommonResult result = WxPayBaseResult.fromXML(responseContent, WxPayCommonResult.class); |
|
|
WxPayCommonResult result = WxPayBaseResult.fromXML(responseContent, WxPayCommonResult.class); |
|
|
this.checkResult(result); |
|
|
|
|
|
|
|
|
result.checkResult(this); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
public File downloadBill(String billDate, String billType, String tarType, String deviceInfo) throws WxErrorException { |
|
|
public File downloadBill(String billDate, String billType, String tarType, String deviceInfo) throws WxErrorException { |
|
|
WxPayDownloadBillRequest request = new WxPayDownloadBillRequest(); |
|
|
WxPayDownloadBillRequest request = new WxPayDownloadBillRequest(); |
|
|
this.initRequest(request); |
|
|
|
|
|
request.setBillType(billType); |
|
|
request.setBillType(billType); |
|
|
request.setBillDate(billDate); |
|
|
request.setBillDate(billDate); |
|
|
request.setTarType(tarType); |
|
|
request.setTarType(tarType); |
|
|
request.setDeviceInfo(deviceInfo); |
|
|
request.setDeviceInfo(deviceInfo); |
|
|
this.checkParameters(request); |
|
|
|
|
|
request.setSign(this.createSign(request)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
request.checkAndSign(this.getConfig()); |
|
|
|
|
|
|
|
|
String url = this.getPayBaseUrl() + "/pay/downloadbill"; |
|
|
String url = this.getPayBaseUrl() + "/pay/downloadbill"; |
|
|
//TODO 返回的内容可能是文件流,也有可能是xml,需要区分对待 |
|
|
//TODO 返回的内容可能是文件流,也有可能是xml,需要区分对待 |
|
|
String responseContent = this.post(url, request.toXML()); |
|
|
String responseContent = this.post(url, request.toXML()); |
|
|
|
|
|
|
|
|
WxPayCommonResult result = WxPayBaseResult.fromXML(responseContent, WxPayCommonResult.class); |
|
|
WxPayCommonResult result = WxPayBaseResult.fromXML(responseContent, WxPayCommonResult.class); |
|
|
this.checkResult(result); |
|
|
|
|
|
|
|
|
result.checkResult(this); |
|
|
//TODO 待实现,暂时无测试帐号,无法调试 |
|
|
//TODO 待实现,暂时无测试帐号,无法调试 |
|
|
return null; |
|
|
return null; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
public WxPayMicropayResult micropay(WxPayMicropayRequest request) throws WxErrorException { |
|
|
public WxPayMicropayResult micropay(WxPayMicropayRequest request) throws WxErrorException { |
|
|
this.initRequest(request); |
|
|
|
|
|
BeanUtils.checkRequiredFields(request); |
|
|
|
|
|
request.setSign(this.createSign(request)); |
|
|
|
|
|
|
|
|
request.checkAndSign(this.getConfig()); |
|
|
|
|
|
|
|
|
String url = this.getPayBaseUrl() + "/pay/micropay"; |
|
|
String url = this.getPayBaseUrl() + "/pay/micropay"; |
|
|
String responseContent = this.post(url, request.toXML()); |
|
|
String responseContent = this.post(url, request.toXML()); |
|
|
WxPayMicropayResult result = WxPayBaseResult.fromXML(responseContent, WxPayMicropayResult.class); |
|
|
WxPayMicropayResult result = WxPayBaseResult.fromXML(responseContent, WxPayMicropayResult.class); |
|
|
this.checkResult(result); |
|
|
|
|
|
|
|
|
result.checkResult(this); |
|
|
|
|
|
return result; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
public WxPayOrderReverseResult reverseOrder(WxPayOrderReverseRequest request) throws WxErrorException { |
|
|
|
|
|
request.checkAndSign(this.getConfig()); |
|
|
|
|
|
|
|
|
|
|
|
String url = this.getPayBaseUrl() + "/secapi/pay/reverse"; |
|
|
|
|
|
String responseContent = this.postWithKey(url, request.toXML()); |
|
|
|
|
|
WxPayOrderReverseResult result = WxPayBaseResult.fromXML(responseContent, WxPayOrderReverseResult.class); |
|
|
|
|
|
result.checkResult(this); |
|
|
return result; |
|
|
return result; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private String post(String url, String xmlParam) { |
|
|
private String post(String url, String xmlParam) { |
|
|
String requestString = null; |
|
|
|
|
|
|
|
|
String requestString = xmlParam; |
|
|
try { |
|
|
try { |
|
|
requestString = new String(xmlParam.getBytes(CharEncoding.UTF_8), CharEncoding.ISO_8859_1); |
|
|
requestString = new String(xmlParam.getBytes(CharEncoding.UTF_8), CharEncoding.ISO_8859_1); |
|
|
} catch (UnsupportedEncodingException e) { |
|
|
} catch (UnsupportedEncodingException e) { |
|
|
|
|
|
//实际上不会发生该异常 |
|
|
e.printStackTrace(); |
|
|
e.printStackTrace(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@@ -520,62 +381,4 @@ public class WxPayServiceImpl implements WxPayService { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
public String createSign(Object xmlBean) { |
|
|
|
|
|
return this.createSign(BeanUtils.xmlBean2Map(xmlBean), this.getConfig().getMchKey()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
public String createSign(Object xmlBean, String signKey) { |
|
|
|
|
|
return this.createSign(BeanUtils.xmlBean2Map(xmlBean), signKey); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
public String createSign(Map<String, String> params) { |
|
|
|
|
|
return this.createSign(params, this.getConfig().getMchKey()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
public String createSign(Map<String, String> params, String signKey) { |
|
|
|
|
|
if (this.getConfig().useSandboxForWxPay()) { |
|
|
|
|
|
//使用仿真测试环境 |
|
|
|
|
|
//TODO 目前测试发现,以下两行代码都会出问题,所以暂不建议使用仿真测试环境 |
|
|
|
|
|
signKey = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456"; |
|
|
|
|
|
//return "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456"; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
SortedMap<String, String> sortedMap = new TreeMap<>(params); |
|
|
|
|
|
|
|
|
|
|
|
StringBuilder toSign = new StringBuilder(); |
|
|
|
|
|
for (String key : sortedMap.keySet()) { |
|
|
|
|
|
String value = params.get(key); |
|
|
|
|
|
if (StringUtils.isNotEmpty(value) && !"sign".equals(key) && !"key".equals(key)) { |
|
|
|
|
|
toSign.append(key + "=" + value + "&"); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
toSign.append("key=" + signKey); |
|
|
|
|
|
return DigestUtils.md5Hex(toSign.toString()).toUpperCase(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
public boolean checkSign(Object xmlBean) { |
|
|
|
|
|
return this.checkSign(BeanUtils.xmlBean2Map(xmlBean), getConfig().getMchKey()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
public boolean checkSign(Object xmlBean, String signKey) { |
|
|
|
|
|
return this.checkSign(BeanUtils.xmlBean2Map(xmlBean), signKey); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
public boolean checkSign(Map<String, String> params) { |
|
|
|
|
|
return this.checkSign(params, getConfig().getMchKey()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
public boolean checkSign(Map<String, String> params, String signKey) { |
|
|
|
|
|
String sign = this.createSign(params, signKey); |
|
|
|
|
|
return sign.equals(params.get("sign")); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |