Visitar URL original
增加XML转换的快速模式,发送请求以及组装响应对象的时候,不再依赖java的反射机制。 by outersky · Pull Request #1390 · binarywang/WxJava · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
完成了最后两个Result的xml解析。
  • Loading branch information
outersky committed Jan 28, 2020
commit cee7d2045d31c676ce17a3438e10a244ff873b16
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import me.chanjar.weixin.common.util.xml.XStreamInitializer;
import org.w3c.dom.Document;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -375,7 +376,24 @@ protected void loadXML(Document d) {
rateValue = readXMLString(d, "rate_value");
signType = readXMLString(d, "sign_type");

//@TODO set couponList
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,43 @@ public static WxPayRefundNotifyResult fromXML(String xmlString, String mchKey) t

private ReqInfo reqInfo;

// 解密后的reqInfo 字符串
private transient String decryptedReqInfo;

@Override
protected void loadXML(Document d) {
//@TODO
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);
}

/**
Expand Down Expand Up @@ -278,6 +312,23 @@ public static ReqInfo fromXML(String xmlString) {
xstream.processAnnotations(ReqInfo.class);
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");
}
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -178,13 +178,13 @@ private void loadBasicXML(Document d) {
sign = readXMLString(d, "sign");
}

protected Integer readXMLInteger(Node d, String tagName) {
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);
}

protected String readXMLString(Node d, String tagName) {
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++) {
Expand All @@ -197,7 +197,7 @@ protected String readXMLString(Node d, String tagName) {
return null;
}

protected String readXMLString(Document d, String tagName) {
public static String readXMLString(Document d, String tagName) {
NodeList elements = d.getElementsByTagName(tagName);
if (elements == null || elements.getLength() == 0) {
return null;
Expand All @@ -210,7 +210,7 @@ protected String readXMLString(Document d, String tagName) {
return node.getNodeValue();
}

protected Integer readXMLInteger(Document d, String tagName) {
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);
Expand Down Expand Up @@ -265,18 +265,19 @@ private Document getXmlDoc() {
if (this.xmlDoc != null) {
return this.xmlDoc;
}
xmlDoc = openXML(xmlString);
return xmlDoc;
}

protected Document openXML(String content) {
try {
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setExpandEntityReferences(false);
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
this.xmlDoc = factory.newDocumentBuilder()
.parse(new ByteArrayInputStream(this.xmlString.getBytes(StandardCharsets.UTF_8)));
return xmlDoc;
return factory.newDocumentBuilder().parse(new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8)));
} catch (Exception e) {
throw new RuntimeException("非法的xml文本内容:\n" + this.xmlString, e);
}

}

/**
Expand All @@ -285,7 +286,7 @@ private Document getXmlDoc() {
* @param path the path
* @return the xml value
*/
String getXmlValue(String... path) {
protected String getXmlValue(String... path) {
Document doc = this.getXmlDoc();
String expression = String.format("/%s//text()", Joiner.on("/").join(path));
try {
Expand All @@ -305,7 +306,7 @@ String getXmlValue(String... path) {
* @param path the path
* @return the xml value as int
*/
Integer getXmlValueAsInt(String... path) {
protected Integer getXmlValueAsInt(String... path) {
String result = this.getXmlValue(path);
if (StringUtils.isBlank(result)) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.github.binarywang.wxpay.service.RedpackService;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.util.SignUtils;
import com.github.binarywang.wxpay.util.XmlConfig;
import com.google.common.base.Joiner;
import com.google.common.collect.Maps;
import jodd.io.ZipUtil;
Expand Down Expand Up @@ -166,7 +167,13 @@ public WxPayOrderNotifyResult parseOrderNotifyResult(String xmlData) throws WxPa
public WxPayRefundNotifyResult parseRefundNotifyResult(String xmlData) throws WxPayException {
try {
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);
return result;
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
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.annotations.*;

Expand Down Expand Up @@ -57,6 +59,27 @@ public void testFromXML() {

Assert.assertEquals(result.getCouponList().get(0).getCouponId(), "10000");
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;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import javax.crypto.spec.SecretKeySpec;
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.testng.annotations.*;

Expand Down Expand Up @@ -78,4 +80,50 @@ public void encodeReqInfo() throws Exception {
cipher.init(Cipher.ENCRYPT_MODE, key);
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;
}
}

}