将SpringMVC中的HttpMessageConverter替换为Gson
读者们看到这个标题也许会感到奇怪,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的更多相关文章
- SpringMVC中注解@RequestBody和@ResponseBody的使用区别
首先上源码 在面试时经常会问到我们如何使用SpringMVC将Http请求转换为java对象,或者又是问如何将结果转换为java的呢? SpringMVC在接收到请求之后HandlerMapping像 ...
- SpringMVC 中HttpMessageConverter简介和Http请求415 Unsupported Media Type的问题
一.概述: 本文介绍且记录如何解决在SpringMVC 中遇到415 Unsupported Media Type 的问题,并且顺便介绍Spring MVC的HTTP请求信息转换器HttpMessag ...
- 第五节 关于SpringMVC中Ajax的配置和应用[下午]
成熟,不是学会表达,而是学会咽下,当你一点一点学会克制住很多东西,才能驾驭好人生. 还有一周,祥云19就算结算了,一个半月的相处希望,胖先生算一个合格的老师 小白,小蔡,2婷婷,小猴,小恒,小崔,小龙 ...
- 关于SpringMVC中找不到<mvc:resources/>标签的解决办法
在springMVC中我们经常会用到<mvc:resources/>标签,但是有些编辑器中的schema过于陈旧.导致找不到<mvc:resources/>标签. 经过试验,有 ...
- JavaEE开发之SpringMVC中的自定义消息转换器与文件上传
上篇博客我们详细的聊了<JavaEE开发之SpringMVC中的静态资源映射及服务器推送技术>,本篇博客依然是JavaEE开发中的内容,我们就来聊一下SpringMVC中的自定义消息转发器 ...
- SpringMVC中Json数据格式转换
1 @RequestBody 作用: @RequestBody注解用于读取http请求的内容(字符串),通过springmvc提供的HttpMessageConverter接口将读到的内容转换为 ...
- SpringMVC中post请求参数注解@requestBody使用问题
一.httpClient发送Post 原文https://www.cnblogs.com/Vdiao/p/5339487.html public static String httpPostWithJ ...
- SpringMVC——消息转换器HttpMessageConverter(转)
文章转自http://blog.csdn.net/cq1982/article/details/44101293 概述 在SpringMVC中,可以使用@RequestBody和@ResponseBo ...
- 详解SpringMVC中Controller的方法中参数的工作原理
Spring MVC中Controller的处理方法的参数可以是Integer,String,自定义对象,ServletRequest,ServletResponse,ModelAndView等等,非 ...
随机推荐
- Python的迭代器与生成器
Python中的生成器和迭代器方便好用,但是平时对生成器和迭代器的特性掌握的不是很到位,今天将这方面的知识整理一下. 迭代器 为了更好的理解迭代器和生成,我们需要简单的回顾一下迭代器协议的概念. 迭代 ...
- win 10 开机后无法显示桌面
我整理了几种方法,可以试一下 1> win + x 然后运行explorer.exe 2> 1/// shift + ctrl + esc 进入 任务管理器 2/// 点击 ...
- VB6之切换桌面
Desktop的API,用于切换或者系统桌面环境.扩展起来可以做一个锁屏程序或者多桌面程序. 模块部分: 'desktop.bas 'too much struct and declare unuse ...
- [UWP]浅谈按钮设计
一时兴起想谈谈UWP按钮的设计. 按钮是UI中最重要的元素之一,可能也是用得最多的交互元素.好的按钮设计可以有效提高用户体验,构造让人眼前一亮的UI.而且按钮通常不会影响布局,小小的按钮无论怎么改也不 ...
- JavaWeb 后端 <九> 之 JDBC加强
一.大结果集的分页(重点,难点) 1.分批次查询:分页 2.基于数据库的分页:依赖的是数据库的分页语句(不同数据库是不同的) MySQL:每页显示10条. select * from XXX limi ...
- AngularJS 和 Bootstrap
AngularJS Bootstrap AngularJS 的首选样式表是 Twitter Bootstrap, Twitter Bootstrap 是目前最受欢迎的前端框架. 查看 Bootstra ...
- jquery中append与appendTo方法区别
1. append(content)方法 方法作用:向每个匹配的元素内部追加内容. 参数介绍:content (<Content>): 要追加到目标中的内容. 用法示例: HTML代码为& ...
- java的字符串操作和for循环的使用
/* "12 0 99 -7 30 4 100 13" 要求对字符串中的数值进行排序.生成一个数值从小到大新字符串. "-7 0 4 12 13 30 99 100&qu ...
- spring基础系列--JavaConfig配置
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/7171011.html 早以前,Spring推荐使用XML的方式来定义Bean及Bean之间 ...
- Python如何实现单步调试
遇到大型python项目,如何定位问题和监控程序的运行状态是一个程序员必须掌握的技能,今天小编为你带来python程序的单步调试方法,方便易用,简单易记! 首先你需要在所调试程序的开头中:import ...