博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringBoot2-第四章:使用Gson作为HttpMessageConverter
阅读量:7059 次
发布时间:2019-06-28

本文共 10572 字,大约阅读时间需要 35 分钟。

上一章我们简单的介绍了Springboot的事务控制,这一章我们来在springboot中使用一下Gson。

本项目的GitHub:https://github.com/pc859107393/Go2SpringBoot.git

有兴趣交流springboot进行快速开发的同学可以加一下下面的企鹅群。

Gson的简单使用

在互联网上面有很多关于Gson的使用介绍,在这里我直接贴出kotlin版本的GsonUtil,具体代码如下:

import com.google.gson.*import java.io.IOExceptionimport java.io.Readerimport java.lang.reflect.Typeimport java.util.ArrayList@SuppressWarnings("unchecked")object GsonUtil {    private var gson: Gson? = null    /**     * 自定义TypeAdapter ,null对象将被解析成空字符串     */    private val STRING = object : TypeAdapter
() { override fun read(reader: JsonReader): String { try { if (reader.peek() == JsonToken.NULL) { reader.nextNull() return ""//原先是返回Null,这里改为返回空字符串 } return reader.nextString() } catch (e: Exception) { e.printStackTrace() } return "" } override fun write(writer: JsonWriter, value: String?) { try { if (value == null) { writer.nullValue() return } writer.value(value) } catch (e: Exception) { e.printStackTrace() } } } /** * 自定义adapter,解决由于数据类型为Int,实际传过来的值为Float,导致解析出错的问题 * 目前的解决方案为将所有Int类型当成Double解析,再强制转换为Int */ private val INTEGER = object : TypeAdapter
() { @Throws(IOException::class) override fun read(`in`: JsonReader): Number { if (`in`.peek() == JsonToken.NULL) { `in`.nextNull() return 0 } try { val i = `in`.nextDouble() return i.toInt() } catch (e: NumberFormatException) { throw JsonSyntaxException(e) } } @Throws(IOException::class) override fun write(out: JsonWriter, value: Number) { out.value(value) } } init { val gsonBulder = GsonBuilder() gsonBulder.registerTypeAdapter(String::class.java, STRING) //所有String类型null替换为字符串“” gsonBulder.registerTypeAdapter(Int::class.javaPrimitiveType, INTEGER) //int类型对float做兼容 gsonBulder.setDateFormat("yyyy-MM-dd HH:mm:ss") //通过反射获取instanceCreators属性 try { val builder = gsonBulder.javaClass as Class<*> val f = builder.getDeclaredField("instanceCreators") f.isAccessible = true //注册数组的处理器 gsonBulder.registerTypeAdapterFactory(CollectionTypeAdapterFactory(ConstructorConstructor(f.get(gsonBulder) as Map
>))) } catch (e: Exception) { e.printStackTrace() } gson = gsonBulder.create() } /** * Json字符串 转为指定对象 * * @param json json字符串 * @param type 对象类型 * @param
对象类型 * @return * @throws JsonSyntaxException
*/ @Throws(JsonSyntaxException::class) fun
toBean(json: String, type: Class
): T { return gson!!.fromJson(json, type) } /** * 将jsonStr转换为javaBean * * @param object * @return json string */ fun toJson(`object`: Any): String { return gson!!.toJson(`object`) } /** * 将jsonStr转换为javaBean * * @param json * @param type * @return instance of type */ fun
fromJson(json: String, type: Class
): V { return gson!!.fromJson(json, type) } /** * 将jsonStr转换为javaBean * * @param json * @param type * @return instance of type */ fun
fromJson(json: String, type: Type): V { return gson!!.fromJson(json, type) } /** * 将reader转换为javaBean * * @param reader * @param type * @return instance of type */ fun
fromJson(reader: Reader, type: Class
): V { return gson!!.fromJson(reader, type) } /** * 将reader转换为javaBean * * @param reader * @param type * @return instance of type */ fun
fromJson(reader: Reader, type: Type): V { return gson!!.fromJson(reader, type) } /** * 将json集合转换为ArrayList * * @param json 需要转换的json集合 * @param type 转出的类型 */ fun
toList(json: String, type: Class
): ArrayList
? { val list = ArrayList
() return try { val parser = JsonParser() parser.parse(json).asJsonArray.forEach { element -> list.add(gson!!.fromJson(element, type)) } ArrayList(list) } catch (e: Exception) { e.printStackTrace() null } }}复制代码

是的没错,上面仅仅是一个kotlin上面用的gson的工具类,简化你的gson操作,但是我们的核心是什么?在SpringMVC中使用Gson解析json数据(HttpMessageConverter)。

SpringMVC的消息转换器HttpMessageConverter

SpringMVC使用消息转换器(HttpMessageConverter)实现将请求信息转换为对象、将对象转换为响应信息。

众所周知,http请求的数据交换完全是依靠数据流的读写来实现的。在servlet中我们是直接使用ServletRequest或者ServletResponse的输入输出流完成一些操作。但是在SPringMVC中我们使用一些注解来完成相关操作,具体使用的注解在org.springframework.web.bind.annotation下面。当然我们常用的一些如:@RequestBody@RequestPart@RequestParam等等。

使用了@RequestBodyHttpMessageConverter的相关实现类就会把数据转换到对应的变量中(@RequestBody标记的某个请求的请求体可以将json自动换转为对应的实体,当然@ResponseBody也是由HttpMessageConverter相关类来转换)。 具体的代码请看org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor,这里暂且不表。

接着我们向下看,可以找到一个FormHttpMessageConverter的实现类,顾名思义就是表单信息转换的转换器。但是具体的内容太多,我们接着查找相关的实现类AllEncompassingFormHttpMessageConverter,具体的代码如下:

public class AllEncompassingFormHttpMessageConverter extends FormHttpMessageConverter {	private static final boolean jaxb2Present =			ClassUtils.isPresent("javax.xml.bind.Binder",					AllEncompassingFormHttpMessageConverter.class.getClassLoader());	private static final boolean jackson2Present =			ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper",					AllEncompassingFormHttpMessageConverter.class.getClassLoader()) &&			ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator",					AllEncompassingFormHttpMessageConverter.class.getClassLoader());	private static final boolean jackson2XmlPresent =			ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper",					AllEncompassingFormHttpMessageConverter.class.getClassLoader());	private static final boolean jackson2SmilePresent =			ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory",					AllEncompassingFormHttpMessageConverter.class.getClassLoader());	private static final boolean gsonPresent =			ClassUtils.isPresent("com.google.gson.Gson",					AllEncompassingFormHttpMessageConverter.class.getClassLoader());	private static final boolean jsonbPresent =			ClassUtils.isPresent("javax.json.bind.Jsonb",					AllEncompassingFormHttpMessageConverter.class.getClassLoader());	public AllEncompassingFormHttpMessageConverter() {		addPartConverter(new SourceHttpMessageConverter<>());		if (jaxb2Present && !jackson2XmlPresent) {			addPartConverter(new Jaxb2RootElementHttpMessageConverter());		}		if (jackson2Present) {			addPartConverter(new MappingJackson2HttpMessageConverter());		}		else if (gsonPresent) {			addPartConverter(new GsonHttpMessageConverter());		}		else if (jsonbPresent) {			addPartConverter(new JsonbHttpMessageConverter());		}		if (jackson2XmlPresent) {			addPartConverter(new MappingJackson2XmlHttpMessageConverter());		}		if (jackson2SmilePresent) {			addPartConverter(new MappingJackson2SmileHttpMessageConverter());		}	}}复制代码

从上面我们可以看到SpringMVC中HttpMessage的转换器队列中已经加入了Jackson和Gson的解析器,所以我们要使用Gson来解析,只需要移除MappingJackson2HttpMessageConverter即可。

接下来我们需要在WebMvcConfigurer中去操作MessageConverters的数据,代码如下:

@SpringBootApplication@EnableWebMvc@EnableSwagger2@MapperScan(value = ["cn.acheng1314.base.dao"])@Configuration@EnableTransactionManagementclass BaseApplication : WebMvcConfigurer {
override fun extendMessageConverters(converters: MutableList
<*>>) { // 删除MappingJackson2HttpMessageConverter,并使用GsonHttpMessageConverter替换 converters.forEach { t: HttpMessageConverter<*>? -> if (t is MappingJackson2HttpMessageConverter) { converters.remove(t) return super.extendMessageConverters(converters) } } } }复制代码

这个时候我们跑一下项目,实现Gson解析json是完全没有问题的,但是新的问题产生了!

问题:在我们的swagger中,不能正确的解析json了,仔细看一下web的调试信息,会提示我们不能正确的解析json,emmm。。。是不是觉得坑来了?是的,没错,我们通过一番查找可以看到在SpringFox的包springfox.documentation.spring.web.json下的JsonJsonSerializer均是采用的Jackson实现,代码如下:

package springfox.documentation.spring.web.json;import com.fasterxml.jackson.annotation.JsonRawValue;import com.fasterxml.jackson.annotation.JsonValue;public class Json {  private final String value;  public Json(String value) {    this.value = value;  }  @JsonValue  @JsonRawValue  public String value() {    return value;  }}package springfox.documentation.spring.web.json;import com.fasterxml.jackson.core.JsonProcessingException;import com.fasterxml.jackson.databind.ObjectMapper;import java.util.List;public class JsonSerializer {  private ObjectMapper objectMapper = new ObjectMapper();  public JsonSerializer(List
modules) { for (JacksonModuleRegistrar each : modules) { each.maybeRegisterModule(objectMapper); } } public Json toJson(Object toSerialize) { try { return new Json(objectMapper.writeValueAsString(toSerialize)); } catch (JsonProcessingException e) { throw new RuntimeException("Could not write JSON", e); } }}复制代码

所以这里就提示我们需要做到Gson实现的json节点都需要伪装成Jackson的样子,处理代码如下:

import java.lang.reflect.Typeimport com.google.gson.*import springfox.documentation.spring.web.json.Json/*** 实现自己的JsonSerializer*/class SpringfoxJsonToGsonAdapter : com.google.gson.JsonSerializer
{ override fun serialize(json: Json, type: Type, context: JsonSerializationContext): JsonElement { val parser = JsonParser() return parser.parse(json.value()) }}复制代码

同样的在我们的WebMvcConfigurer实现类中重写extendMessageConverters方法这里应该使用我们的SpringfoxJsonToGsonAdapter,代码如下:

override fun extendMessageConverters(converters: MutableList
<*>>) { // 删除MappingJackson2HttpMessageConverter,并使用GsonHttpMessageConverter替换 converters.forEach { t: HttpMessageConverter<*>? -> if (t is MappingJackson2HttpMessageConverter) { converters.remove(t) converters.add(object : GsonHttpMessageConverter() { init { //自定义Gson适配器 super.setGson(GsonBuilder() .registerTypeAdapter(Json::class.java, SpringfoxJsonToGsonAdapter()) .create()) } }) // 添加GsonHttpMessageConverter return super.extendMessageConverters(converters) } } }复制代码

现在我们再去试一试swagger,是不是一切恢复原状了?好的今天的东西已经说完了,让我们在结束的时候再安利一下自己!

每天进步一点点,十年磨一剑。加油!

转载地址:http://kdfll.baihongyu.com/

你可能感兴趣的文章
超燃!Apache Flink 全球顶级盛会强势来袭
查看>>
约你一起来写作
查看>>
修改arcgis infowindow 放大和缩小的模板
查看>>
ASP.NET 2.0+Atlas编写鼠标拖放程序(2)
查看>>
ps与top命令简单介绍
查看>>
js12---闭包,原型,继承
查看>>
JavaScript返回上一页代码区别
查看>>
EntityFramework 如何进行异步化(关键词:async·await·SaveChangesAsync·ToListAsync)
查看>>
百度编辑器ueditor每次编辑后多一个空行的解决办法
查看>>
C#扇形的绘制与Hittest交互、图种制作
查看>>
【MVC 4】5.SportsSore —— 一个真实的应用程序
查看>>
Lucene.Net:构造搜索表达式简化搜索
查看>>
Hadoop - Zeppelin 使用心得
查看>>
Android GIS开发系列-- 入门季(2) MapView与图层介绍
查看>>
爪哇国新游记之二十五----图及其遍历查找
查看>>
Windows Live Writer Technical Preview 公布下载
查看>>
iphone:使用NSFileManager取得目录下所有文件(遍历所有文件)
查看>>
IPK僵尸网络 看看其传播手法
查看>>
Visual Studio DSL 入门 14---用Wix制作安装程序
查看>>
SQL Server 各种查询语句执行返回结果
查看>>