利用XStream实现XML与对象间的转换(XStream转换器工厂)

需求原因:最近开发关于企业微信这块,企业微信后台API在我们使用回调的时候会返回给我们一个XML格式的字符串需要我们去解析
格式如下:

<xml>
    <ToUserName><![CDATA[toUser]]></ToUserName>
    <FromUserName><![CDATA[sys]]></FromUserName> 
    <CreateTime>1403610513</CreateTime>
    <MsgType><![CDATA[event]]></MsgType>
    <Event><![CDATA[change_contact]]></Event>
    <ChangeType>create_user</ChangeType>
    <UserID><![CDATA[zhangsan]]></UserID>
    <Name><![CDATA[张三]]></Name>
    <Department><![CDATA[1,2,3]]></Department>
    <IsLeaderInDept><![CDATA[1,0,0]]></IsLeaderInDept>
    <Position><![CDATA[产品经理]]></Position>
    <Mobile>15913215421</Mobile>
    <Gender>1</Gender>
    <Email><![CDATA[zhangsan@gzdev.com]]></Email>
    <Status>1</Status>
    <Avatar><![CDATA[http://wx.qlogo.cn/mmopen/ajNVdqHZLLA3WJ6DSZUfiakYe37PKnQhBIeOQBO4czqrnZDS79FH5Wm5m4X69TBicnHFlhiafvDwklOpZeXYQQ2icg/0]]></Avatar>
    <Alias><![CDATA[zhangsan]]></Alias>
    <Telephone><![CDATA[020-3456788]]></Telephone>
    <Address><![CDATA[广州市]]></Address>
    <ExtAttr>
        <Item>
        <Name><![CDATA[爱好]]></Name>
        <Type>0</Type>
        <Text>
            <Value><![CDATA[旅游]]></Value>
        </Text>
        </Item>
        <Item>
        <Name><![CDATA[卡号]]></Name>
        <Type>1</Type>
        <Web>
            <Title><![CDATA[企业微信]]></Title>
            <Url><![CDATA[https://work.weixin.qq.com]]></Url>
        </Web>
        </Item>
    </ExtAttr>
</xml>

需求:将此格式xml字符串转成我们需要的JAVA对象
开发框架:springboot
首先要设计出一个对应的实体类

import lombok.Data;
import java.util.List;
@Data
public class MembersXML {
    private String toUserName;
    private String fromUserName;
    private String createTime;
    private String msgType;
    private String event;
    private String changeType;
    private String userID;
    private String name;
    private String department;
    private String isLeaderInDept;
    private String position;
    private String mobile;
    private String gender;
    private String email;
    private String status;
    private String avatar;
    private String alias;
    private String telephone;
    private String address;
    private List<Item> extAttr;

    public MembersXML() {
    }

    public MembersXML(String toUserName, String fromUserName, String createTime, String msgType, String event, String changeType, String userID, String name, String department, String isLeaderInDept, String position, String mobile, String gender, String email, String status, String avatar, String alias, String telephone, String address, List<Item> extAttr) {
        this.toUserName = toUserName;
        this.fromUserName = fromUserName;
        this.createTime = createTime;
        this.msgType = msgType;
        this.event = event;
        this.changeType = changeType;
        this.userID = userID;
        this.name = name;
        this.department = department;
        this.isLeaderInDept = isLeaderInDept;
        this.position = position;
        this.mobile = mobile;
        this.gender = gender;
        this.email = email;
        this.status = status;
        this.avatar = avatar;
        this.alias = alias;
        this.telephone = telephone;
        this.address = address;
        this.extAttr = extAttr;
    }
}
@Data
class Item{
    private String name;
    private String type;
    private Text text;
    private Web web;

    public Item() {
    }

    public Item(String name, String type, Text text, Web web) {
        this.name = name;
        this.type = type;
        this.text = text;
        this.web = web;
    }
}
@Data
class Text{
    private String value;

    public Text() {
    }

    public Text(String value) {
        this.value = value;
    }
}
@Data
class Web{
    private String title;
    private String url;

    public Web() {
    }

    public Web(String title, String url) {
        this.title = title;
        this.url = url;
    }
}

接下来我们需要一个转换器,但是转换器需要一些配置
这个XML格式的配置文件主要用于配置类和成员的别名信息

<?xml version="1.0" encoding="utf-8" ?>

<InfoUnits>
    <xml class="com.xxxxxx.xxx.utils.xml.MembersXML">
        <ToUserName en="toUserName" />
        <FromUserName en="fromUserName" />
        <CreateTime en="createTime" />
        <MsgType en="msgType" />
        <Event en="event" />
        <ChangeType en="changeType" />
        <UserID en="userID" />
        <Name en="name" />
        <Department en="department" />
        <IsLeaderInDept en="isLeaderInDept" />
        <Position en="position" />
        <Mobile en="mobile" />
        <Gender en="gender" />
        <Email en="email" />
        <Status en="status" />
        <Avatar en="avatar" />
        <Alias en="alias" />
        <Telephone en="telephone" />
        <Address en="address" />
        <ExtAttr en="extAttr" >
            <Item class="com.xxxxxx.xxx.utils.xml.Item">
                <Name en="name" />
                <Type en="type" />
                <Text class="com.xxxxxx.xxx.utils.xml.Text" en="text" >
                    <Value en="value" />
                </Text>
                <Web class="com.xxxxxx.xxx.utils.xml.Web" en="web" >
                    <Title en="title" />
                    <Url en="url" />
                </Web>
            </Item>
        </ExtAttr>
    </xml>
</InfoUnits>

XML文件位置如下
XML文件位置
接下来就是我们的转换器了

import com.thoughtworks.xstream.XStream;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class XmlUtils {
    public  static  final String CONFIG_FILE = "static/InfoUnits.xml";
    //XStream转换器注册表,也成为转换器工厂。
    public  static  final Map<Class, XStream> converterMap =  new HashMap<Class, XStream>();

    static {
        try {
            reload();
        }  catch (ClassNotFoundException ex) {
            System.out.println(ex.getMessage());
            throw  new RuntimeException(ex);
        }
    }

    /**
     * 重新载入配置文件信息并生成XStream转化器注册表
     *
     * @throws ClassNotFoundException
     */
    public  static  void reload()  throws ClassNotFoundException {
        Document document = getCfgDocument();
        //遍历配置文档,构建转换器工厂。
        for (Iterator<Element> ite = document.getRootElement().elementIterator(); ite.hasNext();) {
            Element element = ite.next();
            XStream xStream =  new XStream();
            getAlias(element, xStream);
            Class clazz = Class.forName(element.selectSingleNode( "@class").getText().trim());
            converterMap.put(clazz, xStream);
        }
    }

    /**
     * 获取配置信息文档对象
     *
     * @return 配置信息文档对象
     */
    public  static Document getCfgDocument()  {
        InputStream ins = XmlUtils.class.getClassLoader().getResourceAsStream(CONFIG_FILE);
        //InputStream ins = XmlUtils.class.getResourceAsStream(CONFIG_FILE);
        SAXReader reader =  new SAXReader();
        Document doucument =  null;
        try {
            doucument = reader.read(ins);
        }  catch (DocumentException ex) {
            System.out.println(ex.getMessage());
            throw  new RuntimeException(ex);
        }
        return doucument;
    }

    public  static Map<Class, XStream> getConverterMap() {
        return converterMap;
    }

    /**
     * 递归设置转换器的别名信息
     *
     * @param element 配置文档元素节点,该节点带有一个class的属性
     * @param xStream 转换器对象
     * @throws ClassNotFoundException
     */
    public  static  void getAlias(Element element, XStream xStream)  throws ClassNotFoundException {
        //如果当前元素具有class属性,则为类型节点,设置类别名
        if (element.selectSingleNode( "@class") !=  null) {
            Class clazz = Class.forName(element.selectSingleNode( "@class").getText().trim());
            //带有class属性的节点名作为类的别名
            xStream.alias(element.getName().trim(), clazz);
        }
        //如果当前元素具有en属性,则为属性节点,设置属性的别名。
        if (element.selectSingleNode( "@en") !=  null) {
            //属性所属的类
            Class fatherClazz = Class.forName(element.getParent().selectSingleNode( "@class").getText().trim());
            xStream.aliasField(element.getName().trim(), fatherClazz, element.selectSingleNode( "@en").getText().trim());
        }
        //递归设置参数元素下所有元素的别名信息
        List<Element> eList = element.elements();
        if (eList.size() > 0) {
            for (Element e : eList) {
                getAlias(e, xStream); //递归设置
            }
        }
    }
}

转换器的目录结构:
在这里插入图片描述
注意:此处用于获取XML格式配置文件的方式
在这里插入图片描述
在这里插入图片描述
由于是springboot项目编译后会打成jar包所以文件一定要用流的方式获取而非File

接下来就是调用了:
str为微信后台传过来的XML格式字符串

XStream xStream = XmlUtils.getConverterMap().get(MembersXML.class);
        MembersXML mem = (MembersXML)xStream.fromXML(str);
        log.info(mem.toString());

结果解析成功
在这里插入图片描述
最后要注意的是maven依赖的问题:

<dependency>
            <groupId>com.thoughtworks.xstream</groupId>
            <artifactId>xstream</artifactId>
            <version>1.4.9</version>
        </dependency>
        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/jaxen/jaxen -->
        <dependency>
            <groupId>jaxen</groupId>
            <artifactId>jaxen</artifactId>
            <version>1.1.6</version>
        </dependency>

尤其是第三个jar包也就是jaxen,一定不能用1.1.1版本,否则在项目启动时会出现ClassNotFound异常,推荐使用1.1.6,反正我1.1.6没事
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值