| @@ -26,11 +26,6 @@ | |||||
| <version>3.7</version> | <version>3.7</version> | ||||
| <!-- 由于较新的3.8版本需要jdk8,故而此处采用较低版本 --> | <!-- 由于较新的3.8版本需要jdk8,故而此处采用较低版本 --> | ||||
| </dependency> | </dependency> | ||||
| <dependency> | |||||
| <groupId>io.rest-assured</groupId> | |||||
| <artifactId>xml-path</artifactId> | |||||
| <version>3.0.1</version> | |||||
| </dependency> | |||||
| <dependency> | <dependency> | ||||
| <groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
| <artifactId>qrcode-utils</artifactId> | <artifactId>qrcode-utils</artifactId> | ||||
| @@ -1,20 +1,26 @@ | |||||
| package com.github.binarywang.wxpay.bean.result; | package com.github.binarywang.wxpay.bean.result; | ||||
| import com.google.common.base.Joiner; | |||||
| import com.google.common.collect.Maps; | import com.google.common.collect.Maps; | ||||
| import com.thoughtworks.xstream.XStream; | import com.thoughtworks.xstream.XStream; | ||||
| import com.thoughtworks.xstream.annotations.XStreamAlias; | import com.thoughtworks.xstream.annotations.XStreamAlias; | ||||
| import io.restassured.internal.path.xml.NodeChildrenImpl; | |||||
| import io.restassured.internal.path.xml.NodeImpl; | |||||
| import io.restassured.path.xml.XmlPath; | |||||
| import io.restassured.path.xml.element.Node; | |||||
| import io.restassured.path.xml.exception.XmlPathException; | |||||
| import me.chanjar.weixin.common.util.ToStringUtils; | import me.chanjar.weixin.common.util.ToStringUtils; | ||||
| import me.chanjar.weixin.common.util.xml.XStreamInitializer; | import me.chanjar.weixin.common.util.xml.XStreamInitializer; | ||||
| import org.apache.commons.lang3.StringUtils; | |||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||
| import org.w3c.dom.Document; | |||||
| import org.w3c.dom.NodeList; | |||||
| import org.xml.sax.SAXException; | |||||
| import javax.xml.parsers.DocumentBuilderFactory; | |||||
| import javax.xml.parsers.ParserConfigurationException; | |||||
| import javax.xml.xpath.XPathConstants; | |||||
| import javax.xml.xpath.XPathExpressionException; | |||||
| import javax.xml.xpath.XPathFactory; | |||||
| import java.io.ByteArrayInputStream; | |||||
| import java.io.IOException; | |||||
| import java.math.BigDecimal; | import java.math.BigDecimal; | ||||
| import java.util.Iterator; | |||||
| import java.util.Map; | import java.util.Map; | ||||
| /** | /** | ||||
| @@ -82,6 +88,11 @@ public abstract class WxPayBaseResult { | |||||
| @XStreamAlias("sign") | @XStreamAlias("sign") | ||||
| private String sign; | private String sign; | ||||
| /** | |||||
| * xml的Document对象,用于解析xml文本 | |||||
| */ | |||||
| private Document xmlDoc; | |||||
| /** | /** | ||||
| * 将单位分转换成单位圆 | * 将单位分转换成单位圆 | ||||
| * | * | ||||
| @@ -211,51 +222,74 @@ public abstract class WxPayBaseResult { | |||||
| * 将bean通过保存的xml字符串转换成map | * 将bean通过保存的xml字符串转换成map | ||||
| */ | */ | ||||
| public Map<String, String> toMap() { | public Map<String, String> toMap() { | ||||
| Map<String, String> result = Maps.newHashMap(); | |||||
| XmlPath xmlPath = new XmlPath(this.xmlString); | |||||
| NodeImpl rootNode = null; | |||||
| try { | |||||
| rootNode = xmlPath.get("xml"); | |||||
| } catch (XmlPathException e) { | |||||
| if (StringUtils.isBlank(this.xmlString)) { | |||||
| throw new RuntimeException("xml数据有问题,请核实!"); | throw new RuntimeException("xml数据有问题,请核实!"); | ||||
| } | } | ||||
| if (rootNode == null) { | |||||
| throw new RuntimeException("xml数据有问题,请核实!"); | |||||
| } | |||||
| Map<String, String> result = Maps.newHashMap(); | |||||
| Document doc = this.getXmlDoc(); | |||||
| Iterator<Node> iterator = rootNode.children().nodeIterator(); | |||||
| while (iterator.hasNext()) { | |||||
| Node node = iterator.next(); | |||||
| result.put(node.name(), node.value()); | |||||
| try { | |||||
| NodeList list = (NodeList) XPathFactory.newInstance().newXPath() | |||||
| .compile("/xml/*") | |||||
| .evaluate(doc, XPathConstants.NODESET); | |||||
| int len = list.getLength(); | |||||
| for (int i = 0; i < len; i++) { | |||||
| result.put(list.item(i).getNodeName(), list.item(i).getTextContent()); | |||||
| } | |||||
| } catch (XPathExpressionException e) { | |||||
| throw new RuntimeException("非法的xml文本内容:" + xmlString); | |||||
| } | } | ||||
| return result; | return result; | ||||
| } | } | ||||
| private String getXmlValue(XmlPath xmlPath, String path) { | |||||
| if (xmlPath.get(path) instanceof NodeChildrenImpl) { | |||||
| if (((NodeChildrenImpl) xmlPath.get(path)).size() == 0) { | |||||
| return null; | |||||
| } | |||||
| /** | |||||
| * 将xml字符串转换成Document对象,以便读取其元素值 | |||||
| */ | |||||
| protected Document getXmlDoc() { | |||||
| if (this.xmlDoc != null) { | |||||
| return this.xmlDoc; | |||||
| } | |||||
| try { | |||||
| this.xmlDoc = DocumentBuilderFactory | |||||
| .newInstance() | |||||
| .newDocumentBuilder() | |||||
| .parse(new ByteArrayInputStream(this.xmlString.getBytes("UTF-8"))); | |||||
| return xmlDoc; | |||||
| } catch (SAXException | IOException | ParserConfigurationException e) { | |||||
| throw new RuntimeException("非法的xml文本内容:" + this.xmlString); | |||||
| } | } | ||||
| return xmlPath.getString(path); | |||||
| } | } | ||||
| protected <T> T getXmlValue(XmlPath xmlPath, String path, Class<T> clz) { | |||||
| String value = this.getXmlValue(xmlPath, path); | |||||
| if (value == null) { | |||||
| return null; | |||||
| /** | |||||
| * 获取xml中元素的值 | |||||
| */ | |||||
| protected String getXmlValue(String... path) { | |||||
| Document doc = this.getXmlDoc(); | |||||
| String expression = String.format("/%s//text()", Joiner.on("/").join(path)); | |||||
| try { | |||||
| return (String) XPathFactory | |||||
| .newInstance() | |||||
| .newXPath() | |||||
| .compile(expression) | |||||
| .evaluate(doc, XPathConstants.STRING); | |||||
| } catch (XPathExpressionException e) { | |||||
| throw new RuntimeException("未找到相应路径的文本:" + expression); | |||||
| } | } | ||||
| } | |||||
| switch (clz.getSimpleName()) { | |||||
| case "String": | |||||
| return (T) value; | |||||
| case "Integer": | |||||
| return (T) Integer.valueOf(value); | |||||
| /** | |||||
| * 获取xml中元素的值,作为int值返回 | |||||
| */ | |||||
| protected Integer getXmlValueAsInt(String... path) { | |||||
| String result = this.getXmlValue(path); | |||||
| if (StringUtils.isBlank(result)) { | |||||
| return null; | |||||
| } | } | ||||
| throw new UnsupportedOperationException("暂时不支持此种类型的数据"); | |||||
| return Integer.valueOf(result); | |||||
| } | } | ||||
| } | } | ||||
| @@ -2,7 +2,6 @@ package com.github.binarywang.wxpay.bean.result; | |||||
| import com.google.common.collect.Lists; | import com.google.common.collect.Lists; | ||||
| import com.thoughtworks.xstream.annotations.XStreamAlias; | import com.thoughtworks.xstream.annotations.XStreamAlias; | ||||
| import io.restassured.path.xml.XmlPath; | |||||
| import java.util.List; | import java.util.List; | ||||
| @@ -395,11 +394,10 @@ public class WxPayOrderQueryResult extends WxPayBaseResult { | |||||
| public void composeCoupons() { | public void composeCoupons() { | ||||
| if (this.couponCount != null && this.couponCount > 0) { | if (this.couponCount != null && this.couponCount > 0) { | ||||
| this.coupons = Lists.newArrayList(); | this.coupons = Lists.newArrayList(); | ||||
| XmlPath xmlPath = new XmlPath(this.getXmlString()); | |||||
| for (int i = 0; i < this.couponCount; i++) { | for (int i = 0; i < this.couponCount; i++) { | ||||
| this.coupons.add(new Coupon(this.getXmlValue(xmlPath, "xml.coupon_type_" + i, String.class), | |||||
| this.getXmlValue(xmlPath, "xml.coupon_id_" + i, String.class), | |||||
| this.getXmlValue(xmlPath, "xml.coupon_fee_" + i, Integer.class))); | |||||
| this.coupons.add(new Coupon(this.getXmlValue("xml/coupon_type_" + i), | |||||
| this.getXmlValue("xml/coupon_id_" + i), | |||||
| this.getXmlValueAsInt("xml/coupon_fee_" + i))); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -2,7 +2,6 @@ package com.github.binarywang.wxpay.bean.result; | |||||
| import com.google.common.collect.Lists; | import com.google.common.collect.Lists; | ||||
| import com.thoughtworks.xstream.annotations.XStreamAlias; | import com.thoughtworks.xstream.annotations.XStreamAlias; | ||||
| import io.restassured.path.xml.XmlPath; | |||||
| import java.util.List; | import java.util.List; | ||||
| @@ -190,22 +189,21 @@ public class WxPayRefundQueryResult extends WxPayBaseResult { | |||||
| public void composeRefundRecords() { | public void composeRefundRecords() { | ||||
| if (this.refundCount != null && this.refundCount > 0) { | if (this.refundCount != null && this.refundCount > 0) { | ||||
| this.refundRecords = Lists.newArrayList(); | this.refundRecords = Lists.newArrayList(); | ||||
| XmlPath xmlPath = new XmlPath(this.getXmlString()); | |||||
| for (int i = 0; i < this.refundCount; i++) { | for (int i = 0; i < this.refundCount; i++) { | ||||
| RefundRecord refundRecord = new RefundRecord(); | RefundRecord refundRecord = new RefundRecord(); | ||||
| this.refundRecords.add(refundRecord); | this.refundRecords.add(refundRecord); | ||||
| refundRecord.setOutRefundNo(this.getXmlValue(xmlPath, "xml.out_refund_no_" + i, String.class)); | |||||
| refundRecord.setRefundId(this.getXmlValue(xmlPath, "xml.refund_id_" + i, String.class)); | |||||
| refundRecord.setRefundChannel(this.getXmlValue(xmlPath, "xml.refund_channel_" + i, String.class)); | |||||
| refundRecord.setRefundFee(this.getXmlValue(xmlPath, "xml.refund_fee_" + i, Integer.class)); | |||||
| refundRecord.setSettlementRefundFee(this.getXmlValue(xmlPath, "xml.settlement_refund_fee_" + i, Integer.class)); | |||||
| refundRecord.setCouponType(this.getXmlValue(xmlPath, "xml.coupon_type_" + i, String.class)); | |||||
| refundRecord.setCouponRefundFee(this.getXmlValue(xmlPath, "xml.coupon_refund_fee_" + i, Integer.class)); | |||||
| refundRecord.setCouponRefundCount(this.getXmlValue(xmlPath, "xml.coupon_refund_count_" + i, Integer.class)); | |||||
| refundRecord.setRefundStatus(this.getXmlValue(xmlPath, "xml.refund_status_" + i, String.class)); | |||||
| refundRecord.setRefundRecvAccout(this.getXmlValue(xmlPath, "xml.refund_recv_accout_" + i, String.class)); | |||||
| refundRecord.setOutRefundNo(this.getXmlValue("xml/out_refund_no_" + i)); | |||||
| refundRecord.setRefundId(this.getXmlValue("xml/refund_id_" + i)); | |||||
| refundRecord.setRefundChannel(this.getXmlValue("xml/refund_channel_" + i)); | |||||
| refundRecord.setRefundFee(this.getXmlValueAsInt("xml/refund_fee_" + i)); | |||||
| refundRecord.setSettlementRefundFee(this.getXmlValueAsInt("xml/settlement_refund_fee_" + i)); | |||||
| refundRecord.setCouponType(this.getXmlValue("xml/coupon_type_" + i)); | |||||
| refundRecord.setCouponRefundFee(this.getXmlValueAsInt("xml/coupon_refund_fee_" + i)); | |||||
| refundRecord.setCouponRefundCount(this.getXmlValueAsInt("xml/coupon_refund_count_" + i)); | |||||
| refundRecord.setRefundStatus(this.getXmlValue("xml/refund_status_" + i)); | |||||
| refundRecord.setRefundRecvAccout(this.getXmlValue("xml/refund_recv_accout_" + i)); | |||||
| if (refundRecord.getCouponRefundCount() == null || refundRecord.getCouponRefundCount() == 0) { | if (refundRecord.getCouponRefundCount() == null || refundRecord.getCouponRefundCount() == 0) { | ||||
| continue; | continue; | ||||
| @@ -215,8 +213,8 @@ public class WxPayRefundQueryResult extends WxPayBaseResult { | |||||
| for (int j = 0; j < refundRecord.getCouponRefundCount(); j++) { | for (int j = 0; j < refundRecord.getCouponRefundCount(); j++) { | ||||
| coupons.add( | coupons.add( | ||||
| new RefundRecord.RefundCoupon( | new RefundRecord.RefundCoupon( | ||||
| this.getXmlValue(xmlPath, "xml.coupon_refund_id_" + i + "_" + j, String.class), | |||||
| this.getXmlValue(xmlPath, "xml.coupon_refund_fee_" + i + "_" + j, Integer.class) | |||||
| this.getXmlValue("xml/coupon_refund_id_" + i + "_" + j), | |||||
| this.getXmlValueAsInt("xml/coupon_refund_fee_" + i + "_" + j) | |||||
| ) | ) | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -1,6 +1,5 @@ | |||||
| package com.github.binarywang.wxpay.bean.result; | package com.github.binarywang.wxpay.bean.result; | ||||
| import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult; | |||||
| import org.testng.*; | import org.testng.*; | ||||
| import org.testng.annotations.*; | import org.testng.annotations.*; | ||||
| @@ -13,6 +12,15 @@ import java.util.Map; | |||||
| * </pre> | * </pre> | ||||
| */ | */ | ||||
| public class WxPayBaseResultTest { | public class WxPayBaseResultTest { | ||||
| @Test | |||||
| public void testGetXmlValue() throws Exception { | |||||
| } | |||||
| @Test | |||||
| public void testXml2Doc() throws Exception { | |||||
| } | |||||
| @Test | @Test | ||||
| public void testToMap() throws Exception { | public void testToMap() throws Exception { | ||||
| WxPayOrderQueryResult result = new WxPayOrderQueryResult(); | WxPayOrderQueryResult result = new WxPayOrderQueryResult(); | ||||
| @@ -40,11 +48,17 @@ public class WxPayBaseResultTest { | |||||
| Map<String, String> map = result.toMap(); | Map<String, String> map = result.toMap(); | ||||
| System.out.println(map); | System.out.println(map); | ||||
| Assert.assertEquals("SUCCESS", map.get("return_code")); | |||||
| Assert.assertEquals("订单额外描述", map.get("attach")); | |||||
| Assert.assertEquals(map.get("return_code"), "SUCCESS"); | |||||
| Assert.assertEquals(map.get("attach"), "订单额外描述"); | |||||
| } | |||||
| result.setXmlString(""); | |||||
| System.out.println(result.toMap()); | |||||
| @Test(expectedExceptions = {RuntimeException.class}) | |||||
| public void testToMap_with_empty_xmlString() { | |||||
| WxPayOrderQueryResult result = new WxPayOrderQueryResult(); | |||||
| result.setXmlString(" "); | |||||
| Map<String, String> map = result.toMap(); | |||||
| System.out.println(map); | |||||
| } | } | ||||
| } | } | ||||