diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxEntPayQueryRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxEntPayQueryRequest.java index 30ff0a87d..f9135c34d 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxEntPayQueryRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxEntPayQueryRequest.java @@ -43,6 +43,11 @@ public class WxEntPayQueryRequest extends WxPayBaseRequest { this.partnerTradeNo = partnerTradeNo; } + @Override + protected void checkConstraints() { + //do nothing + } + @Override public String toString() { return ToStringUtils.toSimpleString(this); diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxEntPayRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxEntPayRequest.java index 56783883a..fd43fb1aa 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxEntPayRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxEntPayRequest.java @@ -154,6 +154,11 @@ public class WxEntPayRequest extends WxPayBaseRequest { private String spbillCreateIp; + @Override + protected void checkConstraints() { + + } + @Override public String getAppid() { return this.mchAppid; diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayBaseRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayBaseRequest.java index 2e34f0a26..4d5cbbaa3 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayBaseRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayBaseRequest.java @@ -1,9 +1,14 @@ package com.github.binarywang.wxpay.bean.request; +import com.github.binarywang.wxpay.config.WxPayConfig; +import com.github.binarywang.wxpay.util.SignUtils; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.annotations.XStreamAlias; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.BeanUtils; import me.chanjar.weixin.common.util.ToStringUtils; import me.chanjar.weixin.common.util.xml.XStreamInitializer; +import org.apache.commons.lang3.StringUtils; import java.math.BigDecimal; @@ -23,6 +28,22 @@ import java.math.BigDecimal; * @author binarywang(Binary Wang) */ public abstract class WxPayBaseRequest { + /** + * 检查请求参数内容,包括必填参数以及特殊约束 + */ + protected void checkFields() throws WxErrorException { + //check required fields + BeanUtils.checkRequiredFields(this); + + //check other parameters + this.checkConstraints(); + } + + /** + * 检查约束情况 + */ + protected abstract void checkConstraints(); + /** *
* 公众账号ID
@@ -180,4 +201,41 @@ public abstract class WxPayBaseRequest {
xstream.processAnnotations(this.getClass());
return xstream.toXML(this);
}
+
+ /**
+ *
+ * 检查参数,并设置签名
+ * 1、检查参数(注意:子类实现需要检查参数的而外功能时,请在调用父类的方法前进行相应判断)
+ * 2、补充系统参数,如果未传入则从配置里读取
+ * 3、生成签名,并设置进去
+ *
+ * @param config 支付配置对象,用于读取相应系统配置信息
+ */
+ public void checkAndSign(WxPayConfig config) throws WxErrorException {
+ this.checkFields();
+
+ if (StringUtils.isBlank(getAppid())) {
+ this.setAppid(config.getAppId());
+ }
+
+ if (StringUtils.isBlank(getMchId())) {
+ this.setMchId(config.getMchId());
+ }
+
+ if (StringUtils.isBlank(getSubAppId())) {
+ this.setSubAppId(config.getSubAppId());
+ }
+
+ if (StringUtils.isBlank(getSubMchId())) {
+ this. setSubMchId(config.getSubMchId());
+ }
+
+ if (StringUtils.isBlank(getNonceStr())) {
+ this.setNonceStr(String.valueOf(System.currentTimeMillis()));
+ }
+
+ //设置签名字段的值
+ this.setSign(SignUtils.createSign(this, config.getMchKey()));
+ }
+
}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayDownloadBillRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayDownloadBillRequest.java
index fac28abaa..ed02060f8 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayDownloadBillRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayDownloadBillRequest.java
@@ -2,6 +2,10 @@ package com.github.binarywang.wxpay.bean.request;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import me.chanjar.weixin.common.annotation.Required;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Arrays;
/**
*
@@ -12,6 +16,8 @@ import me.chanjar.weixin.common.annotation.Required;
*/
@XStreamAlias("xml")
public class WxPayDownloadBillRequest extends WxPayBaseRequest {
+ private static final String[] BILL_TYPE = new String[]{"ALL", "REFUND", "SUCCESS"};
+
/**
*
* 设备号
@@ -120,4 +126,16 @@ public class WxPayDownloadBillRequest extends WxPayBaseRequest {
public void setTarType(String tarType) {
this.tarType = tarType;
}
+
+ @Override
+ protected void checkConstraints() {
+ if (StringUtils.isNotBlank(this.getTarType()) && !"GZIP".equals(this.getTarType())) {
+ throw new IllegalArgumentException("tar_type值如果存在,只能为GZIP");
+ }
+
+ if (!ArrayUtils.contains(BILL_TYPE, this.getBillType())) {
+ throw new IllegalArgumentException(String.format("bill_tpye目前必须为%s其中之一,实际值:%s",
+ Arrays.toString(BILL_TYPE), this.getBillType()));
+ }
+ }
}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayMicropayRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayMicropayRequest.java
index 10aac6499..a02533780 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayMicropayRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayMicropayRequest.java
@@ -261,6 +261,11 @@ public class WxPayMicropayRequest extends WxPayBaseRequest {
this.authCode = authCode;
}
+ @Override
+ protected void checkConstraints() {
+ //do nothing
+ }
+
public static final class Builder {
private String signType;
private String body;
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderCloseRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderCloseRequest.java
index 43206e36a..21968ac98 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderCloseRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderCloseRequest.java
@@ -33,4 +33,8 @@ public class WxPayOrderCloseRequest extends WxPayBaseRequest {
this.outTradeNo = outTradeNo;
}
+ @Override
+ protected void checkConstraints() {
+
+ }
}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderQueryRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderQueryRequest.java
index a0982764b..499727995 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderQueryRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderQueryRequest.java
@@ -1,6 +1,7 @@
package com.github.binarywang.wxpay.bean.request;
import com.thoughtworks.xstream.annotations.XStreamAlias;
+import org.apache.commons.lang3.StringUtils;
/**
*
@@ -61,4 +62,12 @@ public class WxPayOrderQueryRequest extends WxPayBaseRequest {
public void setOutTradeNo(String outTradeNo) {
this.outTradeNo = outTradeNo;
}
+
+ @Override
+ protected void checkConstraints() {
+ if ((StringUtils.isBlank(transactionId) && StringUtils.isBlank(outTradeNo)) ||
+ (StringUtils.isNotBlank(transactionId) && StringUtils.isNotBlank(outTradeNo))) {
+ throw new IllegalArgumentException("transaction_id 和 out_trade_no 不能同时存在或同时为空,必须二选一");
+ }
+ }
}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderReverseRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderReverseRequest.java
new file mode 100644
index 000000000..6aef2aa0f
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayOrderReverseRequest.java
@@ -0,0 +1,163 @@
+package com.github.binarywang.wxpay.bean.request;
+
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ *
+ * 撤销订单请求类
+ * Created by Binary Wang on 2017-3-23.
+ * @author binarywang(Binary Wang)
+ *
+ */
+@XStreamAlias("xml")
+public class WxPayOrderReverseRequest extends WxPayBaseRequest {
+
+ /**
+ *
+ * 微信订单号
+ * transaction_id
+ * String(28)
+ * 1217752501201400000000000000
+ * 微信的订单号,优先使用
+ *
+ */
+ @XStreamAlias("transaction_id")
+ private String transactionId;
+
+ /**
+ *
+ * 商户订单号
+ * out_trade_no
+ * String(32)
+ * 1217752501201400000000000000
+ * 商户系统内部的订单号
+ * transaction_id、out_trade_no二选一,如果同时存在优先级:transaction_id> out_trade_no
+ *
+ */
+ @XStreamAlias("out_trade_no")
+ private String outTradeNo;
+
+ /**
+ *
+ * 签名类型
+ * sign_type
+ * 否
+ * String(32)
+ * HMAC-SHA256
+ * 签名类型,目前支持HMAC-SHA256和MD5,默认为MD5
+ **/
+ @XStreamAlias("sign_type")
+ private String signType;
+
+ private WxPayOrderReverseRequest(Builder builder) {
+ setTransactionId(builder.transactionId);
+ setAppid(builder.appid);
+ setOutTradeNo(builder.outTradeNo);
+ setMchId(builder.mchId);
+ setSignType(builder.signType);
+ setSubAppId(builder.subAppId);
+ setSubMchId(builder.subMchId);
+ setNonceStr(builder.nonceStr);
+ setSign(builder.sign);
+ }
+
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ public String getTransactionId() {
+ return this.transactionId;
+ }
+
+ public void setTransactionId(String transactionId) {
+ this.transactionId = transactionId;
+ }
+
+ public String getOutTradeNo() {
+ return this.outTradeNo;
+ }
+
+ public void setOutTradeNo(String outTradeNo) {
+ this.outTradeNo = outTradeNo;
+ }
+
+ public String getSignType() {
+ return this.signType;
+ }
+
+ public void setSignType(String signType) {
+ this.signType = signType;
+ }
+
+ @Override
+ protected void checkConstraints() {
+ if (StringUtils.isBlank(transactionId) && StringUtils.isBlank(outTradeNo)) {
+ throw new IllegalArgumentException("transaction_id 和 out_trade_no不能同时为空!");
+ }
+ }
+
+ public static final class Builder {
+ private String transactionId;
+ private String appid;
+ private String outTradeNo;
+ private String mchId;
+ private String signType;
+ private String subAppId;
+ private String subMchId;
+ private String nonceStr;
+ private String sign;
+
+ private Builder() {
+ }
+
+ public Builder transactionId(String transactionId) {
+ this.transactionId = transactionId;
+ return this;
+ }
+
+ public Builder appid(String appid) {
+ this.appid = appid;
+ return this;
+ }
+
+ public Builder outTradeNo(String outTradeNo) {
+ this.outTradeNo = outTradeNo;
+ return this;
+ }
+
+ public Builder mchId(String mchId) {
+ this.mchId = mchId;
+ return this;
+ }
+
+ public Builder signType(String signType) {
+ this.signType = signType;
+ return this;
+ }
+
+ public Builder subAppId(String subAppId) {
+ this.subAppId = subAppId;
+ return this;
+ }
+
+ public Builder subMchId(String subMchId) {
+ this.subMchId = subMchId;
+ return this;
+ }
+
+ public Builder nonceStr(String nonceStr) {
+ this.nonceStr = nonceStr;
+ return this;
+ }
+
+ public Builder sign(String sign) {
+ this.sign = sign;
+ return this;
+ }
+
+ public WxPayOrderReverseRequest build() {
+ return new WxPayOrderReverseRequest(this);
+ }
+ }
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRedpackQueryRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRedpackQueryRequest.java
index ae7ec3524..191db4697 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRedpackQueryRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRedpackQueryRequest.java
@@ -54,4 +54,9 @@ public class WxPayRedpackQueryRequest extends WxPayBaseRequest {
public void setMchBillNo(String mchBillNo) {
this.mchBillNo = mchBillNo;
}
+
+ @Override
+ protected void checkConstraints() {
+
+ }
}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundQueryRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundQueryRequest.java
index 06687c363..1efa23db7 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundQueryRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundQueryRequest.java
@@ -1,6 +1,7 @@
package com.github.binarywang.wxpay.bean.request;
import com.thoughtworks.xstream.annotations.XStreamAlias;
+import org.apache.commons.lang3.StringUtils;
/**
*
@@ -132,4 +133,15 @@ public class WxPayRefundQueryRequest extends WxPayBaseRequest {
public void setRefundId(String refundId) {
this.refundId = refundId;
}
+
+ @Override
+ protected void checkConstraints() {
+ 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 必须四选一");
+ }
+
+ }
}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundRequest.java
index 36fb76d68..c7fc8c269 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRefundRequest.java
@@ -1,7 +1,13 @@
package com.github.binarywang.wxpay.bean.request;
+import com.github.binarywang.wxpay.config.WxPayConfig;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import me.chanjar.weixin.common.annotation.Required;
+import me.chanjar.weixin.common.exception.WxErrorException;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Arrays;
/**
*
@@ -13,13 +19,25 @@ import me.chanjar.weixin.common.annotation.Required;
*
* 设备号
@@ -240,6 +258,20 @@ public class WxPayRefundRequest extends WxPayBaseRequest {
this.refundAccount = refundAccount;
}
+ @Override
+ protected void checkConstraints() {
+ if (StringUtils.isNotBlank(this.getRefundAccount())) {
+ if (!ArrayUtils.contains(REFUND_ACCOUNT, this.getRefundAccount())) {
+ throw new IllegalArgumentException(String.format("refund_account目前必须为%s其中之一,实际值:%s",
+ Arrays.toString(REFUND_ACCOUNT), this.getRefundAccount()));
+ }
+ }
+
+ if (StringUtils.isBlank(this.getOutTradeNo()) && StringUtils.isBlank(this.getTransactionId())) {
+ throw new IllegalArgumentException("transaction_id 和 out_trade_no 不能同时为空,必须提供一个");
+ }
+ }
+
public static final class Builder {
private String deviceInfo;
private String appid;
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayReportRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayReportRequest.java
index 6795536f5..8b3f88b9c 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayReportRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayReportRequest.java
@@ -270,4 +270,9 @@ public class WxPayReportRequest extends WxPayBaseRequest {
public void setTime(String time) {
this.time = time;
}
+
+ @Override
+ protected void checkConstraints() {
+ //do nothing
+ }
}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPaySendRedpackRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPaySendRedpackRequest.java
index b49253a41..f7082fc3d 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPaySendRedpackRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPaySendRedpackRequest.java
@@ -217,6 +217,11 @@ public class WxPaySendRedpackRequest extends WxPayBaseRequest {
this.remark = remark;
}
+ @Override
+ protected void checkConstraints() {
+
+ }
+
@Override
public String getAppid() {
return this.wxAppid;
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java
index 4e1d5a5d4..48b059d36 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java
@@ -1,7 +1,13 @@
package com.github.binarywang.wxpay.bean.request;
+import com.github.binarywang.wxpay.config.WxPayConfig;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import me.chanjar.weixin.common.annotation.Required;
+import me.chanjar.weixin.common.exception.WxErrorException;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Arrays;
/**
*
@@ -21,6 +27,7 @@ import me.chanjar.weixin.common.annotation.Required;
*/
@XStreamAlias("xml")
public class WxPayUnifiedOrderRequest extends WxPayBaseRequest {
+ private static final String[] TRADE_TYPES = new String[]{"JSAPI", "NATIVE", "APP"};
/**
*
@@ -409,6 +416,35 @@ public class WxPayUnifiedOrderRequest extends WxPayBaseRequest {
this.openid = openid;
}
+ @Override
+ protected void checkConstraints() {
+ if (!ArrayUtils.contains(TRADE_TYPES, this.getTradeType())) {
+ throw new IllegalArgumentException(String.format("trade_type目前必须为%s其中之一,实际值:%s",
+ Arrays.toString(TRADE_TYPES), this.getTradeType()));
+ }
+
+ if ("JSAPI".equals(this.getTradeType()) && this.getOpenid() == null) {
+ throw new IllegalArgumentException("当 trade_type是'JSAPI'时未指定openid");
+ }
+
+ if ("NATIVE".equals(this.getTradeType()) && this.getProductId() == null) {
+ throw new IllegalArgumentException("当 trade_type是'NATIVE'时未指定product_id");
+ }
+ }
+
+ @Override
+ public void checkAndSign(WxPayConfig config) throws WxErrorException {
+ if (StringUtils.isBlank(this.getNotifyURL())) {
+ this.setNotifyURL(config.getNotifyUrl());
+ }
+
+ if (StringUtils.isBlank(this.getTradeType())) {
+ this.setTradeType(config.getTradeType());
+ }
+
+ super.checkAndSign(config);
+ }
+
public static class WxUnifiedOrderRequestBuilder {
private String appid;
private String mchId;
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBaseResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBaseResult.java
index fed9544c4..899703c84 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBaseResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayBaseResult.java
@@ -1,9 +1,13 @@
package com.github.binarywang.wxpay.bean.result;
+import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
+import com.github.binarywang.wxpay.util.SignUtils;
import com.google.common.base.Joiner;
import com.google.common.collect.Maps;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
+import me.chanjar.weixin.common.bean.result.WxError;
+import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.ToStringUtils;
import me.chanjar.weixin.common.util.xml.XStreamInitializer;
import org.apache.commons.lang3.StringUtils;
@@ -300,4 +304,44 @@ public abstract class WxPayBaseResult {
return Integer.valueOf(result);
}
+
+ /**
+ * 校验返回结果签名
+ */
+ public void checkResult(WxPayServiceImpl wxPayService) throws WxErrorException {
+ //校验返回结果签名
+ Map map = toMap();
+ if (getSign() != null && !SignUtils.checkSign(map, wxPayService.getConfig().getMchKey())) {
+ this.getLogger().debug("校验结果签名失败,参数:{}", map);
+ throw new WxErrorException(WxError.newBuilder().setErrorCode(-1).setErrorMsg("参数格式校验错误!").build());
+ }
+
+ //校验结果是否成功
+ if (!"SUCCESS".equalsIgnoreCase(getReturnCode())
+ || !"SUCCESS".equalsIgnoreCase(getResultCode())) {
+ StringBuilder errorMsg = new StringBuilder();
+ if (getReturnCode() != null) {
+ errorMsg.append("返回代码:").append(getReturnCode());
+ }
+ if (getReturnMsg() != null) {
+ errorMsg.append(",返回信息:").append(getReturnMsg());
+ }
+ if (getResultCode() != null) {
+ errorMsg.append(",结果代码:").append(getResultCode());
+ }
+ if (getErrCode() != null) {
+ errorMsg.append(",错误代码:").append(getErrCode());
+ }
+ if (getErrCodeDes() != null) {
+ errorMsg.append(",错误详情:").append(getErrCodeDes());
+ }
+
+ WxError error = WxError.newBuilder()
+ .setErrorCode(-1)
+ .setErrorMsg(errorMsg.toString())
+ .build();
+ this.getLogger().error("\n结果业务代码异常,返回結果:{},\n{}", map, error);
+ throw new WxErrorException(error);
+ }
+ }
}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayOrderReverseResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayOrderReverseResult.java
new file mode 100644
index 000000000..7732a9627
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayOrderReverseResult.java
@@ -0,0 +1,34 @@
+package com.github.binarywang.wxpay.bean.result;
+
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+
+/**
+ *
+ * 撤销订单响应结果类
+ * Created by Binary Wang on 2017-3-23.
+ * @author binarywang(Binary Wang)
+ *
+ */
+public class WxPayOrderReverseResult extends WxPayBaseResult {
+
+ /**
+ *
+ * 是否重调
+ * recall
+ * 是
+ * String(1)
+ * Y
+ * 是否需要继续调用撤销,Y-需要,N-不需要
+ *
+ **/
+ @XStreamAlias("recall")
+ private String isRecall;
+
+ public String getIsRecall() {
+ return this.isRecall;
+ }
+
+ public void setIsRecall(String isRecall) {
+ this.isRecall = isRecall;
+ }
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java
index 0473d9ba2..902669e7f 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java
@@ -116,84 +116,6 @@ public interface WxPayService {
*/
WxPayOrderNotifyResult getOrderNotifyResult(String xmlData) throws WxErrorException;
- /**
- * 微信公众号支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3)
- *
- * @param xmlbean Bean需要标记有XML注解,默认使用配置中的PartnerKey进行签名
- * @return 签名字符串
- * @see #createSign(Map, String)
- * @since 2.5.0
- */
- String createSign(Object xmlbean);
-
- /**
- * 微信公众号支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3)
- *
- * @param xmlbean Bean需要标记有XML注解
- * @param signKey 签名Key
- * @return 签名字符串
- * @see #createSign(Map, String)
- */
- String createSign(Object xmlbean, String signKey);
-
- /**
- * 微信公众号支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3)
- *
- * @param prams 参数信息,默认使用配置中的PartnerKey进行签名
- * @return 签名字符串
- * @see #createSign(Map, String)
- */
- String createSign(Map prams);
-
-
- /**
- * 微信公众号支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3)
- *
- * @param prams 参数信息
- * @param signKey 签名Key
- * @return 签名字符串
- */
- String createSign(Map prams, String signKey);
-
-
- /**
- * 校验签名是否正确,默认使用配置中的PartnerKey进行签名
- *
- * @param xmlbean Bean需要标记有XML注解
- * @return true - 签名校验成功,false - 签名校验失败
- * @see #checkSign(Map, String)
- */
- boolean checkSign(Object xmlbean);
-
- /**
- * 校验签名是否正确
- *
- * @param xmlbean Bean需要标记有XML注解
- * @param signKey 校验的签名Key
- * @return true - 签名校验成功,false - 签名校验失败
- * @see #checkSign(Map, String)
- */
- boolean checkSign(Object xmlbean, String signKey);
-
- /**
- * 校验签名是否正确,默认使用配置中的PartnerKey进行签名
- *
- * @param prams 需要校验的参数Map
- * @return true - 签名校验成功,false - 签名校验失败
- * @see #checkSign(Map, String)
- */
- boolean checkSign(Map prams);
-
- /**
- * 校验签名是否正确
- *
- * @param params 需要校验的参数Map
- * @param signKey 校验的签名Key
- * @return true - 签名校验成功,false - 签名校验失败
- * @see #checkSign(Map, String)
- */
- boolean checkSign(Map params, String signKey);
-
/**
* 发送微信红包给个人用户
*
@@ -271,6 +193,7 @@ public interface WxPayService {
* 其中XXXXX为商户需要填写的内容,商户将该链接生成二维码,如需要打印发布二维码,需要采用此格式。商户可调用第三方库生成二维码图片。
* 文档详见: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4
*
+ *
* @param productId 产品Id
* @return 生成的二维码URL连接
*/
@@ -328,6 +251,7 @@ public interface WxPayService {
/**
*
* 提交刷卡支付
+ * 文档地址:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_10&index=1
* 应用场景:
* 收银员使用扫码设备读取微信用户刷卡授权码以后,二维码或条码信息传送至商户收银台,由商户收银台或者商户后台调用该接口发起支付。
* 提醒1:提交支付请求后微信会同步返回支付结果。当返回结果为“系统错误”时,商户系统等待5秒后调用【查询订单API】,查询支付实际交易结果;当返回结果为“USERPAYING”时,商户系统可设置间隔时间(建议10秒)重新查询支付结果,直到支付成功或超时(建议30秒);
@@ -337,4 +261,18 @@ public interface WxPayService {
*
*/
WxPayMicropayResult micropay(WxPayMicropayRequest request) throws WxErrorException;
+
+ /**
+ *
+ * 撤销订单API
+ * 文档地址:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_11&index=3
+ * 应用场景:
+ * 支付交易返回失败或支付系统超时,调用该接口撤销交易。如果此订单用户支付失败,微信支付系统会将此订单关闭;如果用户支付成功,微信支付系统会将此订单资金退还给用户。
+ * 注意:7天以内的交易单可调用撤销,其他正常支付的单如需实现相同功能请调用申请退款API。提交支付交易后调用【查询订单API】,没有明确的支付结果再调用【撤销订单API】。
+ * 调用支付接口后请勿立即调用撤销订单API,建议支付后至少15s后再调用撤销订单接口。
+ * 接口链接 :https://api.mch.weixin.qq.com/secapi/pay/reverse
+ * 是否需要证书:请求需要双向证书。
+ *
+ */
+ WxPayOrderReverseResult reverseOrder(WxPayOrderReverseRequest request) throws WxErrorException;
}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java
index 371b50c8c..7ed530bea 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceImpl.java
@@ -5,14 +5,12 @@ import com.github.binarywang.wxpay.bean.request.*;
import com.github.binarywang.wxpay.bean.result.*;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.service.WxPayService;
+import com.github.binarywang.wxpay.util.SignUtils;
import com.google.common.collect.Maps;
import jodd.http.HttpRequest;
import jodd.http.HttpResponse;
import me.chanjar.weixin.common.bean.result.WxError;
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.StringUtils;
import org.apache.http.Consts;
@@ -30,7 +28,8 @@ import org.slf4j.LoggerFactory;
import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.UnsupportedEncodingException;
-import java.util.*;
+import java.util.HashMap;
+import java.util.Map;
/**
* Created by Binary Wang on 2016/7/28.
@@ -38,12 +37,7 @@ import java.util.*;
* @author binarywang (https://github.com/binarywang)
*/
public class WxPayServiceImpl implements WxPayService {
-
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 WxPayConfig config;
@@ -62,126 +56,47 @@ public class WxPayServiceImpl implements WxPayService {
if (this.getConfig().useSandboxForWxPay()) {
return PAY_BASE_URL + "/sandboxnew";
}
+
return PAY_BASE_URL;
}
@Override
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 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;
}
@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 {
- 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();
- this.initRequest(request);
request.setOutTradeNo(StringUtils.trimToNull(outTradeNo));
request.setTransactionId(StringUtils.trimToNull(transactionId));
request.setOutRefundNo(StringUtils.trimToNull(outRefundNo));
request.setRefundId(StringUtils.trimToNull(refundId));
- request.setSign(this.createSign(request));
+
+ request.checkAndSign(this.getConfig());
String url = this.getPayBaseUrl() + "/pay/refundquery";
String responseContent = this.post(url, request.toXML());
- WxPayRefundQueryResult result = WxPayRefundQueryResult.fromXML(responseContent, WxPayRefundQueryResult.class);
+ WxPayRefundQueryResult result = WxPayBaseResult.fromXML(responseContent, WxPayRefundQueryResult.class);
result.composeRefundRecords();
- this.checkResult(result);
+ result.checkResult(this);
return result;
}
- private void checkResult(WxPayBaseResult result) throws WxErrorException {
- //校验返回结果签名
- Map 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
public WxPayOrderNotifyResult getOrderNotifyResult(String xmlData) throws WxErrorException {
try {
log.debug("微信支付回调参数详细:{}", xmlData);
WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlData);
log.debug("微信支付回调结果对象:{}", result);
- this.checkResult(result);
+ result.checkResult(this);
return result;
} catch (WxErrorException e) {
log.error(e.getMessage(), e);
@@ -193,18 +108,17 @@ public class WxPayServiceImpl implements WxPayService {
}
@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";
if (request.getAmtType() != null) {
//裂变红包
url = this.getPayBaseUrl() + "/mmpaymkttransfers/sendgroupredpack";
}
+
String responseContent = this.postWithKey(url, request.toXML());
- WxPaySendRedpackResult result = WxPaySendRedpackResult.fromXML(responseContent, WxPaySendRedpackResult.class);
+ WxPaySendRedpackResult result = WxPayBaseResult.fromXML(responseContent, WxPaySendRedpackResult.class);
//毋须校验,因为没有返回签名信息
// this.checkResult(result);
return result;
@@ -215,28 +129,21 @@ public class WxPayServiceImpl implements WxPayService {
WxPayRedpackQueryRequest request = new WxPayRedpackQueryRequest();
request.setMchBillNo(mchBillNo);
request.setBillType("MCHT");
- initRequest(request);
- request.setSign(this.createSign(request));
+ request.checkAndSign(this.getConfig());
String url = this.getPayBaseUrl() + "/mmpaymkttransfers/gethbinfo";
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;
}
@Override
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();
request.setOutTradeNo(StringUtils.trimToNull(outTradeNo));
request.setTransactionId(StringUtils.trimToNull(transactionId));
- initRequest(request);
- request.setSign(this.createSign(request));
+ request.checkAndSign(this.getConfig());
String url = this.getPayBaseUrl() + "/pay/orderquery";
String responseContent = this.post(url, request.toXML());
@@ -244,9 +151,9 @@ public class WxPayServiceImpl implements WxPayService {
throw new WxErrorException(WxError.newBuilder().setErrorMsg("无响应结果").build());
}
- WxPayOrderQueryResult result = WxPayOrderQueryResult.fromXML(responseContent, WxPayOrderQueryResult.class);
+ WxPayOrderQueryResult result = WxPayBaseResult.fromXML(responseContent, WxPayOrderQueryResult.class);
result.composeCoupons();
- this.checkResult(result);
+ result.checkResult(this);
return result;
}
@@ -258,77 +165,27 @@ public class WxPayServiceImpl implements WxPayService {
WxPayOrderCloseRequest request = new WxPayOrderCloseRequest();
request.setOutTradeNo(StringUtils.trimToNull(outTradeNo));
- this.initRequest(request);
- request.setSign(this.createSign(request));
+ request.checkAndSign(this.getConfig());
String url = this.getPayBaseUrl() + "/pay/closeorder";
String responseContent = this.post(url, request.toXML());
WxPayOrderCloseResult result = WxPayBaseResult.fromXML(responseContent, WxPayOrderCloseResult.class);
- this.checkResult(result);
+ result.checkResult(this);
return result;
}
@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 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;
}
- 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
public Map getPayInfo(WxPayUnifiedOrderRequest request) throws WxErrorException {
WxPayUnifiedOrderResult unifiedOrderResult = this.unifiedOrder(request);
@@ -349,21 +206,18 @@ public class WxPayServiceImpl implements WxPayService {
if ("NATIVE".equals(request.getTradeType())) {
payInfo.put("codeUrl", unifiedOrderResult.getCodeURL());
}
- payInfo.put("paySign", this.createSign(payInfo));
+ payInfo.put("paySign", SignUtils.createSign(payInfo, this.getConfig().getMchKey()));
return payInfo;
}
@Override
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 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;
}
@@ -371,25 +225,24 @@ public class WxPayServiceImpl implements WxPayService {
public WxEntPayQueryResult queryEntPay(String partnerTradeNo) throws WxErrorException {
WxEntPayQueryRequest request = new WxEntPayQueryRequest();
request.setPartnerTradeNo(partnerTradeNo);
- this.initRequest(request);
- request.setSign(this.createSign(request));
+ request.checkAndSign(this.getConfig());
String url = this.getPayBaseUrl() + "/mmpaymkttransfers/gettransferinfo";
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;
}
@Override
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
- 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?");
Map params = Maps.newHashMap();
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("nonce_str", String.valueOf(System.currentTimeMillis()));
- String sign = this.createSign(params);
+ String sign = SignUtils.createSign(params, this.getConfig().getMchKey());
params.put("sign", sign);
@@ -407,72 +260,80 @@ public class WxPayServiceImpl implements WxPayService {
}
String content = codeUrl.toString().substring(0, codeUrl.length() - 1);
- log.debug("扫码支付模式一生成二维码的URL:{}",content);
- return content;
+ log.debug("扫码支付模式一生成二维码的URL:{}", content);
+ return content;
}
@Override
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) {
- if (sideLength == null || sideLength < 1) {
+ if (sideLength == null || sideLength < 1) {
return QrcodeUtils.createQrcode(content, logoFile);
}
+
return QrcodeUtils.createQrcode(content, sideLength, logoFile);
}
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 responseContent = this.post(url, request.toXML());
WxPayCommonResult result = WxPayBaseResult.fromXML(responseContent, WxPayCommonResult.class);
- this.checkResult(result);
+ result.checkResult(this);
}
@Override
public File downloadBill(String billDate, String billType, String tarType, String deviceInfo) throws WxErrorException {
WxPayDownloadBillRequest request = new WxPayDownloadBillRequest();
- this.initRequest(request);
request.setBillType(billType);
request.setBillDate(billDate);
request.setTarType(tarType);
request.setDeviceInfo(deviceInfo);
- this.checkParameters(request);
- request.setSign(this.createSign(request));
+
+ request.checkAndSign(this.getConfig());
String url = this.getPayBaseUrl() + "/pay/downloadbill";
//TODO 返回的内容可能是文件流,也有可能是xml,需要区分对待
String responseContent = this.post(url, request.toXML());
WxPayCommonResult result = WxPayBaseResult.fromXML(responseContent, WxPayCommonResult.class);
- this.checkResult(result);
+ result.checkResult(this);
//TODO 待实现,暂时无测试帐号,无法调试
return null;
}
@Override
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 responseContent = this.post(url, request.toXML());
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;
}
private String post(String url, String xmlParam) {
- String requestString = null;
+ String requestString = xmlParam;
try {
requestString = new String(xmlParam.getBytes(CharEncoding.UTF_8), CharEncoding.ISO_8859_1);
} catch (UnsupportedEncodingException e) {
+ //实际上不会发生该异常
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 params) {
- return this.createSign(params, this.getConfig().getMchKey());
- }
-
- @Override
- public String createSign(Map params, String signKey) {
- if (this.getConfig().useSandboxForWxPay()) {
- //使用仿真测试环境
- //TODO 目前测试发现,以下两行代码都会出问题,所以暂不建议使用仿真测试环境
- signKey = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456";
- //return "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456";
- }
-
- SortedMap 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 params) {
- return this.checkSign(params, getConfig().getMchKey());
- }
-
- @Override
- public boolean checkSign(Map params, String signKey) {
- String sign = this.createSign(params, signKey);
- return sign.equals(params.get("sign"));
- }
}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/util/SignUtils.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/util/SignUtils.java
new file mode 100644
index 000000000..2a6030f39
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/util/SignUtils.java
@@ -0,0 +1,84 @@
+package com.github.binarywang.wxpay.util;
+
+import me.chanjar.weixin.common.util.BeanUtils;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ *
+ * 签名相关工具类
+ * Created by Binary Wang on 2017-3-23.
+ * @author binarywang(Binary Wang)
+ *
+ */
+public class SignUtils {
+
+ /**
+ * 微信公众号支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3)
+ *
+ * @param xmlBean Bean需要标记有XML注解
+ * @param signKey 签名Key
+ * @return 签名字符串
+ */
+ public static String createSign(Object xmlBean, String signKey) {
+ return createSign(BeanUtils.xmlBean2Map(xmlBean), signKey);
+ }
+
+ /**
+ * 微信公众号支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3)
+ *
+ * @param params 参数信息
+ * @param signKey 签名Key
+ * @return 签名字符串
+ */
+ public static String createSign(Map params, String signKey) {
+// if (this.getConfig().useSandboxForWxPay()) {
+// //使用仿真测试环境
+// //TODO 目前测试发现,以下两行代码都会出问题,所以暂不建议使用仿真测试环境
+// signKey = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456";
+// //return "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456";
+// }
+
+ SortedMap 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();
+ }
+
+ /**
+ * 校验签名是否正确
+ *
+ * @param xmlBean Bean需要标记有XML注解
+ * @param signKey 校验的签名Key
+ * @return true - 签名校验成功,false - 签名校验失败
+ * @see #checkSign(Map, String)
+ */
+ public static boolean checkSign(Object xmlBean, String signKey) {
+ return checkSign(BeanUtils.xmlBean2Map(xmlBean), signKey);
+ }
+
+ /**
+ * 校验签名是否正确
+ *
+ * @param params 需要校验的参数Map
+ * @param signKey 校验的签名Key
+ * @return true - 签名校验成功,false - 签名校验失败
+ * @see #checkSign(Map, String)
+ */
+ public static boolean checkSign(Map params, String signKey) {
+ String sign = createSign(params, signKey);
+ return sign.equals(params.get("sign"));
+ }
+}