读者们看到这个标题也许会感到奇怪,SpringMVC中默认的HttpMessageConverter不是Jackson吗,但是我在使用的过程中发现Jackson并不好用,如果有一些复杂的嵌套类型,当然更重要的是让Gson自动实例化抽象类对应的子类,Jackson并不能很好的转换为对应的Json,但是Gson却没有这个问题,可能我没有深入研究Jackson吧,因为之前开发过Android,那是Json转换一直使用的是Gson,通过查阅资料发现SpringMVC还是可以实现我的设想的。

我已经实现了这个功能,我们就倒推一些吧,看看我是如何做到的。简要介绍一下业务场景:我的代码中有一个AbstractDatabase的抽象类,它由OracleDatabase、HiveDatabase的子类,我们需要根据json文件中数据库的类型生成对应的子类。

修改spring-mvc.xml配置文件

我将SpringMVC的一些配置信息写到了spring-mvc.xml文件中,当然也包括HttpMessageConveter。

 <bean id = "stringHttpMessageConverter" class = "org.springframework.http.converter.StringHttpMessageConverter">
        <constructor-arg value="UTF-8" />
    </bean>

    <bean id="gsonHttpMessageConverter" class="org.springframework.http.converter.json.GsonHttpMessageConverter">
        <property name="gson">

            <bean class="tabletools.util.database.GsonDbFactory" factory-method="create"/>

        </property>
    </bean>

    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
            <list>
                <ref bean="gsonHttpMessageConverter" />
                <ref bean= "stringHttpMessageConverter" />
            </list>
        </property>
    </bean>

我们可以看到messageConverters中配置了两个bean,一个是关于编码的,另外一个就是关于Gson的,我们来看看这个id为gsonHttpMessageConverter的这个bean,它里面有一个GsonDbFactory的bean,这个说法不准确,因为它是一个工厂类,它会创造出一个Gson类供SpringMVC使用。

编写GsonDbFactory类

这个一个工厂类,代码也很少,这里我贴一下代码:

public class GsonDbFactory {

    public static Gson create() {

        return new GsonBuilder().registerTypeAdapter(AbstractDatabase.class, new DbTypeAdapter())
                .registerTypeAdapter(AbstractTable.class, new TbTypeAdapter())
                .registerTypeAdapter(AbstractValue.class,new ValueTypeAdapter()).create();

    }

}

上面的代码我们使用GsonBuilder,向它注册相应的适配器。

编写TypeAdapter

GsonBuilder中我注册和很多适配器,这里我只介绍一个,剩下的原理都是一样的,我们来看看DbTypeAdapter是如何实现的:

public class DbTypeAdapter extends TypeAdapter<AbstractDatabase> {

    @Override
    public void write(JsonWriter out, AbstractDatabase value) throws IOException {

        setDbByJsonWriter(out, value);

    }

    public static void setDbByJsonWriter(JsonWriter out, AbstractDatabase value) throws IOException {

        out.beginObject();
        if (value != null) {

            out.name("name").value(value.getName());
            out.name("host").value(value.getHost());
            out.name("port").value(value.getPort());
            out.name("userName").value(value.getUserName());
            out.name("password").value(value.getPassword());
            out.name("type").value(value.getType());
            out.name("schema").value(value.getSchema());
            out.name("catalog").value(value.getCatalog());
            if(value instanceof OracleDatabase){

                OracleDatabase database = (OracleDatabase) value;
                out.name("sid").value(database.getSid());
            }

        } else {

            out.nullValue();

        }
        out.endObject();

    }

    @Override
    public AbstractDatabase read(JsonReader in) throws IOException {

        return getDbByJsonReader(in);

    }

    public static AbstractDatabase getDbByJsonReader(JsonReader in) throws IOException {

        String name = null;
        String host = null;
        int port = 0;
        String userName = null;
        String password = null;
        String type = null;
        String schema = null;
        String catalog = null;

        String sid = null;

        AbstractDatabase database = null;
        in.beginObject();
        while (in.hasNext()) {

            switch (in.nextName()) {

                case "name":
                    name = in.nextString();
                    break;

                case "host":
                    host = in.nextString();
                    break;

                case "port":
                    port = in.nextInt();
                    break;

                case "userName":
                    userName = in.nextString();
                    break;

                case "password":
                    password = in.nextString();
                    break;

                case "type":
                    type = in.nextString();
                    break;

                case "schema":
                    schema = in.nextString();
                    break;

                case "catalog":
                    catalog = in.nextString();
                    break;

                case "sid":
                    sid = in.nextString();

            }

        }

        if (type != null) {

            switch (type) {

                case JdbcValidate.TYPE_DATABASE_MYSQL:
                    database = new MySqlDatabase(name, host
                            , port, userName
                            , password, type
                            , schema);
                    break;

                case JdbcValidate.TYPE_DATABASE_ORACLE:
                    database = new OracleDatabase(name, host
                            , port, userName
                            , password, type, sid);

                    break;

                case JdbcValidate.TYPE_DATABASE_HIVE:
                    database = new HiveDatabase(name, host
                            , port, type
                            , schema);
                    break;

                case JdbcValidate.TYPE_DATABASE_ODPS:
                    database = new OdpsDatabase(name, host
                            , port, userName
                            , password, type
                            , schema);

                    break;

            }

            if (database != null)
                database.setCatalog(catalog);

        }

        in.endObject();

        return database;

    }

}

DbTypeAdapter继承了TypeAdapter这个类,它是Gson提供给我们的,它有两个抽象方法需要我们来实现,一个write,另外一个就是read。其中write主要是实现对象的序列化,也就是我们的Object已怎样的形式写入到Json文件中,read方法就是反序列化了,通过读入json实例化对应的Object。其实这两个方法和xml的解析方很像是,我记得xml有两种解析方式一种是DOM,还有一种是SAX解析解析(不一定准确),我们这里的适配器很像SAX解析,这种解析方式就是依次解析文本的每一行数据。如果你写的TypeAdapter报错,那很有可能是你的解析方式有问题,这里介绍一些JsonWriter和JsonReader中的一些方法。

  • JsonWriter
    out.beginObject() |这个是开始一个对象,对应json中的'{'符号
    out.endObject()对应json中的'}'符号
    out.name("name").value("long")对应json中的"name" : "long"
    当然还有还有out.beginArray()对应的就是json中的'['标签了,out.endArray()对应json中的']'。
  • JsonReader
    in.beginObject()和in.endObject()表示的内容和JsonWriter一样,我们开看看不一样的,in.hasNext()试探后面是否还有内容,inNextName()读取json键值对中的key,然后根据我们知道的key在实体类中对应的数据类型调用相应的方法获取数据,比如有in.nextString()、in.nextInt()等方法供我们调用。

将SpringMVC中的HttpMessageConverter替换为Gson的更多相关文章

  1. SpringMVC中注解@RequestBody和@ResponseBody的使用区别

    首先上源码 在面试时经常会问到我们如何使用SpringMVC将Http请求转换为java对象,或者又是问如何将结果转换为java的呢? SpringMVC在接收到请求之后HandlerMapping像 ...

  2. SpringMVC 中HttpMessageConverter简介和Http请求415 Unsupported Media Type的问题

    一.概述: 本文介绍且记录如何解决在SpringMVC 中遇到415 Unsupported Media Type 的问题,并且顺便介绍Spring MVC的HTTP请求信息转换器HttpMessag ...

  3. 第五节 关于SpringMVC中Ajax的配置和应用[下午]

    成熟,不是学会表达,而是学会咽下,当你一点一点学会克制住很多东西,才能驾驭好人生. 还有一周,祥云19就算结算了,一个半月的相处希望,胖先生算一个合格的老师 小白,小蔡,2婷婷,小猴,小恒,小崔,小龙 ...

  4. 关于SpringMVC中找不到<mvc:resources/>标签的解决办法

    在springMVC中我们经常会用到<mvc:resources/>标签,但是有些编辑器中的schema过于陈旧.导致找不到<mvc:resources/>标签. 经过试验,有 ...

  5. JavaEE开发之SpringMVC中的自定义消息转换器与文件上传

    上篇博客我们详细的聊了<JavaEE开发之SpringMVC中的静态资源映射及服务器推送技术>,本篇博客依然是JavaEE开发中的内容,我们就来聊一下SpringMVC中的自定义消息转发器 ...

  6. SpringMVC中Json数据格式转换

    1    @RequestBody 作用: @RequestBody注解用于读取http请求的内容(字符串),通过springmvc提供的HttpMessageConverter接口将读到的内容转换为 ...

  7. SpringMVC中post请求参数注解@requestBody使用问题

    一.httpClient发送Post 原文https://www.cnblogs.com/Vdiao/p/5339487.html public static String httpPostWithJ ...

  8. SpringMVC——消息转换器HttpMessageConverter(转)

    文章转自http://blog.csdn.net/cq1982/article/details/44101293 概述 在SpringMVC中,可以使用@RequestBody和@ResponseBo ...

  9. 详解SpringMVC中Controller的方法中参数的工作原理

    Spring MVC中Controller的处理方法的参数可以是Integer,String,自定义对象,ServletRequest,ServletResponse,ModelAndView等等,非 ...

随机推荐

  1. 在win7下如何设置计划任务每一分钟执行一次

  2. alt和title的区别与用法

    alt和title的是我们工作中经常用到这两个属性,但是一直没有总结他们的区别.现在就对他们两个的用法做一下总结.相同点:他们都会飘出一个小浮层,显示文本内容.不同点:1.alt只能是元素的属性,而t ...

  3. 【jframe】Java Web应用程序框架 - 第01篇:Get Started

    jframe是什么? jframe是一个基于MIT协议开源的java web应用程序框架,汇聚了我们团队之于java web应用程序的核心架构思想以及大量最佳实践,并且持续在实际项目中不断完善优化. ...

  4. html网页的兼容性和css优先级

    网页不仅是在一个浏览器上显示的网页,也要多考虑其他浏览器的兼容性,火狐.谷歌.搜狗等浏览器总体来说,网页的变化不大,最主要的是还是IE浏览器. color:red\9; IE6  IE7   IE8  ...

  5. C#调用TSC条码打印机打印二维码

    #region 调用TSC打印机打印 /// <summary> /// 调用TSC打印机打印 /// </summary> /// <param name=" ...

  6. 读书共享 Primer Plus C-part 7

    第十章  数组和指针 1.关于二维数组跟指针 #include<stdio.h> int main() { ][]={{,,,},{,,,},{,,,}}; ; ;i< ;i++) ...

  7. Tagged Pointer

    前言 在2013年9月,苹果推出了iPhone5s,与此同时,iPhone5s配备了首个采用64位架构的A7双核处理器,为了节省内存和提高执行效率,苹果提出了Tagged Pointer的概念.对于6 ...

  8. Java 中基本类型和字符串之间的转换

    Java 中基本类型和字符串之间的转换 在程序开发中,我们经常需要在基本数据类型和字符串之间进行转换. 其中,基本类型转换为字符串有三种方法: 1. 使用包装类的 toString() 方法 2. 使 ...

  9. .net core建站踩坑记录

    系统:win10 VS版本:2017 .NET Core 版本: 1.1 零.读取配置文件 参考:http://www.tuicool.com/articles/QfYVBvi 此版本无需添加其他组件 ...

  10. oracle预定义角色

    角色是相关权限的集合,使用角色能够简化权限的管理.简而言之就是oracle可以事先把一系列权限集中在一起(角色),打包赋予给用户,那么用户就具有了角色的一系列权限. oracle预定义角色有25种,它 ...