SpringMVC XStream 返回Xml时完美支持List,Map输出
2013-09-05 16:23
645 查看
此篇日志参考了
http://www.cnblogs.com/lucious/archive/2013/05/28/3104348.html
并在此源码上进行改动。
现支持,多种容器组合,无限循环嵌套,基本数据类型为null,则设置默认值,日期格式化。
改动源代码后,对于List的支持.每一个对象都是由data标签包裹。
后台代码:
注意,在使用过程中,List不支持,基本类型的Xml转换,只支持对象Xml转换。
此方法是错误的。正确的方法【要使用对象包装属性,并提供get set 方法】,得到的结果如下图:
改动源代码后,对于Map的完美支持。
改动源代码后,对于Java Ben的支持.Java Ben 中可放List,Map等容器,递归支持无限循环Xml节点组装。
User类源码:
XStreamMarshaller类源码:
其中 DataTypeConverter 比较重要,在XStreamMarshaller 类的构造函数中, xStream中注册了DataTypeConverter。
如果单独使用XStream,直接将DataTypeConverter类拿出即可,并注册.
如果是在SprinMVC配置文件中,配置配置即可.
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>
相关文章推荐
- LogUtils:一个强大的Android日志管理器,支持对象、List、Map、数组等输出
- springMVC框架下返回json格式的对象,list,map
- springMVC框架下返回json格式的对象,list,map
- xStream完美转换XML、JSON xStream框架 xStream可以轻易的将Java对象和xml文档相互转换,而且可以修改某个特定的属性和节点名称,而且也支持json的转换; 前面有介
- springMVC框架下返回json格式的对象,list,map
- [Java]一则自定义的XStream转换器,主要用于POJO XML反序列化为Map/List
- xStream框架完美实现Java对象和xml文档JSON、XML相互转换
- 在hibernate中查询使用List,Map和类对象定制返回类型
- xStream完美转换XML、JSON
- springMVC 返回类型选择 以及 SpringMVC中model,modelMap.request,session取值顺序 .
- xStream完美转换XML、JSON
- XStream 数组(List)输出结构
- xStream完美转换XML、JSON
- xStream之xml json javabean map的转换
- xStream完美转换XML、JSON
- springMVC 【@response 返回对象自动变成json并且防止乱码】 & 【配置支持实体类中的@DateTimeFormat注解】
- xStream完美转换XML、JSON
- xStream完美转换XML、JSON
- springmvc接收前台(可以是ajax)传来的数组list,map,set等集合,复杂对象集合等图文详解
- mybatis返回List<Map<String,Object>>