在 Spring MVC 中设置 JSON Content Type
1、简介
Content Type 表示请求/响应数据的媒体类型(Media Type)。当 Conroller 收到 Web 请求时,它会根据 Content Type 解析请求数据,然后根据 Content Type 响应数据。目前在 REST 中最流行的 Content Type 就是 JSON。
本文将会带你了解如何在 Spring MVC 中设置请求和响应的 Content Type。
2、@RequestMapping 注解
简而言之,@RequestMapping
是将 Web 请求映射到 Spring Controller 的重要注解。它有各种属性,包括 HTTP 方法、请求参数、Header 和媒体类型。
一般来说,媒体类型分为两类:消费(请求)、生产(响应)。也可以在 Spring 中定义自定义媒体类型。
其目的在于限制 Handler 可消费、生产的媒体类型。
2.1、请求的媒体类型
通过 consumes
属性指定 Controller 可接受的媒体类型,可以有多个。
定义一个简单的端点:
@RequestMapping(value = "/greetings", method = RequestMethod.POST, consumes="application/json")
public void addGreeting(@RequestBody ContentType type, Model model) {
}
如果 Controller 不支持客户端指定的媒体类型,则会返回 HTTP “415 Unsupported Media Type” 错误。
2.2、响应的媒体类型
与 consumes
属性不同,produces
指定 Controller 发送回客户端的媒体类型,这也是一个列表,可以指定多个。如果系统不能按照这个媒体类型响应资源,则会响应 “406 Not Acceptable” 错误。
一个响应 JSON 字符串的示例 API 端点。
@GetMapping(
value = "/greetings-with-response-body",
produces="application/json"
)
public String getGreetingWhileReturnTypeIsString() {
return "{\"test\": \"Hello\"}";
}
使用 cURL 进行测试:
curl http://localhost:8080/greetings-with-response-body
响应如下:
{ "test": "Hello" }
3、在 Spring Boot 中使用 Rest Controller
如果在 Spring Boot 中使用 Rest Controller,那么通过一个注解就可以处理很多事情。@RestController
注解将 @Controller
和 @ResponseBody
注解合二为一,这会应用于该类中定义的所有端点。
3.1、使用 @RestController 注解
Jackson ObjectMapper
类可从字符串、Stream 或文件解析 JSON。如果 classpath 上有 Jackson,Spring 应用中的任何 Controller 都会默认渲染 JSON 响应。
添加一个单元测试,以验证响应:
@Test
public void givenReturnTypeIsString_whenJacksonOnClasspath_thenDefaultContentTypeIsJSON()
throws Exception {
String expectedMimeType = "application/json";
String actualMimeType = this.mockMvc.perform(MockMvcRequestBuilders.get("/greetings-with-response-body", 1))
.andReturn().getResponse().getContentType();
Assert.assertEquals(expectedMimeType, actualMimeType);
}
3.2、使用 ResponseEntity
与 @ResponseBody
相反,ResponseEntity
是一种通用类型,代表整个 HTTP 响应。因此,可以控制其中的任何内容:状态码、Header 和 Body。
定义一个新的端点:
@GetMapping(
value = "/greetings-with-response-entity",
produces = "application/json"
)
public ResponseEntity<String> getGreetingWithResponseEntity() {
final HttpHeaders httpHeaders= new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
return new ResponseEntity<String>("{\"test\": \"Hello with ResponseEntity\"}", httpHeaders, HttpStatus.OK);
}
在浏览器的控制台中,可以看到以下响应:
{"test": "Hello with ResponseEntity"}
通过测试用例来验证响应的 Content Type:
@Test
public void givenReturnTypeIsResponseEntity_thenDefaultContentTypeIsJSON() throws Exception {
String expectedMimeType = "application/json";
String actualMimeType = this.mockMvc.perform(MockMvcRequestBuilders.get("/greetings-with-response-entity", 1))
.andReturn().getResponse().getContentType();
Assert.assertEquals(expectedMimeType, actualMimeType);
}
3.3、返回 Map<String, Object>
还可以返回一个通用的 Map
,这个 Map
会被解析为 JSON 字符串后响应给客户端。
定义一个新的端点:
@GetMapping(
value = "/greetings-with-map-return-type",
produces = "application/json"
)
public Map<String, Object> getGreetingWhileReturnTypeIsMap() {
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("test", "Hello from map");
return map;
}
测试:
curl http://localhost:8080/greetings-with-map-return-type
响应如下:
{ "test": "Hello from map" }
4、总结
本文介绍了如何在 Spring boot 中为 Spring MVC 中设置请求和响应的 Content Type,以及如何通过 ResponseEntity 类控制响应的状态码、Header 和 Body。
Ref:https://www.baeldung.com/spring-mvc-set-json-content-type