一、XStream的用途
XStream是一个Java对象和XML相互转换的工具,很好很强大。提供了所有的基础类型、数组、集合等类型直接转换的支持。
因此XML常用于数据交换、对象序列化(这种序列化和Java对象的序列化技术有着本质的区别)。
Stream对象相当Java对象和XML之间的转换器,转换过程是双向的。创建XSteam对象的方式很简单,只需要new XStream()即
可。
Java到xml,用toXML()方法。
Xml到Java,用fromXML()方法。
废话不多说直接上例子
<!--XStream依赖-->
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.9</version>
</dependency>
<!--dom4J依赖-->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
package test.com.wanggs.course.util;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.junit.Test;
import java.util.List;
/**
* Created by wanggs on 2017/6/30.
*/
public class Dom4jAndXStreamTest {
@Test
// dom4j先热热身
public void dom4j() throws DocumentException {
//构造XML字符串
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
stringBuffer.append("<person>");
stringBuffer.append("<name>ton</name>");
stringBuffer.append("<sex>男</sex>");
stringBuffer.append("<address>郑州市</address>");
stringBuffer.append("</person>");
System.out.println(stringBuffer.toString());
//通过解析xml创建document对象
Document document = DocumentHelper.parseText(stringBuffer.toString());
//得到xml的根元素即(person)
Element root = document.getRootElement();
//得到根元素的所有子节点
List<Element> elementList = root.elements();
//遍历所有子节点
for (Element element : elementList) {
System.out.println(element.getName() + "=>>" + element.getText());
}
}
/**
* 输出结果:
* name=>>ton
* sex=>>男
* address=>>郑州市
*/
/**
* java 对象装xml
*/
@Test
public void xStreamTest() {
//构建Person对象
Person person = new Person();
person.setName("tom");
person.setSex("男");
person.setAddress("河南");
/**
* 对象转xml
*/
XStream xStream = new XStream(new DomDriver());
// 给Person定义别名
xStream.alias("person", person.getClass());
System.out.println(xStream.toXML(person));
/**
* 输出:
* <person>
<name>tom</name>
<sex>男</sex>
<address>河南</address>
<outer-class/>
</person>
*/
}
/**
* xml装java对象
*/
@Test
public void xml2Java() {
String xml = "<person><name>ton</name><sex>男</sex><address>河南</address></person>";
XStream stream = new XStream(new DomDriver());
stream.alias("person", Person.class);
Person person = (Person) stream.fromXML(xml);
System.out.println(person);
//输出: Person{name='ton', sex='男', address='河南'}
}
//实体类,便于观看写在了一个类中
class Person {
private String name;
private String sex;
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
'}';
}
}
}
注解
package com.wanggs.xstream;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.io.xml.DomDriver;
/**
* Created by wanggs on 2017/7/28.
*/
@XStreamAlias("message")
public class RendezvousMessage {
@XStreamAlias("type")
private int messageType;
public RendezvousMessage(int messageType) {
this.messageType = messageType;
}
}
class Tutorial {
public static void main(String[] args) {
XStream xStream = new XStream(new DomDriver());
// 默认情况下XStream是不会扫描Annotations的
xStream.processAnnotations(RendezvousMessage.class);
RendezvousMessage rendezvousMessage = new RendezvousMessage(15);
System.out.println(xStream.toXML(rendezvousMessage));
/**
* <message>
<type>15</type>
</message>
*/
}
}
package com.kaishengit.course.util;
import com.thoughtworks.xstream.XStream;
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 org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import com.kaishengit.course.message.resp.*;
import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 消息处理工具类
*
* @author liufeng
* @date 2013-09-15
*/
public class MessageUtil {
// 请求消息类型:文本
public static final String REQ_MESSAGE_TYPE_TEXT = "text";
// 请求消息类型:图片
public static final String REQ_MESSAGE_TYPE_IMAGE = "image";
// 请求消息类型:语音
public static final String REQ_MESSAGE_TYPE_VOICE = "voice";
// 请求消息类型:视频
public static final String REQ_MESSAGE_TYPE_VIDEO = "video";
// 请求消息类型:地理位置
public static final String REQ_MESSAGE_TYPE_LOCATION = "location";
// 请求消息类型:链接
public static final String REQ_MESSAGE_TYPE_LINK = "link";
// 请求消息类型:事件推送
public static final String REQ_MESSAGE_TYPE_EVENT = "event";
// 事件类型:subscribe(订阅)
public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";
// 事件类型:unsubscribe(取消订阅)
public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";
// 事件类型:scan(用户已关注时的扫描带参数二维码)
public static final String EVENT_TYPE_SCAN = "scan";
// 事件类型:LOCATION(上报地理位置)
public static final String EVENT_TYPE_LOCATION = "LOCATION";
// 事件类型:CLICK(自定义菜单)
public static final String EVENT_TYPE_CLICK = "CLICK";
// 响应消息类型:文本
public static final String RESP_MESSAGE_TYPE_TEXT = "text";
// 响应消息类型:图片
public static final String RESP_MESSAGE_TYPE_IMAGE = "image";
// 响应消息类型:语音
public static final String RESP_MESSAGE_TYPE_VOICE = "voice";
// 响应消息类型:视频
public static final String RESP_MESSAGE_TYPE_VIDEO = "video";
// 响应消息类型:音乐
public static final String RESP_MESSAGE_TYPE_MUSIC = "music";
// 响应消息类型:图文
public static final String RESP_MESSAGE_TYPE_NEWS = "news";
/**
* 解析微信发来的请求(XML)
*
* @param request
* @return Map<String, String>
* @throws Exception
*/
@SuppressWarnings("unchecked")
public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {
// 将解析结果存储在HashMap中
Map<String, String> map = new HashMap<String, String>();
// 从request中取得输入流
InputStream inputStream = request.getInputStream();
// 读取输入流
SAXReader reader = new SAXReader();
Document document = reader.read(inputStream);
// 得到xml根元素
Element root = document.getRootElement();
// 得到根元素的所有子节点
List<Element> elementList = root.elements();
// 遍历所有子节点
for (Element e : elementList)
map.put(e.getName(), e.getText());
// 释放资源
inputStream.close();
inputStream = null;
return map;
}
/**
* 扩展xstream使其支持CDATA
*/
private static XStream xstream = new XStream(new XppDriver() {
public HierarchicalStreamWriter createWriter(Writer out) {
return new PrettyPrintWriter(out) {
// 对所有xml节点的转换都增加CDATA标记
boolean cdata = true;
@SuppressWarnings("unchecked")
public void startNode(String name, Class clazz) {
super.startNode(name, clazz);
}
protected void writeText(QuickWriter writer, String text) {
if (cdata) {
writer.write("<![CDATA[");
writer.write(text);
writer.write("]]>");
} else {
writer.write(text);
}
}
};
}
});
/**
* 文本消息对象转换成xml
*
* @param textMessage 文本消息对象
* @return xml
*/
public static String messageToXml(TextMessage textMessage) {
xstream.alias("xml", textMessage.getClass());
return xstream.toXML(textMessage);
}
/**
* 图片消息对象转换成xml
*
* @param imageMessage 图片消息对象
* @return xml
*/
public static String messageToXml(ImageMessage imageMessage) {
xstream.alias("xml", imageMessage.getClass());
return xstream.toXML(imageMessage);
}
/**
* 语音消息对象转换成xml
*
* @param voiceMessage 语音消息对象
* @return xml
*/
public static String messageToXml(VoiceMessage voiceMessage) {
xstream.alias("xml", voiceMessage.getClass());
return xstream.toXML(voiceMessage);
}
/**
* 视频消息对象转换成xml
*
* @param videoMessage 视频消息对象
* @return xml
*/
public static String messageToXml(VideoMessage videoMessage) {
xstream.alias("xml", videoMessage.getClass());
return xstream.toXML(videoMessage);
}
/**
* 音乐消息对象转换成xml
*
* @param musicMessage 音乐消息对象
* @return xml
*/
public static String messageToXml(MusicMessage musicMessage) {
xstream.alias("xml", musicMessage.getClass());
return xstream.toXML(musicMessage);
}
/**
* 图文消息对象转换成xml
*
* @param newsMessage 图文消息对象
* @return xml
*/
public static String messageToXml(NewsMessage newsMessage) {
xstream.alias("xml", newsMessage.getClass());
xstream.alias("item", new Article().getClass());
return xstream.toXML(newsMessage);
}
}
工具类
/**
* 输出xml和解析xml的工具类
*@ClassName:XmlUtil
*@author: chenyoulong Email: chen.youlong@payeco.com
*@date :2012-9-29 上午9:51:28
*@Description:TODO
*/
public class XmlUtil{
/**
* java 转换成xml
* @Title: toXml
* @Description: TODO
* @param obj 对象实例
* @return String xml字符串
*/
public static String toXml(Object obj){
XStream xstream=new XStream();
// XStream xstream=new XStream(new DomDriver()); //直接用jaxp dom来解释
// XStream xstream=new XStream(new DomDriver("utf-8")); //指定编码解析器,直接用jaxp dom来解释
////如果没有这句,xml中的根元素会是<包.类名>;或者说:注解根本就没生效,所以的元素名就是类的属性
xstream.processAnnotations(obj.getClass()); //通过注解方式的,一定要有这句话
return xstream.toXML(obj);
}
/**
* 将传入xml文本转换成Java对象
* @Title: toBean
* @Description: TODO
* @param xmlStr
* @param cls xml对应的class类
* @return T xml对应的class类的实例对象
*
* 调用的方法实例:PersonBean person=XmlUtil.toBean(xmlStr, PersonBean.class);
*/
public static <T> T toBean(String xmlStr,Class<T> cls){
//注意:不是new Xstream(); 否则报错:java.lang.NoClassDefFoundError: org/xmlpull/v1/XmlPullParserFactory
XStream xstream=new XStream(new DomDriver());
xstream.processAnnotations(cls);
T obj=(T)xstream.fromXML(xmlStr);
return obj;
}
/**
* 写到xml文件中去
* @Title: writeXMLFile
* @Description: TODO
* @param obj 对象
* @param absPath 绝对路径
* @param fileName 文件名
* @return boolean
*/
public static boolean toXMLFile(Object obj, String absPath, String fileName ){
String strXml = toXml(obj);
String filePath = absPath + fileName;
File file = new File(filePath);
if(!file.exists()){
try {
file.createNewFile();
} catch (IOException e) {
log.error("创建{"+ filePath +"}文件失败!!!" + Strings.getStackTrace(e));
return false ;
}
}// end if
OutputStream ous = null ;
try {
ous = new FileOutputStream(file);
ous.write(strXml.getBytes());
ous.flush();
} catch (Exception e1) {
log.error("写{"+ filePath +"}文件失败!!!" + Strings.getStackTrace(e1));
return false;
}finally{
if(ous != null )
try {
ous.close();
} catch (IOException e) {
log.error("写{"+ filePath +"}文件关闭输出流异常!!!" + Strings.getStackTrace(e));
}
}
return true ;
}
/**
* 从xml文件读取报文
* @Title: toBeanFromFile
* @Description: TODO
* @param absPath 绝对路径
* @param fileName 文件名
* @param cls
* @throws Exception
* @return T
*/
public static <T> T toBeanFromFile(String absPath, String fileName,Class<T> cls) throws Exception{
String filePath = absPath +fileName;
InputStream ins = null ;
try {
ins = new FileInputStream(new File(filePath ));
} catch (Exception e) {
throw new Exception("读{"+ filePath +"}文件失败!", e);
}
String encode = useEncode(cls);
XStream xstream=new XStream(new DomDriver(encode));
xstream.processAnnotations(cls);
T obj =null;
try {
obj = (T)xstream.fromXML(ins);
} catch (Exception e) {
// TODO Auto-generated catch block
throw new Exception("解析{"+ filePath +"}文件失败!",e);
}
if(ins != null)
ins.close();
return obj;
}
}