Spring OXM-XStream转换器

简介: Spring OXM-XStream转换器

概述


我们在开发的过程中,有的时候需要转换一些自定义类型,此时默认的映射方式可能无法满足需要。


XStream为我们提供了丰富的扩展,用户可以实现自己的转换器,然后调用registerConverter方法注册自定义的转换器。


实现自定义的转换器很简单,只需要实现XStream提供的Converter接口并实现其方法即可。


示例

我们在上个案例中的代码

package com.xgj.oxm.xstream.quickDemo.convert;
import java.text.ParseException;
import java.util.Date;
import java.util.Locale;
import com.thoughtworks.xstream.XStream;
import com.xgj.oxm.xstream.quickDemo.domain.LoginLog;
import com.xgj.oxm.xstream.quickDemo.domain.User;
public class XStreamConverterDemo {
    private static XStream xstream;
    static {
        // 创建一个Xstream实例,使用默认的XPP解析器
        xstream = new XStream();
        // (1)设置类别名,修改默认的全限定名的名称
        xstream.alias("user", User.class);
        xstream.alias("loginLog", LoginLog.class);
        // (2)设置类成员别名 <id>1</id> 改为<userId>1</userId>
        xstream.aliasField("userId", User.class, "id");
        // (3)把LoginLog的userId属性视为xml属性,默认为xml的元素
        xstream.aliasAttribute(LoginLog.class, "userId", "id");
        xstream.useAttributeFor(LoginLog.class, "userId");
        // (4)去掉集合类型生成XML的父节点,即忽略xml中的<logs></logs>标记
        xstream.addImplicitCollection(User.class, "logs");
    }
    /**
     * 
     * 
     * @Title: getUser
     * 
     * @Description: 初始化转换对象
     * 
     * @return
     * 
     * @return: User
     * @throws ParseException
     */
    public static User getUser() throws ParseException {
        LoginLog log = new LoginLog();
        log.setIp("127.0.0.1");
        log.setLoginLogId(99);
        log.setUserId(1);
        log.setLoginDate(new Date());
        LoginLog log2 = new LoginLog();
        log2.setIp("192.168.1.1");
        log2.setLoginLogId(22);
        log2.setUserId(2);
        log2.setLoginDate(new Date());
        User user = new User();
        user.setId(1);
        user.setUserName("Artisan");
        user.setPassword("artisan");
        user.setCredits(1000);
        user.setLastVisit(new Date());
        user.addLoginLog(log);
        user.addLoginLog(log2);
        return user;
    }
    /**
     * 
     * 
     * @Title: objectToXml
     * 
     * @Description: Java对象转换成XML
     * 
     * @throws Exception
     * 
     * @return: void
     */
    public static void objectToXml() throws Exception {
        // 获取转换的User对象实例
        User user = getUser();
        // 输出内容到控制台,查看一下
        System.out.println(xstream.toXML(user));
    }
    public static void main(String[] args) throws Exception {
        objectToXml();
    }
}


输出如下

<user>
  <userId>1</userId>
  <userName>Artisan</userName>
  <password>artisan</password>
  <credits>1000</credits>
  <lastVisit>2017-12-06 12:32:06.504 UTC</lastVisit>
  <loginLog id="1">
    <loginLogId>99</loginLogId>
    <ip>127.0.0.1</ip>
    <loginDate>2017-12-06 12:32:06.504 UTC</loginDate>
  </loginLog>
  <loginLog id="2">
    <loginLogId>22</loginLogId>
    <ip>192.168.1.1</ip>
    <loginDate>2017-12-06 12:32:06.504 UTC</loginDate>
  </loginLog>
</user>


可以看到时间格式如下:

2017-12-06 12:32:06.504 UTC



UTC与格林尼治平均时(GMT, Greenwich Mean Time)一样,都与英国伦敦的本地时相同,UTC + 时区差=本地时间

如果我们希望显示北京时间呢?

就需要用到转换器了

package com.xgj.oxm.xstream.quickDemo.convert;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import com.thoughtworks.xstream.converters.ConversionException;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
public class DateConverter implements Converter {
    private Locale locale;
    public DateConverter(Locale locale) {
        super();
        this.locale = locale;
    }
    /**
     * 重写该方法,判断需要转换的类型
     */
    @Override
    public boolean canConvert(Class type) {
        return Date.class.isAssignableFrom(type);
    }
    /**
     * 重写该方法,编写Java 到 XML 的转换逻辑
     */
    @Override
    public void marshal(Object source, HierarchicalStreamWriter writer,
            MarshallingContext context) {
        // DateFormat format = DateFormat.getDateInstance(DateFormat.DATE_FIELD,
        // this.locale);
        SimpleDateFormat format = new SimpleDateFormat(
                "yyyy-MM-dd HH:mm:ss", this.locale);
        writer.setValue(format.format(source));
    }
    /**
     * 重写该方法,编写XML 到 Java 的转换逻辑
     */
    @Override
    public Object unmarshal(HierarchicalStreamReader reader,
            UnmarshallingContext context) {
        GregorianCalendar calendar = new GregorianCalendar();
        // DateFormat format = DateFormat.getDateInstance(DateFormat.DATE_FIELD,
        // this.locale);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss",
                this.locale);
        try {
            calendar.setTime(format.parse(reader.getValue()));
        } catch (Exception e) {
            throw new ConversionException(e.getMessage(), e);
        }
        return calendar.getGregorianChange();
    }
}


解析

  • 通过 canConvert 方法来判断转换逻辑
  • 通过marshal方法,完成对象编组(对象转XML)操作的处理逻辑
  • 通过unmarshal方法,完成对象f反编组(XML转对象)操作的处理逻辑
  • 最后调用registerConverter方法注册自定义的转换器

修改生成xml的代码注册转换器,完整代码如下

package com.xgj.oxm.xstream.quickDemo.convert;
import java.text.ParseException;
import java.util.Date;
import java.util.Locale;
import com.thoughtworks.xstream.XStream;
import com.xgj.oxm.xstream.quickDemo.domain.LoginLog;
import com.xgj.oxm.xstream.quickDemo.domain.User;
public class XStreamConverterDemo {
    private static XStream xstream;
    static {
        // 创建一个Xstream实例,使用默认的XPP解析器
        xstream = new XStream();
        // (1)设置类别名,修改默认的全限定名的名称
        xstream.alias("user", User.class);
        xstream.alias("loginLog", LoginLog.class);
        // (2)设置类成员别名 <id>1</id> 改为<userId>1</userId>
        xstream.aliasField("userId", User.class, "id");
        // (3)把LoginLog的userId属性视为xml属性,默认为xml的元素
        xstream.aliasAttribute(LoginLog.class, "userId", "id");
        xstream.useAttributeFor(LoginLog.class, "userId");
        // (4)去掉集合类型生成XML的父节点,即忽略xml中的<logs></logs>标记
        xstream.addImplicitCollection(User.class, "logs");
        // 注册转换器
        xstream.registerConverter(new DateConverter(Locale.CHINESE));
    }
    /**
     * 
     * 
     * @Title: getUser
     * 
     * @Description: 初始化转换对象
     * 
     * @return
     * 
     * @return: User
     * @throws ParseException
     */
    public static User getUser() throws ParseException {
        LoginLog log = new LoginLog();
        log.setIp("127.0.0.1");
        log.setLoginLogId(99);
        log.setUserId(1);
        log.setLoginDate(new Date());
        LoginLog log2 = new LoginLog();
        log2.setIp("192.168.1.1");
        log2.setLoginLogId(22);
        log2.setUserId(2);
        log2.setLoginDate(new Date());
        User user = new User();
        user.setId(1);
        user.setUserName("Artisan");
        user.setPassword("artisan");
        user.setCredits(1000);
        user.setLastVisit(new Date());
        user.addLoginLog(log);
        user.addLoginLog(log2);
        return user;
    }
    /**
     * 
     * 
     * @Title: objectToXml
     * 
     * @Description: Java对象转换成XML
     * 
     * @throws Exception
     * 
     * @return: void
     */
    public static void objectToXml() throws Exception {
        // 获取转换的User对象实例
        User user = getUser();
        // 输出内容到控制台,查看一下
        System.out.println(xstream.toXML(user));
    }
    public static void main(String[] args) throws Exception {
        objectToXml();
    }
}

输出

<user>
  <userId>1</userId>
  <userName>Artisan</userName>
  <password>artisan</password>
  <credits>1000</credits>
  <lastVisit>2017-12-06 20:34:42</lastVisit>
  <loginLog id="1">
    <loginLogId>99</loginLogId>
    <ip>127.0.0.1</ip>
    <loginDate>2017-12-06 20:34:42</loginDate>
  </loginLog>
  <loginLog id="2">
    <loginLogId>22</loginLogId>
    <ip>192.168.1.1</ip>
    <loginDate>2017-12-06 20:34:42</loginDate>
  </loginLog>
</user>


可以看到时间已经是 2017-12-06 20:34:42 北京时间了。 转换器起作用了。


示例源码


代码已托管到Github—> https://github.com/yangshangwei/SpringMaster


相关文章
|
缓存 Java Spring
详解Spring自定义消息格式转换器及底层源码分析
详解Spring自定义消息格式转换器及底层源码分析
|
XML JSON Java
Spring Boot添加消息转换器HttpMessageConverter
spring boot添加消息转换器HttpMessageConverter
2708 0
Spring Boot添加消息转换器HttpMessageConverter
|
前端开发 Java Spring
《Spring MVC》 第六章 MVC类型转换器、格式化器
《Spring MVC》 第六章 MVC类型转换器、格式化器
190 0
|
XML JavaScript Java
Spring OXM-XStream流化对象
Spring OXM-XStream流化对象
92 0
|
XML 缓存 Java
Spring OXM-XStream注解
Spring OXM-XStream注解
112 0
|
XML 存储 Java
Spring OXM-XStream使用别名
Spring OXM-XStream使用别名
97 0
|
XML 存储 JavaScript
Spring OXM-XStream快速入门
Spring OXM-XStream快速入门
103 0
|
SQL JSON 前端开发
基于Springboot外卖系统08:员工账号状态管理功能+对象转换器+扩展Spring mvc的消息转换器
在员工管理列表页面,可以对某个员工账号进行启用或者禁用操作。账号禁用的员工不能登录系统,启用后的员工可以正常登录。如果某个员工账号状态为正常,则按钮显示为 "禁用",如果员工账号状态为已禁用,则按钮显示为"启用"。
173 0
|
数据采集 XML 前端开发
Spring MVC(spring-webmvc)之全局数据处理、拦截器、自定义类型转换器等使用指南
Spring MVC(spring-webmvc)之全局数据处理、拦截器、自定义类型转换器等使用指南
234 0
Spring MVC(spring-webmvc)之全局数据处理、拦截器、自定义类型转换器等使用指南
|
JSON 前端开发 Java
Spring MVC自定义消息转换器(可解决Long类型数据传入前端精度丢失的问题)
对于Long 类型的数据,如果我们在Controller层通过@ResponseBody将返回数据自动转换成json时,不做任何处理,而直接传给前端的话,在Long长度大于17位时会出现精度丢失的问题。
340 0