SpringMVC自定义消息转换器(Geometry序列化)

2 篇文章 0 订阅

        @ResponseBody、@RequestBody是我们开发中常用的注解,因为SpringMVC会扫描该类注解,选择适当的转换器进行数据转换。目前主流的是使用JSON格式数据,因此SpringMVC中有提供 MappingJackson2HttpMessageConverter 转换器,该转换器是我们最常用到的(网上有很多文章,都有进行过源码追踪,有兴趣的读者可以去了解下SpringMVC是如何把请求消息或返回对象进行转换)。

        当然在进行文件下载的情况下会使用流传输,这时候是根据请求头或响应头来选择合适的converter,想进一步了解可以参考下这篇文章:https://blog.csdn.net/zbajie001/article/details/79738181

下面我主要分三点描述:

1.spring MVC 配置自定义转换器

2.spring cloud服务调用Feign的Decoder、Encoder配置自定义转换器

3.redisTemplate 实现对Geometry的序列化

下面例子主要是介绍场景供参考,大家可以参考下面的思路来解决问题

 

1.spring MVC 配置自定义转换器

        我目前遇到的情况是java代码里我用到了

com.vividsolutions.jts.geom.Geometry;

该类是图形数据对象,无法序列化为JSON,必须要依靠自定义的序列化方式,后来我在网上扒到了一个开源项目,专门处理图形对象的序列化,附上链接:https://github.com/bedatadriven/jackson-datatype-jts

结合jackson的ObjectMapper来使用,MappingJackson2HttpMessageConverter转换器也正是使用ObjectMapper来序列化的。


/**
 * @author chenws
 */
@Configuration
@EnableWebMvc
@Slf4j
public class WebConfiguration implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        //初始化MappingJackson2HttpMessageConverter,注册自定义模块
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder().modules(new JtsModule());
        MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter(builder.build());

        ByteArrayHttpMessageConverter byteArrayHttpMessageConverter = new ByteArrayHttpMessageConverter();
        StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
        ResourceHttpMessageConverter resourceHttpMessageConverter = new ResourceHttpMessageConverter();
        ResourceRegionHttpMessageConverter resourceRegionHttpMessageConverter = new ResourceRegionHttpMessageConverter();
        SourceHttpMessageConverter sourceHttpMessageConverter = new SourceHttpMessageConverter();
        AllEncompassingFormHttpMessageConverter allEncompassingFormHttpMessageConverter = new AllEncompassingFormHttpMessageConverter();
        Jaxb2RootElementHttpMessageConverter jaxb2RootElementHttpMessageConverter = new Jaxb2RootElementHttpMessageConverter();

        //转换器,根据实际情况添加或减少
        //此处的mappingJackson2HttpMessageConverter就是我们自定义的转换器,其实核心就是
        //初始化的时候注册了JtsModule,支持Geometry的序列化
        converters.add(mappingJackson2HttpMessageConverter);
        converters.add(stringHttpMessageConverter);
        converters.add(resourceHttpMessageConverter);
        converters.add(byteArrayHttpMessageConverter);
        converters.add(resourceRegionHttpMessageConverter);
        converters.add(sourceHttpMessageConverter);
        converters.add(allEncompassingFormHttpMessageConverter);
        converters.add(jaxb2RootElementHttpMessageConverter);
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
        registry.addResourceHandler("/templates/**").addResourceLocations("classpath:/templates/");
        // 放行swagger
        registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }


}

大家也可以参考JtsModule来编写自己的序列化工具,网上也很多教程。

简单的一个配置类,就可以完成对Geometry类的JSON字符串转换。

 

2.spring cloud服务调用Feign的Decoder、Encoder配置自定义转换器

        第一点解决的只是出口的序列化,现在springcloud成为微服务主流,服务间调用时不可避免的,因此问题是进行服务调用的时候我们也需要对解码编码下功夫,让他支持Geometry的序列化和反序列化。

同样我们也需要一个配置文件(Feign)

/**
 * @author chenws
 */
@Configuration
@Slf4j
public class FeignConfig {

	@Autowired
	private ObjectFactory<HttpMessageConverters> messageConverters;

	@Bean
	public Encoder feignFormEncoder() {
		Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder().modules(new JtsModule());
		ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(new MappingJackson2HttpMessageConverter(builder.build()));
		return new SpringFormEncoder(new SpringEncoder(objectFactory));
	}

	@Bean
	public Decoder feignDecoder() {
		Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder().modules(new JtsModule());
		ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(new MappingJackson2HttpMessageConverter(builder.build()));
		return new ResponseEntityDecoder(new SpringDecoder(objectFactory));
	}

}

此配置也是一个全局配置,同样的道理,自定义MappingJackson2HttpMessageConverter,支持Geometry

3.redisTemplate 实现对Geometry的序列化

RedisTemplate我也还是使用了jackson自带的支持redis序列化类Jackson2JsonRedisSerializer,直接看代码

/**
 * @author chenws
 */

@Configuration
public class RedisTemplateConfig {
	@Bean
	public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) {
		RedisTemplate template = new RedisTemplate();
		template.setConnectionFactory(connectionFactory);

		//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
		Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);

		ObjectMapper mapper = new ObjectMapper();
		mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
		mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
		mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
                //CustomJtsModule
		mapper.registerModule(new CustomJtsModule());
		serializer.setObjectMapper(mapper);

		template.setValueSerializer(serializer);
		//使用StringRedisSerializer来序列化和反序列化redis的key值
		template.setKeySerializer(new StringRedisSerializer());
		template.afterPropertiesSet();
		return template;
	}
}

重点是在mapper.registerModule(new CustomJtsModule()),这里其实原理跟上面的都一样,都是调用ObjectMapper来进行序列化和反序列化,此处需要注意的是,我自定义了一个CustomJtsModule,因为我ObjectMapper序列化的时候使用了数据类型和数据绑定,

mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

开源的jackson-datatype-jts 的GeometrySerializer会有问题,它少实现了一个方法serializeWithType。

参考:https://stackoverflow.com/questions/27876027/json-jackson-exception-when-serializing-a-polymorphic-class-with-custom-serial

 

结束

        本文主要是解决了在三种情况下,特殊字段无法序列化的问题,其实实现原理都是一样的。我们可以参考用法,实现自己的序列化方式,当然我们也不一定用Jackson,也可以用阿里的fastjson,反正就根据我们的实际情况,来自定义转换器或redis序列化方式。

 

如需转载请标明出处:https://blog.csdn.net/shuoshuo132

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

碩果

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值