springboot请求参数绑定原理篇

news2024/9/29 21:29:20

上篇文章写了SpringBoot 参数接收只看这一篇文章就够了,只是写了使用方法,没有写为什么,原理是什么,这篇文章也是之前的预先的计划,稍微花点时间整理下,

知其然知其所以然,才算是能彻底掌握,但是说实在话,都是工具,会用是硬道理。有精力了再去搞原理。

1、原理

百度上看到一张图,还蛮好的,直接拿来用了,侵权删。

Spring容器管理的RequestMappingHandlerAdapter对象会自动帮我们分解参数并组装成所需要的对象。

RequestMappingHandlerAdapter完全按照名称匹配且只能组装在request的参数域中提供参数的对象。

上图我花了两个红色框,一个HttpMessageConverter 和 HandlerMethodArgumentResolver

这两个也是今天的重点。

2、HandlerMethodArgumentResolver

2.1 基础概念

HandlerMethodArgumentResolver 方法参数解析器,是Spring Web(SpringMVC)组件中的众多解析器之一,主要用来对Controller中方法的参数进行处理。

2.2 内置resolver

参数

Resolver

HttpServletRequest

ServletRequestMethodArgumentResolver

HttpServletResponse

ServletResponseMethodArgumentResolver

@RequestParam

RequestParamMapMethodArgumentResolver

@PathVariable

PathVariableMapMethodArgumentResolver

@RequestHeader

RequestHeaderMapMethodArgumentResolver

@RequestBody

RequestResponseBodyMethodProcessor

@ModelAttribute

ModelAttributeMethodProcessor

@RequestPart

RequestPartMethodArgumentResolver

@CookieValue

ServletCookieValueMethodArgumentResolver

HttpEntity/RequestEntity

HttpEntityMethodProcessor

2.3 接口说明

public interface HandlerMethodArgumentResolver{/**
	 * 给定的方法参数parameter是否受此解析程序支持。
	 * @param parameter:要检查的方法参数
	 **/
	booleansupportsParameter(MethodParameterparameter);
	/**
	 * 将方法参数从给定请求解析为参数值。
	 * @param parameter: 请求参数
	 * @param mavContainer: 容器
	 * @param webRequest: 请求
	 * @param binderFactory: 用于创建一个WebDataBinder用于数据绑定、校验
	 **/
	Object resolveArgument(MethodParameterparameter,@NullableModelAndViewContainermavContainer,
			NativeWebRequestwebRequest,@NullableWebDataBinderFactorybinderFactory)throwsException;}

3、HttpMessageConverter

3.1 基础概念

负责将请求信息转换为一个对象(类型为 T)

3.2 内置Converter

MappingJackson2HttpMessageConverter 负责读、写JSON格式数据(利用Jackson)

AllEncompassingFormHttpMessageConverter 负责读、写Form表单数据

Jaxb2RootElementHttpMessageConverter 负责读、写XML格式数据(使用JAXB)

ByteArrayHttpMessageConverter 负责读、写二进制格式数据

StringHttpMessageConverter 负责读、写字符串格式数据

ResourceHttpMessageConverter 负责读、写资源文件数据

SourceHttpMessageConverter 负责读、写资源数据

3.3 接口说明

public interface HttpMessageConverter<T> {
    boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);
    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;
}

getSupportedMediaTypes:获取支持的MediaType集合(如:text/html,text/plain,application/json)

canRead:判断是否能读,针对请求

read:将请求数据进行格式转换(canRead方法返回值为true时调用)

canWrite:判断是否能写,针对响应

write:将响应数据进行格式转换(canWrite方法返回值为true时调用)

4、自定义HandlerMethodArgumentResolver

自定义的过程基本上就是继承接口,然后加入到系统里

4.1、创建springboot项目

直接跟着指引,下一步就可以完成了,并没有太多的技术含量,这里也不再赘述

4.2、创建自定义HandlerMethodArgumentResolver

import com.example.webdemo.domain.po.Person;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

public class PersonArgumentResolver implements HandlerMethodArgumentResolver {
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterType().equals(Person.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        String s = webRequest.getParameter("person");
        String[] split = s.split(":");
        Person person = new Person();
        person.setName(split[0]);
        person.setAge(split[1]);
        return person;
    }
}

Person定义

@Data
public class Person {
    private String name;
    private String age;
}

4.3、将自定义Resolver加入到系统中

@Configuration
public class MyWebmvcConfiguration implements WebMvcConfigurer {
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new PersonArgumentResolver());
    }
}

4.4 测试接口

@RestController
@RequestMapping
public class TestController{
@RequestMapping("/up")public Stringtest1(Personperson){
System.out.println(person);return"Hello";
}
}

测试脚本

curl --request GET \
  --url 'http://localhost:16002/up?person=chongxin: 1'

记得在PersonArgumentResolver里面打个断点哦

5、自定义Converter

5.1、创建springboot项目

直接沿用上面的吧,稍微的删除下

5.2、自定义MessageConverter

public class SecondHttpMessageConverter extends AbstractHttpMessageConverter<Person> {
    public SecondHttpMessageConverter() {
        super(new MediaType("application", "x-xiangcai", Charset.forName("UTF-8")));
    }
    @Override
    protected boolean supports(Class<?> clazz) {
        return Person.class.isAssignableFrom(clazz);
    }

    @Override
    protected Person readInternal(Class<? extends Person> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        String s = StreamUtils.copyToString(inputMessage.getBody(), Charset.defaultCharset());
        String[] split = s.split(":");
        Person person = new Person();
        person.setName(split[0]);
        person.setAge(split[1]);
        return person;
    }
    @Override
    protected void writeInternal(Person person, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
    }
}

5.3 加入配置中

@Configuration
public class MyWebmvcConfiguration implements WebMvcConfigurer{
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>>converters){
SecondHttpMessageConvertersecondHttpMessageConverter=newSecondHttpMessageConverter();
converters.add(secondHttpMessageConverter);
}}

5.4 测试代码

@RestController
public class TestController {
    @RequestMapping("/up")
    public String test1(@RequestBody Person person) {
        System.out.println(person);
        return "Hello";
    }

}

注意看这里的代码和上面是不同的,不要使用上面的接口哦

测试脚本

curl --request POST \
  --url http://localhost:16002/up \
  --header 'Content-Type: application/x-xiangcai' \
  --header 'content-type: text/plain' \
  --data 'chongxin: 1'

注意这里使用的是post,并且设置了Content-Type: application/x-xiangcai

5.5 注意点

处理过程会按集合顺序匹配合适的消息转换器,如果有合适的,就会使用该消息转换器处理(读、写),后续的消息转换器不再执行。

自定义的消息转换器要想生效,必须放到集合中相同类型的消息转换器前面,原因参考第二点。

WebMvcConfigurer.configureMessageConverters方法会覆盖默认消息转换器集合

WebMvcConfigurer.extendMessageConverters方法不会覆盖默认消息转换器集合

6、总结

6.1 converter和Resolver的区别:

Converter 主要是用来做数据body的计息,针对@RequestBody

Resolver 主要是用来做数据类型转换,主要是用来解析参数,针对基于键值对的

6.2 自定义套路

继承相应的接口,在Configuration加入列表中

6.3 调用顺序

从数据流图中可以看到先是使用resolver,然后调用converter

6.4 最后贴下debug的图

方便你找到断点,贯穿整个流程

赠人玫瑰,手留余香,感谢点赞

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/186143.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何用IDEA创建SpringBoot项目

一、创建一个 Spring Initializr 工程 next后选择2.7.8版本&#xff0c;勾选以下几个 Web里的spring bootTemplate Engines 里的 ThymeleafSQL里的MyBatis Framework 和 Mysql Driver 然后finish完成 二、配置resources文件 2.1、 application.properties&#xff1a; #??…

Docker容器命令无权限,WEB访问403

问题背景(描述) 部署dockerWeb后&#xff0c;重启访问403,详细如下 docker容器正常运行,且开机自启 #通过如下命令开机自启 docker update --restart always 容器id但是访问web服务出现403. 进入容器后,输入命令提示如下: 解决方案 关闭selinux SELinux(Security-Enhanced…

【网络安全】记一次红队渗透实战项目

前言 【一一帮助安全学习&#xff08;网络安全面试题学习路线视频教程工具&#xff09;一一】 一、信息收集 信息收集非常重要&#xff0c;有了信息才能知道下一步该如何进行&#xff0c;接下来将用nmap来演示信息收集 1、nmap扫描存活IP 由于本项目环境是nat模式需要项目…

【Java基础】——面向对象:封装

【Java基础】——面向对象:封装一、类和对象二、类的结构&#xff1a;属性、方法、构造器1、属性2、方法2.1、方法的定义2.2、方法的重载2.3、可变个数的形参2.4、方法参数的值传递机制3、构造器3.1、构造器的特征3.2、构造器的作用&#xff1a;3.3、构造器重载三、封装与隐藏1…

细菌,真菌,病毒——感染,免疫反应以及治疗用药差异

谷禾健康 与人类密切相关的微生物 我们的世界大到浩瀚宇宙&#xff0c;小到微观下的生物分子。我们总说漫天繁星&#xff0c;其实身边微生物数量可能更多。动物、植物、真菌、细菌、病毒等&#xff0c;共同构成了丰富多彩的生命世界。 细菌、真菌、病毒是其中的三个大类&#x…

spring integration使用:消息路由

系列文章目录 …TODO spring integration开篇&#xff1a;说明 …TODO spring integration使用&#xff1a;消息路由 spring integration使用&#xff1a;消息路由系列文章目录前言消息路由的概念二、路由的分类基于内容的路由器spring integration中的实现RecipientListRoute…

Python property()函数:定义属性

我们一直在用“类对象.属性”的方式访问类中定义的属性&#xff0c;其实这种做法是欠妥的&#xff0c;因为它破坏了类的封装原则。正常情况下&#xff0c;类包含的属性应该是隐藏的&#xff0c;只允许通过类提供的方法来间接实现对类属性的访问和操作。因此&#xff0c;在不破坏…

AOP的四种增强方式

1. 前置增强&#xff0c;在核心功能之前执行的额外功能 public class MyBeforeAdvice implements MethodBeforeAdvice{Overridepublic void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {System.out.print("this is my before advice!");Str…

渲染函数render

文章目录节点、树以及虚拟 DOM树节点虚拟 DOMvue中render函数的作用render函数去创建子组件内容createElement官方文档参考节点、树以及虚拟 DOM 在深入渲染函数之前&#xff0c;了解一些浏览器的工作原理是很重要的。以下面这段 HTML 为例&#xff1a; <div><h1>…

user-select:none真的能禁止文本的复制粘贴吗?

1. 前言 面向搜索引擎开发时&#xff0c;我们经常看到这样的情况&#xff1a;登录后复制。 由于设置了css属性 user-select:none&#xff0c;此时鼠标无法实现选中文本&#xff0c;也就无法复制文本&#xff0c;通常会采用这种方式来禁止复制文本。打开开发者工具-审查元素&am…

k-means聚类

一、概述 当前人工智能技术实现的一种主要手段是机器学习&#xff0c;而机器学习能够解决的问题主要有三种&#xff1a;分类、聚类、回归&#xff0c;有监督的是分类&#xff0c;无监督的是聚类。所谓聚类&#xff0c;就是以一定的方法将一堆样本依它们本身的数据特性划分成不同…

docker安装mongdb

MongoDB是一个介于关系数据库和非关系数据库之间的产品&#xff0c;是非关系数据库当中功能最丰富&#xff0c;最像关系数据库的。它支持的数据结构非常松散&#xff0c;是类似json的bson格式&#xff0c;因此可以存储比较复杂的数据类型。Mongo最大的特点是它支持的查询语言非…

【操作系统】备忘录

进程上下文切换 用户态、内核态 内核态&#xff1a;也叫内核空间&#xff0c;是内核进程/线程所在的区域。主要负责运行系统、硬件交互。 用户态&#xff1a;也叫用户空间&#xff0c;是用户进程/线程所在的区域。主要用于执行用户程序。 内核态与用户态的区别 内核态与用户…

spring mvc文档阅读笔记——02

目录标题一、Asynchronous Requests&#xff08;异步请求&#xff09;&#xff08;一&#xff09;阻塞和非阻塞,同步和异步&#xff08;二&#xff09;DeferredResult&#xff08;三&#xff09;Callable二、跨域请求CORS&#xff08;一&#xff09;实现跨域请求的方式&#xf…

数据持久化-RDB-AOF

定义 将数据从掉电易失的内存放到永久储存的设备上 因为所有的数据都在内存是&#xff0c;所有必须得持久化 redis提供两种持久化方案 RDB默认开启、AOF RDB 1,保存真是的数据 2&#xff0c;将服务器包含的所有数据库数据以二进制文件形式保存到磁盘里面 3&#xff0c;默认…

JDBC管理事务

基本介绍 就是处理在mysql的事务 复习一下:事务是一组sql语句需要开启和提交&#xff0c;事务中的sql语句要么全部生效&#xff0c;要么全部不生效&#xff0c;提交之后就是全部生效&#xff0c;中间可以设置保存点&#xff0c;回退到保存点&#xff0c;或直接回退到最开始事务…

1.2.1存储结构:层次化存储结构、外存(辅存)、内存(主存)、CPU内部的寄存器、Cache(相联存储器)

1.2.1存储结构&#xff1a;层次化存储结构、外存&#xff08;辅存&#xff09;、内存&#xff08;主存&#xff09;、CPU内部的寄存器、Cache&#xff08;相联存储器&#xff09;存储系统--层次化存储结构外存&#xff08;辅存&#xff09;内存&#xff08;主存&#xff09;CPU…

并发编程学习(八):ReentrantLock

ReentrantLock 是java.util.concurrent.locks包下的类。相对于synchronized,它具备如下特性&#xff1a;可中断。可以设置超时时间。可以设置公平锁。支持多个条件变量。即可以有个多个waitset等待队列。与synchronized都支持可重入。ReentrantLock的基本语法&#xff1a;// 获…

数学建模相关竞赛零基础上手与入门介绍

文章目录1、赛事介绍与报名2、学习与训练2.1 比赛题目选择范围2.2 赛前组队与分工2.3 比赛时间分配1、赛事介绍与报名 什么是数学建模&#xff1f; 定义&#xff1a; 生活中的各种问题(如股票预测、火灾报警统计等)&#xff0c;运用数学的方式去阐述并解决它。 数学建模赛事 …

cisp证书含金量怎么样?值不值得考?

这是CISP考试报名条件参考&#xff1a; 成为CISP&#xff0c;必须满足以下基本要求&#xff1a; 申请CISE、CISO注册资质&#xff0c;需满足以下教育和工作经验要求&#xff1a; &#xff08;1&#xff09;教育和工作经历要求&#xff1a;硕士及硕士以上学历&#xff0c;具备…