|
@@ -11,6 +11,7 @@ import javax.xml.xpath.XPathConstants;
|
|
|
import javax.xml.xpath.XPathExpressionException;
|
|
|
import javax.xml.xpath.XPathFactory;
|
|
|
|
|
|
+import com.github.binarywang.wxpay.util.XmlConfig;
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
import org.slf4j.Logger;
|
|
|
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.xml.XStreamInitializer;
|
|
|
|
|
|
+import org.w3c.dom.*;
|
|
|
+
|
|
|
/**
|
|
|
* <pre>
|
|
|
* 微信支付结果共用属性类.
|
|
@@ -107,8 +110,9 @@ public abstract class BaseWxPayResult implements Serializable {
|
|
|
|
|
|
/**
|
|
|
* 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
|
|
|
*/
|
|
|
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.processAnnotations(clz);
|
|
|
T result = (T) xstream.fromXML(xmlString);
|
|
@@ -137,6 +153,70 @@ public abstract class BaseWxPayResult implements Serializable {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
+ * 从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.
|
|
|
*
|
|
|
* @return the logger
|
|
@@ -185,18 +265,19 @@ public abstract class BaseWxPayResult implements Serializable {
|
|
|
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);
|
|
|
}
|
|
|
-
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -205,7 +286,7 @@ public abstract class BaseWxPayResult implements Serializable {
|
|
|
* @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 {
|
|
@@ -225,7 +306,7 @@ public abstract class BaseWxPayResult implements Serializable {
|
|
|
* @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;
|