类继承体系
默认转换器即springmvc默认的转换器, 用的比较多的是以下两种, 无需自己声明以及使用。
相关的类的内容这里不做展示,有兴趣大家可以下载源码看一下。
-
默认json转换器
-
默认xml转换器
核心类与接口说明
在Spring框架中,HttpMessageConverter
是一个非常重要的接口,它用于在HTTP请求和响应与Java对象之间进行转换。如果你需要实现自定义的报文转换器,可以按照以下步骤进行:
-
实现
HttpMessageConverter
接口:创建一个类实现HttpMessageConverter<T>
接口,其中T
是你希望转换的目标类型。你需要实现以下方法:canRead(Class<?> clazz, MediaType mediaType)
:判断转换器是否能够读取指定类型和媒体类型的数据。canWrite(Class<?> clazz, MediaType mediaType)
:判断转换器是否能够写入指定类型和媒体类型的数据。getSupportedMediaTypes()
:返回转换器支持的媒体类型列表。read(Class<? extends T> clazz, HttpInputMessage inputMessage)
:从HttpInputMessage
中读取数据并转换为T
类型的对象。write(T t, MediaType contentType, HttpOutputMessage outputMessage)
:将T
类型的对象转换并写入HttpOutputMessage
中。
-
继承
AbstractHttpMessageConverter
:Spring提供了AbstractHttpMessageConverter
类,它简化了HttpMessageConverter
接口的实现。你只需要重写supports(Class<?> clazz)
、readInternal(Class<? extends T> clazz, HttpInputMessage inputMessage)
和writeInternal(T t, HttpOutputMessage outputMessage)
方法。 -
配置Spring MVC使用自定义转换器:你需要在Spring的配置中注册自定义的
HttpMessageConverter
。这可以通过实现WebMvcConfigurer
接口并重写configureMessageConverters
或extendMessageConverters
方法来完成。例如:@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void extendMessageConverters(List<HttpMessageConverter<?>> converters) { converters.add(new MyMessageConverter()); } }
其中
MyMessageConverter
是你的自定义转换器类。 -
使用自定义转换器:一旦注册,Spring MVC将自动使用你的自定义转换器来处理匹配的请求和响应。
在实现自定义转换器时,你可以定义自己的序列化和反序列化逻辑,例如处理XML、JSON或其他自定义格式的数据。自定义转换器可以让你更灵活地处理HTTP请求和响应数据,满足特定的业务需求。
底层调用链
在Spring MVC中,HttpMessageConverter
是一个核心接口,它负责将HTTP请求和响应的消息体与Java对象之间进行转换。下面我将解释Spring MVC中调用这些报文转换器的流程。
-
请求到达:当一个HTTP请求到达Spring MVC的
DispatcherServlet
时,它将请求委托给RequestMappingHandlerMapping
来解析。 -
选择处理器:
RequestMappingHandlerMapping
根据请求的URL和HTTP方法等信息找到匹配的控制器方法。 -
处理器适配器:找到控制器方法后,
DispatcherServlet
使用一个适当的HandlerAdapter
来处理请求。对于使用@RequestMapping
注解的方法,通常会使用RequestMappingHandlerAdapter
。 -
调用链:
RequestMappingHandlerAdapter
中的invokeHandlerMethod
方法被调用。- 在这个方法内部,会创建一个
ServletInvocableHandlerMethod
对象,该对象封装了对控制器方法的调用。 ServletInvocableHandlerMethod
对象持有从RequestMappingHandlerAdapter
获取的messageConverters
列表,这个列表包含了所有可用的消息转换器。
-
参数解析:
- 如果控制器方法有参数,并且这些参数需要从请求体中读取(例如,使用了
@RequestBody
注解),ServletInvocableHandlerMethod
将使用RequestResponseBodyMethodProcessor
来解析这些参数。 RequestResponseBodyMethodProcessor
会遍历所有的messageConverters
,使用canRead
方法检查哪个转换器能够读取给定的媒体类型(Media Type)和目标类。- 一旦找到合适的转换器,它将使用
read
方法将请求体转换为相应的Java对象。
- 如果控制器方法有参数,并且这些参数需要从请求体中读取(例如,使用了
-
控制器方法执行:参数解析完成后,控制器方法被执行。
-
处理返回值:
- 控制器方法执行后,如果方法上有
@ResponseBody
注解,ServletInvocableHandlerMethod
将再次使用RequestResponseBodyMethodProcessor
来处理返回值。 RequestResponseBodyMethodProcessor
会遍历所有的messageConverters
,使用canWrite
方法检查哪个转换器能够写入给定的媒体类型和对象类。- 找到合适的转换器后,它将使用
write
方法将Java对象转换为响应体消息。
- 控制器方法执行后,如果方法上有
-
响应返回:最终,转换后的消息体被写入HTTP响应中,并返回给客户端。
在整个调用链中,HttpMessageConverter
的实现类负责具体的序列化和反序列化逻辑。开发者可以通过实现WebMvcConfigurer
接口的extendMessageConverters
方法来添加自定义的转换器,或者通过配置文件中的<mvc:message-converters>
标签来注册自定义转换器。
这个调用流程涉及到了多个组件和步骤,每个组件都在Spring MVC的请求处理中扮演了特定的角色。通过这种方式,Spring MVC提供了高度可定制的消息转换机制,以适应不同的数据处理需求。
完整示例
下面我将通过一个简单的例子来说明如何创建并集成一个自定义的HttpMessageConverter
到Spring MVC中。
假设我们有一个简单的Java对象MyObject
,我们想要通过一种非标准的媒体类型application/x-myobject
来序列化和反序列化这个对象。我们将创建一个自定义的HttpMessageConverter
来处理这个任务。
步骤 1: 创建自定义的HttpMessageConverter
首先,我们创建一个类MyObjectHttpMessageConverter
,继承自AbstractHttpMessageConverter<MyObject>
:
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.util.StreamUtils;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
public class MyObjectHttpMessageConverter extends AbstractHttpMessageConverter<MyObject> {
public MyObjectHttpMessageConverter() {
super(new MediaType("application", "x-myobject"));
}
@Override
protected boolean supports(Class<?> clazz) {
return MyObject.class.isAssignableFrom(clazz);
}
@Override
protected MyObject readInternal(Class<? extends MyObject> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
String body = StreamUtils.copyToString(inputMessage.getBody(), Charset.defaultCharset());
// 假设MyObject的构造函数接受一个字符串
return new MyObject(body);
}
@Override
protected void writeInternal(MyObject myObject, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
OutputStreamWriter writer = new OutputStreamWriter(outputMessage.getBody(), getCharset());
// 假设我们要将MyObject转换成字符串进行输出
writer.write(myObject.toString());
writer.flush();
}
}
步骤 2: 配置Spring MVC使用自定义转换器
接下来,我们需要在Spring MVC的配置中注册我们的自定义转换器。如果你使用的是Java配置,可以像下面这样实现WebMvcConfigurer
接口:
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
// 如何自定义的转换器与默认转换器冲突,可以将自己的转换器放到默认转换器前面
converters.add(new MyObjectHttpMessageConverter());
}
}
如果你使用的是XML配置,可以在<mvc:annotation-driven/>
标签中添加一个<bean>
来注册你的转换器:
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="com.example.MyObjectHttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
步骤 3: 使用自定义转换器
现在,当你的控制器方法返回一个MyObject
类型的实例,或者接受一个MyObject
类型的参数时,Spring MVC将使用你的自定义转换器来处理序列化和反序列化。
例如,你的控制器可能看起来像这样:
@RestController
public class MyObjectController {
@PostMapping(value = "/myobject", consumes = "application/x-myobject")
public MyObject handleMyObject(@RequestBody MyObject myObject) {
// 处理myObject
return myObject;
}
}
在这个例子中,当客户端以application/x-myobject
类型发送数据到/myobject
端点时,Spring MVC将使用MyObjectHttpMessageConverter
来解析请求体中的字符串并创建MyObject
实例。同样,当控制器方法返回一个MyObject
实例时,Spring MVC也将使用这个转换器将实例转换为响应体。
这样,你就成功地将自定义的报文转换器集成到了Spring MVC中。