🎨 #1390 微信支付增加XML转换的快速模式,发送请求以及组装响应对象的时候不再依赖反射机制

* 增加XML的快速模式,发送请求以及组装响应对象的时候,不再依赖java的反射机制。
1:提升性能
2:可以通过 graalvm 生成native image.

本次完成:全部BaseWxPayRequest的改造,部分BaseWxPayResult子类的改造。

* clean code

* 标记 xmlDoc 为 transient 否则toString()方法中Gson可能会堆栈溢出

* 完成大多数BaseWxPayResult子类的改造。还有 notify.*Result下面留了两个TODO需要处理。

* toXML时遗漏了sign参数

* 使用dom4j简化了toXML,同时根据本版本构建native-image的demo已经提交: https://github.com/outersky/wx-micronaut-graal.git 供参考。

* 完成了最后两个Result的xml解析。
This commit is contained in:
outersky 2020-01-28 20:21:06 +08:00 committed by Binary Wang
parent 15f7de33f9
commit ccb25345ff
77 changed files with 1420 additions and 37 deletions

View File

@ -5,6 +5,8 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*; import lombok.*;
import me.chanjar.weixin.common.annotation.Required; import me.chanjar.weixin.common.annotation.Required;
import java.util.Map;
/** /**
* <pre> * <pre>
* 查询代金券信息请求对象类 * 查询代金券信息请求对象类
@ -120,4 +122,15 @@ public class WxPayCouponInfoQueryRequest extends BaseWxPayRequest {
//do nothing //do nothing
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("coupon_id", couponId);
map.put("stock_id", stockId);
map.put("openid", openid);
map.put("op_user_id", opUserId);
map.put("device_info", deviceInfo);
map.put("version", version);
map.put("type", type);
}
} }

View File

@ -5,6 +5,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
/** /**
* <pre> * <pre>
@ -227,4 +228,23 @@ public class WxPayCouponInfoQueryResult extends BaseWxPayResult {
@XStreamAlias("is_partial_use") @XStreamAlias("is_partial_use")
private String isPartialUse; private String isPartialUse;
@Override
protected void loadXML(Document d) {
deviceInfo = readXMLString(d, "device_info");
couponStockId = readXMLString(d, "coupon_stock_id");
couponId = readXMLString(d, "coupon_id");
couponValue = readXMLInteger(d, "coupon_value");
couponMinimum = readXMLInteger(d, "coupon_minimum");
couponName = readXMLString(d, "coupon_name");
couponState = readXMLString(d, "coupon_state");
couponDesc = readXMLString(d, "coupon_desc");
couponUseValue = readXMLInteger(d, "coupon_use_value");
couponRemainValue = readXMLInteger(d, "coupon_remain_value");
beginTime = readXMLString(d, "begin_time");
endTime = readXMLString(d, "end_time");
sendTime = readXMLString(d, "send_time");
consumerMchId = readXMLString(d, "consumer_mch_id");
sendSource = readXMLString(d, "send_source");
isPartialUse = readXMLString(d, "is_partial_use");
}
} }

View File

@ -5,6 +5,8 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*; import lombok.*;
import me.chanjar.weixin.common.annotation.Required; import me.chanjar.weixin.common.annotation.Required;
import java.util.Map;
/** /**
* <pre> * <pre>
* 发送代金券请求对象类 * 发送代金券请求对象类
@ -132,4 +134,16 @@ public class WxPayCouponSendRequest extends BaseWxPayRequest {
protected void checkConstraints() { protected void checkConstraints() {
//do nothing //do nothing
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("coupon_stock_id", couponStockId);
map.put("openid_count", openidCount.toString());
map.put("partner_trade_no", partnerTradeNo);
map.put("openid", openid);
map.put("op_user_id", opUserId);
map.put("device_info", deviceInfo);
map.put("version", version);
map.put("type", type);
}
} }

View File

@ -5,6 +5,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
/** /**
* <pre> * <pre>
@ -136,4 +137,16 @@ public class WxPayCouponSendResult extends BaseWxPayResult {
@XStreamAlias("ret_msg") @XStreamAlias("ret_msg")
private String retMsg; private String retMsg;
@Override
protected void loadXML(Document d) {
deviceInfo = readXMLString(d, "device_info");
couponStockId = readXMLString(d, "coupon_stock_id");
respCount = readXMLInteger(d, "resp_count");
successCount = readXMLInteger(d, "success_count");
failedCount = readXMLInteger(d, "failed_count");
openid = readXMLString(d, "openid");
retCode = readXMLString(d, "ret_code");
couponId = readXMLString(d, "coupon_id");
retMsg = readXMLString(d, "ret_msg");
}
} }

View File

@ -5,6 +5,8 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*; import lombok.*;
import me.chanjar.weixin.common.annotation.Required; import me.chanjar.weixin.common.annotation.Required;
import java.util.Map;
/** /**
* <pre> * <pre>
* 查询代金券批次请求对象类 * 查询代金券批次请求对象类
@ -91,4 +93,13 @@ public class WxPayCouponStockQueryRequest extends BaseWxPayRequest {
//do nothing //do nothing
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("coupon_stock_id", couponStockId);
map.put("op_user_id", opUserId);
map.put("device_info", deviceInfo);
map.put("version", version);
map.put("type", type);
}
} }

View File

@ -6,6 +6,7 @@ import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
/** /**
* <pre> * <pre>
@ -191,4 +192,20 @@ public class WxPayCouponStockQueryResult extends BaseWxPayResult {
@XStreamAlias("coupon_budget") @XStreamAlias("coupon_budget")
private Integer couponBudget; private Integer couponBudget;
@Override
protected void loadXML(Document d) {
deviceInfo = readXMLString(d, "device_info");
couponStockId = readXMLString(d, "coupon_stock_id");
couponName = readXMLString(d, "coupon_name");
couponValue = readXMLInteger(d, "coupon_value");
couponMinimum = readXMLInteger(d, "coupon_mininumn");
couponStockStatus = readXMLInteger(d, "coupon_stock_status");
couponTotal = readXMLInteger(d, "coupon_total");
maxQuota = readXMLInteger(d, "max_quota");
isSendNum = readXMLInteger(d, "is_send_num");
beginTime = readXMLString(d, "begin_time");
endTime = readXMLString(d, "end_time");
createTime = readXMLString(d, "create_time");
couponBudget = readXMLInteger(d, "coupon_budget");
}
} }

View File

@ -5,6 +5,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
/** /**
* <pre> * <pre>
@ -93,4 +94,17 @@ public class EntPayBankQueryResult extends BaseWxPayResult {
@XStreamAlias("reason") @XStreamAlias("reason")
private String failReason; private String failReason;
@Override
protected void loadXML(Document d) {
partnerTradeNo = readXMLString(d, "partner_trade_no");
paymentNo = readXMLString(d, "payment_no");
bankNoMd5 = readXMLString(d, "bank_no_md5");
trueNameMd5 = readXMLString(d, "true_name_md5");
amount = readXMLInteger(d, "amount");
status = readXMLString(d, "status");
cmmsAmount = readXMLInteger(d, "cmms_amt");
createTime = readXMLString(d, "create_time");
paySuccessTime = readXMLString(d, "pay_succ_time");
failReason = readXMLString(d, "reason");
}
} }

View File

@ -10,6 +10,8 @@ import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import me.chanjar.weixin.common.annotation.Required; import me.chanjar.weixin.common.annotation.Required;
import java.util.Map;
/** /**
* <pre> * <pre>
* 企业付款到银行卡的请求对象类 * 企业付款到银行卡的请求对象类
@ -121,6 +123,16 @@ public class EntPayBankRequest extends BaseWxPayRequest {
return new String[]{"sign_type"}; return new String[]{"sign_type"};
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("partner_trade_no", partnerTradeNo);
map.put("enc_bank_no", encBankNo);
map.put("enc_true_name", encTrueName);
map.put("bank_code", bankCode);
map.put("amount", amount.toString());
map.put("desc", description);
}
@Override @Override
protected boolean ignoreAppid() { protected boolean ignoreAppid() {
return true; return true;

View File

@ -5,6 +5,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
/** /**
* <pre> * <pre>
@ -48,4 +49,11 @@ public class EntPayBankResult extends BaseWxPayResult {
@XStreamAlias("cmms_amt") @XStreamAlias("cmms_amt")
private Integer cmmsAmount; private Integer cmmsAmount;
@Override
protected void loadXML(Document d) {
amount = readXMLInteger(d, "amount");
partnerTradeNo = readXMLString(d, "partner_trade_no");
paymentNo = readXMLString(d, "payment_no");
cmmsAmount = readXMLInteger(d, "cmms_amt");
}
} }

View File

@ -10,6 +10,8 @@ import lombok.NoArgsConstructor;
import me.chanjar.weixin.common.annotation.Required; import me.chanjar.weixin.common.annotation.Required;
import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.common.util.json.WxGsonBuilder;
import java.util.Map;
/** /**
* <pre> * <pre>
* 企业付款请求对象. * 企业付款请求对象.
@ -55,4 +57,9 @@ public class EntPayQueryRequest extends BaseWxPayRequest {
protected String[] getIgnoredParamsForSign() { protected String[] getIgnoredParamsForSign() {
return new String[]{"sign_type"}; return new String[]{"sign_type"};
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("partner_trade_no", partnerTradeNo);
}
} }

View File

@ -5,6 +5,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
/** /**
* <pre> * <pre>
@ -81,4 +82,17 @@ public class EntPayQueryResult extends BaseWxPayResult {
@XStreamAlias("desc") @XStreamAlias("desc")
private String desc; private String desc;
@Override
protected void loadXML(Document d) {
partnerTradeNo = readXMLString(d, "partner_trade_no");
detailId = readXMLString(d, "detail_id");
status = readXMLString(d, "status");
reason = readXMLString(d, "reason");
openid = readXMLString(d, "openid");
transferName = readXMLString(d, "transfer_name");
paymentAmount = readXMLInteger(d, "payment_amount");
transferTime = readXMLString(d, "transfer_time");
paymentTime = readXMLString(d, "payment_time");
desc = readXMLString(d, "desc");
}
} }

View File

@ -5,8 +5,11 @@ import com.github.binarywang.wxpay.exception.WxPayException;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*; import lombok.*;
import java.util.Map;
/** /**
* 红包发送记录查询请求 * 红包发送记录查询请求
*
* @author wuyong * @author wuyong
* @date 2019-12-01 17:19 * @date 2019-12-01 17:19
*/ */
@ -30,4 +33,9 @@ public class EntPayRedpackQueryRequest extends BaseWxPayRequest {
protected void checkConstraints() throws WxPayException { protected void checkConstraints() throws WxPayException {
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("mch_billno", mchBillNo);
}
} }

View File

@ -5,6 +5,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
/** /**
* 红包发送记录查询返回 * 红包发送记录查询返回
@ -130,4 +131,24 @@ public class EntPayRedpackQueryResult extends BaseWxPayResult {
@XStreamAlias("sender_header_media_id") @XStreamAlias("sender_header_media_id")
private Integer senderHeaderMediaId; private Integer senderHeaderMediaId;
@Override
protected void loadXML(Document d) {
mchBillNo = readXMLString(d, "mch_billno");
detailId = readXMLString(d, "detailId");
status = readXMLString(d, "status");
sendType = readXMLString(d, "send_type");
totalAmount = readXMLInteger(d, "total_amount");
reason = readXMLInteger(d, "reason");
sendTime = readXMLString(d, "send_time");
refundTime = readXMLString(d, "refund_time");
refundAmount = readXMLInteger(d, "refund_amount");
wishing = readXMLString(d, "wishing");
remark = readXMLString(d, "remark");
actName = readXMLString(d, "act_name");
openid = readXMLString(d, "openid");
amount = readXMLInteger(d, "amount");
rcvTime = readXMLInteger(d, "rcv_time");
senderName = readXMLInteger(d, "sender_name");
senderHeaderMediaId = readXMLInteger(d, "sender_header_media_id");
}
} }

View File

@ -6,8 +6,11 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*; import lombok.*;
import me.chanjar.weixin.common.annotation.Required; import me.chanjar.weixin.common.annotation.Required;
import java.util.Map;
/** /**
* 发送企业红包 * 发送企业红包
*
* @author wuyong * @author wuyong
* @date 2019-12-1 * @date 2019-12-1
*/ */
@ -144,4 +147,19 @@ public class EntPayRedpackRequest extends BaseWxPayRequest {
protected boolean isWxWorkSign() { protected boolean isWxWorkSign() {
return true; return true;
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("mch_billno", mchBillNo);
map.put("wxappid", wxAppId);
map.put("sender_name", senderName);
map.put("agentid", agentId);
map.put("sender_header_media_id", senderHeaderMediaId);
map.put("re_openid", reOpenid);
map.put("total_amount", totalAmount.toString());
map.put("wishing", wishing);
map.put("act_name", actName);
map.put("remark", remark);
map.put("scene_id", sceneId);
}
} }

View File

@ -5,11 +5,13 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
import java.io.Serializable; import java.io.Serializable;
/** /**
* 企业微信红包返回 * 企业微信红包返回
*
* @author wuyong * @author wuyong
* @date 2019-12-01 11:31 * @date 2019-12-01 11:31
*/ */
@ -77,4 +79,15 @@ public class EntPayRedpackResult extends BaseWxPayResult implements Serializable
@XStreamAlias("sender_header_media_id") @XStreamAlias("sender_header_media_id")
private String senderHeaderMediaId; private String senderHeaderMediaId;
@Override
protected void loadXML(Document d) {
mchBillNo = readXMLString(d, "mch_billno");
mchId = readXMLString(d, "mch_id");
wxAppId = readXMLString(d, "wxappid");
reOpenid = readXMLString(d, "re_openid");
totalAmount = readXMLString(d, "totalAmount");
sendListId = readXMLString(d, "sendListid");
senderName = readXMLString(d, "sender_name");
senderHeaderMediaId = readXMLString(d, "sender_header_media_id");
}
} }

View File

@ -10,6 +10,8 @@ import lombok.NoArgsConstructor;
import me.chanjar.weixin.common.annotation.Required; import me.chanjar.weixin.common.annotation.Required;
import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.common.util.json.WxGsonBuilder;
import java.util.Map;
/** /**
* <pre> * <pre>
* 企业付款请求对象. * 企业付款请求对象.
@ -195,4 +197,18 @@ public class EntPayRequest extends BaseWxPayRequest {
protected String[] getIgnoredParamsForSign() { protected String[] getIgnoredParamsForSign() {
return new String[]{"sign_type"}; return new String[]{"sign_type"};
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("mch_appid", mchAppid);
map.put("mchid", mchId);
map.put("device_info", deviceInfo);
map.put("partner_trade_no", partnerTradeNo);
map.put("openid", openid);
map.put("check_name", checkName);
map.put("re_user_name", reUserName);
map.put("amount", amount.toString());
map.put("desc", description);
map.put("spbill_create_ip", spbillCreateIp);
}
} }

View File

@ -5,6 +5,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
/** /**
* <pre> * <pre>
@ -56,4 +57,13 @@ public class EntPayResult extends BaseWxPayResult {
@XStreamAlias("payment_time") @XStreamAlias("payment_time")
private String paymentTime; private String paymentTime;
@Override
protected void loadXML(Document d) {
mchId = readXMLString(d, "mchid");
mchAppid = readXMLString(d, "mch_appid");
deviceInfo = readXMLString(d, "device_info");
partnerTradeNo = readXMLString(d, "partner_trade_no");
paymentNo = readXMLString(d, "payment_no");
paymentTime = readXMLString(d, "payment_time");
}
} }

View File

@ -4,6 +4,7 @@ import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import org.w3c.dom.Document;
/** /**
* <pre> * <pre>
@ -28,4 +29,10 @@ public class GetPublicKeyResult extends BaseWxPayResult {
*/ */
@XStreamAlias("pub_key") @XStreamAlias("pub_key")
private String pubKey; private String pubKey;
@Override
protected void loadXML(Document d) {
mchId = readXMLString(d, "mch_id");
pubKey = readXMLString(d, "pub_key");
}
} }

View File

@ -13,7 +13,9 @@ import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.common.util.json.WxGsonBuilder;
import me.chanjar.weixin.common.util.xml.XStreamInitializer; import me.chanjar.weixin.common.util.xml.XStreamInitializer;
import org.w3c.dom.Document;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -349,6 +351,51 @@ public class WxPayOrderNotifyResult extends BaseWxPayResult {
return resultMap; return resultMap;
} }
@Override
protected void loadXML(Document d) {
promotionDetail = readXMLString(d, "promotion_detail");
deviceInfo = readXMLString(d, "device_info");
openid = readXMLString(d, "openid");
isSubscribe = readXMLString(d, "is_subscribe");
subOpenid = readXMLString(d, "sub_openid");
subIsSubscribe = readXMLString(d, "sub_is_subscribe");
tradeType = readXMLString(d, "trade_type");
bankType = readXMLString(d, "bank_type");
totalFee = readXMLInteger(d, "total_fee");
settlementTotalFee = readXMLInteger(d, "settlement_total_fee");
feeType = readXMLString(d, "fee_type");
cashFee = readXMLInteger(d, "cash_fee");
cashFeeType = readXMLString(d, "cash_fee_type");
couponFee = readXMLInteger(d, "coupon_fee");
couponCount = readXMLInteger(d, "coupon_count");
transactionId = readXMLString(d, "transaction_id");
outTradeNo = readXMLString(d, "out_trade_no");
attach = readXMLString(d, "attach");
timeEnd = readXMLString(d, "time_end");
version = readXMLString(d, "version");
rateValue = readXMLString(d, "rate_value");
signType = readXMLString(d, "sign_type");
composeCoupons();
}
/**
* 通过xml组装couponList属性内容.
*/
protected void composeCoupons() {
if (this.couponCount == null || this.couponCount == 0) {
return;
}
this.couponList = new ArrayList(couponCount);
for (int i = 0; i < this.couponCount; i++) {
WxPayOrderNotifyCoupon coupon = new WxPayOrderNotifyCoupon();
coupon.setCouponId(this.getXmlValue("xml/coupon_id_" + i));
coupon.setCouponType(this.getXmlValue("xml/coupon_type_" + i));
coupon.setCouponFee(this.getXmlValueAsInt("xml/coupon_fee_" + i));
couponList.add(coupon);
}
}
@Override @Override
public String toString() { public String toString() {
return WxGsonBuilder.create().toJson(this); return WxGsonBuilder.create().toJson(this);

View File

@ -19,6 +19,7 @@ import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.common.util.json.WxGsonBuilder;
import me.chanjar.weixin.common.util.xml.XStreamInitializer; import me.chanjar.weixin.common.util.xml.XStreamInitializer;
import org.w3c.dom.Document;
/** /**
* <pre> * <pre>
@ -80,6 +81,45 @@ public class WxPayRefundNotifyResult extends BaseWxPayResult implements Serializ
private ReqInfo reqInfo; private ReqInfo reqInfo;
// 解密后的reqInfo 字符串
private transient String decryptedReqInfo;
@Override
protected void loadXML(Document d) {
reqInfoString = readXMLString(d, "req_info");
}
/**
* 解密并解析reqInfo
*
* @param mchKey
* @throws WxPayException
*/
public void decryptReqInfo(String mchKey) throws WxPayException {
//如果是失败直接返回不用解析
if (WxPayConstants.ResultCode.FAIL.equals(getReturnCode())) {
return;
}
try {
final String keyMd5String = DigestUtils.md5Hex(mchKey).toLowerCase();
SecretKeySpec key = new SecretKeySpec(keyMd5String.getBytes(StandardCharsets.UTF_8), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
decryptedReqInfo = new String(cipher.doFinal(Base64.decodeBase64(reqInfoString)), StandardCharsets.UTF_8);
loadReqInfo(decryptedReqInfo);
} catch (Exception e) {
throw new WxPayException("解密退款通知加密信息时出错", e);
}
}
// 本方法独立出来方便测试
protected void loadReqInfo(String decryptedReqInfo) {
Document document = openXML(decryptedReqInfo);
reqInfo = new ReqInfo();
reqInfo.loadXML(document);
}
/** /**
* 加密信息字段解密后的内容. * 加密信息字段解密后的内容.
*/ */
@ -272,6 +312,23 @@ public class WxPayRefundNotifyResult extends BaseWxPayResult implements Serializ
xstream.processAnnotations(ReqInfo.class); xstream.processAnnotations(ReqInfo.class);
return (ReqInfo) xstream.fromXML(xmlString); return (ReqInfo) xstream.fromXML(xmlString);
} }
public void loadXML(Document d) {
transactionId = readXMLString(d, "transaction_id");
outTradeNo = readXMLString(d, "out_trade_no");
refundId = readXMLString(d, "refund_id");
outRefundNo = readXMLString(d, "out_refund_no");
totalFee = readXMLInteger(d, "total_fee");
settlementTotalFee = readXMLInteger(d, "settlement_total_fee");
refundFee = readXMLInteger(d, "refund_fee");
settlementRefundFee = readXMLInteger(d, "settlement_refund_fee");
refundStatus = readXMLString(d, "refund_status");
successTime = readXMLString(d, "success_time");
refundRecvAccout = readXMLString(d, "refund_recv_accout");
refundAccount = readXMLString(d, "refund_account");
refundRequestSource = readXMLString(d, "refund_request_source");
}
} }
} }

View File

@ -5,6 +5,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
/** /**
* <pre> * <pre>
@ -45,4 +46,11 @@ public class WxScanPayNotifyResult extends BaseWxPayResult {
@XStreamAlias("product_id") @XStreamAlias("product_id")
private String productId; private String productId;
@Override
protected void loadXML(Document d) {
openid = readXMLString(d, "openid");
isSubscribe = readXMLString(d, "is_subscribe");
productId = readXMLString(d, "product_id");
}
} }

View File

@ -7,6 +7,8 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*; import lombok.*;
import me.chanjar.weixin.common.annotation.Required; import me.chanjar.weixin.common.annotation.Required;
import java.util.Map;
/** /**
* @author Wang GuangXin 2019/10/23 14:02 * @author Wang GuangXin 2019/10/23 14:02
* @version 1.0 * @version 1.0
@ -67,4 +69,11 @@ public class ProfitSharingFinishRequest extends BaseWxPayRequest {
protected void checkConstraints() throws WxPayException { protected void checkConstraints() throws WxPayException {
this.setSignType(WxPayConstants.SignType.HMAC_SHA256); this.setSignType(WxPayConstants.SignType.HMAC_SHA256);
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("transaction_id", transactionId);
map.put("out_order_no", outOrderNo);
map.put("description", description);
}
} }

View File

@ -7,6 +7,8 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*; import lombok.*;
import me.chanjar.weixin.common.annotation.Required; import me.chanjar.weixin.common.annotation.Required;
import java.util.Map;
/** /**
* @author Wang GuangXin 2019/10/22 15:44 * @author Wang GuangXin 2019/10/22 15:44
* @version 1.0 * @version 1.0
@ -56,4 +58,10 @@ public class ProfitSharingQueryRequest extends BaseWxPayRequest {
public boolean ignoreAppid() { public boolean ignoreAppid() {
return true; return true;
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("transaction_id", transactionId);
map.put("out_order_no", outOrderNo);
}
} }

View File

@ -8,6 +8,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
/** /**
* @author Wang GuangXin 2019/10/22 15:51 * @author Wang GuangXin 2019/10/22 15:51
@ -67,6 +68,18 @@ public class ProfitSharingQueryResult extends BaseWxPayResult {
return gson.fromJson(receivers, Receivers.class); return gson.fromJson(receivers, Receivers.class);
} }
@Override
protected void loadXML(Document d) {
transactionId = readXMLString(d, "transaction_id");
outOrderNo = readXMLString(d, "out_order_no");
orderId = readXMLString(d, "orderId");
status = readXMLString(d, "status");
closeReason = readXMLString(d, "close_reason");
receivers = readXMLString(d, "receivers");
amount = readXMLInteger(d, "amount");
description = readXMLString(d, "description");
}
@Data @Data
public class Receivers { public class Receivers {
/** /**

View File

@ -7,6 +7,8 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*; import lombok.*;
import me.chanjar.weixin.common.annotation.Required; import me.chanjar.weixin.common.annotation.Required;
import java.util.Map;
/** /**
* 添加/删除分账接受方请求对象 * 添加/删除分账接受方请求对象
* *
@ -44,4 +46,9 @@ public class ProfitSharingReceiverRequest extends BaseWxPayRequest {
protected void checkConstraints() throws WxPayException { protected void checkConstraints() throws WxPayException {
this.setSignType(WxPayConstants.SignType.HMAC_SHA256); this.setSignType(WxPayConstants.SignType.HMAC_SHA256);
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("receiver", receiver);
}
} }

View File

@ -6,6 +6,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
/** /**
* @author Wang GuangXin 2019/10/22 14:54 * @author Wang GuangXin 2019/10/22 14:54
@ -22,4 +23,9 @@ public class ProfitSharingReceiverResult extends BaseWxPayResult {
*/ */
@XStreamAlias("receiver") @XStreamAlias("receiver")
private String receiver; private String receiver;
@Override
protected void loadXML(Document d) {
receiver = readXMLString(d, "receiver");
}
} }

View File

@ -7,6 +7,8 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*; import lombok.*;
import me.chanjar.weixin.common.annotation.Required; import me.chanjar.weixin.common.annotation.Required;
import java.util.Map;
/** /**
* @author Wang GuangXin 2019/10/21 17:57 * @author Wang GuangXin 2019/10/21 17:57
* @version 1.0 * @version 1.0
@ -81,4 +83,11 @@ public class ProfitSharingRequest extends BaseWxPayRequest {
// 目前仅支持HMAC-SHA256. // 目前仅支持HMAC-SHA256.
this.setSignType(WxPayConstants.SignType.HMAC_SHA256); this.setSignType(WxPayConstants.SignType.HMAC_SHA256);
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("transaction_id", transactionId);
map.put("out_order_no", outOrderNo);
map.put("receivers", receivers);
}
} }

View File

@ -5,6 +5,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
/** /**
* @author Wang GuangXin 2019/10/22 10:06 * @author Wang GuangXin 2019/10/22 10:06
@ -30,4 +31,11 @@ public class ProfitSharingResult extends BaseWxPayResult {
*/ */
@XStreamAlias("order_id") @XStreamAlias("order_id")
private String orderId; private String orderId;
@Override
protected void loadXML(Document d) {
transactionId = readXMLString(d, "transaction_id");
outOrderNo = readXMLString(d, "out_order_no");
orderId = readXMLString(d, "order_id");
}
} }

View File

@ -8,6 +8,8 @@ import lombok.*;
import me.chanjar.weixin.common.annotation.Required; import me.chanjar.weixin.common.annotation.Required;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.Map;
/** /**
* @author Wang GuangXin 2019/10/23 15:32 * @author Wang GuangXin 2019/10/23 15:32
* @version 1.0 * @version 1.0
@ -69,4 +71,11 @@ public class ProfitSharingReturnQueryRequest extends BaseWxPayRequest {
} }
this.setSignType(WxPayConstants.SignType.HMAC_SHA256); this.setSignType(WxPayConstants.SignType.HMAC_SHA256);
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("order_id", orderId);
map.put("out_order_no", outOrderNo);
map.put("out_return_no", outReturnNo);
}
} }

View File

@ -8,6 +8,8 @@ import lombok.*;
import me.chanjar.weixin.common.annotation.Required; import me.chanjar.weixin.common.annotation.Required;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.Map;
/** /**
* @author Wang GuangXin 2019/10/23 14:27 * @author Wang GuangXin 2019/10/23 14:27
* @version 1.0 * @version 1.0
@ -130,4 +132,15 @@ public class ProfitSharingReturnRequest extends BaseWxPayRequest {
} }
this.setSignType(WxPayConstants.SignType.HMAC_SHA256); this.setSignType(WxPayConstants.SignType.HMAC_SHA256);
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("order_id", orderId);
map.put("out_order_no", outOrderNo);
map.put("out_return_no", outReturnNo);
map.put("return_account_type", returnAccountType);
map.put("return_account", returnAccount);
map.put("return_amount", returnAmount.toString());
map.put("description", description);
}
} }

View File

@ -5,6 +5,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
/** /**
* @author Wang GuangXin 2019/10/23 14:41 * @author Wang GuangXin 2019/10/23 14:41
@ -71,4 +72,19 @@ public class ProfitSharingReturnResult extends BaseWxPayResult {
*/ */
@XStreamAlias("finish_time") @XStreamAlias("finish_time")
private String finishTime; private String finishTime;
@Override
protected void loadXML(Document d) {
orderId = readXMLString(d, "order_id");
outOrderNo = readXMLString(d, "out_order_no");
outReturnNo = readXMLString(d, "out_return_no");
returnNo = readXMLString(d, "return_no");
returnAccountType = readXMLString(d, "return_account_type");
returnAccount = readXMLString(d, "return_account");
returnAmount = readXMLInteger(d, "return_amount");
description = readXMLString(d, "description");
result = readXMLString(d, "result");
failReason = readXMLString(d, "fail_reason");
finishTime = readXMLString(d, "finish_time");
}
} }

View File

@ -3,6 +3,7 @@ package com.github.binarywang.wxpay.bean.request;
import com.github.binarywang.wxpay.config.WxPayConfig; import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException; import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.util.SignUtils; import com.github.binarywang.wxpay.util.SignUtils;
import com.github.binarywang.wxpay.util.XmlConfig;
import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
@ -12,9 +13,14 @@ import me.chanjar.weixin.common.util.BeanUtils;
import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.common.util.json.WxGsonBuilder;
import me.chanjar.weixin.common.util.xml.XStreamInitializer; import me.chanjar.weixin.common.util.xml.XStreamInitializer;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import static com.github.binarywang.wxpay.constant.WxPayConstants.SignType.ALL_SIGN_TYPES; import static com.github.binarywang.wxpay.constant.WxPayConstants.SignType.ALL_SIGN_TYPES;
@ -202,14 +208,52 @@ public abstract class BaseWxPayRequest implements Serializable {
* @return the string * @return the string
*/ */
public String toXML() { public String toXML() {
XStream xstream = XStreamInitializer.getInstance();
//涉及到服务商模式的两个参数在为空值时置为null以免在请求时将空值传给微信服务器 //涉及到服务商模式的两个参数在为空值时置为null以免在请求时将空值传给微信服务器
this.setSubAppId(StringUtils.trimToNull(this.getSubAppId())); this.setSubAppId(StringUtils.trimToNull(this.getSubAppId()));
this.setSubMchId(StringUtils.trimToNull(this.getSubMchId())); this.setSubMchId(StringUtils.trimToNull(this.getSubMchId()));
if (XmlConfig.fastMode) {
return toFastXml();
}
XStream xstream = XStreamInitializer.getInstance();
xstream.processAnnotations(this.getClass()); xstream.processAnnotations(this.getClass());
return xstream.toXML(this); return xstream.toXML(this);
} }
/**
* 使用快速算法组装xml
*
* @return
*/
private String toFastXml() {
try {
Document document = DocumentHelper.createDocument();
Element root = document.addElement(xmlRootTagName());
Map<String, String> signParams = getSignParams();
signParams.put("sign", sign);
for (Map.Entry<String, String> entry : signParams.entrySet()) {
if (entry.getValue() == null) {
continue;
}
Element elm = root.addElement(entry.getKey());
elm.addText(entry.getValue());
}
return document.asXML();
} catch (Exception e) {
throw new RuntimeException("generate xml error", e);
}
}
/**
* 返回xml结构的根节点名称
*
* @return 默认返回"xml", 特殊情况可以在子类中覆盖
*/
protected String xmlRootTagName() {
return "xml";
}
/** /**
* 签名时是否忽略appid. * 签名时是否忽略appid.
* *
@ -228,14 +272,14 @@ public abstract class BaseWxPayRequest implements Serializable {
return false; return false;
} }
protected boolean ignoreSubMchId(){ protected boolean ignoreSubMchId() {
return false; return false;
} }
/** /**
* 是否是企业微信字段 * 是否是企业微信字段
*/ */
protected boolean isWxWorkSign(){ protected boolean isWxWorkSign() {
return false; return false;
} }
@ -248,6 +292,32 @@ public abstract class BaseWxPayRequest implements Serializable {
return new String[0]; return new String[0];
} }
/**
* 获取签名时需要的参数.
* 注意不含sign属性
*/
public Map<String, String> getSignParams() {
Map<String, String> map = new HashMap<>();
map.put("appid", appid);
map.put("mch_id", mchId);
map.put("sub_appid", subAppId);
map.put("sub_mch_id", subMchId);
map.put("nonce_str", nonceStr);
map.put("sign_type", signType);
storeMap(map);
return map;
}
/**
* 将属性组装到一个Map中供签名和最终发送XML时使用.
* 这里需要将所有的属性全部保存进来签名的时候会自动调用getIgnoredParamsForSign进行忽略
* 不用担心否则最终生成的XML会缺失
*
* @param map 传入的属性Map
*/
abstract protected void storeMap(Map<String, String> map);
/** /**
* <pre> * <pre>
* 检查参数并设置签名. * 检查参数并设置签名.

View File

@ -3,6 +3,8 @@ package com.github.binarywang.wxpay.bean.request;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*; import lombok.*;
import java.util.Map;
/** /**
* <pre> * <pre>
* 授权码查询openid接口请求对象类 * 授权码查询openid接口请求对象类
@ -35,4 +37,10 @@ public class WxPayAuthcode2OpenidRequest extends BaseWxPayRequest {
protected void checkConstraints() { protected void checkConstraints() {
// nothing to do // nothing to do
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("auth_code", authCode);
}
} }

View File

@ -2,6 +2,8 @@ package com.github.binarywang.wxpay.bean.request;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
import java.util.Map;
/** /**
* <pre> * <pre>
* 支付请求默认对象类 * 支付请求默认对象类
@ -21,4 +23,8 @@ public class WxPayDefaultRequest extends BaseWxPayRequest {
protected boolean ignoreAppid() { protected boolean ignoreAppid() {
return true; return true;
} }
@Override
protected void storeMap(Map<String, String> map) {
}
} }

View File

@ -9,6 +9,7 @@ import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.Arrays; import java.util.Arrays;
import java.util.Map;
/** /**
* <pre> * <pre>
@ -95,4 +96,13 @@ public class WxPayDownloadBillRequest extends BaseWxPayRequest {
Arrays.toString(BILL_TYPES), this.getBillType())); Arrays.toString(BILL_TYPES), this.getBillType()));
} }
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("device_info", deviceInfo);
map.put("bill_type", billType);
map.put("bill_date", billDate);
map.put("tar_type", tarType);
}
} }

View File

@ -9,6 +9,7 @@ import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.Arrays; import java.util.Arrays;
import java.util.Map;
/** /**
* <pre> * <pre>
@ -87,4 +88,11 @@ public class WxPayDownloadFundFlowRequest extends BaseWxPayRequest {
*/ */
this.setSignType(SIGN_TYPE_HMAC_SHA256); this.setSignType(SIGN_TYPE_HMAC_SHA256);
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("bill_date", billDate);
map.put("account_type", accountType);
map.put("tar_type", tarType);
}
} }

View File

@ -4,6 +4,8 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*; import lombok.*;
import me.chanjar.weixin.common.annotation.Required; import me.chanjar.weixin.common.annotation.Required;
import java.util.Map;
/** /**
* <pre> * <pre>
* 获取微信刷脸调用凭证请求对象类 * 获取微信刷脸调用凭证请求对象类
@ -123,4 +125,15 @@ public class WxPayFaceAuthInfoRequest extends BaseWxPayRequest {
//do nothing //do nothing
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("store_id", storeId);
map.put("store_name", storeName);
map.put("device_id", deviceId);
map.put("attach", attach);
map.put("rawdata", rawdata);
map.put("now", now);
map.put("version", version);
}
} }

View File

@ -4,6 +4,8 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*; import lombok.*;
import me.chanjar.weixin.common.annotation.Required; import me.chanjar.weixin.common.annotation.Required;
import java.util.Map;
/** /**
* <pre> * <pre>
* 提交刷脸支付请求对象类 * 提交刷脸支付请求对象类
@ -174,4 +176,19 @@ public class WxPayFacepayRequest extends BaseWxPayRequest {
//do nothing //do nothing
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("device_info", deviceInfo);
map.put("body", body);
map.put("detail", detail);
map.put("attach", attach);
map.put("out_trade_no", outTradeNo);
map.put("total_fee", totalFee.toString());
map.put("fee_type", feeType);
map.put("spbill_create_ip", spbillCreateIp);
map.put("goods_tag", goodsTag);
map.put("openid", openid);
map.put("face_code", faceCode);
}
} }

View File

@ -4,6 +4,8 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*; import lombok.*;
import me.chanjar.weixin.common.annotation.Required; import me.chanjar.weixin.common.annotation.Required;
import java.util.Map;
/** /**
* <pre> * <pre>
* 提交付款码支付请求对象类 * 提交付款码支付请求对象类
@ -255,4 +257,22 @@ public class WxPayMicropayRequest extends BaseWxPayRequest {
//do nothing //do nothing
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("version", version);
map.put("body", body);
map.put("detail", detail);
map.put("attach", attach);
map.put("out_trade_no", outTradeNo);
map.put("total_fee", totalFee.toString());
map.put("fee_type", feeType);
map.put("spbill_create_ip", spbillCreateIp);
map.put("goods_tag", goodsTag);
map.put("limit_pay", limitPay);
map.put("time_start", timeStart);
map.put("time_expire", timeExpire);
map.put("auth_code", authCode);
map.put("scene_info", sceneInfo);
}
} }

View File

@ -3,6 +3,8 @@ package com.github.binarywang.wxpay.bean.request;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*; import lombok.*;
import java.util.Map;
/** /**
* <pre> * <pre>
* 关闭订单请求对象类 * 关闭订单请求对象类
@ -36,4 +38,10 @@ public class WxPayOrderCloseRequest extends BaseWxPayRequest {
protected void checkConstraints() { protected void checkConstraints() {
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("out_trade_no", outTradeNo);
}
} }

View File

@ -5,6 +5,8 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*; import lombok.*;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.Map;
/** /**
* <pre> * <pre>
* 订单查询请求对象 * 订单查询请求对象
@ -76,4 +78,12 @@ public class WxPayOrderQueryRequest extends BaseWxPayRequest {
throw new WxPayException("transaction_id 和 out_trade_no 不能同时存在或同时为空,必须二选一"); throw new WxPayException("transaction_id 和 out_trade_no 不能同时存在或同时为空,必须二选一");
} }
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("version", version);
map.put("transaction_id", transactionId);
map.put("out_trade_no", outTradeNo);
}
} }

View File

@ -5,6 +5,8 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*; import lombok.*;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.Map;
/** /**
* <pre> * <pre>
* 撤销订单请求类 * 撤销订单请求类
@ -53,4 +55,10 @@ public class WxPayOrderReverseRequest extends BaseWxPayRequest {
} }
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("transaction_id", transactionId);
map.put("out_trade_no", outTradeNo);
}
} }

View File

@ -5,6 +5,8 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*; import lombok.*;
import me.chanjar.weixin.common.annotation.Required; import me.chanjar.weixin.common.annotation.Required;
import java.util.Map;
/** /**
* <pre> * <pre>
* 拉取订单评价数据接口的请求参数封装类. * 拉取订单评价数据接口的请求参数封装类.
@ -84,4 +86,14 @@ public class WxPayQueryCommentRequest extends BaseWxPayRequest {
protected void checkConstraints() throws WxPayException { protected void checkConstraints() throws WxPayException {
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("begin_time", beginTime);
map.put("end_time", endTime);
map.put("offset", offset.toString());
if (limit != null) {
map.put("limit", limit.toString());
}
}
} }

View File

@ -3,6 +3,8 @@ package com.github.binarywang.wxpay.bean.request;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*; import lombok.*;
import java.util.Map;
/** /**
* <pre> * <pre>
* 注释中各行对应含义 * 注释中各行对应含义
@ -27,8 +29,9 @@ public class WxPayRedpackQueryRequest extends BaseWxPayRequest {
@Override @Override
protected String[] getIgnoredParamsForSign() { protected String[] getIgnoredParamsForSign() {
return new String[]{"sub_appid","sub_mch_id","sign_type"}; return new String[]{"sub_appid", "sub_mch_id", "sign_type"};
} }
/** /**
* 商户订单号 * 商户订单号
* mch_billno * mch_billno
@ -55,4 +58,10 @@ public class WxPayRedpackQueryRequest extends BaseWxPayRequest {
protected void checkConstraints() { protected void checkConstraints() {
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("mch_billno", mchBillNo);
map.put("bill_type", billType);
}
} }

View File

@ -5,6 +5,8 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*; import lombok.*;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.Map;
/** /**
* <pre> * <pre>
* Created by Binary Wang on 2016-11-24. * Created by Binary Wang on 2016-11-24.
@ -91,4 +93,13 @@ public class WxPayRefundQueryRequest extends BaseWxPayRequest {
} }
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("device_info", deviceInfo);
map.put("transaction_id", transactionId);
map.put("out_trade_no", outTradeNo);
map.put("out_refund_no", outRefundNo);
map.put("refund_id", refundId);
}
} }

View File

@ -10,6 +10,7 @@ import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.Arrays; import java.util.Arrays;
import java.util.Map;
/** /**
* <pre> * <pre>
@ -165,7 +166,7 @@ public class WxPayRefundRequest extends BaseWxPayRequest {
* 类型String(256) * 类型String(256)
* 示例值https://weixin.qq.com/notify/ * 示例值https://weixin.qq.com/notify/
* 描述 异步接收微信支付退款结果通知的回调地址通知URL必须为外网可访问的url不允许带参数 * 描述 异步接收微信支付退款结果通知的回调地址通知URL必须为外网可访问的url不允许带参数
如果参数中传了notify_url则商户平台上配置的回调地址将不会生效 * 如果参数中传了notify_url则商户平台上配置的回调地址将不会生效
* </pre> * </pre>
*/ */
@XStreamAlias("notify_url") @XStreamAlias("notify_url")
@ -194,4 +195,19 @@ public class WxPayRefundRequest extends BaseWxPayRequest {
} }
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("device_info", deviceInfo);
map.put("transaction_id", transactionId);
map.put("out_trade_no", outTradeNo);
map.put("out_refund_no", outRefundNo);
map.put("total_fee", totalFee.toString());
map.put("refund_fee", refundFee.toString());
map.put("refund_fee_type", refundFeeType);
map.put("op_user_id", opUserId);
map.put("refund_account", refundAccount);
map.put("refund_desc", refundDesc);
map.put("notify_url", notifyUrl);
}
} }

View File

@ -4,6 +4,8 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*; import lombok.*;
import me.chanjar.weixin.common.annotation.Required; import me.chanjar.weixin.common.annotation.Required;
import java.util.Map;
/** /**
* <pre> * <pre>
* 微信支付-交易保障请求参数 * 微信支付-交易保障请求参数
@ -174,4 +176,19 @@ public class WxPayReportRequest extends BaseWxPayRequest {
protected void checkConstraints() { protected void checkConstraints() {
//do nothing //do nothing
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("device_info", deviceInfo);
map.put("interface_url", interfaceUrl);
map.put("execute_time_", executeTime.toString());
map.put("return_code", returnCode);
map.put("return_msg", returnMsg);
map.put("result_code", resultCode);
map.put("err_code", errCode);
map.put("err_code_des", errCodeDes);
map.put("out_trade_no", outTradeNo);
map.put("user_ip", userIp);
map.put("time", time);
}
} }

View File

@ -4,6 +4,8 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*; import lombok.*;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import java.util.Map;
/** /**
* 发送小程序红包请求参数对象. * 发送小程序红包请求参数对象.
* *
@ -119,6 +121,21 @@ public class WxPaySendMiniProgramRedpackRequest extends BaseWxPayRequest {
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("mch_billno", mchBillNo);
map.put("send_name", sendName);
map.put("re_openid", reOpenid);
map.put("total_amount", totalAmount.toString());
map.put("total_num", totalNum.toString());
map.put("wishing", wishing);
map.put("act_name", actName);
map.put("remark", remark);
map.put("notify_way", notifyWay);
map.put("scene_id", sceneId);
map.put("wxappid", wxAppid);
}
@Override @Override
public String getAppid() { public String getAppid() {
return this.wxAppid; return this.wxAppid;

View File

@ -3,6 +3,8 @@ package com.github.binarywang.wxpay.bean.request;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*; import lombok.*;
import java.util.Map;
/** /**
* 发送红包请求参数对象. * 发送红包请求参数对象.
* Created by Binary Wang on 2016/9/24. * Created by Binary Wang on 2016/9/24.
@ -181,4 +183,18 @@ public class WxPaySendRedpackRequest extends BaseWxPayRequest {
this.wxAppid = appid; this.wxAppid = appid;
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("mch_billno", mchBillNo);
map.put("send_name", sendName);
map.put("re_openid", reOpenid);
map.put("total_amount", totalAmount.toString());
map.put("total_num", totalNum.toString());
map.put("amt_type", amtType);
map.put("wishing", wishing);
map.put("client_ip", clientIp);
map.put("act_name", actName);
map.put("remark", remark);
}
} }

View File

@ -3,6 +3,8 @@ package com.github.binarywang.wxpay.bean.request;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*; import lombok.*;
import java.util.Map;
/** /**
* <pre> * <pre>
* 转换短链接请求对象类 * 转换短链接请求对象类
@ -35,4 +37,9 @@ public class WxPayShorturlRequest extends BaseWxPayRequest {
protected void checkConstraints() { protected void checkConstraints() {
//do nothing //do nothing
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("long_url", longUrl);
}
} }

View File

@ -9,6 +9,8 @@ import lombok.experimental.Accessors;
import me.chanjar.weixin.common.annotation.Required; import me.chanjar.weixin.common.annotation.Required;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.Map;
/** /**
* <pre> * <pre>
* 统一下单请求参数对象. * 统一下单请求参数对象.
@ -396,4 +398,30 @@ public class WxPayUnifiedOrderRequest extends BaseWxPayRequest {
super.checkAndSign(config); super.checkAndSign(config);
} }
@Override
protected void storeMap(Map<String, String> map) {
map.put("version", version);
map.put("device_info", deviceInfo);
map.put("body", body);
map.put("detail", detail);
map.put("attach", attach);
map.put("out_trade_no", outTradeNo);
map.put("fee_type", feeType);
map.put("total_fee", totalFee.toString());
map.put("spbill_create_ip", spbillCreateIp);
map.put("time_start", timeStart);
map.put("time_expire", timeExpire);
map.put("goods_tag", goodsTag);
map.put("notify_url", notifyUrl);
map.put("trade_type", tradeType);
map.put("product_id", productId);
map.put("limit_pay", limitPay);
map.put("openid", openid);
map.put("sub_openid", subOpenid);
map.put("receipt", receipt);
map.put("scene_info", sceneInfo);
map.put("fingerprint", fingerprint);
map.put("profit_sharing", profitSharing);
}
} }

View File

@ -11,6 +11,7 @@ import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory; import javax.xml.xpath.XPathFactory;
import com.github.binarywang.wxpay.util.XmlConfig;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -30,6 +31,8 @@ import lombok.Data;
import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.common.util.json.WxGsonBuilder;
import me.chanjar.weixin.common.util.xml.XStreamInitializer; import me.chanjar.weixin.common.util.xml.XStreamInitializer;
import org.w3c.dom.*;
/** /**
* <pre> * <pre>
* 微信支付结果共用属性类. * 微信支付结果共用属性类.
@ -107,8 +110,9 @@ public abstract class BaseWxPayResult implements Serializable {
/** /**
* xml的Document对象用于解析xml文本. * xml的Document对象用于解析xml文本.
* make xmlDoc transient to ensure toString() can work.
*/ */
private Document xmlDoc; private transient Document xmlDoc;
/** /**
* 将单位分转换成单位圆. * 将单位分转换成单位圆.
@ -129,6 +133,18 @@ public abstract class BaseWxPayResult implements Serializable {
* @return the t * @return the t
*/ */
public static <T extends BaseWxPayResult> T fromXML(String xmlString, Class<T> clz) { public static <T extends BaseWxPayResult> T fromXML(String xmlString, Class<T> clz) {
if (XmlConfig.fastMode) {
try {
BaseWxPayResult t = clz.newInstance();
t.setXmlString(xmlString);
Document doc = t.getXmlDoc();
t.loadBasicXML(doc);
t.loadXML(doc);
return (T) t;
} catch (Exception e) {
throw new RuntimeException("parse xml error", e);
}
}
XStream xstream = XStreamInitializer.getInstance(); XStream xstream = XStreamInitializer.getInstance();
xstream.processAnnotations(clz); xstream.processAnnotations(clz);
T result = (T) xstream.fromXML(xmlString); T result = (T) xstream.fromXML(xmlString);
@ -136,6 +152,70 @@ public abstract class BaseWxPayResult implements Serializable {
return result; return result;
} }
/**
* 从XML文档中加载属性,供子类覆盖加载额外的属性
*
* @param d Document
*/
protected abstract void loadXML(Document d);
/**
* 从XML文档中加载基础属性
*
* @param d Document
*/
private void loadBasicXML(Document d) {
returnCode = readXMLString(d, "return_code");
returnMsg = readXMLString(d, "return_msg");
resultCode = readXMLString(d, "result_code");
errCode = readXMLString(d, "err_code");
errCodeDes = readXMLString(d, "err_code_des");
appid = readXMLString(d, "appid");
mchId = readXMLString(d, "mch_id");
subAppId = readXMLString(d, "sub_appid");
subMchId = readXMLString(d, "sub_mch_id");
nonceStr = readXMLString(d, "nonce_str");
sign = readXMLString(d, "sign");
}
public static Integer readXMLInteger(Node d, String tagName) {
String content = readXMLString(d, tagName);
if (content == null || content.trim().length() == 0) return null;
return Integer.parseInt(content);
}
public static String readXMLString(Node d, String tagName) {
if (!d.hasChildNodes()) return null;
NodeList childNodes = d.getChildNodes();
for (int i = 0, j = childNodes.getLength(); i < j; i++) {
Node node = childNodes.item(i);
if (tagName.equals(node.getNodeName())) {
if (!node.hasChildNodes()) return null;
return node.getFirstChild().getNodeValue();
}
}
return null;
}
public static String readXMLString(Document d, String tagName) {
NodeList elements = d.getElementsByTagName(tagName);
if (elements == null || elements.getLength() == 0) {
return null;
}
Node node = elements.item(0).getFirstChild();
if (node == null) {
return null;
}
return node.getNodeValue();
}
public static Integer readXMLInteger(Document d, String tagName) {
String content = readXMLString(d, tagName);
if (content == null || content.trim().length() == 0) return null;
return Integer.parseInt(content);
}
/** /**
* Gets logger. * Gets logger.
* *
@ -185,18 +265,19 @@ public abstract class BaseWxPayResult implements Serializable {
if (this.xmlDoc != null) { if (this.xmlDoc != null) {
return this.xmlDoc; return this.xmlDoc;
} }
xmlDoc = openXML(xmlString);
return xmlDoc;
}
protected Document openXML(String content) {
try { try {
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setExpandEntityReferences(false); factory.setExpandEntityReferences(false);
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
this.xmlDoc = factory.newDocumentBuilder() return factory.newDocumentBuilder().parse(new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8)));
.parse(new ByteArrayInputStream(this.xmlString.getBytes(StandardCharsets.UTF_8)));
return xmlDoc;
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException("非法的xml文本内容\n" + this.xmlString, e); throw new RuntimeException("非法的xml文本内容\n" + this.xmlString, e);
} }
} }
/** /**
@ -205,7 +286,7 @@ public abstract class BaseWxPayResult implements Serializable {
* @param path the path * @param path the path
* @return the xml value * @return the xml value
*/ */
String getXmlValue(String... path) { protected String getXmlValue(String... path) {
Document doc = this.getXmlDoc(); Document doc = this.getXmlDoc();
String expression = String.format("/%s//text()", Joiner.on("/").join(path)); String expression = String.format("/%s//text()", Joiner.on("/").join(path));
try { try {
@ -225,7 +306,7 @@ public abstract class BaseWxPayResult implements Serializable {
* @param path the path * @param path the path
* @return the xml value as int * @return the xml value as int
*/ */
Integer getXmlValueAsInt(String... path) { protected Integer getXmlValueAsInt(String... path) {
String result = this.getXmlValue(path); String result = this.getXmlValue(path);
if (StringUtils.isBlank(result)) { if (StringUtils.isBlank(result)) {
return null; return null;

View File

@ -4,6 +4,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
/** /**
* <pre> * <pre>
@ -30,4 +31,14 @@ public class WxPayAuthcode2OpenidResult extends BaseWxPayResult {
@XStreamAlias("openid") @XStreamAlias("openid")
private String openid; private String openid;
/**
* 从XML结构中加载额外的熟悉
*
* @param d Document
*/
@Override
protected void loadXML(Document d) {
openid = readXMLString(d, "openid");
}
} }

View File

@ -1,6 +1,7 @@
package com.github.binarywang.wxpay.bean.result; package com.github.binarywang.wxpay.bean.result;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
import org.w3c.dom.Document;
/** /**
* <pre> * <pre>
@ -12,4 +13,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
*/ */
@XStreamAlias("xml") @XStreamAlias("xml")
public class WxPayCommonResult extends BaseWxPayResult { public class WxPayCommonResult extends BaseWxPayResult {
@Override
protected void loadXML(Document d) {
}
} }

View File

@ -4,6 +4,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
import java.io.Serializable; import java.io.Serializable;
@ -35,4 +36,15 @@ public class WxPayFaceAuthInfoResult extends BaseWxPayResult implements Serializ
@XStreamAlias("expires_in") @XStreamAlias("expires_in")
private String expiresIn; private String expiresIn;
/**
* 从XML结构中加载额外的熟悉
*
* @param d Document
*/
@Override
protected void loadXML(Document d) {
authinfo = readXMLString(d, "authinfo");
expiresIn = readXMLString(d, "expires_in");
}
} }

View File

@ -4,6 +4,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
/** /**
* <pre> * <pre>
@ -242,4 +243,30 @@ public class WxPayFacepayResult extends BaseWxPayResult {
@XStreamAlias("time_end") @XStreamAlias("time_end")
private String timeEnd; private String timeEnd;
/**
* 从XML结构中加载额外的熟悉
*
* @param d Document
*/
@Override
protected void loadXML(Document d) {
deviceInfo = readXMLString(d, "device_info");
openid = readXMLString(d, "openid");
isSubscribe = readXMLString(d, "is_subscribe");
subOpenid = readXMLString(d, "sub_openid");
subsSubscribe = readXMLString(d, "sub_is_subscribe");
tradeType = readXMLString(d, "trade_type");
bankType = readXMLString(d, "bank_type");
feeType = readXMLString(d, "fee_type");
totalFee = readXMLInteger(d, "total_fee");
cashFeeType = readXMLString(d, "cash_fee_type");
cashFee = readXMLInteger(d, "cash_fee");
transactionId = readXMLString(d, "transaction_id");
outTradeNo = readXMLString(d, "out_trade_no");
detail = readXMLString(d, "detail");
attach = readXMLString(d, "attach");
promotionDetail = readXMLString(d, "promotion_detail");
timeEnd = readXMLString(d, "time_end");
}
} }

View File

@ -4,6 +4,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
/** /**
* <pre> * <pre>
@ -215,4 +216,28 @@ public class WxPayMicropayResult extends BaseWxPayResult {
@XStreamAlias("promotion_detail") @XStreamAlias("promotion_detail")
private String promotionDetail; private String promotionDetail;
/**
* 从XML结构中加载额外的熟悉
*
* @param d Document
*/
@Override
protected void loadXML(Document d) {
openid = readXMLString(d, "openid");
isSubscribe = readXMLString(d, "is_subscribe");
tradeType = readXMLString(d, "trade_type");
bankType = readXMLString(d, "bank_type");
feeType = readXMLString(d, "fee_type");
totalFee = readXMLInteger(d, "total_fee");
settlementTotalFee = readXMLInteger(d, "settlement_total_fee");
couponFee = readXMLInteger(d, "coupon_fee");
cashFeeType = readXMLString(d, "cash_fee_type");
cashFee = readXMLInteger(d, "cash_fee");
transactionId = readXMLString(d, "transaction_id");
outTradeNo = readXMLString(d, "out_trade_no");
attach = readXMLString(d, "attach");
timeEnd = readXMLString(d, "time_end");
promotionDetail = readXMLString(d, "promotion_detail");
}
} }

View File

@ -4,6 +4,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
/** /**
* <pre> * <pre>
@ -25,4 +26,14 @@ public class WxPayOrderCloseResult extends BaseWxPayResult {
@XStreamAlias("result_msg") @XStreamAlias("result_msg")
private String resultMsg; private String resultMsg;
/**
* 从XML结构中加载额外的熟悉
*
* @param d Document
*/
@Override
protected void loadXML(Document d) {
resultMsg = readXMLString(d, "result_msg");
}
} }

View File

@ -10,6 +10,7 @@ import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
/** /**
* <pre> * <pre>
@ -290,6 +291,29 @@ public class WxPayOrderQueryResult extends BaseWxPayResult {
} }
} }
/**
* 从XML结构中加载额外的熟悉
*
* @param d Document
*/
@Override
protected void loadXML(Document d) {
promotionDetail = readXMLString(d, "promotion_detail");
deviceInfo = readXMLString(d, "device_info");
openid = readXMLString(d, "openid");
isSubscribe = readXMLString(d, "is_subscribe");
tradeType = readXMLString(d, "trade_type");
tradeState = readXMLString(d, "trade_state");
bankType = readXMLString(d, "bank_type");
totalFee = readXMLInteger(d, "total_fee");
settlementTotalFee = readXMLInteger(d, "settlement_total_fee");
feeType = readXMLString(d, "fee_type");
cashFee = readXMLInteger(d, "cash_fee");
cashFeeType = readXMLString(d, "cash_fee_type");
couponFee = readXMLInteger(d, "coupon_fee");
couponCount = readXMLInteger(d, "coupon_count");
}
/** /**
* The type Coupon. * The type Coupon.
*/ */
@ -338,4 +362,5 @@ public class WxPayOrderQueryResult extends BaseWxPayResult {
private Integer couponFee; private Integer couponFee;
} }
} }

View File

@ -4,6 +4,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
/** /**
* <pre> * <pre>
@ -32,4 +33,14 @@ public class WxPayOrderReverseResult extends BaseWxPayResult {
@XStreamAlias("recall") @XStreamAlias("recall")
private String isRecall; private String isRecall;
/**
* 从XML结构中加载额外的熟悉
*
* @param d Document
*/
@Override
protected void loadXML(Document d) {
isRecall = readXMLString(d, "recall");
}
} }

View File

@ -1,12 +1,16 @@
package com.github.binarywang.wxpay.bean.result; package com.github.binarywang.wxpay.bean.result;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/** /**
* <pre> * <pre>
@ -223,6 +227,43 @@ public class WxPayRedpackQueryResult extends BaseWxPayResult {
@XStreamAlias("hblist") @XStreamAlias("hblist")
private List<RedpackInfo> redpackList; private List<RedpackInfo> redpackList;
/**
* 从XML结构中加载额外的熟悉
*
* @param d Document
*/
@Override
protected void loadXML(Document d) {
mchBillNo = readXMLString(d, "mch_billno");
detailId = readXMLString(d, "detail_id");
status = readXMLString(d, "status");
sendType = readXMLString(d, "send_type");
hbType = readXMLString(d, "hb_type");
totalNum = readXMLInteger(d, "total_num");
totalAmount = readXMLInteger(d, "total_amount");
sendTime = readXMLString(d, "send_time");
refundTime = readXMLString(d, "refund_time");
refundAmount = readXMLInteger(d, "refund_amount");
wishing = readXMLString(d, "wishing");
remark = readXMLString(d, "remark");
actName = readXMLString(d, "act_name");
NodeList nodeList = d.getElementsByTagName("hbinfo");
List<RedpackInfo> list = new ArrayList<>(nodeList.getLength());
for (int i = 0, j = nodeList.getLength(); i < j; i++) {
Node node = nodeList.item(i);
RedpackInfo rp = new RedpackInfo();
rp.amount = readXMLInteger(node, "amount");
rp.openid = readXMLString(node, "openid");
rp.receiveTime = readXMLString(node, "rcv_time");
list.add(rp);
}
redpackList = list;
}
/** /**
* The type Redpack info. * The type Redpack info.
*/ */

View File

@ -9,6 +9,7 @@ import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
/** /**
* <pre> * <pre>
@ -172,6 +173,23 @@ public class WxPayRefundQueryResult extends BaseWxPayResult {
} }
} }
/**
* 从XML结构中加载额外的熟悉
*
* @param d Document
*/
@Override
protected void loadXML(Document d) {
deviceInfo = readXMLString(d, "device_info");
transactionId = readXMLString(d, "transaction_id");
outTradeNo = readXMLString(d, "out_trade_no");
totalFee = readXMLInteger(d, "total_fee");
settlementTotalFee = readXMLInteger(d, "settlement_total_fee");
feeType = readXMLString(d, "fee_type");
cashFee = readXMLInteger(d, "cash_fee");
refundCount = readXMLInteger(d, "refund_count");
}
/** /**
* The type Refund record. * The type Refund record.
*/ */

View File

@ -8,6 +8,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
/** /**
* <pre> * <pre>
@ -119,7 +120,7 @@ public class WxPayRefundResult extends BaseWxPayResult implements Serializable {
/** /**
* 组装生成退款代金券信息. * 组装生成退款代金券信息.
*/ */
private void composeRefundCoupons() { public void composeRefundCoupons() {
List<WxPayRefundCouponInfo> coupons = Lists.newArrayList(); List<WxPayRefundCouponInfo> coupons = Lists.newArrayList();
Integer refundCount = this.getCouponRefundCount(); Integer refundCount = this.getCouponRefundCount();
if (refundCount == null) { if (refundCount == null) {
@ -140,9 +141,27 @@ public class WxPayRefundResult extends BaseWxPayResult implements Serializable {
this.setRefundCoupons(coupons); this.setRefundCoupons(coupons);
} }
public static WxPayRefundResult fromXML(String xml) { /**
WxPayRefundResult result = BaseWxPayResult.fromXML(xml, WxPayRefundResult.class); * 从XML结构中加载额外的熟悉
result.composeRefundCoupons(); *
return result; * @param d Document
*/
@Override
protected void loadXML(Document d) {
transactionId = readXMLString(d, "transaction_id");
outTradeNo = readXMLString(d, "out_trade_no");
outRefundNo = readXMLString(d, "out_refund_no");
refundId = readXMLString(d, "refund_id");
refundFee = readXMLInteger(d, "refund_fee");
settlementRefundFee = readXMLInteger(d, "settlement_refund_fee");
totalFee = readXMLInteger(d, "total_fee");
settlementTotalFee = readXMLInteger(d, "settlement_total_fee");
feeType = readXMLString(d, "fee_type");
cashFee = readXMLInteger(d, "cash_fee");
cashFeeType = readXMLString(d, "cash_fee_type");
cashRefundFee = readXMLInteger(d, "cash_refund_fee");
couponRefundCount = readXMLInteger(d, "coupon_refund_count");
couponRefundFee = readXMLInteger(d, "coupon_refund_fee");
} }
} }

View File

@ -4,6 +4,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
/** /**
* <pre> * <pre>
@ -31,4 +32,14 @@ public class WxPaySandboxSignKeyResult extends BaseWxPayResult {
@XStreamAlias("sandbox_signkey") @XStreamAlias("sandbox_signkey")
private String sandboxSignKey; private String sandboxSignKey;
/**
* 从XML结构中加载额外的熟悉
*
* @param d Document
*/
@Override
protected void loadXML(Document d) {
sandboxSignKey = readXMLString(d, "sandbox_signkey");
}
} }

View File

@ -4,6 +4,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
import java.io.Serializable; import java.io.Serializable;
@ -53,4 +54,13 @@ public class WxPaySendMiniProgramRedpackResult extends BaseWxPayResult implement
@XStreamAlias("send_listid") @XStreamAlias("send_listid")
private String sendListId; private String sendListId;
@Override
protected void loadXML(Document d) {
mchBillNo = readXMLString(d, "mch_billno");
wxAppid = readXMLString(d, "wxappid");
reOpenid = readXMLString(d, "re_openid");
totalAmount = readXMLInteger(d, "total_amount");
packageName = readXMLString(d, "package");
sendListId = readXMLString(d, "send_listid");
}
} }

View File

@ -4,6 +4,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
import java.io.Serializable; import java.io.Serializable;
@ -38,4 +39,19 @@ public class WxPaySendRedpackResult extends BaseWxPayResult implements Serializa
@XStreamAlias("send_listid") @XStreamAlias("send_listid")
private String sendListid; private String sendListid;
/**
* 从XML结构中加载额外的熟悉
*
* @param d Document
*/
@Override
protected void loadXML(Document d) {
mchBillno = readXMLString(d, "mch_billno");
wxappid = readXMLString(d, "wxappid");
reOpenid = readXMLString(d, "re_openid");
totalAmount = readXMLInteger(d, "total_amount");
sendTime = readXMLString(d, "send_time");
sendListid = readXMLString(d, "send_listid");
}
} }

View File

@ -4,6 +4,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
/** /**
* <pre> * <pre>
@ -31,4 +32,14 @@ public class WxPayShorturlResult extends BaseWxPayResult {
@XStreamAlias("short_url") @XStreamAlias("short_url")
private String shortUrl; private String shortUrl;
/**
* 从XML结构中加载额外的熟悉
*
* @param d Document
*/
@Override
protected void loadXML(Document d) {
shortUrl = readXMLString(d, "short_url");
}
} }

View File

@ -4,6 +4,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
/** /**
* <pre> * <pre>
@ -43,4 +44,17 @@ public class WxPayUnifiedOrderResult extends BaseWxPayResult {
@XStreamAlias("code_url") @XStreamAlias("code_url")
private String codeURL; private String codeURL;
/**
* 从XML结构中加载额外的熟悉
*
* @param d Document
*/
@Override
protected void loadXML(Document d) {
prepayId = readXMLString(d, "prepay_id");
tradeType = readXMLString(d, "trade_type");
mwebUrl = readXMLString(d, "mweb_url");
codeURL = readXMLString(d, "code_url");
}
} }

View File

@ -21,6 +21,7 @@ import com.github.binarywang.wxpay.service.ProfitSharingService;
import com.github.binarywang.wxpay.service.RedpackService; import com.github.binarywang.wxpay.service.RedpackService;
import com.github.binarywang.wxpay.service.WxPayService; import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.util.SignUtils; import com.github.binarywang.wxpay.util.SignUtils;
import com.github.binarywang.wxpay.util.XmlConfig;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import jodd.io.ZipUtil; import jodd.io.ZipUtil;
@ -117,7 +118,8 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
} }
String responseContent = this.post(url, request.toXML(), true); String responseContent = this.post(url, request.toXML(), true);
WxPayRefundResult result = WxPayRefundResult.fromXML(responseContent); WxPayRefundResult result = BaseWxPayResult.fromXML(responseContent, WxPayRefundResult.class);
result.composeRefundCoupons();
result.checkResult(this, request.getSignType(), true); result.checkResult(this, request.getSignType(), true);
return result; return result;
} }
@ -165,7 +167,13 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
public WxPayRefundNotifyResult parseRefundNotifyResult(String xmlData) throws WxPayException { public WxPayRefundNotifyResult parseRefundNotifyResult(String xmlData) throws WxPayException {
try { try {
log.debug("微信支付退款异步通知参数:{}", xmlData); log.debug("微信支付退款异步通知参数:{}", xmlData);
WxPayRefundNotifyResult result = WxPayRefundNotifyResult.fromXML(xmlData, this.getConfig().getMchKey()); WxPayRefundNotifyResult result;
if (XmlConfig.fastMode) {
result = BaseWxPayResult.fromXML(xmlData, WxPayRefundNotifyResult.class);
result.decryptReqInfo(this.getConfig().getMchKey());
} else {
result = WxPayRefundNotifyResult.fromXML(xmlData, this.getConfig().getMchKey());
}
log.debug("微信支付退款异步通知解析后的对象:{}", result); log.debug("微信支付退款异步通知解析后的对象:{}", result);
return result; return result;
} catch (Exception e) { } catch (Exception e) {

View File

@ -65,7 +65,18 @@ public class SignUtils {
* @return 签名字符串 string * @return 签名字符串 string
*/ */
public static String createSign(Object xmlBean, String signType, String signKey, String[] ignoredParams) { public static String createSign(Object xmlBean, String signType, String signKey, String[] ignoredParams) {
return createSign(xmlBean2Map(xmlBean), signType, signKey, ignoredParams); Map<String, String> map = null;
if (XmlConfig.fastMode) {
if (xmlBean instanceof BaseWxPayRequest) {
map = ((BaseWxPayRequest) xmlBean).getSignParams();
}
}
if (map == null) {
map = xmlBean2Map(xmlBean);
}
return createSign(map, signType, signKey, ignoredParams);
} }
/** /**
@ -91,7 +102,7 @@ public class SignUtils {
if (shouldSign) { if (shouldSign) {
toSign.append(key).append("=").append(value).append("&"); toSign.append(key).append("=").append(value).append("&");
} }
} }
toSign.append("key=").append(signKey); toSign.append("key=").append(signKey);
@ -104,25 +115,26 @@ public class SignUtils {
/** /**
* 企业微信签名 * 企业微信签名
*
* @param signType md5 目前接口要求使用的加密类型 * @param signType md5 目前接口要求使用的加密类型
*/ */
public static String createEntSign(String actName,String mchBillNo,String mchId,String nonceStr, public static String createEntSign(String actName, String mchBillNo, String mchId, String nonceStr,
String reOpenid,Integer totalAmount,String wxAppId,String signKey, String reOpenid, Integer totalAmount, String wxAppId, String signKey,
String signType){ String signType) {
Map<String, String> sortedMap = new HashMap<>(); Map<String, String> sortedMap = new HashMap<>();
sortedMap.put("act_name",actName); sortedMap.put("act_name", actName);
sortedMap.put("mch_billno",mchBillNo); sortedMap.put("mch_billno", mchBillNo);
sortedMap.put("mch_id",mchId); sortedMap.put("mch_id", mchId);
sortedMap.put("nonce_str",nonceStr); sortedMap.put("nonce_str", nonceStr);
sortedMap.put("re_openid",reOpenid); sortedMap.put("re_openid", reOpenid);
sortedMap.put("total_amount", totalAmount + ""); sortedMap.put("total_amount", totalAmount + "");
sortedMap.put("wxappid",wxAppId); sortedMap.put("wxappid", wxAppId);
Map<String, String> sortParams = new TreeMap<>(sortedMap); Map<String, String> sortParams = new TreeMap<>(sortedMap);
Set<Map.Entry<String, String>> entries = sortParams.entrySet(); Set<Map.Entry<String, String>> entries = sortParams.entrySet();
Iterator<Map.Entry<String, String>> iterator = entries.iterator(); Iterator<Map.Entry<String, String>> iterator = entries.iterator();
StringBuilder toSign = new StringBuilder(); StringBuilder toSign = new StringBuilder();
while(iterator.hasNext()){ while (iterator.hasNext()) {
Map.Entry entry = iterator.next(); Map.Entry entry = iterator.next();
String key = String.valueOf(entry.getKey()); String key = String.valueOf(entry.getKey());
String value = String.valueOf(entry.getValue()); String value = String.valueOf(entry.getValue());

View File

@ -0,0 +1,23 @@
package com.github.binarywang.wxpay.util;
public class XmlConfig {
/**
* 是否使用快速模式
*
* 如果设置为true将会影响下面的方法不再使用反射的方法来进行xml转换
* 1: BaseWxPayRequest的toXML方法
* 2: BaseWxPayResult的fromXML方法
* @see com.github.binarywang.wxpay.bean.request.BaseWxPayRequest#toXML
* @see com.github.binarywang.wxpay.bean.result.BaseWxPayResult#fromXML
*
* 启用快速模式后将能
* 1性能提升约 10 ~ 15倍
* 2可以通过 graalvm 生成native image大大减少系统开销(CPU,RAM)加快应用启动速度(亚秒级)加快系统部署速度脱离JRE.
*
* 参考测试案例: com.github.binarywang.wxpay.bean.result.WxPayRedpackQueryResultTest#benchmark
* 参考网址: https://www.graalvm.org/
*/
public static boolean fastMode = false;
}

View File

@ -1,5 +1,7 @@
package com.github.binarywang.wxpay.bean.notify; package com.github.binarywang.wxpay.bean.notify;
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
import com.github.binarywang.wxpay.util.XmlConfig;
import org.testng.*; import org.testng.*;
import org.testng.annotations.*; import org.testng.annotations.*;
@ -57,6 +59,27 @@ public class WxPayOrderNotifyResultTest {
Assert.assertEquals(result.getCouponList().get(0).getCouponId(), "10000"); Assert.assertEquals(result.getCouponList().get(0).getCouponId(), "10000");
Assert.assertEquals(result.getCouponList().get(1).getCouponId(), "10001"); Assert.assertEquals(result.getCouponList().get(1).getCouponId(), "10001");
//fast mode test
XmlConfig.fastMode = true;
try {
result = BaseWxPayResult.fromXML(xmlString, WxPayOrderNotifyResult.class);
Assert.assertEquals(result.getCouponCount().intValue(), 2);
Assert.assertNotNull(result.getCouponList());
Assert.assertEquals(result.getCouponList().size(), 2);
Assert.assertEquals(result.getCouponList().get(0).getCouponFee().intValue(), 100);
Assert.assertEquals(result.getCouponList().get(1).getCouponFee().intValue(), 200);
Assert.assertEquals(result.getCouponList().get(0).getCouponType(), "CASH");
Assert.assertEquals(result.getCouponList().get(1).getCouponType(), "NO_CASH");
Assert.assertEquals(result.getCouponList().get(0).getCouponId(), "10000");
Assert.assertEquals(result.getCouponList().get(1).getCouponId(), "10001");
} finally {
XmlConfig.fastMode = false;
}
} }
} }

View File

@ -7,6 +7,8 @@ import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
import javax.inject.Inject; import javax.inject.Inject;
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
import com.github.binarywang.wxpay.util.XmlConfig;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import org.testng.annotations.*; import org.testng.annotations.*;
@ -78,4 +80,50 @@ public class WxPayRefundNotifyResultTest {
cipher.init(Cipher.ENCRYPT_MODE, key); cipher.init(Cipher.ENCRYPT_MODE, key);
System.out.println(Base64.encodeBase64String(cipher.doFinal(xml.getBytes(StandardCharsets.UTF_8)))); System.out.println(Base64.encodeBase64String(cipher.doFinal(xml.getBytes(StandardCharsets.UTF_8))));
} }
/**
* Test from xml.
* fast mode
*
* @throws WxPayException the wx pay exception
*/
public void testFromXMLFastMode() throws WxPayException {
String xmlString = "<xml>" +
"<return_code>SUCCESS</return_code>" +
"<appid><![CDATA[****]]></appid>" +
"<mch_id><![CDATA[****]]></mch_id>" +
"<nonce_str><![CDATA[1ee38e38b04990449808688cf3a763b7]]></nonce_str>" +
"<req_info><![CDATA[q1QZlV5j/4I7CsJ3voq1zDgVAuzNM/Gg5JYHcpMZCLtg9KQlB6vShzsh8tgK60dU6yG2WVa0zeSDlK4B7wJCad1lUUP8Ar0Hm18M1ZEjw5vQU17wMzypRM0M9A4CcRLBezRZYzCka9CAH90E2FZ74y6VRe4DNR87t5n3DWVtSbWTBoaFUexHtNs6pyrqX77VvbilIyLZMv5ZYQYOobbQ1U3kime5He7ShEWZ0GPI3gq+z/ZOLsnIdJ5bsT4kokhq/531hSoZ5006vxRGGXnhJt8IYiG7R+oSQxZOYqYR5SKWF+0z2/g0zzM2QQlT2ynLWvBKvdVCLlgCjFN1DF4z/7IEK5FAISFP0GGF51hYw/LofL3ftlD7h7jvjOIgH5viJ0yFGmGCEFHcLKqg0DPXmzwXIrkgQSSQPsuZ6UbHUUG0L8YTRgLnl2FwNFskJIaNx0179Il6xveR1sCXbwSDGvGN78sFuQMztbnx+gFu6VYgv7C+5pFr87wHFAeuDXGTkVM6ucAwSanP7HuxSVvf7SrSrcovKslyqj869pSqn/AB0atiQ4eoq3kWaOqx87NHOV1st9SQW1SYH7SKz4jd9uhrQyDuPb6KJSg1Z2B4sU4187NjPzL4NpzZySgiYk2yXpWKhCLIz6BdZuWX79zgqxLbGxJJnhyy3tOzRWIlMkDOppGJyh8LO0LOqhXzwyrCYzPA+h2xcr7xN5WIW1IGJSZqHdURUtlemcB+yZivuzARNH0LE2MGUfuoNgZ5j1Osn7K88IrkAyKupcIEmG3ktVnPOd1A9RQ9eWbU+C7yKrl6u5ZRZOX0eElVszKfBFy4tu3XHlT7hd/zMFK5NJt8sE89k5m7M8KCGSgJ+Y90ZnUclQvDVtoR5CFkfqsP9fSpA1L+aKYsl2ESq5+fzcqsYRL3YLEhIipBKKrvg6Gy698oNeG+9oCIyuiFexJDq8ycBZ/AWiR+pFQVbNRaFbfKPR9zCW8gHwYOGnENNY9gABuuENqxxXDx9tEYkACd0H9ezLnu9psC6AuR41ACfo6wGKUA1TnpVEHsDbdvJBWDcw60l1hkmHQN2lYFy+eMusEX]]></req_info></xml>";
String xmlDecryptedReqInfo = "<root>\n" +
"<out_refund_no><![CDATA[R4001312001201707262674894706_4]]></out_refund_no>\n" +
"<out_trade_no><![CDATA[201707260201501501005710775]]></out_trade_no>\n" +
"<refund_account><![CDATA[REFUND_SOURCE_UNSETTLED_FUNDS]]></refund_account>\n" +
"<refund_fee><![CDATA[15]]></refund_fee>\n" +
"<refund_id><![CDATA[50000203702017072601461713166]]></refund_id>\n" +
"<refund_recv_accout><![CDATA[用户零钱]]></refund_recv_accout>\n" +
"<refund_request_source><![CDATA[API]]></refund_request_source>\n" +
"<refund_status><![CDATA[SUCCESS]]></refund_status>\n" +
"<settlement_refund_fee><![CDATA[15]]></settlement_refund_fee>\n" +
"<settlement_total_fee><![CDATA[100]]></settlement_total_fee>\n" +
"<success_time><![CDATA[2017-07-26 02:45:49]]></success_time>\n" +
"<total_fee><![CDATA[100]]></total_fee>\n" +
"<transaction_id><![CDATA[4001312001201707262674894706]]></transaction_id>\n" +
"</root>";
XmlConfig.fastMode = true;
try {
WxPayRefundNotifyResult refundNotifyResult = BaseWxPayResult.fromXML(xmlString, WxPayRefundNotifyResult.class);
System.out.println(refundNotifyResult.getReqInfoString());
refundNotifyResult.loadReqInfo(xmlDecryptedReqInfo);
assertEquals(refundNotifyResult.getReqInfo().getRefundFee().intValue(), 15);
assertEquals(refundNotifyResult.getReqInfo().getRefundStatus(), "SUCCESS");
assertEquals(refundNotifyResult.getReqInfo().getRefundRecvAccout(), "用户零钱");
System.out.println(refundNotifyResult);
} finally {
XmlConfig.fastMode = false;
}
}
} }

View File

@ -1,5 +1,6 @@
package com.github.binarywang.wxpay.bean.notify; package com.github.binarywang.wxpay.bean.notify;
import com.github.binarywang.wxpay.util.XmlConfig;
import org.testng.annotations.*; import org.testng.annotations.*;
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult; import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
@ -50,4 +51,38 @@ public class WxScanPayNotifyResultTest {
assertThat(result.getSign()).isEqualTo("C380BEC2BFD727A4B6845133519F3AD6"); assertThat(result.getSign()).isEqualTo("C380BEC2BFD727A4B6845133519F3AD6");
} }
/**
* Test from xml.
* fast mode.
*/
@Test
public void testFromXMLFastMode() {
String xmlString = "<xml>\n" +
" <appid><![CDATA[wx8888888888888888]]></appid>\n" +
" <openid><![CDATA[o8GeHuLAsgefS_80exEr1cTqekUs]]></openid>\n" +
" <mch_id><![CDATA[1900000109]]></mch_id>\n" +
" <is_subscribe><![CDATA[Y]]></is_subscribe>\n" +
" <nonce_str><![CDATA[5K8264ILTKCH16CQ2502SI8ZNMTM67VS]]></nonce_str>\n" +
" <product_id><![CDATA[88888]]></product_id>\n" +
" <sign><![CDATA[C380BEC2BFD727A4B6845133519F3AD6]]></sign>\n" +
"</xml>";
XmlConfig.fastMode = true;
try {
WxScanPayNotifyResult result = BaseWxPayResult.fromXML(xmlString, WxScanPayNotifyResult.class);
assertThat(result).isNotNull();
assertThat(result.getAppid()).isEqualTo("wx8888888888888888");
assertThat(result.getOpenid()).isEqualTo("o8GeHuLAsgefS_80exEr1cTqekUs");
assertThat(result.getMchId()).isEqualTo("1900000109");
assertThat(result.getNonceStr()).isEqualTo("5K8264ILTKCH16CQ2502SI8ZNMTM67VS");
assertThat(result.getProductId()).isEqualTo("88888");
assertThat(result.getSign()).isEqualTo("C380BEC2BFD727A4B6845133519F3AD6");
} finally {
XmlConfig.fastMode = false;
}
}
} }

View File

@ -1,5 +1,6 @@
package com.github.binarywang.wxpay.bean.result; package com.github.binarywang.wxpay.bean.result;
import com.github.binarywang.wxpay.util.XmlConfig;
import org.testng.annotations.*; import org.testng.annotations.*;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -42,8 +43,8 @@ public class WxPayRedpackQueryResultTest {
"</hblist>\n" + "</hblist>\n" +
"</xml>"; "</xml>";
WxPayRedpackQueryResult orderQueryResult = WxPayRedpackQueryResult.fromXML(xmlString, WxPayRedpackQueryResult.class); WxPayRedpackQueryResult orderQueryResult = BaseWxPayResult.fromXML(xmlString, WxPayRedpackQueryResult.class);
System.out.println(orderQueryResult); // System.out.println(orderQueryResult);
assertThat(orderQueryResult).isNotNull(); assertThat(orderQueryResult).isNotNull();
assertThat(orderQueryResult.getRedpackList()).isNotEmpty(); assertThat(orderQueryResult.getRedpackList()).isNotEmpty();
@ -51,4 +52,65 @@ public class WxPayRedpackQueryResultTest {
assertThat(orderQueryResult.getRedpackList().get(0).getOpenid()).isEqualTo("o3yHF0uHuckI3yE6lwWiFQBQdVDI"); assertThat(orderQueryResult.getRedpackList().get(0).getOpenid()).isEqualTo("o3yHF0uHuckI3yE6lwWiFQBQdVDI");
assertThat(orderQueryResult.getRedpackList().get(0).getReceiveTime()).isEqualTo("2018-01-23 13:45:31"); assertThat(orderQueryResult.getRedpackList().get(0).getReceiveTime()).isEqualTo("2018-01-23 13:45:31");
} }
/**
* Test from xml.
* FastMode
*/
@Test
public void testFromXMLFastMode() {
XmlConfig.fastMode = true;
String xmlString = "<xml>\n" +
"<return_code><![CDATA[SUCCESS]]></return_code>\n" +
"<return_msg><![CDATA[OK]]></return_msg>\n" +
"<result_code><![CDATA[SUCCESS]]></result_code>\n" +
"<err_code><![CDATA[SUCCESS]]></err_code>\n" +
"<err_code_des><![CDATA[OK]]></err_code_des>\n" +
"<mch_billno><![CDATA[1473919402201801230145075410]]></mch_billno>\n" +
"<mch_id><![CDATA[1497236182]]></mch_id>\n" +
"<detail_id><![CDATA[1000041701201801233000139830103]]></detail_id>\n" +
"<status><![CDATA[RECEIVED]]></status>\n" +
"<send_type><![CDATA[API]]></send_type>\n" +
"<hb_type><![CDATA[NORMAL]]></hb_type>\n" +
"<total_num>1</total_num>\n" +
"<total_amount>100</total_amount>\n" +
"<send_time><![CDATA[2018-01-23 13:45:08]]></send_time>\n" +
"<hblist>\n" +
"<hbinfo>\n" +
"<openid><![CDATA[o3yHF0uHuckI3yE6lwWiFQBQdVDI]]></openid>\n" +
"<amount>100</amount>\n" +
"<rcv_time><![CDATA[2018-01-23 13:45:31]]></rcv_time>\n" +
"</hbinfo>\n" +
"</hblist>\n" +
"</xml>";
try {
WxPayRedpackQueryResult orderQueryResult = BaseWxPayResult.fromXML(xmlString, WxPayRedpackQueryResult.class);
// System.out.println(orderQueryResult);
assertThat(orderQueryResult).isNotNull();
assertThat(orderQueryResult.getRedpackList()).isNotEmpty();
assertThat(orderQueryResult.getRedpackList().get(0).getAmount()).isEqualTo(100);
assertThat(orderQueryResult.getRedpackList().get(0).getOpenid()).isEqualTo("o3yHF0uHuckI3yE6lwWiFQBQdVDI");
assertThat(orderQueryResult.getRedpackList().get(0).getReceiveTime()).isEqualTo("2018-01-23 13:45:31");
} finally {
XmlConfig.fastMode = false;
}
}
@Test
void benchmark() {
long now = System.currentTimeMillis();
int loops = 10000;
for (int i = 0; i < loops; i++) {
testFromXML();
}
System.out.println(" reflect mode:\t" + (System.currentTimeMillis() - now) + " (ms) ");
now = System.currentTimeMillis();
for (int i = 0; i < loops; i++) {
testFromXMLFastMode();
}
System.out.println(" fast mode:\t" + (System.currentTimeMillis() - now) + " (ms) ");
}
} }

View File

@ -1,5 +1,6 @@
package com.github.binarywang.wxpay.bean.result; package com.github.binarywang.wxpay.bean.result;
import com.github.binarywang.wxpay.util.XmlConfig;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -40,11 +41,67 @@ public class WxPayRefundResultTest {
" <refund_fee>2</refund_fee> \n" + " <refund_fee>2</refund_fee> \n" +
"</xml>"; "</xml>";
WxPayRefundResult result = WxPayRefundResult.fromXML(xmlString); WxPayRefundResult result = BaseWxPayResult.fromXML(xmlString, WxPayRefundResult.class);
result.composeRefundCoupons();
assertThat(result.getRefundCoupons()).isNotEmpty(); assertThat(result.getRefundCoupons()).isNotEmpty();
assertThat(result.getRefundCoupons().get(0).getCouponRefundId()).isEqualTo("123"); assertThat(result.getRefundCoupons().get(0).getCouponRefundId()).isEqualTo("123");
assertThat(result.getRefundCoupons().get(0).getCouponType()).isEqualTo("CASH"); assertThat(result.getRefundCoupons().get(0).getCouponType()).isEqualTo("CASH");
assertThat(result.getRefundCoupons().get(0).getCouponRefundFee()).isEqualTo(1); assertThat(result.getRefundCoupons().get(0).getCouponRefundFee()).isEqualTo(1);
} }
@Test
public void testFromXMLFastMode() {
/*
该xml字符串来自于官方文档示例稍加改造加上代金卷
refund_channel 是个什么鬼官方文档只字不提
*/
String xmlString = "<xml>\n" +
" <return_code><![CDATA[SUCCESS]]></return_code>\n" +
" <return_msg><![CDATA[OK]]></return_msg>\n" +
" <appid><![CDATA[wx2421b1c4370ec43b]]></appid>\n" +
" <mch_id><![CDATA[10000100]]></mch_id>\n" +
" <nonce_str><![CDATA[NfsMFbUFpdbEhPXP]]></nonce_str>\n" +
" <sign><![CDATA[B7274EB9F8925EB93100DD2085FA56C0]]></sign>\n" +
" <result_code><![CDATA[SUCCESS]]></result_code>\n" +
" <transaction_id><![CDATA[1008450740201411110005820873]]></transaction_id>\n" +
" <out_trade_no><![CDATA[1415757673]]></out_trade_no>\n" +
" <out_refund_no><![CDATA[1415701182]]></out_refund_no>\n" +
" <refund_id><![CDATA[2008450740201411110000174436]]></refund_id>\n" +
" <refund_channel><![CDATA[]]></refund_channel>\n" +
" <coupon_refund_fee>1</coupon_refund_fee>\n" +
" <coupon_refund_count>1</coupon_refund_count>\n" +
" <coupon_refund_id_0>123</coupon_refund_id_0>\n" +
" <coupon_refund_fee_0>1</coupon_refund_fee_0>\n" +
" <coupon_type_0><![CDATA[CASH]]></coupon_type_0>\n" +
" <refund_fee>2</refund_fee> \n" +
"</xml>";
XmlConfig.fastMode = true;
try {
WxPayRefundResult result = BaseWxPayResult.fromXML(xmlString, WxPayRefundResult.class);
result.composeRefundCoupons();
assertThat(result.getRefundCoupons()).isNotEmpty();
assertThat(result.getRefundCoupons().get(0).getCouponRefundId()).isEqualTo("123");
assertThat(result.getRefundCoupons().get(0).getCouponType()).isEqualTo("CASH");
assertThat(result.getRefundCoupons().get(0).getCouponRefundFee()).isEqualTo(1);
} finally {
XmlConfig.fastMode = false;
}
}
@Test
void benchmark() {
long now = System.currentTimeMillis();
int loops = 10000;
for (int i = 0; i < loops; i++) {
testFromXML();
}
System.out.println(" reflect mode:\t" + (System.currentTimeMillis() - now) + " (ms) ");
now = System.currentTimeMillis();
for (int i = 0; i < loops; i++) {
testFromXMLFastMode();
}
System.out.println(" fast mode:\t" + (System.currentTimeMillis() - now) + " (ms) ");
}
} }

View File

@ -17,6 +17,7 @@ import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService; import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.testbase.ApiTestModule; import com.github.binarywang.wxpay.testbase.ApiTestModule;
import com.github.binarywang.wxpay.testbase.XmlWxPayConfig; import com.github.binarywang.wxpay.testbase.XmlWxPayConfig;
import com.github.binarywang.wxpay.util.XmlConfig;
import com.google.inject.Inject; import com.google.inject.Inject;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -566,8 +567,18 @@ public class BaseWxPayServiceImplTest {
" <coupon_fee_1>200</coupon_fee_1>\n" + " <coupon_fee_1>200</coupon_fee_1>\n" +
"</xml>"; "</xml>";
WxPayOrderNotifyResult result = this.payService.parseOrderNotifyResult(xmlString); XmlConfig.fastMode = true;
WxPayOrderNotifyResult result;
try {
result = BaseWxPayResult.fromXML(xmlString, WxPayOrderNotifyResult.class);
System.out.println(result);
} finally {
XmlConfig.fastMode = false;
}
result = this.payService.parseOrderNotifyResult(xmlString);
System.out.println(result); System.out.println(result);
} }
/** /**