(三)、SpringBoot核心功能
2.Web
4.数据响应与内容协商
(1).响应JSON
(1.1)jackson.jar+@ResponseBody
在SpringMVC场景中,并不会自动给我们返回Json字符串的也没有Json字符串的过滤器,在SpringBoot中
只要我们使用了@ResponseBody (就会利用返回值处理器里面的消息转换器进行处理)
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> web场景自动引入了json场景 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-json</artifactId> <version>2.3.4.RELEASE</version> <scope>compile</scope> </dependency>
给前端自动返回json数据;
package com.jsxs.controller; import com.jsxs.bean.Person; import com.jsxs.bean.Pet; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody; import java.text.ParseException; import java.text.SimpleDateFormat; /** * @Author Jsxs * @Date 2023/7/6 10:16 * @PackageName:com.jsxs.controller * @ClassName: ResponseTestController * @Description: TODO * @Version 1.0 */ @Controller @ResponseBody public class ResponseTestController { @GetMapping("/test/person") public Person person() throws ParseException { Person person = new Person("jsxs", 12, new SimpleDateFormat("yyyy-MM-dd").parse("2012-02-01"), new Pet("哈吉米", 2)); return person; } }
(1.1.1)、返回值解析器
15个方法返回值解析器
try { this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); }
@Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType); if (handler == null) { throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName()); } handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); }
RequestResponseBodyMethodProcessor 类。 @Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { mavContainer.setRequestHandled(true); ServletServerHttpRequest inputMessage = createInputMessage(webRequest); ServletServerHttpResponse outputMessage = createOutputMessage(webRequest); // 使用消息转换器进行调用 // Try even with null return value. ResponseBodyAdvice could get involved. ⭐ writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage); }
(1.1.2)、返回值解析器原理
- 1、返回值处理器判断是否支持这种类型返回值 supportsReturnType
- 2、返回值处理器调用 handleReturnValue 进行处理
- 3、
RequestResponseBodyMethodProcessor
可以处理返回值标了@ResponseBody
注解的。
- 利用
MessageConverters
进行处理 将数据写为json
- 1、内容协商(浏览器默认会以请求头的方式告诉服务器他能接受什么样的内容类型 浏览器接受7种)
- 2、服务器最终根据自己自身的能力,
决定服务器能生产出什么样内容类型的数据
, - 3、SpringMVC会挨个遍历所有容器底层的
HttpMessageConverter (消息转换器)
,看谁能处理?
- 1、得到MappingJackson2HttpMessageConverter可以将对象写为json
- 2、利用MappingJackson2HttpMessageConverter将对象转为json再写出去。
(1.2).SpringMVC到底支持哪些返回值
这里对应着15种返回值解析器
ModelAndView Model View ResponseEntity ResponseBodyEmitter StreamingResponseBody HttpEntity HttpHeaders Callable DeferredResult ListenableFuture CompletionStage WebAsyncTask 有 @ModelAttribute 且为对象类型的 @ResponseBody 注解 ---> RequestResponseBodyMethodProcessor;
(1.3)/HTTPMessageConverter原理
(1.3.1)、MessageConverter规范
HttpMessageConverter: 看是否支持将 此 Class类型的对象,转为MediaType类型的数据。
例子:Person对象转为JSON。或者 JSON转为Person
(1.3.2)、默认的MessageConverter
0 - 只支持Byte类型的 1 - String 2 - String 3 - Resource 4 - ResourceRegion 5 - DOMSource.class \ SAXSource.class) \ StAXSource.class \StreamSource.class \Source.class 6 - MultiValueMap 7 - true (不管是谁直接为true,也就是说不管是啥文件直接接受) 8 - true (不管是谁直接为true,也就是说不管是啥文件直接接受) 9 - 支持注解方式 xml处理的。
最终 MappingJackson2HttpMessageConverter 把对象转为JSON(利用底层的jackson的objectMapper转换的)
·AbstractGenericHttpMessageConverter类种的·
outputMessage.getBody().flush();
(2).内容协商 (MessageConverter)
根据客户端接收能力不同,返回不同媒体类型的数据。
(2.1)、引入XML文件
<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> </dependency>
(2.2)、postman分别测试返回json和xml
只需要改变请求头中Accept字段。Http协议中规定的,告诉服务器本客户端可以接收的数据类型。
(2.3)、基于请求参数的内容协商 ⭐⭐
为了方便内容协商,开启基于请求参数的内容协商功能。
spring: mvc: contentnegotiation: favor-parameter: true #开启请求参数内容协商模式
通过点开源码我们发现我们需要什么样的类型,我们只需要在路径后面添加上 format='xxx'
格式即可。前提是我们需要什么类型的时候要有依赖在 pom.xml 中。比如我们需要使用xml的,我们要有上面的那个 jackson-dataformat-xml
依赖。
获取json: http://localhost:8080/test/person?format=json
获取xml格式: http://localhost:8080/test/person?format=xml
源码中发现相比于以前的请求头的内容协商多了一个参数的请求协商。
确定客户端接收什么样的内容类型;
1、Parameter策略优先确定是要返回json数据(获取请求头中的format的值
)
2、最终进行内容协商返回给客户端xml即可。