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

本文详细介绍了如何在SpringMVC、SpringCloud Feign及RedisTemplate中配置自定义序列化器,以解决特定类型如Geometry的序列化问题。通过示例代码展示了如何利用Jackson的ObjectMapper并注册自定义模块,实现对特殊字段的序列化与反序列化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

        当然在进行文件下载的情况下会使用流传输,这时候是根据请求头或响应头来选择合适的converter,想进一步了解可以参考下这篇文章:https://blog.youkuaiyun.com/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.youkuaiyun.com/shuoshuo132

### 如何在 Spring MVC 中创建和配置自定义消息转换器 #### 创建自定义消息转换器类 为了实现自定义的消息转换功能,需创建一个实现了`HttpMessageConverter<T>`接口的类。此接口提供了三个主要的方法用于读取、写入以及判断是否支持特定媒体类型。 ```java import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpOutputMessage; import org.springframework.http.MediaType; import org.springframework.http.converter.AbstractHttpMessageConverter; import java.io.IOException; import java.util.List; public class CustomMessageConverter extends AbstractHttpMessageConverter<CustomObject> { public CustomMessageConverter() { super(MediaType.APPLICATION_JSON_UTF8); } @Override protected boolean supports(Class<?> clazz) { return CustomObject.class.equals(clazz); // 只处理指定类型的对象 } @Override protected CustomObject readInternal(Class<? extends CustomObject> clazz, HttpInputMessage inputMessage) throws IOException { // 实现从HTTP请求体中解析并返回CustomObject实例逻辑 return null; // 返回解析后的对象 } @Override protected void writeInternal(CustomObject object, HttpOutputMessage outputMessage) throws IOException { // 将给定的对象序列化到响应流中的具体实现 } } ``` 上述代码展示了如何通过继承`AbstractHttpMessageConverter`来简化工作量[^1]。 #### 配置Spring容器注册自定义转换器 为了让Spring知道要使用这个新的消息转换器,在Spring配置文件(`springmvc.xml`)里添加如下设置: ```xml <mvc:annotation-driven> <mvc:message-converters register-defaults="true"> <!-- 自定义消息转换器 --> <bean class="com.example.CustomMessageConverter"/> </mvc:message-converters> </mvc:annotation-driven> ``` 这段XML片段告诉Spring除了默认的消息转换器外还要加载自定义消息转换器[^3]。 这样就完成了整个过程——既定义了一个能够理解特定数据格式的新组件,又将其集成到了现有的Web应用程序架构之中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

碩果

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

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

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

打赏作者

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

抵扣说明:

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

余额充值