前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringMVC XStream 返回Xml时完美支持List,Map输出 顶

SpringMVC XStream 返回Xml时完美支持List,Map输出 顶

作者头像
linapex
发布2019-03-26 10:08:53
2.3K0
发布2019-03-26 10:08:53
举报
文章被收录于专栏:区块链实战区块链实战

并在此源码上进行改动。

现支持,多种容器组合,无限循环嵌套,基本数据类型为null,则设置默认值,日期格式化。

改动源代码后,对于List的支持.每一个对象都是由data标签包裹。

后台代码:

代码语言:javascript
复制
List<User> users = new ArrayList<User>();
        users.add(new User(1));
        users.add(new User(2));
        users.add(new User(3));

        model.addAttribute("list", users );

注意,在使用过程中,List不支持,基本类型的Xml转换,只支持对象Xml转换。

此方法是错误的正确的方法【要使用对象包装属性,并提供get set 方法】,得到的结果如下图:

代码语言:javascript
复制
List<String> list = new ArrayList<String>();
		 list.add("l1");
		 list.add("l2");
		 list.add("l3");
		 model.addAttribute("list", list);

改动源代码后,对于Map的完美支持。

代码语言:javascript
复制
Map<String, Object> maps = new HashMap<String, Object>();
		maps.put("qqqq", "qqqqqq");
		maps.put("qqqq2", "qqqqqq2");
		maps.put("users", users);

		Map<String, Object> mm = new HashMap<String, Object>();
		mm.put("w1", "w1");
		mm.put("w2", "w2");
		mm.put("w3", "w3");

		Map<String, Object> mm2 = new HashMap<String, Object>();
		mm2.put("w1", "w1");
		mm2.put("w2", "w2");
		mm2.put("w3", "w3");

		mm.put("w4", mm2);
		maps.put("mm", mm);


		model.addAttribute("User1", maps);

改动源代码后,对于Java Ben的支持.Java Ben 中可放List,Map等容器,递归支持无限循环Xml节点组装。

代码语言:javascript
复制
User u = new User();
		u.setUserID(userID);
		u.setUserName("测试一下");
		u.setBirth(new Date());

		List<User> users = new ArrayList<User>();
		users.add(new User(1));
		users.add(new User(2));
		users.add(new User(3));

		Map<String, Object> maps = new HashMap<String, Object>();
		maps.put("qqqq", "qqqqqq");
		maps.put("qqqq2", "qqqqqq2");
		maps.put("users", users);

		Map<String, Object> mm = new HashMap<String, Object>();
		mm.put("w1", "w1");
		mm.put("w2", "w2");
		mm.put("w3", "w3");

		Map<String, Object> mm2 = new HashMap<String, Object>();
		mm2.put("w1", "w1");
		mm2.put("w2", "w2");
		mm2.put("w3", "w3");

		mm.put("mm2", mm2);
		maps.put("mm", mm);

		u.setUsers(users);
		u.setMaps(maps);
		
		model.addAttribute("User", u);

User类源码:

代码语言:javascript
复制
package com.linapex.models;

import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.xml.bind.annotation.XmlRootElement;

/**
 * 项目名称:SpringMVC_build
 * 
 * 类名称:User
 * 
 * 创建人:LinApex
 * 
 * 创建时间:2013-9-4 下午3:05:28
 * 
 * 功能描述:
 */

@XmlRootElement
public class User
{

	private long userID;

	private String userName;

	private Date birth;

	private List<User> users;

	private Map<String, Object> maps;

	public Map<String, Object> getMaps()
	{
		return maps;
	}

	public void setMaps(Map<String, Object> maps)
	{
		this.maps = maps;
	}

	public User(long userID)
	{
		super();
		this.userID = userID;
	}

	public User()
	{
		super();
	}

	public List<User> getUsers()
	{
		return users;
	}

	public void setUsers(List<User> users)
	{
		this.users = users;
	}

	public String getUserName()
	{

		return userName;

	}

	public void setUserName(String userName)
	{

		this.userName = userName;

	}

	public Date getBirth()
	{

		return birth;

	}

	public void setBirth(Date birth)
	{

		this.birth = birth;

	}

	public long getUserID()
	{

		return userID;

	}

	public void setUserID(long userID)
	{

		this.userID = userID;

	}

	@Override
	public String toString()
	{
		return "User [userID=" + userID + ", userName=" + userName + ", birth=" + birth + ", users=" + users + "]";
	}

}

XStreamMarshaller类源码:

代码语言:javascript
复制
package com.linapex.web.expand;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.oxm.MarshallingFailureException;
import org.springframework.oxm.UncategorizedMappingException;
import org.springframework.oxm.UnmarshallingFailureException;
import org.springframework.oxm.XmlMappingException;
import org.springframework.oxm.support.AbstractMarshaller;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.StaxUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.ext.LexicalHandler;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.ConversionException;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.ConverterMatcher;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.SingleValueConverter;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamDriver;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.StreamException;
import com.thoughtworks.xstream.io.xml.CompactWriter;
import com.thoughtworks.xstream.io.xml.DomReader;
import com.thoughtworks.xstream.io.xml.DomWriter;
import com.thoughtworks.xstream.io.xml.QNameMap;
import com.thoughtworks.xstream.io.xml.SaxWriter;
import com.thoughtworks.xstream.io.xml.StaxReader;
import com.thoughtworks.xstream.io.xml.StaxWriter;
import com.thoughtworks.xstream.io.xml.XmlFriendlyReplacer;
import com.thoughtworks.xstream.io.xml.XppReader;
import com.thoughtworks.xstream.mapper.CannotResolveClassException;

/**
 * 项目名称:SpringMVC_build
 * 
 * 类名称:XStreamMarshaller
 * 
 * 创建人:LinApex
 * 
 * 创建时间:2013-9-4 下午5:25:18
 * 
 * 功能描述:
 */

public class XStreamMarshaller extends AbstractMarshaller implements InitializingBean, BeanClassLoaderAware
{

	/**
	 * The default encoding used for stream access: UTF-8.
	 */
	public static final String DEFAULT_ENCODING = "UTF-8";

	private final XStream xstream = new XStream();

	private HierarchicalStreamDriver streamDriver;

	private String encoding = DEFAULT_ENCODING;

	private Class[] supportedClasses;

	private ClassLoader classLoader;

	public XStreamMarshaller()
	{
		xstream.registerConverter(new DataTypeConverter());
	}

	/**
	 * Returns the XStream instance used by this marshaller.
	 */
	public XStream getXStream()
	{
		return this.xstream;
	}

	/**
	 * Set the XStream mode.
	 * 
	 * @see XStream#XPATH_REFERENCES
	 * @see XStream#ID_REFERENCES
	 * @see XStream#NO_REFERENCES
	 */
	public void setMode(int mode)
	{
		this.getXStream().setMode(mode);
	}

	/**
	 * Set the <code>Converters</code> or <code>SingleValueConverters</code> to
	 * be registered with the <code>XStream</code> instance.
	 * 
	 * @see Converter
	 * @see SingleValueConverter
	 */
	public void setConverters(ConverterMatcher[] converters)
	{
		for (int i = 0; i < converters.length; i++)
		{
			if (converters[i] instanceof Converter)
			{
				this.getXStream().registerConverter((Converter) converters[i], i);
			} else if (converters[i] instanceof SingleValueConverter)
			{
				this.getXStream().registerConverter((SingleValueConverter) converters[i], i);
			} else
			{
				throw new IllegalArgumentException("Invalid ConverterMatcher [" + converters[i] + "]");
			}
		}
	}

	/**
	 * Sets an alias/type map, consisting of string aliases mapped to classes.
	 * Keys are aliases; values are either {@code Class} instances, or String
	 * class names.
	 * 
	 * @see XStream#alias(String, Class)
	 */
	public void setAliases(Map<String, ?> aliases) throws ClassNotFoundException
	{
		Map<String, Class<?>> classMap = toClassMap(aliases);

		for (Map.Entry<String, Class<?>> entry : classMap.entrySet())
		{
			this.getXStream().alias(entry.getKey(), entry.getValue());
		}
	}

	/**
	 * Sets the aliases by type map, consisting of string aliases mapped to
	 * classes. Any class that is assignable to this type will be aliased to the
	 * same name. Keys are aliases; values are either {@code Class} instances,
	 * or String class names.
	 * 
	 * @see XStream#aliasType(String, Class)
	 */
	public void setAliasesByType(Map<String, ?> aliases) throws ClassNotFoundException
	{
		Map<String, Class<?>> classMap = toClassMap(aliases);

		for (Map.Entry<String, Class<?>> entry : classMap.entrySet())
		{
			this.getXStream().aliasType(entry.getKey(), entry.getValue());
		}
	}

	private Map<String, Class<?>> toClassMap(Map<String, ?> map) throws ClassNotFoundException
	{
		Map<String, Class<?>> result = new LinkedHashMap<String, Class<?>>(map.size());

		for (Map.Entry<String, ?> entry : map.entrySet())
		{
			String key = entry.getKey();
			Object value = entry.getValue();
			Class type;
			if (value instanceof Class)
			{
				type = (Class) value;
			} else if (value instanceof String)
			{
				String s = (String) value;
				type = ClassUtils.forName(s, classLoader);
			} else
			{
				throw new IllegalArgumentException("Unknown value [" + value + "], expected String or Class");
			}
			result.put(key, type);
		}
		return result;
	}

	/**
	 * Sets a field alias/type map, consiting of field names
	 * 
	 * @param aliases
	 * @throws ClassNotFoundException
	 * @throws NoSuchFieldException
	 * @see XStream#aliasField(String, Class, String)
	 */
	public void setFieldAliases(Map<String, String> aliases) throws ClassNotFoundException, NoSuchFieldException
	{
		for (Map.Entry<String, String> entry : aliases.entrySet())
		{
			String alias = entry.getValue();
			String field = entry.getKey();
			int idx = field.lastIndexOf('.');
			if (idx != -1)
			{
				String className = field.substring(0, idx);
				Class clazz = ClassUtils.forName(className, classLoader);
				String fieldName = field.substring(idx + 1);
				this.getXStream().aliasField(alias, clazz, fieldName);
			} else
			{
				throw new IllegalArgumentException("Field name [" + field + "] does not contain '.'");
			}
		}
	}

	/**
	 * Set types to use XML attributes for.
	 * 
	 * @see XStream#useAttributeFor(Class)
	 */
	public void setUseAttributeForTypes(Class[] types)
	{
		for (Class type : types)
		{
			this.getXStream().useAttributeFor(type);
		}
	}

	/**
	 * Set the types to use XML attributes for. The given map can contain either
	 * {@code <String, Class>} pairs, in which case
	 * {@link XStream#useAttributeFor(String, Class)} is called. Alternatively,
	 * the map can contain {@code <Class, String>} or
	 * {@code <Class, List<String>>} pairs, which results in
	 * {@link XStream#useAttributeFor(Class, String)} calls.
	 */
	public void setUseAttributeFor(Map<?, ?> attributes)
	{
		for (Map.Entry<?, ?> entry : attributes.entrySet())
		{
			if (entry.getKey() instanceof String)
			{
				if (entry.getValue() instanceof Class)
				{
					this.getXStream().useAttributeFor((String) entry.getKey(), (Class) entry.getValue());
				} else
				{
					throw new IllegalArgumentException("Invalid argument 'attributes'. 'useAttributesFor' property takes map of <String, Class>," + " when using a map key of type String");
				}
			} else if (entry.getKey() instanceof Class)
			{
				Class<?> key = (Class<?>) entry.getKey();
				if (entry.getValue() instanceof String)
				{
					this.getXStream().useAttributeFor(key, (String) entry.getValue());
				} else if (entry.getValue() instanceof List)
				{
					List list = (List) entry.getValue();

					for (Object o : list)
					{
						if (o instanceof String)
						{
							this.getXStream().useAttributeFor(key, (String) o);
						}
					}
				} else
				{
					throw new IllegalArgumentException("Invalid argument 'attributes'. " + "'useAttributesFor' property takes either <Class, String> or <Class, List<String>> map," + " when using a map key of type Class");
				}
			} else
			{
				throw new IllegalArgumentException("Invalid argument 'attributes. " + "'useAttributesFor' property takes either a map key of type String or Class");
			}
		}
	}

	/**
	 * Specify implicit collection fields, as a Map consisting of
	 * <code>Class</code> instances mapped to comma separated collection field
	 * names.
	 * 
	 * @see XStream#addImplicitCollection(Class, String)
	 */
	public void setImplicitCollections(Map<Class<?>, String> implicitCollections)
	{
		for (Map.Entry<Class<?>, String> entry : implicitCollections.entrySet())
		{
			String[] collectionFields = StringUtils.commaDelimitedListToStringArray(entry.getValue());
			for (String collectionField : collectionFields)
			{
				this.getXStream().addImplicitCollection(entry.getKey(), collectionField);
			}
		}
	}

	/**
	 * Specify omitted fields, as a Map consisting of <code>Class</code>
	 * instances mapped to comma separated field names.
	 * 
	 * @see XStream#omitField(Class, String)
	 */
	public void setOmittedFields(Map<Class<?>, String> omittedFields)
	{
		for (Map.Entry<Class<?>, String> entry : omittedFields.entrySet())
		{
			String[] fields = StringUtils.commaDelimitedListToStringArray(entry.getValue());
			for (String field : fields)
			{
				this.getXStream().omitField(entry.getKey(), field);
			}
		}
	}

	/**
	 * Set the classes for which mappings will be read from class-level JDK 1.5+
	 * annotation metadata.
	 * 
	 * @see XStream#processAnnotations(Class)
	 */
	public void setAnnotatedClass(Class<?> annotatedClass)
	{
		Assert.notNull(annotatedClass, "'annotatedClass' must not be null");
		this.getXStream().processAnnotations(annotatedClass);
	}

	/**
	 * Set annotated classes for which aliases will be read from class-level JDK
	 * 1.5+ annotation metadata.
	 * 
	 * @see XStream#processAnnotations(Class[])
	 */
	public void setAnnotatedClasses(Class<?>[] annotatedClasses)
	{
		Assert.notEmpty(annotatedClasses, "'annotatedClasses' must not be empty");
		this.getXStream().processAnnotations(annotatedClasses);
	}

	/**
	 * Set the autodetection mode of XStream.
	 * <p>
	 * <strong>Note</strong> that auto-detection implies that the XStream is
	 * configured while it is processing the XML streams, and thus introduces a
	 * potential concurrency problem.
	 * 
	 * @see XStream#autodetectAnnotations(boolean)
	 */
	public void setAutodetectAnnotations(boolean autodetectAnnotations)
	{
		this.getXStream().autodetectAnnotations(autodetectAnnotations);
	}

	/**
	 * Set the XStream hierarchical stream driver to be used with stream readers
	 * and writers.
	 */
	public void setStreamDriver(HierarchicalStreamDriver streamDriver)
	{
		this.streamDriver = streamDriver;
	}

	/**
	 * Set the encoding to be used for stream access.
	 * 
	 * @see #DEFAULT_ENCODING
	 */
	public void setEncoding(String encoding)
	{
		this.encoding = encoding;
	}

	/**
	 * Set the classes supported by this marshaller.
	 * <p>
	 * If this property is empty (the default), all classes are supported.
	 * 
	 * @see #supports(Class)
	 */
	public void setSupportedClasses(Class[] supportedClasses)
	{
		this.supportedClasses = supportedClasses;
	}

	public void setBeanClassLoader(ClassLoader classLoader)
	{
		this.classLoader = classLoader;
	}

	public final void afterPropertiesSet() throws Exception
	{
		customizeXStream(getXStream());
	}

	/**
	 * Template to allow for customizing of the given {@link XStream}.
	 * <p>
	 * The default implementation is empty.
	 * 
	 * @param xstream
	 *            the {@code XStream} instance
	 */
	protected void customizeXStream(XStream xstream)
	{
	}

	public boolean supports(Class clazz)
	{
		if (ObjectUtils.isEmpty(this.supportedClasses))
		{
			return true;
		} else
		{
			for (Class supportedClass : this.supportedClasses)
			{
				if (supportedClass.isAssignableFrom(clazz))
				{
					return true;
				}
			}
			return false;
		}
	}

	// Marshalling

	@Override
	protected void marshalDomNode(Object graph, Node node) throws XmlMappingException
	{
		HierarchicalStreamWriter streamWriter;
		if (node instanceof Document)
		{
			streamWriter = new DomWriter((Document) node);
		} else if (node instanceof Element)
		{
			streamWriter = new DomWriter((Element) node, node.getOwnerDocument(), new XmlFriendlyReplacer());
		} else
		{
			throw new IllegalArgumentException("DOMResult contains neither Document nor Element");
		}
		marshal(graph, streamWriter);
	}

	@Override
	protected void marshalXmlEventWriter(Object graph, XMLEventWriter eventWriter) throws XmlMappingException
	{
		ContentHandler contentHandler = StaxUtils.createContentHandler(eventWriter);
		marshalSaxHandlers(graph, contentHandler, null);
	}

	@Override
	protected void marshalXmlStreamWriter(Object graph, XMLStreamWriter streamWriter) throws XmlMappingException
	{
		try
		{
			marshal(graph, new StaxWriter(new QNameMap(), streamWriter));
		} catch (XMLStreamException ex)
		{
			throw convertXStreamException(ex, true);
		}
	}

	@Override
	protected void marshalOutputStream(Object graph, OutputStream outputStream) throws XmlMappingException, IOException
	{
		marshalWriter(graph, new OutputStreamWriter(outputStream, this.encoding));
	}

	@Override
	protected void marshalSaxHandlers(Object graph, ContentHandler contentHandler, LexicalHandler lexicalHandler) throws XmlMappingException
	{

		SaxWriter saxWriter = new SaxWriter();
		saxWriter.setContentHandler(contentHandler);
		marshal(graph, saxWriter);
	}

	@Override
	protected void marshalWriter(Object graph, Writer writer) throws XmlMappingException, IOException
	{
		if (this.streamDriver != null)
		{
			marshal(graph, this.streamDriver.createWriter(writer));
		} else
		{
			marshal(graph, new CompactWriter(writer));
		}
	}

	/**
	 * Marshals the given graph to the given XStream HierarchicalStreamWriter.
	 * Converts exceptions using {@link #convertXStreamException}.
	 */
	private void marshal(Object graph, HierarchicalStreamWriter streamWriter)
	{
		try
		{
			// 转换别名,用类名作为别名
			if (graph instanceof List)
			{
				getXStream().marshal(graph, streamWriter);
			} else if (graph instanceof Map)
			{
				getXStream().marshal(graph, streamWriter);
			} else
			{
				xstream.alias(graph.getClass().getSimpleName(), graph.getClass());
				getXStream().marshal(graph, streamWriter);
			}
		} catch (Exception ex)
		{
			throw convertXStreamException(ex, true);
		} finally
		{
			try
			{
				streamWriter.flush();
			} catch (Exception ex)
			{
				logger.debug("Could not flush HierarchicalStreamWriter", ex);
			}
		}
	}

	// Unmarshalling

	@Override
	protected Object unmarshalDomNode(Node node) throws XmlMappingException
	{
		HierarchicalStreamReader streamReader;
		if (node instanceof Document)
		{
			streamReader = new DomReader((Document) node);
		} else if (node instanceof Element)
		{
			streamReader = new DomReader((Element) node);
		} else
		{
			throw new IllegalArgumentException("DOMSource contains neither Document nor Element");
		}
		return unmarshal(streamReader);
	}

	@Override
	protected Object unmarshalXmlEventReader(XMLEventReader eventReader) throws XmlMappingException
	{
		try
		{
			XMLStreamReader streamReader = StaxUtils.createEventStreamReader(eventReader);
			return unmarshalXmlStreamReader(streamReader);
		} catch (XMLStreamException ex)
		{
			throw convertXStreamException(ex, false);
		}
	}

	@Override
	protected Object unmarshalXmlStreamReader(XMLStreamReader streamReader) throws XmlMappingException
	{
		return unmarshal(new StaxReader(new QNameMap(), streamReader));
	}

	@Override
	protected Object unmarshalInputStream(InputStream inputStream) throws XmlMappingException, IOException
	{
		return unmarshalReader(new InputStreamReader(inputStream, this.encoding));
	}

	@Override
	protected Object unmarshalReader(Reader reader) throws XmlMappingException, IOException
	{
		if (streamDriver != null)
		{
			return unmarshal(streamDriver.createReader(reader));
		} else
		{
			return unmarshal(new XppReader(reader));
		}
	}

	@Override
	protected Object unmarshalSaxReader(XMLReader xmlReader, InputSource inputSource) throws XmlMappingException, IOException
	{

		throw new UnsupportedOperationException("XStreamMarshaller does not support unmarshalling using SAX XMLReaders");
	}

	private Object unmarshal(HierarchicalStreamReader streamReader)
	{
		try
		{
			return this.getXStream().unmarshal(streamReader);
		} catch (Exception ex)
		{
			throw convertXStreamException(ex, false);
		}
	}

	/**
	 * Convert the given XStream exception to an appropriate exception from the
	 * <code>org.springframework.oxm</code> hierarchy.
	 * <p>
	 * A boolean flag is used to indicate whether this exception occurs during
	 * marshalling or unmarshalling, since XStream itself does not make this
	 * distinction in its exception hierarchy.
	 * 
	 * @param ex
	 *            XStream exception that occured
	 * @param marshalling
	 *            indicates whether the exception occurs during marshalling (
	 *            <code>true</code>), or unmarshalling (<code>false</code>)
	 * @return the corresponding <code>XmlMappingException</code>
	 */
	protected XmlMappingException convertXStreamException(Exception ex, boolean marshalling)
	{
		if (ex instanceof StreamException || ex instanceof CannotResolveClassException || ex instanceof ConversionException)
		{
			if (marshalling)
			{
				return new MarshallingFailureException("XStream marshalling exception", ex);
			} else
			{
				return new UnmarshallingFailureException("XStream unmarshalling exception", ex);
			}
		} else
		{
			// fallback
			return new UncategorizedMappingException("Unknown XStream exception", ex);
		}
	}
}

class DataTypeConverter implements Converter
{

	public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context)
	{
		if (null == source)
		{
			return;
		}

		Class<?> cType = source.getClass();
		// 判断是否是List
		// 判断是否是Map
		// 判断是否是对象
		if (source instanceof List)
		{
			// 这里不需要自己指定list,因为在此构造函数中,已经设置了别名。
			// writer.startNode("list");
			for (Object o : (List<?>) source)
			{
				boolean isBaseType = isBaseType(o.getClass());
				if (isBaseType)
				{
					writeData(o, o.getClass(), writer);
				} else
				{
					writer.startNode("data");
					// 递归组装xml.
					marshal(o, writer, context);
					writer.endNode();
				}
			}
			// writer.endNode();
		} else if (source instanceof Map)
		{
			// writer.startNode("map");
			for (Map.Entry<?, ?> entry : ((Map<?, ?>) source).entrySet())
			{
				writer.startNode(entry.getKey().toString());
				Object o = entry.getValue();
				boolean isBaseType = isBaseType(o.getClass());
				if (isBaseType)
				{
					writeData(o, o.getClass(), writer);
				} else
				{
					marshal(o, writer, context);
				}
				// writer.startNode("list");
				// marshal(o, writer, context);
				// writer.endNode();
				writer.endNode();
			} // 递归组装xml.
				// writer.endNode();
		} else
		{
			try
			{
				Field[] fields = cType.getDeclaredFields();
				for (Field field : fields)
				{
					// 获得get方法
					String temp1 = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
					Method m = null;
					try
					{
						m = cType.getMethod(temp1, null);
					} catch (Exception e)
					{
						continue;
					}

					String methodName = m.getName();
					if (methodName.startsWith("get") && methodName != "getClass")
					{
						boolean isBaseType = isBaseType(m.getReturnType());
						Object objGetValue = m.invoke(source, null);
						if (isBaseType)
						{
							writer.startNode(field.getName());
							writeData(objGetValue, m.getReturnType(), writer);
							writer.endNode();
						} else if (m.getReturnType().equals(List.class))
						{
							writer.startNode(field.getName());
							if (objGetValue != null)
							{
								for (Object o : (List<?>) objGetValue)
								{
									isBaseType = isBaseType(o.getClass());
									if (isBaseType)
									{
										writeData(o, o.getClass(), writer);
									} else
									{
										writer.startNode("data");
										// 递归组装xml.
										marshal(o, writer, context);
										writer.endNode();
									}
								} // 递归组装xml.
							}
							writer.endNode();
						} else if (m.getReturnType().equals(Map.class))
						{
							writer.startNode(field.getName());
							if (objGetValue != null)
							{
								for (Map.Entry<?, ?> entry : ((Map<?, ?>) objGetValue).entrySet())
								{
									Object o = entry.getValue();
									if (o == null)
									{
										continue;
									}
									isBaseType = isBaseType(o.getClass());
									if (isBaseType)
									{
										writer.startNode(entry.getKey().toString());
										writeData(o, o.getClass(), writer);
										writer.endNode();
									} else
									{
										writer.startNode(entry.getKey().toString());
										marshal(o, writer, context);
										writer.endNode();
									}
								} // 递归组装xml.
							}
							writer.endNode();
						}
					}// end if
				}// end for
			} catch (Exception e)
			{
				e.printStackTrace();
			}// end catch
		}// end if
	}

	/**
	 * 改写输出XML
	 * 
	 * @param o
	 * @param ReturnType
	 * @param writer
	 */
	private void writeData(Object o, Class<?> ReturnType, HierarchicalStreamWriter writer)
	{
		// 如果是数字类型的话就要预设为0而不能为空
		// 如果是日期,则做转换yyyy-MM-dd HH:mm:ss.
		if (isNumValueType(ReturnType))
		{
			if (o == null)
			{
				writer.setValue("0");
			} else if (ReturnType.equals(Double.class) || ReturnType.equals(double.class) || ReturnType.equals(BigDecimal.class))
			{
				DecimalFormat df = new DecimalFormat("#.##");
				writer.setValue(df.format(o));
			} else
			{
				writer.setValue(o.toString());
			}
		} else if (ReturnType.equals(Date.class))
		{
			if (o == null)
			{
				writer.setValue("");
			} else
			{
				String result = "";
				try
				{
					result = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(o);
				} catch (Exception e)
				{
				} finally
				{
					writer.setValue(result);
				}
			}// end if (o == null)
		} else
		{
			writer.setValue(o == null ? "" : o.toString());
		}
	}

	public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context)
	{
		return null;
	}

	public boolean canConvert(Class type)
	{
		return true;
	}

	/**
	 * 判断是否为支持的数据类型
	 * 
	 * @param type
	 * @return boolean
	 */
	private boolean isBaseType(Class<?> type)
	{
		if (type.equals(Integer.class) || type.equals(Double.class) || type.equals(String.class) || type.equals(Boolean.class) || type.equals(Long.class) || type.equals(Short.class) || type.equals(Byte.class) || type.equals(Float.class) || type.equals(BigDecimal.class) || type.equals(int.class) || type.equals(float.class) || type.equals(long.class) || type.equals(double.class) || type.equals(short.class) || type.equals(boolean.class) || type.equals(byte.class) || type.equals(Date.class))
		{
			return true;
		}
		return false;
	}

	/**
	 * 判断是否为数字类型
	 * 
	 * @param type
	 * @return boolean
	 */
	public boolean isNumValueType(Class<?> type)
	{
		if (type.equals(Integer.class) || type.equals(Double.class) || type.equals(Long.class) || type.equals(Short.class) || type.equals(Float.class) || type.equals(BigDecimal.class) || type.equals(int.class) || type.equals(float.class) || type.equals(long.class) || type.equals(double.class) || type.equals(short.class))
		{
			return true;
		}
		return false;
	}

}

其中 DataTypeConverter 比较重要,在XStreamMarshaller 类的构造函数中, xStream中注册了DataTypeConverter。

如果单独使用XStream,直接将DataTypeConverter类拿出即可,并注册.

代码语言:javascript
复制
xstream.registerConverter(new DataTypeConverter());

如果是在SprinMVC配置文件中,配置配置即可.

代码语言:javascript
复制
<!-- 根据客户端的不同的请求决定不同的view进行响应, 如 /blog/1.json /blog/1.xml -->
	<bean
		class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"
		p:order="1">
		<!-- 设置为true以忽略对Accept Header的支持 -->
		<property name="ignoreAcceptHeader" value="true" />
		<!-- 扩展名至mimeType的映射,即 /user.json => application/json -->
		<property name="favorPathExtension" value="true" />
		<!-- 在没有扩展名时即: "/user/1" 时的默认展现形式 -->
		<property name="defaultContentType" value="text/html" />
		<!-- 用于开启 /userinfo/123?format=json 的支持 -->
		<property name="favorParameter" value="false" />

		<!-- 扩展名至mimeType的映射,即 /user.json => application/json,需开启favorPathExtension为true的支持 -->
		<property name="mediaTypes">
			<map>
				<entry key="xml" value="application/xml" />
			</map>
		</property>
		<property name="defaultViews">
			<list>
				<!-- for application/xml -->
				<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
					<property name="marshaller">
						<bean class="com.linapex.web.expand.XStreamMarshaller" />
					</property>
				</bean>
			</list>
		</property>
	</bean>

(adsbygoogle = window.adsbygoogle || []).push({});

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2013/09/05 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档