微信XML,Object,MAP相互轉換

pom.xmlphp

<dependency>
    <groupId>com.thoughtworks.xstream</groupId>
    <artifactId>xstream</artifactId>
    <version>1.4.7</version>
</dependency>

<dependency>
    <groupId>com.thoughtworks.xstream</groupId>
    <artifactId>xstream</artifactId>
    <version>1.4.7</version>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.18</version>
    <scope>provided</scope>
</dependency>

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>18.0</version>
</dependency>

 

 

 

XStreamInitializer:java

package cn.edu360.bike.test;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
import com.thoughtworks.xstream.security.NullPermission;
import com.thoughtworks.xstream.security.PrimitiveTypePermission;

import java.io.Writer;

public class XStreamInitializer {





    public static XStream getInstance() {
        XStream xstream = new XStream(new PureJavaReflectionProvider(), new XppDriver() {

            @Override
            public HierarchicalStreamWriter createWriter(Writer out) {
                return new PrettyPrintWriter(out, getNameCoder()) {
                    protected String PREFIX_CDATA = "<![CDATA[";
                    protected String SUFFIX_CDATA = "]]>";
                    protected String PREFIX_MEDIA_ID = "<MediaId>";
                    protected String SUFFIX_MEDIA_ID = "</MediaId>";

                    @Override
                    protected void writeText(QuickWriter writer, String text) {
                        if (text.startsWith(this.PREFIX_CDATA) && text.endsWith(this.SUFFIX_CDATA)) {
                            writer.write(text);
                        } else if (text.startsWith(this.PREFIX_MEDIA_ID) && text.endsWith(this.SUFFIX_MEDIA_ID)) {
                            writer.write(text);
                        } else {
                            super.writeText(writer, text);
                        }

                    }

                    @Override
                    public String encodeNode(String name) {
                        return name;//防止將_轉換成__
                    }
                };
            }
        });

        xstream.ignoreUnknownElements();
        xstream.setMode(XStream.NO_REFERENCES);
        xstream.addPermission(NullPermission.NULL);
        xstream.addPermission(PrimitiveTypePermission.PRIMITIVES);
        return xstream;
    }

}

 

 

 

 

BaseWxPayResult:git

package cn.edu360.bike.test;

import com.google.common.base.Joiner;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*;
import org.apache.commons.lang3.StringUtils;
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.util.HashMap;
import java.util.Map;

@Data
public abstract class BaseWxPayResult {


    /**
     * 返回狀態碼.
     */
    @XStreamAlias("return_code")
    protected String returnCode;
    /**
     * 返回信息.
     */
    @XStreamAlias("return_msg")
    protected String returnMsg;

    //當return_code爲SUCCESS的時候,還會包括如下字段:

    /**
     * 業務結果.
     */
    @XStreamAlias("result_code")
    private String resultCode;

    /**
     * 錯誤代碼.
     */
    @XStreamAlias("err_code")
    private String errCode;

    /**
     * 錯誤代碼描述.
     */
    @XStreamAlias("err_code_des")
    private String errCodeDes;


    /**
     * 公衆帳號ID.
     */
    @XStreamAlias("appid")
    private String appid;

    /**
     * 商戶號.
     */
    @XStreamAlias("mch_id")
    private String mchId;

    /**
     * 服務商模式下的子公衆帳號ID.
     */
    @XStreamAlias("sub_appid")
    private String subAppId;

    /**
     * 服務商模式下的子商戶號.
     */
    @XStreamAlias("sub_mch_id")
    private String subMchId;

    /**
     * 隨機字符串.
     */
    @XStreamAlias("nonce_str")
    private String nonceStr;

    /**
     * 簽名.
     */
    @XStreamAlias("sign")
    private String sign;

    //如下爲輔助屬性
    /**
     * xml字符串.
     */
    private String xmlString;

    /**
     * xml的Document對象,用於解析xml文本.
     */
    private Document xmlDoc;


    /**
     * 將xml字符串轉換成Document對象,以便讀取其元素值.
     */
    private 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);
        }

    }


    /**
     * 將bean經過保存的xml字符串轉換成map.
     */
    public Map<String, String> toMap() {
        if (StringUtils.isBlank(this.xmlString)) {
            throw new RuntimeException("xml數據有問題,請覈實!");
        }

        Map<String, String> result = new HashMap<>();
        Document doc = this.getXmlDoc();

        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;
    }


    /**
     * 從xml字符串建立bean對象.
     */
    public static <T extends BaseWxPayResult> T fromXML(String xmlString, Class<T> clz) {
        XStream xstream = XStreamInitializer.getInstance();
        xstream.processAnnotations(clz);
        T result = (T) xstream.fromXML(xmlString);
        result.setXmlString(xmlString);
        return result;
    }


    /**
     * 獲取xml中元素的值.
     */
    public 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);
        }
    }


    /**
     * 獲取xml中元素的值,做爲int值返回.
     */
    Integer getXmlValueAsInt(String... path) {
        String result = this.getXmlValue(path);
        if (StringUtils.isBlank(result)) {
            return null;
        }

        return Integer.valueOf(result);
    }


}

 

 

WxPayOrderQueryResult:spring

package cn.edu360.bike.test;

import com.google.common.collect.Lists;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*;

import java.util.List;

/**
 * <pre>
 *  查詢訂單 返回結果對象
 * Created by Binary Wang on 2016-10-24.
 * 註釋中各行每一個字段描述對應以下:
 * <li>字段名
 * <li>變量名
 * <li>是否必填
 * <li>類型
 * <li>示例值
 * <li>描述
 * </pre>
 *
 */

@Data
@NoArgsConstructor
@XStreamAlias("xml")
public class WxPayOrderQueryResult extends BaseWxPayResult {
    /**
     * <pre>
     * 字段名:營銷詳情.
     * 變量名:promotion_detail
     * 是否必填:否,單品優惠纔有
     * 類型:String(6000)
     * 示例值:[{"promotion_detail":[{"promotion_id":"109519","name":"單品惠-6","scope":"SINGLE","type":"DISCOUNT","amount":5,"activity_id":"931386","wxpay_contribute":0,"merchant_contribute":0,"other_contribute":5,"goods_detail":[{"goods_id":"a_goods1","goods_remark":"商品備註","quantity":7,"price":1,"discount_amount":4},{"goods_id":"a_goods2","goods_remark":"商品備註","quantity":1,"price":2,"discount_amount":1}]}]}
     * 描述:單品優惠專用參數,詳見https://pay.weixin.qq.com/wiki/doc/api/danpin.php?chapter=9_201&index=3
     * </pre>
     */
    @XStreamAlias("promotion_detail")
    private String promotionDetail;

    /**
     * <pre>設備號
     * device_info
     * 否
     * String(32)
     * 013467007045764
     * 微信支付分配的終端設備號,
     * </pre>
     */
    @XStreamAlias("device_info")
    private String deviceInfo;

    /**
     * <pre>用戶標識
     * openid
     * 是
     * String(128)
     * oUpF8uMuAJO_M2pxb1Q9zNjWeS6o
     * 用戶在商戶appid下的惟一標識
     * </pre>
     */
    @XStreamAlias("openid")
    private String openid;

    /**
     * <pre>是否關注公衆帳號
     * is_subscribe
     * 否
     * String(1)
     * Y
     * 用戶是否關注公衆帳號,Y-關注,N-未關注,僅在公衆帳號類型支付有效
     * </pre>
     */
    @XStreamAlias("is_subscribe")
    private String isSubscribe;

    /**
     * <pre>交易類型
     * trade_type
     * 是
     * String(16)
     * JSAPI
     * 調用接口提交的交易類型,取值以下:JSAPI,NATIVE,APP,MICROPAY,詳細說明見參數規定
     * </pre>
     */
    @XStreamAlias("trade_type")
    private String tradeType;

    /**
     * <pre>交易狀態
     * trade_state
     * 是
     * String(32)
     * SUCCESS
     * SUCCESS—支付成功,REFUND—轉入退款,NOTPAY—未支付,CLOSED—已關閉,REVOKED—已撤銷(刷卡支付),USERPAYING--用戶支付中,PAYERROR--支付失敗(其餘緣由,如銀行返回失敗)
     * </pre>
     */
    @XStreamAlias("trade_state")
    private String tradeState;

    /**
     * <pre>付款銀行
     * bank_type
     * 是
     * String(16)
     * CMC
     * 銀行類型,採用字符串類型的銀行標識
     * </pre>
     */
    @XStreamAlias("bank_type")
    private String bankType;

    /**
     * <pre>訂單金額
     * total_fee
     * 是
     * Int
     * 100
     * 訂單總金額,單位爲分
     * </pre>
     */
    @XStreamAlias("total_fee")
    private Integer totalFee;

    /**
     * <pre>應結訂單金額
     * settlement_total_fee
     * 否
     * Int
     * 100
     * 應結訂單金額=訂單金額-非充值代金券金額,應結訂單金額<=訂單金額。
     * </pre>
     */
    @XStreamAlias("settlement_total_fee")
    private Integer settlementTotalFee;

    /**
     * <pre>貨幣種類
     * fee_type
     * 否
     * String(8)
     * CNY
     * 貨幣類型,符合ISO 4217標準的三位字母代碼,默認人民幣:CNY,其餘值列表詳見貨幣類型
     * </pre>
     */
    @XStreamAlias("fee_type")
    private String feeType;

    /**
     * <pre>現金支付金額
     * cash_fee
     * 是
     * Int
     * 100
     * 現金支付金額訂單現金支付金額,詳見支付金額
     * </pre>
     */
    @XStreamAlias("cash_fee")
    private Integer cashFee;

    /**
     * <pre>現金支付貨幣類型
     * cash_fee_type
     * 否
     * String(16)
     * CNY
     * 貨幣類型,符合ISO 4217標準的三位字母代碼,默認人民幣:CNY,其餘值列表詳見貨幣類型
     * </pre>
     */
    @XStreamAlias("cash_fee_type")
    private String cashFeeType;

    /**
     * <pre>代金券金額
     * coupon_fee
     * 否
     * Int
     * 100
     * 「代金券」金額<=訂單金額,訂單金額-「代金券」金額=現金支付金額,詳見支付金額
     * </pre>
     */
    @XStreamAlias("coupon_fee")
    private Integer couponFee;

    /**
     * <pre>代金券使用數量
     * coupon_count
     * 否
     * Int
     * 1
     * 代金券使用數量
     * </pre>
     */
    @XStreamAlias("coupon_count")
    private Integer couponCount;

    private List<Coupon> coupons;
    /**
     * <pre>微信支付訂單號
     * transaction_id
     * 是
     * String(32)
     * 1009660380201506130728806387
     * 微信支付訂單號
     * </pre>
     */
    @XStreamAlias("transaction_id")
    private String transactionId;
    /**
     * <pre>商戶訂單號
     * out_trade_no
     * 是
     * String(32)
     * 20150806125346
     * 商戶系統的訂單號,與請求一致。
     * </pre>
     */
    @XStreamAlias("out_trade_no")
    private String outTradeNo;
    /**
     * <pre>附加數據
     * attach
     * 否
     * String(128)
     * 深圳分店
     * 附加數據,原樣返回
     * </pre>
     */
    @XStreamAlias("attach")
    private String attach;

    /**
     * <pre>支付完成時間
     * time_end
     * 是
     * String(14)
     * 20141030133525
     * 訂單支付時間,格式爲yyyyMMddHHmmss,如2009年12月25日9點10分10秒錶示爲20091225091010。其餘詳見時間規則
     * </pre>
     */
    @XStreamAlias("time_end")
    private String timeEnd;
    /**
     * <pre>交易狀態描述
     * trade_state_desc
     * 是
     * String(256)
     * 支付失敗,請從新下單支付
     * 對當前查詢訂單狀態的描述和下一步操做的指引
     * </pre>
     */
    @XStreamAlias("trade_state_desc")
    private String tradeStateDesc;

    /**
     * 經過xml組裝coupons屬性內容
     */
    public void composeCoupons() {
        if (this.couponCount != null && this.couponCount > 0) {
            this.coupons = Lists.newArrayList();
            for (int i = 0; i < this.couponCount; i++) {
                this.coupons.add(new Coupon(this.getXmlValue("xml/coupon_type_" + i),
                        this.getXmlValue("xml/coupon_id_" + i),
                        this.getXmlValueAsInt("xml/coupon_fee_" + i)));
            }
        }
    }

    @Data
    @Builder(builderMethodName = "newBuilder")
    @AllArgsConstructor
    public static class Coupon {
        /**
         * <pre>代金券類型
         * coupon_type_$n
         * 否
         * String
         * CASH
         * <li>CASH--充值代金券
         * <li>NO_CASH---非充值代金券
         *     訂單使用代金券時有返回(取值:CASH、NO_CASH)。$n爲下標,從0開始編號,舉例:coupon_type_$0
         * </pre>
         */
        private String couponType;

        /**
         * <pre>代金券ID
         * coupon_id_$n
         * 否
         * String(20)
         * 10000
         * 代金券ID, $n爲下標,從0開始編號
         * </pre>
         */
        private String couponId;

        /**
         * <pre>單個代金券支付金額
         * coupon_fee_$n
         * 否
         * Int
         * 100
         * 單個代金券支付金額, $n爲下標,從0開始編號
         * </pre>
         */
        private Integer couponFee;

    }

}

 

test:express

package cn.edu360.bike.test;


public class XmlTest {






    public static void main(String[] args){
//        String xml = "<xml><return_code>200</return_code><return_msg>SUCCESS</return_msg><total>123</total></xml>";
//        BaseWxPayResult baseWxPayResult = BaseWxPayResult.fromXML(xml, BaseWxPayResult.class);
//        System.out.println(baseWxPayResult);
//        System.out.println(baseWxPayResult.toMap());
//        System.out.println(baseWxPayResult.getXmlValue("xml/return_msg"));
//        System.out.println(baseWxPayResult.getXmlValueAsInt("xml/total"));


        String xml2 = "<xml>" +
                "<cash_fee>200</cash_fee><coupon_count>1</coupon_count>" +
                "<transaction_id>123123123</transaction_id>" +
                    "<coupon_type_0>type0</coupon_type_0>" +
                    "<coupon_id_0>0</coupon_id_0>" +
                    "<coupon_fee_0>0</coupon_fee_0></xml>";

        WxPayOrderQueryResult queryResult = WxPayOrderQueryResult.fromXML(xml2, WxPayOrderQueryResult.class);
        queryResult.composeCoupons();
        System.out.println(queryResult);
    }
}

 

參考:
https://gitee.com/52itstyle/spring-boot-pay/tree/master/src/main/java/com/itstyle/modules/weixinpay/controllerapache

相關文章
相關標籤/搜索