文档章节

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

linapex
 linapex
发布于 2013/09/05 16:23
字数 2974
阅读 1435
收藏 1
此篇日志参考了
http://www.cnblogs.com/lucious/archive/2013/05/28/3104348.html

并在此源码上进行改动。


现支持,多种容器组合,无限循环嵌套,基本数据类型为null,则设置默认值,日期格式化。
改动源代码后,对于List的支持.每一个对象都是由data标签包裹。




后台代码:
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 方法,得到的结果如下图:

List<String> list = new ArrayList<String>();
		 list.add("l1");
		 list.add("l2");
		 list.add("l3");
		 model.addAttribute("list", list);





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


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节点组装。

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类源码:

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类源码:
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类拿出即可,并注册.

xstream.registerConverter(new DataTypeConverter());

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

<!-- 根据客户端的不同的请求决定不同的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>




© 著作权归作者所有

共有 人打赏支持
linapex
粉丝 42
博文 13
码字总数 17697
作品 0
深圳
程序员
SpringMVC整合JSON、XML视图

原创不易,转载请注明出处:SpringMVC整合JSON、XML视图 代码下载地址:http://www.zuidaima.com/share/1751862737554432.htm SpringMVC中整合了JSON、XML的视图,可以通过这些视图完成Java对...

最代码
2014/04/16
0
0
xStream完美转换XML、JSON

xStream框架 xStream可以轻易的将Java对象和xml文档相互转换,而且可以修改某个特定的属性和节点名称,而且也支持json的转换; 前面有介绍过json-lib这个框架,在线博文:http://www.cnblog...

DavidBao
2015/05/01
0
1
使用java开发SDK你可能会用的4个库

使用java开发SDK你可能会用的4个库 xstream okhttp fastjson spring boot xstream https://github.com/x-stream/xstream/ 用法特别简单 定义javabean 然后写个简单的测试 返回结果 xstream ...

i5ting
2015/08/12
0
2
JavaBean到XML和JSON的转换

XML和JSON是当今常用的两种数据描述与传输的格式,特别是涉及到JS时使用JSON颇为频繁。自然,在Java的世界里少不了完成JavaBean与这两种格式相互转换的组件,那就是XStream和JSON-lib。这里我...

Idiot_s_Sky
2014/01/14
0
0
Spring3 MVC Restful 多请求类型(json,xml,k-v),多视图配置(J...

beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="ht......

李长春
2011/09/15
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

此生1.3

颜值是开胃菜,不要太在意,正餐才是重点。

colinux
今天
1
0
[雪峰磁针石博客]软件测试专家工具包1web测试

web测试 本章主要涉及功能测试、自动化测试(参考: 软件自动化测试初学者忠告) 、接口测试(参考:10分钟学会API测试)、跨浏览器测试、可访问性测试和可用性测试的测试工具列表。 安全测试工具...

python测试开发人工智能安全
今天
3
0
JS:异步 - 面试惨案

为什么会写这篇文章,很明显不符合我的性格的东西,原因是前段时间参与了一个面试,对于很多程序员来说,面试时候多么的鸦雀无声,事后心里就有多么的千军万马。去掉最开始毕业干了一年的Jav...

xmqywx
今天
3
0
Win10 64位系统,PHP 扩展 curl插件

执行:1. 拷贝php安装目录下,libeay32.dll、ssleay32.dll 、 libssh2.dll 到 C:\windows\system32 目录。2. 拷贝php/ext目录下, php_curl.dll 到 C:\windows\system32 目录; 3. p...

放飞E梦想O
今天
1
0
谈谈神秘的ES6——(五)解构赋值【对象篇】

上一节课我们了解了有关数组的解构赋值相关内容,这节课,我们接着,来讲讲对象的解构赋值。 解构不仅可以用于数组,还可以用于对象。 let { foo, bar } = { foo: "aaa", bar: "bbb" };fo...

JandenMa
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部