微信XML,Object,MAP相互转换

pom.xml

<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:

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:

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:

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:

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/controller

 

转载于:https://my.oschina.net/u/2253438/blog/1828984

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值