文档章节

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

linapex
 linapex
发布于 2013/09/05 16:23
字数 2974
阅读 1428
收藏 1
点赞 0
评论 0
此篇日志参考了
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
深圳
程序员
JavaWeb15-HTML篇笔记(三)

1.1 案例三:使用JQuery完成仿百度的信息提示:1.1.1 需求: 在一个搜索页面中,键盘输入一些信息,在文本框下面给出一些提示信息(需要从服务器端进行查询的). 1.1.2 分析:1.1.2.1 步骤分析: ...

我是小谷粒 ⋅ 06/01 ⋅ 0

程序员你为什么这么累? - 配置规范

导读:程序员你为什么这么累? 接口定义规范 controller规范 日志规范 异常处理规范 国际化和参数校验规范 工具类规范 函数编写建议 配置建议 配置规范 工作中少不了要制定各种各样的配置文件...

晓风轻 ⋅ 05/16 ⋅ 0

Spring Framework体系结构简介

说明:以下转自Spring官方文档,用的版本为4.3.11版本。 一、引用官方文档 所述核心容器由以下部分组成, ,,,和(弹簧表达式语言)模块。 的和模块提供框架的基本零件,包括IOC和依赖注入...

easonjim ⋅ 2017/09/16 ⋅ 0

共享定制云平台 - AWCP

AWCP 是一个共享定制云平台,集成了 jflow 工作流引擎,并完成了基于钉钉的开发框架自动生成,可快速搭建基于钉钉管理系统。完成了钉钉端页面配置管理,审核审批,完成了钉钉 PC 端页面配置管...

曹勇 ⋅ 2017/10/23 ⋅ 9

xStream完美转换XML、JSON

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

ibm_hoojo ⋅ 2011/04/22 ⋅ 0

xStream完美转换XML、JSON

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

DavidBao ⋅ 2015/05/01 ⋅ 1

SpringMVC整合JSON、XML视图

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

最代码 ⋅ 2014/04/16 ⋅ 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

SpringMVC 中整合JSON、XML视图一

SpringMVC中整合了JSON、XML的视图,可以通过这些视图完成Java对象到XML、JSON的转换。转换XML提供了MarshallingView,开发者只需用注入相应的marshaller、和属性配置,即可自动完成Java的M...

ibm_hoojo ⋅ 2011/04/29 ⋅ 0

注解 springMVC

web.xml中配置servlet <?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLo......

silenceyawen ⋅ 2016/05/07 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

数据结构与算法之双向链表

一、双向链表 1.双向链表的结点结构 typedef struct DualNode{ ElemType data; struct DualNode *prior; // 前驱结点 struct DualNode *next; // 后继结点}DualNode, *DuL...

aibinxiao ⋅ 23分钟前 ⋅ 0

五大最核心的大数据技术

大数据技术有5个核心部分,数据采集、数据存储、数据清洗、数据挖掘、数据可视化。关于这5个部分,有哪些核心技术?这些技术有哪些潜在价值?看完今天的文章就知道了。 大数据学习群:7165810...

董黎明 ⋅ 24分钟前 ⋅ 0

PhpStorm 头部注释、类注释和函数注释的设置

首先,PhpStorm中文件、类、函数等注释的设置在:setting-》Editor-》FIle and Code Template-》Includes下设置即可,其中方法的默认是这样的: /**${PARAM_DOC}#if (${TYPE_HINT} != "v...

nsns ⋅ 24分钟前 ⋅ 0

spring.net AOP

http://www.springframework.net/doc-latest/reference/html/aop-quickstart.html https://www.cnblogs.com/wujy/archive/2013/04/06/3003120.html...

whoisliang ⋅ 29分钟前 ⋅ 0

【HAVENT原创】创建 Dockerfile 生成新的镜像,并发布到 DockerHub

注意:Win7 与 Win10 的版本存在差异,Win7 版本使用 Docker Quickstart Terminal 进入控制台,Win10下面直接用管理员权限打开控制台或者 PowerShell 即可;另外 Win7 下面只能访问 C盘,/ap...

HAVENT ⋅ 29分钟前 ⋅ 0

pom.xml出现web.xml is missing ...解决方案

提示信息应该能看懂。也就是缺少了web.xml文件,<failOnMissingWebXml>被设置成true了。 搜索了一下,Stack Overflow上的答案解决了问题,分享一下。 目前被顶次数最多的回答原文如下: This...

源哥L ⋅ 30分钟前 ⋅ 0

js时间戳与日期格式之间相互转换

1. 将时间戳转换成日期格式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 // 简单的一句代码 var date = new Date(时间戳); //获取一个时间对象 /** 1. 下面是获取时间日期的方法,需要什么样的格式自己...

Jack088 ⋅ 35分钟前 ⋅ 0

web添加log4j

添加xml配置log4j.properties # Global logging configuration---root日志设置#log4j.rootLogger=info,dailyRollingFile,stdoutlog4j.rootLogger=debug,stdout,dailyRollingFile---......

黄柳淞 ⋅ 36分钟前 ⋅ 0

如何解决生产环境宕机问题

写在前面:该篇宕机问题的排查难度远比上一篇(记一次解决线上OOM的心路历程)大的太多,上一篇中内存泄漏的问题是有迹可循的,本次的宕机在业务日志上没有任何征兆,另外本文有许多值得深挖...

寰宇01 ⋅ 48分钟前 ⋅ 0

Redis查漏补缺:最易错过的技术要点大扫盲

作者介绍 孤独烟,中国平安研发工程师,目前负责规则云平台架构设计以及需求研发工作。毕业后一直从事Java开发工作,在Web开发、架构设计上有多年的实战经验。在MySQL性能优化、JVM调优、分布...

kim_o ⋅ 49分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部