第二十八讲-消息转换器MessageConverter
第二十八讲-消息转换器MessageConverter
本讲我们来了解一一下消息转换器MessageConverter。其实我们在前面很多地方都用过消息转换器,如上一讲的返回处理器中的@ResponseBody中讲Java对象转为JSON
,只不过一笔带过。本讲我们来介绍一下消息转换器。
我们首先看一下下面的代码:
public static class User {
private String name;
private int age;
@JsonCreator
public User(@JsonProperty("name") String name, @JsonProperty("age") int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
下面我们来看一下MessageConverter将Java对象和消息转换?
1. 对象转JSON格式的例子
如下面的代码:
public static void test1() throws IOException {
// 准备一个输出消息对象
MockHttpOutputMessage message = new MockHttpOutputMessage();
// 创建一个基于Jackson实现的消息转换器-->将消息转为JSON(声明一个基于JSON的消息转换器)
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
// 该方法判断能否将一个JAVA对象转为目标消息类型(JSON)
if (converter.canWrite(User.class, MediaType.APPLICATION_JSON)) {
// 调用消息转换器的write方法将消息对象转为目标类型的消息(JSON)
// 并将转化后的结果写入消息输出对象中
converter.write(new User("张三", 18), MediaType.APPLICATION_JSON, message);
// 打印输出一下转化后的消息
System.out.println(message.getBodyAsString());
}
}
编写主方法测试:
public class A28 {
public static void main(String[] args) throws IOException, NoSuchMethodException, HttpMediaTypeNotAcceptableException {
test1();
}
}
{"name":"张三","age":18}
可以看到已经将JAVA对象成功转为了JSON数据!
2. 对象转为XML格式的例子
接下来我们看一下JAVA对象转为XML格式的例子。看一下下面的示例代码:
private static void test2() throws IOException {
MockHttpOutputMessage message = new MockHttpOutputMessage();
// 创建一个XML消息转换器
MappingJackson2XmlHttpMessageConverter converter = new MappingJackson2XmlHttpMessageConverter();
if (converter.canWrite(User.class, MediaType.APPLICATION_XML)) {
converter.write(new User("李四", 20), MediaType.APPLICATION_XML, message);
System.out.println(message.getBodyAsString());
}
}
由于改段代码和上面的代码非常类似,这里代码就不写详细的注释了。编写主方法测试:
public class A28 {
public static void main(String[] args) throws IOException, NoSuchMethodException, HttpMediaTypeNotAcceptableException {
test2();
}
}
<User>
<name>李四</name
><age>20</age>
</User>
3. JSON格式消息转JAVA对象的例子
前面我们看了JAVA对象转消息的例子,那么消息能够转为JAVA对象呢?答案是当然可以的。
我们来看一下JSON消息转为JAVA对象的例子:
private static void test3() throws IOException {
// 创建一个输入消息对象,并创建一个JSON消息
MockHttpInputMessage message = new MockHttpInputMessage("""
{
"name":"李四",
"age":20
}
""".getBytes(StandardCharsets.UTF_8));
// 声明一个支持JSON格式消息转换的转换器
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
// 如果该消息可以转为JAVA对象
if (converter.canRead(User.class, MediaType.APPLICATION_JSON)) {
// 将该消息转为JAVA对象
Object read = converter.read(User.class, message);
// 打印转换后的JAVA对象
System.out.println(read);
}
}
编写测试代码:
public class A28 {
public static void main(String[] args) throws IOException, NoSuchMethodException, HttpMediaTypeNotAcceptableException {
test3();
}
}
User{name='李四', age=20}
我们可以看到,JSON消息成功转为了JAVA对象。
当然,XML消息转为JAVA对象当然也是可以的,这里呢,我写一段代码,代码很简单,我们可以直接看一下运行结果:
4. XML格式消息转JAVA对象的例子
public static void test5() throws IOException {
MockHttpInputMessage message = new MockHttpInputMessage(
"""
<User>
<name>李四</name>
<age>20</age>
</User>
""".getBytes(StandardCharsets.UTF_8));
MappingJackson2XmlHttpMessageConverter converter = new MappingJackson2XmlHttpMessageConverter();
if (converter.canRead(User.class, MediaType.APPLICATION_XML)){
Object read = converter.read(User.class, message);
System.out.println(read);
}
}
User{name='李四', age=20}
5. 存在多个消息处理器的情况
现在我们再来看一下如果有若多个消息处理器,它们之间是如何协同工作的,我们先看一下如下的代码:
private static void test4() throws IOException, HttpMediaTypeNotAcceptableException, NoSuchMethodException {
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
ServletWebRequest webRequest = new ServletWebRequest(request, response);
request.addHeader("Accept", "application/xml");
// response.setContentType("application/json");
// 添加对@RequestBody和@ResponseBody注解的解析和处理的处理器
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(
List.of(
// 添加两个消息转换器:JAVA对象转JSON的消息转换器和JAVA对象转XML的消息转换器
new MappingJackson2HttpMessageConverter(), new MappingJackson2XmlHttpMessageConverter()
));
// 处理一个返回值
processor.handleReturnValue(
new User("张三", 18),
new MethodParameter(A28.class.getMethod("user"), -1),
new ModelAndViewContainer(),
webRequest
);
// 将最终转换的结果放到response中
System.out.println(new String(response.getContentAsByteArray(), StandardCharsets.UTF_8));
}
我们可以思考一下,最终转换的结果是JSON格式的消息还是XML格式的消息呢?我们测试一下:
19:06:04.897 [main] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - Using 'application/json', given [*/*] and supported [application/json, application/*+json, application/xml;charset=UTF-8, text/xml;charset=UTF-8, application/*+xml;charset=UTF-8]
19:06:04.906 [main] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - Writing [User{name='张三', age=18}]
{"name":"张三","age":18}
我们发现,最终转换的结果是JSON格式的数据,这是为什么呢?
原来啊,最终转换消息的类型和多个消息转换器添加的先后顺序有关,第一个添加的是哪种类型的消息转换器,就先转换成什么类型的消息,上面的例子中我们将转为JSON类型的消息转换器排在了前面,因此JAVA对象转为了JSON类型。
现在我们将转为XML格式的消息转换器排在前面再测试一下:
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(
List.of(
// 添加两个消息转换器:JAVA对象转JSON的消息转换器和JAVA对象转XML的消息转换器
new MappingJackson2XmlHttpMessageConverter(), new MappingJackson2HttpMessageConverter()
));
19:09:08.340 [main] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - Using 'application/xml;charset=UTF-8', given [*/*] and supported [application/xml;charset=UTF-8, text/xml;charset=UTF-8, application/*+xml;charset=UTF-8, application/json, application/*+json]
19:09:08.351 [main] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - Writing [User{name='张三', age=18}]
<User><name>张三</name><age>18</age></User>
我们发现消息为XML类型。结果变为了XML。
如果有一些特殊的设置,转换规则就会复杂一些。比如:request.addHeader("Accept", "application/xml");表明客户端告诉服务器客户端要的是XML格式的响应,即使现在JSON消息转换器在前,XML消息转换器在后,Spring会优先将JAVA对象转为XML格式的消息返回给客户端,如下面的代码:
private static void test4() throws IOException, HttpMediaTypeNotAcceptableException, NoSuchMethodException {
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
ServletWebRequest webRequest = new ServletWebRequest(request, response);
request.addHeader("Accept", "application/xml");
// response.setContentType("application/json");
// 添加对@RequestBody和@ResponseBody注解的解析和处理的处理器
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(
List.of(
// 添加两个消息转换器:JAVA对象转JSON的消息转换器和JAVA对象转XML的消息转换器
new MappingJackson2HttpMessageConverter(), new MappingJackson2XmlHttpMessageConverter()
));
// 处理一个返回值
processor.handleReturnValue(
new User("张三", 18),
new MethodParameter(A28.class.getMethod("user"), -1),
new ModelAndViewContainer(),
webRequest
);
// 将最终转换的结果放到response中
System.out.println(new String(response.getContentAsByteArray(), StandardCharsets.UTF_8));
}
}
19:13:53.623 [main] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - Using 'application/xml;charset=UTF-8', given [application/xml] and supported [application/json, application/*+json, application/xml;charset=UTF-8, text/xml;charset=UTF-8, application/*+xml;charset=UTF-8]
19:13:53.642 [main] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - Writing [User{name='张三', age=18}]
<User><name>张三</name><age>18</age></User>
除了设置request.addHeader("Accept", "application/xml");以外,还有一个更高优先级的设置,例如: response.setContentType("application/json");
也就是说如果在response中设置了contentType,其对应的消息转换器的优先级会高于request的accept。如下面的代码:
private static void test4() throws IOException, HttpMediaTypeNotAcceptableException, NoSuchMethodException {
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
ServletWebRequest webRequest = new ServletWebRequest(request, response);
request.addHeader("Accept", "application/xml");
response.setContentType("application/json");
// 添加对@RequestBody和@ResponseBody注解的解析和处理的处理器
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(
List.of(
// 添加两个消息转换器:JAVA对象转JSON的消息转换器和JAVA对象转XML的消息转换器
new MappingJackson2HttpMessageConverter(), new MappingJackson2XmlHttpMessageConverter()
));
// 处理一个返回值
processor.handleReturnValue(
new User("张三", 18),
new MethodParameter(A28.class.getMethod("user"), -1),
new ModelAndViewContainer(),
webRequest
);
// 将最终转换的结果放到response中
System.out.println(new String(response.getContentAsByteArray(), StandardCharsets.UTF_8));
}
}
19:18:36.428 [main] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - Found 'Content-Type:application/json' in response
19:18:36.501 [main] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - Writing [User{name='张三', age=18}]
{"name":"张三","age":18}
这里呢,我们总结一下存在多个消息转换器的优先响应关系:
- 优先级最高的是设置了response.setContentType()的消息转换器
- 如果没有设置response.setContentType(), 则以request请求头中的accept为准
- 如果上述两者都没有设定,则以按照多个加入的消息转换器的顺序为准,先添加的优先级高,后添加的优先级低
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
2021-08-13 计算机网络-4-5-ICMP协议