xstream与resttemplate的联合使用

来源:互联网 发布:ubuntu拷贝文件夹 编辑:程序博客网 时间:2024/04/30 08:32

最近做微信支付开发,接口都是xml数据,决定应xstream。用之后发现spring的默认XStreamMarshaller不能达到要求,所以做了自定义

配置如下

<bean id="xStreamMarshaller" class="cloudolp.CustomXStreamMarshaller">    <property name="annotatedClasses">        <array>            <value>com.cloudolp.base.SmsResponse</value>            <value>com.cloudolp.base.weixinpay.UnifiedorderRequest</value>            <value>com.cloudolp.base.weixinpay.UnifiedorderResponse</value>        </array>    </property>    <property name="streamDriver">        <bean class="cloudolp.CustomXppDriver">            <constructor-arg>                <bean class="com.thoughtworks.xstream.io.naming.NoNameCoder"/>            </constructor-arg>        </bean>    </property></bean>


这里有两个自己实现类CustomXStreamMarshaller和CustomXppDriver

package cloudolp;import com.thoughtworks.xstream.XStream;import com.thoughtworks.xstream.annotations.XStreamAlias;import com.thoughtworks.xstream.core.util.QuickWriter;import com.thoughtworks.xstream.io.*;import com.thoughtworks.xstream.io.naming.NameCoder;import com.thoughtworks.xstream.io.xml.*;import java.io.Writer;import java.lang.reflect.Field;import org.springframework.oxm.xstream.XStreamMarshaller;/** * 增加ignoreUnknownElements */public class CustomXStreamMarshaller extends XStreamMarshaller {    private boolean ignoreUnknow=false;    public CustomXStreamMarshaller() {        super();    }    public void setIgnoreUnknow(boolean ignoreUnknow) {        this.ignoreUnknow = ignoreUnknow;    }    @Override    protected void customizeXStream(XStream xstream) {        if(ignoreUnknow){            xstream.ignoreUnknownElements();        }    }}
这个类直接继承spring默认实现的XStreamMarshaller ,增加了一个选项:反序列化时是否忽略对象中不存在的属性。微信返回的xml中的很多字段我是不需要的,如果没加入这个选项,自定义的bean中必须包含所有xml中的标签,否则反序列换出错。


package cloudolp;import com.thoughtworks.xstream.annotations.XStreamAlias;import com.thoughtworks.xstream.core.util.QuickWriter;import com.thoughtworks.xstream.io.HierarchicalStreamWriter;import com.thoughtworks.xstream.io.naming.NameCoder;import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;import com.thoughtworks.xstream.io.xml.XppDriver;import java.io.Writer;import java.lang.reflect.Field;/** * Created by chao.zeng on 2016/10/20. */public class CustomXppDriver extends XppDriver {    public CustomXppDriver(){        super();    }    public CustomXppDriver(NameCoder nameCoder){        super(nameCoder);    }    @Override    public HierarchicalStreamWriter createWriter(Writer out) {        return new PrettyPrintWriter(out,getNameCoder()) {            boolean cdata = false;            Class<?> targetClass = null;            private boolean needCDATA(Class<?> targetClass, String fieldAlias){                boolean cdata = false;                //first, scan self                cdata = existsCDATA(targetClass, fieldAlias);                if(cdata) return cdata;                //if cdata is false, scan supperClass until java.lang.Object                Class<?> superClass = targetClass.getSuperclass();                while(!superClass.equals(Object.class)){                    cdata = existsCDATA(superClass, fieldAlias);                    if(cdata) return cdata;                    superClass = superClass.getClass().getSuperclass();                }                return false;            }            private boolean existsCDATA(Class<?> clazz, String fieldAlias){                //scan fields                Field[] fields = clazz.getDeclaredFields();                for (Field field : fields) {                    //1. exists XStreamCDATA                    if(field.getAnnotation(XStreamCDATA.class) != null ){                        XStreamAlias xStreamAlias = field.getAnnotation(XStreamAlias.class);                        //2. exists XStreamAlias                        if(null != xStreamAlias){                            if(fieldAlias.equals(xStreamAlias.value()))//matched                                return true;                        }else{// not exists XStreamAlias                            if(fieldAlias.equals(field.getName()))                                return true;                        }                    }                }                return false;            }            @Override            public void startNode(String name,@SuppressWarnings("rawtypes") Class clazz) {                super.startNode(name, clazz);                //业务处理,对于用XStreamCDATA标记的Field,需要加上CDATA标签                if(!name.equals("xml")){                    cdata = needCDATA(targetClass, name);                }else{                    targetClass = clazz;                }            }            @Override            protected void writeText(QuickWriter writer, String text) {                if (cdata) {                    if(text!=null && !text.startsWith("<![CDATA[")){                        writer.write("<![CDATA["+text+"]]>");                    }else{                        writer.write("text");                    }                } else {                    writer.write(text);                }            }        };    }}


package cloudolp;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * Created by chao.zeng on 2016/10/20. */@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.FIELD})public @interface XStreamCDATA {}

有时候我们的标签的内容可能会包含特殊字符,这就需要使用<![CDATA[]]>将内容包裹起来,微信支付的很多标签都要求用<![CDATA[]]>包裹,这个自定义的driver就是实现此功能。

这里还有一个需要注意的类NoNameCoder,这个类不会把下划线转换成双下划线,而默认的是XmlFriendlyNameCoder会变成双下划线,微信支付的接口的很多XML都是a_b的结构,我们的bean属性的命名一一般是aB,所以会加上别名@XStreamAlias("a_b"),这时候一定要指定NoNameCoder,否则生成的标签是带双下划线的,导致接口调用失败

0 0
原创粉丝点击