返回顶部
首页 > 资讯 > 后端开发 > Python >SpringBoot响应处理实现流程详解
  • 320
分享到

SpringBoot响应处理实现流程详解

2024-04-02 19:04:59 320人浏览 泡泡鱼

Python 官方文档:入门教程 => 点击学习

摘要

目录1、相关依赖2、ReturnValueHandlers—返回值处理器3、HttpMessageConvert—消息转换器4、开启浏览器参数方式内容协商功能

1、相关依赖

WEB项目引入的启动器spring-boot-starter-web中含有

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-JSON</artifactId>
	<version>2.7.0</version>
	<scope>compile</scope>
</dependency>

这个依赖下面又有jackson的相关依赖,用于json的转换

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.13.3</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.datatype</groupId>
  <artifactId>jackson-datatype-jdk8</artifactId>
  <version>2.13.3</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.datatype</groupId>
  <artifactId>jackson-datatype-jsr310</artifactId>
  <version>2.13.3</version>
  <scope>compile</scope>
</dependency>

2、ReturnValueHandlers—返回值处理器

之前我们分析了参数解析器argumentResolvers的相关源码,了解了请求中的参数是如何找到合适的参数解析器,并与方法的入参进行绑定的,那么问题来了,响应值的返回值处理器是如何找到的呢?

要分析源码,我们还是得进入DispatcherServlet这个类下的doDiapatch()方法

与之前分析参数解析器一样的流程,我们跟到了RequestMappingHandlerAdapter这个类下的invokeHandlerMethod()方法

通过断点可以看到我们默认支持15种返回值解析器

那么他是怎么从这么多返回值解析器中选出自己支持的那一个呢?

我们可以发现,这些返回值解析器都是实现了HandlerMethodReturnValueHandler接口

package org.springframework.web.method.support;
import org.springframework.core.MethodParameter;
import org.springframework.lang.Nullable;
import org.springframework.web.context.request.NativeWebRequest;
public interface HandlerMethodReturnValueHandler {
    boolean supportsReturnType(MethodParameter returnType);
    void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}

此接口下只有2个方法,一个是判断是否支持此类型返回值,另一个是处理返回值的方法

是不是和之前的参数解析器的接口类有异曲同工之妙?

没错,我们正是使用这两个方法来寻找适合自己的返回值解析器以及处理我们的返回值

跟着断点一直向下,我们跟到了HandlerMethodReturnValueHandlerComposite类下的handleReturnValue()方法,在这里,我们就找到了对应的解析器并执行了相关方法

public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
	// 获取自己适合的返回值解析器
    HandlerMethodReturnValueHandler handler = this.selectHandler(returnValue, returnType);
    if (handler == null) {
        throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
    } else {
    	// 调用该返回值解析器中的处理返回值的方法
        handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
    }
}
@Nullable
private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
	// 判断是否是异步的返回值
    boolean isAsyncValue = this.isAsyncReturnValue(value, returnType);
    Iterator var4 = this.returnValueHandlers.iterator();
    HandlerMethodReturnValueHandler handler;
    // 使用do-while进行遍历,找出支持当前返回值类型的解析器
    do {
        do {
            if (!var4.hasNext()) {
                return null;
            }

            handler = (HandlerMethodReturnValueHandler)var4.next();
        } while(isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler));
    } while(!handler.supportsReturnType(returnType));
    return handler;
}

最终,我们确定使用解析器RequestResponseBodyMethodProcessor可以处理标注了@ResponseBody的返回值

3、HttpMessageConvert—消息转换器

除了寻找合适的返回值解析器之外,我们还有一个问题要思考

为什么我们在控制器类的方法上加一个@ResponseBody注解就能将响应信息转换成json格式呢?

这个转换是怎样实现的呢?

我们接着上面的代码继续往下debug

之前我们已经定位到了使用RequestResponseBodyMethodProcessor来处理@ResponseBody的返回值,所以我们继续深入到这个类下的handleReturnValue()

public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
	mavContainer.setRequestHandled(true);
	// 创建输入和输出信息
	ServletServerHttpRequest inputMessage = this.createInputMessage(webRequest);
	ServletServerHttpResponse outputMessage = this.createOutputMessage(webRequest);
	// 使用消息转换器进行写出操作
	this.writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}

然后我们来分析解析器父类AbstractMessageConverterMethodProcessor下的writeWithMessageConverters()方法

首先我们了解一个概念:什么是内容协商?

浏览器默认会以请求头的方式告诉服务器他能接受什么样的内容类型,这里的q代表优先级

然后服务器最终根据自己自身的能力,决定服务器能生产出什么样内容类型的数据

所以在writeWithMessageConverters()方法中我们获取到浏览器能接受什么内容

以及服务器能产生什么内容

然后我们经过协商,决定返回application/json格式的数据

重点来了:这里有一系列的消息转换器,我们到底使用哪个呢?

随便点进一个消息转换器,我们发现他都是实现了HttpMessageConverter这个接口

这里面有2个方法,canRead()和canWrite()来帮助我们判断能否支持源类型和目标类型的消息读写

最终我们确定了,使用MappingJackson2HttpMessageConverter这个消息转换器来进行json转换

package org.springframework.http.converter;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
public interface HttpMessageConverter<T> {
	// 读取,将我们当前消息转换器支持的对象以某种格式读取进来,例如将json数据读取成Person对象
    boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);
	// 写出,我们当前消息转换器支持的对象以某种格式写出去,例如将Person对象以json格式写出去
    boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);
    List<MediaType> getSupportedMediaTypes();
    default List<MediaType> getSupportedMediaTypes(Class<?> clazz) {
        return !this.canRead(clazz, (MediaType)null) && !this.canWrite(clazz, (MediaType)null) ? Collections.emptyList() : this.getSupportedMediaTypes();
    }
    T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException;
    void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException;
}

然后我们在此处调用MappingJackson2HttpMessageConverter父类AbstractGenericHttpMessageConverter中的write()方法

走到AbstractJackson2HttpMessageConverter类下的writeInternal()方法

可以看出,它利用了底层的Jackson的objectMapper进行转换

这样,我们就完成了Person数据到json格式的转换

大概流程如下

  • 判断当前响应头中是否已经有确定的媒体类型,即MediaType
  • 获取客户端(PostMan、浏览器)支持接收的内容类型(获取客户端Accept请求头字段)
  • 遍历循环所有当前系统的 MessageConverter,看谁支持操作这个对象(Person),找到支持操作Person的converter,把该converter支持的媒体类型统计出来放到集合中,这样就获取到服务端能提供哪些媒体类型
  • 进行内容协商,找到最佳匹配媒体类型
  • 用 支持 将对象转为 最佳匹配媒体类型 的converter,调用它进行转化

4、开启浏览器参数方式内容协商功能

如果需要返回xml格式的数据,那么需要额外导入相关依赖

<dependency>
	<groupId>com.fasterxml.jackson.datafORMat</groupId>
	<artifactId>jackson-dataformat-xml</artifactId>
</dependency>

我们可以看到,浏览器是默认支持如下返回格式的,一般情况下,我们无法指定自己需要的返回格式

但是我们可以通过修改配置+添加参数的方式指定我们需要的格式

首先,我们在yaml文件中,开启基于浏览器参数方式内容协商功能

spring:
  mvc:
    contentneGotiation:
      favor-parameter: true

一旦此参数设置为true,那么我们的内容协商管理器contentNegotiationManager中,除了原有的从请求头获取媒体类型的策略之外,还多了一个从请求参数中获取媒体类型的策略,它支持xml和json两种媒体类型

然后我们使用http://localhost:8080/testPathVariable/001/split/decade?format=xml或者http://localhost:8080/testPathVariable/001/split/decade?format=json指定我们需要的返回格式

到此这篇关于SpringBoot响应处理实现流程详解的文章就介绍到这了,更多相关SpringBoot响应处理内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: SpringBoot响应处理实现流程详解

本文链接: https://lsjlt.com/news/168920.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • SpringBoot响应处理实现流程详解
    目录1、相关依赖2、ReturnValueHandlers—返回值处理器3、HttpMessageConvert—消息转换器4、开启浏览器参数方式内容协商功能...
    99+
    2024-04-02
  • SpringBoot封装响应数据实现过程详解
    目录业务处理封装响应值传值容器ModelModelMapHttpServletRequest重定向传值业务处理 这是通过 Spring 在 Controller中注入Service模...
    99+
    2023-05-20
    SpringBoot封装响应数据 SpringBoot响应数据的封装
  • SpringBoot封装响应处理超详细讲解
    目录背景报文基本格式创建枚举类定义统一返回结果实体类定义返回工具类统一报文封装在接口中的使用统一异常处理小结背景 越来越多的项目开始基于前后端分离的模式进行开发,这对后端接口的报文格...
    99+
    2022-12-23
    SpringBoot封装响应处理 SpringBoot封装
  • 详解SpringBoot异常处理流程及原理
    异常处理流程 执行目标方法,目标方法运行期间有任何异常都会被catch捕获,并标志当前请求结束,dispatchException抛出异常 进入视图解析流程,并渲染页面,发生异常时...
    99+
    2024-04-02
  • SpringBoot错误处理流程深入详解
    目录一、错误处理二、底层相关组件三、异常处理流程四、定制错误处理逻辑1、自定义错误页面2、使用注解或者默认的异常处理3、自定义异常处理解析器一、错误处理 默认情况下,Spring B...
    99+
    2024-04-02
  • 处理流式 HTTP 响应
    php小编子墨为您介绍处理流式 HTTP 响应的方法。在开发Web应用程序时,我们经常需要处理大文件的下载或者实时流媒体的传输。而传统的一次性加载整个响应内容的方式会导致内存占用过高,...
    99+
    2024-02-09
    内存占用
  • SpringBoot详解各类请求和响应的处理方法
    目录1. HttpServletRequest与HttpServletResponse2. GET类型的请求2.1 /studentscurrent=1&limit=202....
    99+
    2024-04-02
  • SpringBoot自定义Starter实现流程详解
    目录starter起步依赖starter命名规则自定义starternew module添加依赖simplebean自动配置类META-INF\spring.factories在sp...
    99+
    2024-04-02
  • Springboot详解实现食品仓库管理系统流程
    目录一,项目简介二,环境介绍三,系统展示3.1 系统功能模块设计3.1.1 登录模块3.1.2 客户管理模块3.1.3 供应商管理功能3.1.4 商品管理模块3.1.5 商品进货管理...
    99+
    2024-04-02
  • SpringMVC响应处理详细解读
    目录数据处理及跳转1.结果跳转方式2.ResponseBody响应json数据1、导入关键jar导入依赖2、标签配置不过滤静态资源数据处理及跳转 1.结果跳转方式 ①.ModelAn...
    99+
    2024-04-02
  • VUE响应式原理的实现详解
    目录总结前言 相信vue学习者都会发现,vue使用起来上手非常方便,例如双向绑定机制,让我们实现视图、数据层的快速同步,但双向绑定机制实现的核心数据响应的原理是怎么样的呢,接下来让我...
    99+
    2024-04-02
  • 详解vue3 响应式的实现原理
    目录核心设计思想Vue.js 2.x 响应式Vue.js 3.x 响应式依赖收集:get 函数派发通知:set 函数总结源码参考核心设计思想 除了组件化,Vue.js 另一个核心设计...
    99+
    2024-04-02
  • Springboot详解RocketMQ实现广播消息流程
    RocketMQ消息模式主要有两种:广播模式、集群模式(负载均衡模式) 广播模式是每个消费者,都会消费消息; 负载均衡模式是每一个消费只会被某一个消费者消费一次; 我们业务上一般用的...
    99+
    2024-04-02
  • SpringBoot整合Mybatis与druid实现流程详解
    目录SpringBoot整合junitSpringBoot整合junitSpringBoot整合junit的classesSpringBoot整合Mybatis整合前的准备整合Myb...
    99+
    2022-11-13
    SpringBoot整合Mybatis与druid SpringBoot整合Mybatis SpringBoot整合druid
  • SpringBoot超详细讲解请求处理流程机制
    目录1. 背景2. Spring Boot 的请求处理流程设计3. Servlet服务模式请求流程分析3.1 ServletWebServerApplicationContext分析...
    99+
    2024-04-02
  • Java 实现限流器处理Rest接口请求详解流程
    Maven依赖 <dependency> <groupId>com.google.guava</groupI...
    99+
    2024-04-02
  • Spring MVC数据响应处理详解
    目录1. 内置视图解析器2. 使用原生servlet的对象传递数据3. 使用ModelAndView对象传输数据4. 使用Model、Map、ModelMap传输数据5. 使用ses...
    99+
    2024-04-02
  • 图解Vue 响应式流程及原理
    目录阅读本文能够帮助你什么?一、组件化流程1. 整个new Vue阶段做了什么?2. 普通dom元素如何渲染到页面?3. 组件如何渲染到页面?4. Vue组件化简化流程二、响应式流程...
    99+
    2024-04-02
  • springboot与vue详解实现短信发送流程
    目录一、前期工作1.开启邮箱服务2.导入依赖3.配置application.yaml文件二、实现流程1.导入数据库2.后端实现编写实体类编写工具类ResultVo编写dao层接口配置...
    99+
    2024-04-02
  • Springboot实现动态定时任务流程详解
    目录一、静态二、动态1、基本代码2、方案详解2.1 初始化2.2 单次执行2.3 停止任务2.4 启用任务三、小结一、静态 静态的定时任务可以直接使用注解@Scheduled,并在启...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作