Spring核心接口:HandlerMethodArgumentResolver参数解析器

Spring是一个广泛使用的Java框架,其中一个重要的特性是对HTTP请求的处理。在处理HTTP请求时,Spring提供了许多工具和机制来帮助开发人员更容易地处理请求参数。其中一个机制就是参数解析器。本文将全面介绍Spring中的参数解析器,包括其工作原理、不同类型的参数解析器、如何自定义参数解析器以及如何配置参数解析器。HandlerMethodArgumentResolver

1. 什么是参数解析器

在Spring中,参数解析器是一个接口,它负责将HTTP请求中的参数解析为控制器方法的参数。Spring提供了许多内置的参数解析器,用于处理不同类型的请求参数,例如查询参数、路径变量、请求头、请求体等。开发人员还可以自定义参数解析器,以处理特定的请求参数。

2. Spring中的参数解析器工作原理

当Spring接收到一个HTTP请求时,它会根据请求的URL找到相应的控制器方法。然后,Spring会将请求参数传递给控制器方法。在这个过程中,Spring会使用参数解析器来解析请求参数。

具体来说,Spring会按照以下步骤处理请求参数:

  1. 检查控制器方法的参数类型,以确定应该使用哪个参数解析器。
  2. 根据请求参数的类型和位置,选择一个适当的参数解析器。
  3. 调用参数解析器的resolveArgument方法,将请求参数解析为控制器方法的参数。
  4. 将解析后的参数传递给控制器方法。

3. Spring中内置的参数解析器

Spring提供了许多内置的参数解析器,用于处理不同类型的请求参数。以下是一些常见的参数解析器:

3.1 RequestParamMethodArgumentResolver

RequestParamMethodArgumentResolver用于解析请求参数中的查询参数。它支持简单类型(如int、long、String等)和复杂类型(如POJO等)的查询参数。以下是一个示例:

@GetMapping("/users")
public ResponseEntity<List<User>> getUsers(@RequestParam("name") String name, @RequestParam("age") Integer age) {// ...
}

在这个示例中,Spring会使用RequestParamMethodArgumentResolver来解析name和age查询参数,并将它们传递给getUsers方法。

3.2 PathVariableMethodArgumentResolver

PathVariableMethodArgumentResolver用于解析请求参数中的路径变量。它支持简单类型和复杂类型的路径变量。以下是一个示例:

@GetMapping("/users/{userId}")
public ResponseEntity<User> getUser(@PathVariable("userId") Long userId) {// ...
}

在这个示例中,Spring会使用PathVariableMethodArgumentResolver来解析userId路径变量,并将它传递给getUser方法。

3.3 RequestHeaderMethodArgumentResolver

RequestHeaderMethodArgumentResolver用于解析请求头中的参数。它支持简单类型和复杂类型的请求头参数。以下是一个示例:

@GetMapping("/users")
public ResponseEntity<List<User>> getUsers(@RequestHeader("X-AUTH-TOKEN") String authToken) {// ...
}

在这个示例中,Spring会使用RequestHeaderMethodArgumentResolver来解析X-AUTH-TOKEN请求头参数,并将它传递给getUsers方法。

3.4 RequestBodyMethodArgumentResolver

RequestBodyMethodArgumentResolver用于解析请求体中的参数。它支持简单类型和复杂类型的请求体参数。以下是一个示例:

@PostMapping("/users")
public ResponseEntity<User> createUser(@RequestBody User user) {// ...
}

在这个示例中,Spring会使用RequestBodyMethodArgumentResolver来解析请求体中的JSON数据,并将其映射为User对象,然后传递给createUser方法。

3.5 ServletModelAttributeMethodProcessor

ServletModelAttributeMethodProcessor用于将请求参数绑定到模型对象中。它支持简单类型和复杂类型的模型属性。以下是一个示例:

@GetMapping("/users")
public ResponseEntity<List<User>> getUsers(UserQuery query, Model model) {// ...
}

在这个示例中,Spring会使用ServletModelAttributeMethodProcessor来将请求参数绑定到UserQuery对象中,并将其添加到模型对象中。

3.6 PrincipalMethodArgumentResolver

PrincipalMethodArgumentResolver用于解析当前认证用户的主体信息。它支持Authentication和Principal类型的参数。以下是一个示例:

@GetMapping("/users/me")
public ResponseEntity<User> getCurrentUser(Principal principal) {// ...
}

在这个示例中,Spring会使用PrincipalMethodArgumentResolver来解析当前认证用户的主体信息,并将其传递给getCurrentUser方法。

4. 自定义参数解析器

除了Spring提供的内置参数解析器外,开发人员还可以自定义参数解析器,以处理特定的请求参数。自定义参数解析器需要实现HandlerMethodArgumentResolver接口,并在配置类中将其添加到WebMvcConfigurer中。以下是一个示例:

public class CustomMethodArgumentResolver implements HandlerMethodArgumentResolver {@Overridepublic boolean supportsParameter(MethodParameter parameter) {// 检查参数是否为特定类型return parameter.getParameterType().isAssignableFrom(CustomType.class);}@Overridepublic Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {// 从请求参数中解析CustomType对象String customParam = webRequest.getParameter("customParam");CustomType customType = CustomType.valueOf(customParam);return customType;}
}@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {argumentResolvers.add(new CustomMethodArgumentResolver());}
}

在这个示例中,CustomMethodArgumentResolver用于解析请求参数中的customParam参数,并将其映射为CustomType枚举类型。然后,它被添加到WebMvcConfigurer中,以便Spring在处理请求时使用它。

5. 配置参数解析器

Spring允许开发人员通过配置来自定义参数解析器的行为。以下是一些常见的配置选项:

5.1 启用和禁用参数解析器

开发人员可以通过配置来启用和禁用特定的参数解析器。以下是一个示例:

@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {// 禁用RequestParamMethodArgumentResolverargumentResolvers.removeIf(resolver -> resolver instanceof RequestParamMethodArgumentResolver);// 添加自定义参数解析器argumentResolvers.add(new CustomMethodArgumentResolver());}
}

在这个示例中,RequestParamMethodArgumentResolver被禁用,并添加了一个自定义参数解析器。

5.2 自定义参数解析器的顺序

开发人员可以通过配置来自定义参数解析器的顺序。以下是一个示例:

@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {// 添加自定义参数解析器argumentResolvers.add(new CustomMethodArgumentResolver());// 将自定义参数解析器移动到第一个位置List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(argumentResolvers);resolvers.removeIf(resolver -> resolver instanceof CustomMethodArgumentResolver);resolvers.add(0, new CustomMethodArgumentResolver());argumentResolvers.clear();argumentResolvers.addAll(resolvers);}
}

在这个示例中,自定义参数解析器被移动到了第一个位置,以便Spring优先使用它。

5.3 配置请求参数的数据绑定

开发人员可以通过配置来自定义请求参数的数据绑定行为。以下是一个示例:

@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addFormatters(FormatterRegistry registry) {// 注册自定义日期格式化器registry.addFormatter(new DateFormatter("yyyy-MM-dd"));}
}

在这个示例中,注册了一个自定义日期格式化器,以便Spring在绑定请求参数时使用它。

6. 结论

本文介绍了Spring中的参数解析器,包括其工作原理、不同类型的参数解析器、如何自定义参数解析器以及如何配置参数解析器。通过使用参数解析器,开发人员可以更容易地处理HTTP请求中的参数,从而更快速地开发Web应用程序。

7.原理解析

这里以PathVariableMethodArgumentResolver为例。

PathVariableMethodArgumentResolver 是 Spring 框架中用来处理带 @PathVariable 注解的方法参数解析的内置解析器。Spring 框架内部已经提供了 PathVariableMethodArgumentResolver 的实现,开发者通常不需要自己实现它,但是了解其背后的机制会对理解 Spring MVC 的工作方式有所帮助。下面我将提供一个类似 PathVariableMethodArgumentResolver 功能的简化版本的自定义参数解析器的实现。

首先,我们需要创建一个实现了 HandlerMethodArgumentResolver 接口的类,并且实现 supportsParameterresolveArgument 方法:

import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.HandlerMapping;import javax.servlet.http.HttpServletRequest;
import java.util.Map;@Component
public class CustomPathVariableMethodArgumentResolver implements HandlerMethodArgumentResolver {@Overridepublic boolean supportsParameter(MethodParameter parameter) {// 检查参数是否有 @PathVariable 注解return parameter.hasParameterAnnotation(PathVariable.class);}@Overridepublic Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,HttpServletRequest request, WebDataBinderFactory binderFactory)throws Exception {// 获取 @PathVariable 注解的 value,即路径变量名称PathVariable pathVariable = parameter.getParameterAnnotation(PathVariable.class);Assert.state(pathVariable != null, "No PathVariable annotation");String pathVariableName = pathVariable.value();// 从请求中获取路径变量的 MapMap<String, String> uriTemplateVars =(Map<String, String>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);if (!uriTemplateVars.containsKey(pathVariableName)) {throw new ServletRequestBindingException("Missing path variable '" + pathVariableName + "' for method parameter type [" + parameter.getParameterType() + "]");}// 获取路径变量的值String pathVariableValue = uriTemplateVars.get(pathVariableName);// 这里你可以根据需要将字符串值转换为方法参数的实际类型// 例如,你可以使用 binderFactory 来转换值,或者直接调用适当的转换方法// 简单起见,这里的代码假设方法参数类型是 Stringreturn pathVariableValue;}
}

上面这个简化的自定义参数解析器类 CustomPathVariableMethodArgumentResolver 通过检查方法参数是否使用了 @PathVariable 注解来决定是否支持该参数的解析。resolveArgument 方法利用请求中的 HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE 属性来获取所有的路径变量,并解析出需要的那个参数值。

在实际的 Spring 应用上下文中,你需要将这个自定义参数解析器注册为一个 Bean。你可以通过添加 @Component 注解(我们这里已经添加了)使得 Spring 在启动时自动检测和注册它,或者你可以在配置类中显式地声明它:

@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate CustomPathVariableMethodArgumentResolver customPathVariableMethodArgumentResolver;@Overridepublic void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {resolvers.add(customPathVariableMethodArgumentResolver);}
}

通过这种方式,当 Spring MVC 遇到带有 @PathVariable 注解的控制器方法参数时,它将使用你定义的 CustomPathVariableMethodArgumentResolver 来解析这个参数。

在Spring MVC中,HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE是一个在请求处理过程中使用的常量,它代表了映射在URL路径中的模板变量的Map对象。这个Map对象包含了哪些以{}括起来的路径变量,并且它们的值是在请求的URL中解析得到的。

例如,假设你有一个URL路径模式如下:

/user/{userId}/profile/{profileId}

当一个请求例如/user/42/profile/7匹配到上面的路径模式时,Spring MVC的一个HandlerMapping会解析这个URL,并将路径变量userIdprofileId及其对应的值427放入Map中。然后,这个Map会被存储在请求的属性中,属性名为HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE

在请求处理流程后续的某个阶段,如果你的controller方法需要那个路径变量,PathVariableMethodArgumentResolver或者你自己定义的类似实现将会使用这个Map来获取路径变量的值。

以下是一个包含路径变量的@GetMapping方法例子:

@GetMapping("/user/{userId}/profile/{profileId}")
public String getUserProfile(@PathVariable String userId,@PathVariable String profileId) {// ...
}

当上面的方法被调用时,Spring会使用PathVariableMethodArgumentResolver解析器来查找HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE属性里的路径变量,取出userIdprofileId各自对应的值,并将它们注入方法参数中。

这个属性是Spring内部使用的,作为开发者通常我们不直接与它打交道,除非你正在自定义路径变量解析逻辑或者处理一些高级的路由功能。在正常使用Spring MVC时,@PathVariable注解和参数解析机制已经足够满足大多数的URL路径变量解析需要了。

8. 参考资料

  1. Spring Framework Reference Documentation: https://docs.spring.io/spring-framework/docs/current/reference/html/
  2. Spring Web MVC: https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc
  3. HandlerMethodArgumentResolver: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/method/support/HandlerMethodArgumentResolver.html
  4. WebMvcConfigurer: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/WebMvcConfigurer.html

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

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

相关文章

高防服务器、高防IP、高防CDN的工作原理是什么

高防IP高防CDN我们先科普一下是什么是高防。“高防”&#xff0c;顾名思义&#xff0c;就犹如网络上加了类似像盾牌一样很高的防御&#xff0c;主要是指IDC领域的IDC机房或者线路有防御DDOS能力。 高防服务器主要是比普通服务器多了防御服务&#xff0c;一般都是在机房出口架设…

矩阵最大路径与

题目描述 东九日在学习dp的时候&#xff0c;解决了经典的矩阵最大路径和问题&#xff1b; 他向队友小夨阐述他的感悟&#xff0c;dp要做的就是感受解空间&#xff1b; 为了防止东九日赛上犯病&#xff0c;小夨决定出一道改编版检查东九日的实力。 以上为题目背景&#xff1b…

北方天途航空——无人船、植保无人机及VR教学系统

4月29日&#xff0c;2019中国北京世界园艺博览会在北京的延庆区正式拉开大幕&#xff0c;这一场A1类的世界园艺博览会吸引了110个国家以及国际组织正式确认参展。北方天途航空技术发展(北京)有限公司受邀参与了此次世园会&#xff0c;并在博览会上应用无人船、植保无人机及VR虚…

网络七层模型之网络层:理解网络通信的架构(三)

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

centos 7安装pgsql14

参考 yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm终端直接运行&#xff1a;yum install -y postgresql14-server 1. 初始化数据库 使用yum安装后&#xff0c;会在系统中创建一个postgres的无密码…

【快速解决】谷歌浏览器驱动的安装及selenium的安装

目录 快速安装Selenium 快速下载对应谷歌驱动 找不到对应版本号的解决方法 快速安装Selenium 安装 Selenium 环境就用下面的代码进行安装&#x1f447;&#x1f447;&#x1f447;&#x1f447;&#x1f447; pip install selenium3.141.0 快速下载对应谷歌驱动 点击这个链接…

关于RPC

初识RPC RPC VS REST HTTP Dubbo Dubbo 特性&#xff1a; 基于接口动态代理的远程方法调用 Dubbo对开发者屏蔽了底层的调用细节&#xff0c;在实际代码中调用远程服务就像调用一个本地接口类一样方便。这个功能和Fegin很类似&#xff0c;但是Dubbo用起来比Fegin还要简单很多&a…

Mac上配置host

要在Mac上配置host&#xff0c;可以按照以下步骤进行操作&#xff1a; 打开终端&#xff1a;输入以下命令并按下回车键&#xff0c;以获取管理员权限&#xff1a; sudo nano /etc/hosts 这将打开一个文本编辑器&#xff0c;用于编辑hosts文件。 输入你想要配置的host记录。…

pe启动盘破解windows密码wins电脑登录密码修改重置

目录 1.进入电脑BIOS&#xff0c;设置电脑第一启动项为U盘启动2.进入微pe系统3.然后点击界面最左下方的Windows图标4.点击windows密码选择对应用户名称修改&#xff1b; 1.进入电脑BIOS&#xff0c;设置电脑第一启动项为U盘启动 把u盘插到要清除密码的电脑&#xff0c;然后开机…

Java语法学习 正则表达式

Java语法学习 正则表达式 大纲 具体案例 需求&#xff1a;使用正则表达式完成对文本的查询&#xff0c;regular expression&#xff08;正则表达式&#xff09; 源码解析group package com.wantian.regular;import java.util.regex.Matcher; import java.util.regex.Patt…

日新增百万数据clickhouse大数据解决方案记录分享

公司广告业务需求&#xff0c;需要多个维度统计每个应用的设备数&#xff0c;点击率&#xff0c;展示率&#xff0c;等相关数据&#xff0c;而且数据需要进行去重&#xff0c;我第一时间想到的是利用clickhouse来做统计&#xff0c;因为我们平台访问量比较大&#xff0c;用mysq…

C++(5): std::ofstream的使用

1. ofstream 之前讲到&#xff0c;ifstream具有将文件从硬盘中读进内存的功能。而ofstream则是执行反操作&#xff0c;它提供了将文件从内存写入磁盘的功能。 std::ofstream 是 C 标准库中用于文件输出的类&#xff0c;它提供了向文件写入数据的能力。std::ofstream 属于 <…

服务器上虚拟环境里的jupyter notebook连接不上kernal,显示not connection to kernel

问题描述 在服务器上新建了一个虚拟环境&#xff0c;下载了相关的包后&#xff0c;使用以下代码新建了kernal pip install ipykernel python -m ipykernel install --user --namepytorch-0.3.0然后输入jupyter notebook启动&#xff0c;却显示not connection to kernel 解决…

浅谈WPF之MVVM工具包

在之前的WPF示例中&#xff0c;都会用到一个MVVM框&#xff0c;也是一个比较常的MVVM框架&#xff0c;就是MVVM工具包【CommunityToolkit.Mvvm】&#xff0c;今天专门以一个简单的小例子&#xff0c;简述一下MVVM工具包的常见用法&#xff0c;仅供学习分享使用&#xff0c;如有…

选项式API和组合式API的区别

选项式(options) API 和组合式(composition) API两种不同的风格书写&#xff0c;Vue3 的组件可以使用这两种api来编写。 选项式API和组合式API的区别 选项式API 选项式 API&#xff0c;具有相同功能的放在一起&#xff0c;可以用包含多个选项的对象来描述组件的逻辑&…

WPF---1.入门学习

学习来源 布局 wpf布局原则 一个窗口中只能包含一个元素 不应显示设置元素尺寸 不应使用坐标设置元素的位置 可以嵌套布局容器 StackPanel-->表单条件查找布局 DataGrid wpf布局容器 StackPanel: 水平或垂直排列元素&#xff0c;Orientation属性分别: Horizontal / Vertic…

Java数据结构-ArrayList

目录 1. 初识集合框架2. ArrayList的介绍3. ArrayList的使用3.1 构造方法3.2 add3.3 addAll3.4 remove3.5 get3.6 set3.7 contains3.8 IndexOf3.9 lastIndexOf3.10 subList 4. ArrayList的遍历4.1 简单粗暴法4.2 循环遍历法4.3 迭代器 1. 初识集合框架 Java集合框架是Java编程…

图论记录之最短路迪杰斯特拉

简述思想 这个思想能用一句话来概括&#xff0c;精简到的极致:每次找到一个最短距离的点并更新起点到各个点的最短距离 如果要可视化的化&#xff0c;B站搜索Dijksra算法&#xff0c;有视频讲解 代码 这里是Acwing的851题&#xff0c;下面的有注释 import java.util.*;publ…

基于OneAPI+ChatGLM3-6B+FastGPT搭建LLM大语言模型知识库问答系统

搭建大语言模型知识库问答系统 部署OneAPI部署一个LLM模型部署嵌入模型部署FastGPT新建FastGPT对话应用新建 FastGPT 知识库应用 部署OneAPI 拉取镜像 docker pull justsong/one-api创建挂载目录 mkdir -p /usr/local/docker/oneapi启动容器 docker run --name one-api -d …

03 React 基础样式控制

在React中&#xff0c;有多种方式可以管理组件的样式&#xff0c;每种方式都有其优劣势。以下是一些常见的样式管理方法以及它们之间的比较&#xff1a; 内联样式&#xff08;Inline Styles&#xff09;&#xff1a; function MyComponent() {const style {color: red,backg…