Spring 提供的将资源的 Java 表述形式转换为发送给客户端的形式

  • 内容协商 - Content Negotiation: 选择一个视图,将模型渲染为呈现给客户端的表述形式
  • 消息转换器 - Message Conversion: 通过一个消息转换器将控制器所返回的的的对象转换为呈现给客户端的表述形式

内容协商 - Content Negotiation

内容协商的步骤:

  1. 确定请求的媒体类型
    • 先根据请求 URI 的文件扩展名,如 .json 确定请求的类型是 Json
    • 文件扩展名不能得到任何媒体类型的话,考虑请求 Accept 头部信息。Accept 头部接受的类型就表明了客户端的想要的 MIME 类型
    • 没有头部信息,默认接受 / 作为默认的内容类型,也就是可以接受各种形式的资源表述
  2. 找到适合请求媒体类型的最佳视图

为此,提供了一个 ContentNegotiatingViewResolver 内容协商视图解析器

ContentNegotiatingViewResolver要求其他的视图解析器将逻辑视图名解析为视图。解析得到的每个视图都会放到一个列表中。这个列表装配完成后,ContentNegotiatingViewResolver会循环客户端请求的所有媒体类型,在候选的视图中查找能够产生对应内容类型的视图。第一个匹配的视图会用来渲染模型。

假设控制器方法返回了一个 spittles 逻辑视图名称, 程序中定义了两个试图解析器,对应的视图渲染的表述形式不一样,如 HTML 和 Json, 如果都存在对应的视图,这时,会根据请求要求的类型,找到第一个匹配其类型的视图,渲染模型数据。

消息转换器 - Message Conversion

@ResponseBody注解会告知Spring,我们要将返回的对象作为资源发送给客户端,并将其转换为客户端可接受的表述形式。DispatcherServlet将会考虑到请求中Accept头部信息,并查找能够为客户端提供所需表述形式的消息转换器。

使用 MappingJackson2XmlHttpMessageConverter, 实现 Json 与 Java 对象转换需要引入依赖:

1
2
3
4
5
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>

使用 MappingJackson2XmlHttpMessageConverter, 实现 XML 与 Java 对象转换需要引入依赖:

1
2
3
4
5
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.9.8</version>
</dependency>

@RestController 注解

表明该控制器的所有处理方法都应用了消息转换功能,相当于为每个方法添加 @ResponseBody 注解,能将方法返回的 Java 对象转换为合适的资源表述,作为响应返回给客户端。

FactoryBean

Restful Client

编写 Restful Client 的代码也同样存在样板式代码,也就是说有很多相同的代码要重复写,如

  • 创建 HttpClient 客户端
  • 创建请求,填充头部信息,请求体
  • 执行请求,对返回的响应进行解析处理

RestTemplate 解救人民于水火,提供了各种 Http Method 的请求,并且简化了请求的代码,只需要初始化一个 Template, 就可以调用各种 Http Method 对应的方法执行请求, RestTemplate 可以通过注入的方式来使用。

示例代码:

Get 请求 (template.getForObject)

1
2
3
4
RestTemplate template = new RestTemplate();
String parameterUri = "http://localhost:8080/rest/blog/responseEntity/{name}";
MessageEntity messageEntity = template.getForObject(parameterUri, MessageEntity.class, "Guoph");
System.out.println(messageEntity);

指定请求头部的 Post 请求 (template.exchange)

1
2
3
4
5
6
7
8
9
10
String parameterUri = "http://localhost:8080/rest/blog/responseEntity/{name}";

HttpHeaders headers = new HttpHeaders();
headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
HttpEntity<Object> httpEntity = new HttpEntity<>(headers);

ResponseEntity<MessageEntity> responseEntity = template.exchange(parameterUri, HttpMethod.GET, httpEntity,
MessageEntity.class, "Guoph");

System.out.println(responseEntity);