SpringMvc 之处理器方法参数解析器(HandlerMethodArgumentResolver)

news2024/11/9 17:21:45

概述

HandlerMethodArgumentResolver 是 Spring MVC 框架中的一个关键组件,用于解析控制器(Controller)方法的参数。在 Spring MVC 中,当一个请求到达时,DispatcherServlet 会负责找到对应的处理器(即控制器中的方法)来处理这个请求。在处理之前,需要解析方法的参数,这就是HandlerMethodArgumentResolver 的作用。换句话说,它负责将请求中的信息转换成处理器方法所需的参数类型,即它允许开发者将请求参数直接映射到处理器方法的参数上,而无需手动解析请求。

从代码角度说HandlerMethodArgumentResolver是一个接口,开发者实现该接口可以实现自定义的Controller方法的参数的自动注入。

public interface HandlerMethodArgumentResolver {
  
  /**
  * 对应的方法参数是否支持该处理器解析处理,只有返回true才会执行resolveArgument中的逻辑
  * @param 要检查的方法参数,MethodParameter Spring MVC中对方法参数的包装类
  * @return 如果支持该参数则返回true,否则返回false
  */
  boolean supportsParameter(MethodParameter parameter);

  /**
  * 从给定的request中解析出方法参数所需要的值,并返回
  * ModelAndViewContainer 提供了request中的model
  * WebDataBinderFactory 提供了创建WebDataBinder实例的方法(当需要绑定数据和类型转换时)
  * @param parameter 要解析的方法参数。
  * @param mavContainer 当前请求的ModelAndViewContainer
  * @param webRequest 当前请求对象request
  * @param binderFactory 创建WebDataBinder实例的工厂
  * @return 返回解析后的参数值,如果不能解析返回null
  * @throws Exception 如果解析参数值出错抛出异常
  */
  @Nullable
  Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}

HandlerMethodArgumentResolver简介

HandlerMethodArgumentResolver 是 Spring MVC 提供的一个接口,用于将 HTTP 请求中的数据解析并绑定到控制器方法的参数上。它定义了两个主要的方法:supportsParameterresolveArgumentsupportsParameter 方法用于判断当前解析器是否支持给定的方法参数,而 resolveArgument 方法则用于实际解析请求中的数据,并将其作为参数值返回。

下面是mvc处理流程:

在这里插入图片描述

工作流程

当 Spring MVC 接收到一个 HTTP 请求并确定要调用的控制器方法后,它会按照以下步骤使用 HandlerMethodArgumentResolver 来解析方法的参数:

1. 确定解析器

Spring MVC 会遍历所有已注册的 HandlerMethodArgumentResolver 实现,并调用每个解析器的 supportsParameter 方法来检查是否有解析器支持当前方法的参数。一旦找到支持的解析器,就会使用该解析器来解析参数。

2. 解析参数

一旦确定了合适的解析器,Spring MVC 就会调用该解析器的 resolveArgument 方法来实际解析请求中的数据。这个过程可能涉及从请求头、请求体、路径变量、查询参数等不同来源提取数据,并将其转换为方法参数所需的类型。

3. 异常处理

如果在解析过程中发生异常,解析器通常会抛出一个异常,该异常随后会被 Spring MVC 的异常处理机制捕获并处理。这允许开发者为不同的异常类型提供自定义的错误响应。

自定义解析器

除了内置解析器外,Spring MVC 还允许开发者自定义 HandlerMethodArgumentResolver 实现类,以处理特殊的参数类型或实现自定义的解析逻辑。自定义解析器需要实现 HandlerMethodArgumentResolver 接口,并重写 supportsParameterresolveArgument 方法。然后,通过注册自定义解析器到 Spring MVC 的配置中,使其能够参与到参数解析的过程中。

实现步骤

自定义HandlerMethodArgumentResolver一般包含以下步骤:

  1. 创建自定义解析器类,实现 HandlerMethodArgumentResolver 接口。

  2. 覆盖 supportsParameter(MethodParameter parameter)resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,NativeWebRequest webRequest, WebDataBinderFactory binderFactory)

    • boolean supportsParameter(MethodParameter parameter);
      这个方法用于判断当前的解析器是否支持给定的方法参数(MethodParameter)。如果支持,返回 true;否则返回 false。
      参数 parameter 表示需要解析的方法参数。
    • @Nullable Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
      这个方法用于解析处理器方法的参数,并返回解析后的结果。方法返回一个 @Nullable 注解修饰的 Object 类型的对象,表示解析后的方法参数。如果解析失败或者不适用,可以返回 null。方法可能会抛出异常 Exception,表示解析过程中出现的异常情况。
      • 参数 parameter 表示需要解析的方法参数。
      • 参数 mavContainer 是一个可空的 ModelAndViewContainer 对象,用于在解析期间存储模型和视图的相关信息。
      • 参数 webRequest 表示当前的 Web 请求对象,类型为 NativeWebRequest。
      • 参数 binderFactory 是一个可空的 WebDataBinderFactory 对象,用于创建 WebDataBinder 对象,用于数据绑定和验证

    MethodParameter 是 Spring Framework 提供的一个类,用于描述方法参数的元数据信息。它提供了丰富的方法,用于获取和操作方法参数的各种信息。

方法描述
getParameterType()获取方法参数的类型
getParameterIndex()获取方法参数在方法参数列表中的索引位置
getGenericParameterType()获取方法参数的泛型类型
getMethod()获取包含此方法参数的方法
hasParameterAnnotation(Class<? extends Annotation> annotationType)判断方法参数是否有指定类型的注解
getParameterAnnotations()获取方法参数上的所有注解
getParameterName()获取方法参数的名称(需要编译时开启 -parameters 选项)
initParameterNameDiscovery(ParameterNameDiscoverer parameterNameDiscoverer)初始化参数名称发现器,用于在运行时获取方法参数的名称
  1. 在 Spring MVC 配置中注册自定义解析器。某个被@Configuration注解的类并且实现WebMvcConfigurer接口,在addArgumentResolvers方法中添加。
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {

    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.defaultContentType(MediaType.APPLICATION_JSON);
    }

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(myArgumentResolver());
    }

    @Bean
    public MyArgumentResolver myArgumentResolver() {
        return new MyArgumentResolver();
    }
}

常用场景

自定义HandlerMethodArgumentResolver通常在以下情况下使用:

  • 当需要解析的请求参数类型不是 Spring MVC 默认支持的。
  • 当需要在参数解析过程中添加特定的逻辑,如权限检查、数据验证等

用法方法

下面代码中,创建一个自定义解析器来解析一个自定义的注解 @CurrentUser,该注解用于将当前用户的信息注入到控制器方法的参数中。

首先,定义 @CurrentUser 注解:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface CurrentUser {
}

然后,创建自定义的 HandlerMethodArgumentResolver

import org.springframework.core.MethodParameter;
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;
import org.springframework.stereotype.Component;

@Component
public class CurrentUserArgumentResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(CurrentUser.class) && 	
          parameter.getParameterType().equals(User.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        // 假设已经有获取当前用户的方法
        User currentUser = getCurrentUser(webRequest);
        return currentUser;
    }

    private User getCurrentUser(NativeWebRequest webRequest) {
        // 这里是你的逻辑来获取当前用户,例如从Session或Security Context中
        // 返回一个新的User实例
        return new User(); 
    }
}

然后,在Spring配置中注册这个解析器,如果使用的是Java配置,可以在配置类中添加:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Configuration
public class MyWebMVCConfig implements WebMvcConfigurer {

    @Autowired
    private CurrentUserArgumentResolver currentUserArgumentResolver;

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(currentUserArgumentResolver);
    }
}

最后,在控制器中使用这个注解:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @GetMapping("/user/info")
    public String getUserInfo(@CurrentUser User currentUser) {
        // 这里可以使用currentUser对象,它已经被解析器填充了
        return "User info for: " + currentUser.getName(); 
    }
}

结语

HandlerMethodArgumentResolver 是 Spring MVC 框架中用于解析请求参数的关键接口。通过内置解析器和自定义解析器,Spring MVC 提供了灵活而强大的参数解析能力,使得开发者可以轻松处理各种复杂的请求参数场景。深入理解 HandlerMethodArgumentResolver 的工作原理对于掌握 Spring MVC 框架的请求处理流程和提高开发效率具有重要意义。

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

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

相关文章

9月9日星期一今日早报简报微语报早读

9月9日星期一&#xff0c;农历八月初七&#xff0c;早报微语早读。 1、庆祝第40个教师节&#xff0c;全国585个单位、1790人受表彰&#xff1b; 2、中国残奥军团94金76银50铜收官&#xff1a;连续6届残奥会金牌和奖牌榜第一&#xff1b; 3、三部门&#xff1a;拟允许在京津沪…

1688电商运营到底怎么做竞品分析(超细节)

你得学会看同行数据&#xff0c;因为同行是蕞好的老师。你把同行分析透&#xff0c;把市场分析透以后&#xff0c;你才能真正的做好这个类目。我们就来详细的讲一下具体该怎么去分析同行&#xff0c;以及要看竞品的哪些数据。 一、分析市场 就是先看一下你的这个产品&#xf…

【go-zero】api与rpc使用k8s服务发现和部署

【go-zero】api与rpc使用k8s服务发现和部署 k8s安装 参考 debian12极简快速安装k8s 1、代码准备 参考上一篇【go-zero】api与rpc使用etcd服务发现 代码搬过来&#xff0c;因为要用到k8s环境换到linux了 &#xff0c;做一下修改 rpc 修改一下rpc的logic文件&#xff0c;增…

运放双电源供电和单电源供电的区别

运放是一种常见的电路元器件&#xff0c;广泛应用于模拟电路中。它可以使用不同的电源电压进行供电&#xff0c;其中最常见的是双电源供电和单电源供电。 下面将详细介绍它们之间的区别。 1.双电源供电 双电源供电意味着运放有两个电源引脚&#xff1a;正极和负极。正极一般连…

docker部署it工具箱,各种工具包

1.效果 2.步骤 2.1安装docker&&docker-compose 复制粘贴两脚本 bash <(curl -sSL https://cdn.jsdelivr.net/gh/SuperManito/LinuxMirrorsmain/DockerInstallation.sh)curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose…

调度任务是什么?如何设置调度任务?

本文将解释什么是调度任务&#xff0c;并且以FineDataLink为例说明如何设置调度任务。 一. 什么是调度任务&#xff1f; 调度平台是管理和自动化 ETL 的任务执行工具&#xff0c;通过指定任务依赖关系和执行顺序实现任务的自动执行&#xff0c;一般需要代码开发&#xff0c;使…

一些面试和找工作的技巧-新资要的低并不会给你加分薪资要的高不会成为公司拒绝你的核心理由

面试相关 自我介绍的模板 使用STAR描述->描述项目介绍 核心岗位是内推&#xff0c;或者朋友 所以给同事留个好印象 面试最后一道送命题目 你还有什么想问的吗? 这个问题体现了你深度思考的能力&#xff0c;对 一轮面试官可能是你的直属领导&#xff0c;你可以问题你进…

GIS大事件!Bentley收购Cesium

9月6日&#xff0c;Cesium官方宣布加入Bentley。 Bentley我们并不陌生。最初Acute3D被Bentley公司收购&#xff0c;旗下软件由Smart3DCapture转型到ContextCapture&#xff0c;现又改名 iTwin Capture。 如今又收购了Cesium。 Cesium官方表示&#xff0c;Cesium开发平台与iTwi…

python编程二维码里放视频

动植物标本制作大赛 需要制作一个关于植物标本的二维码 存放采集植物的视频 笑了 pip install qrcode pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple 新建文件贴入代码如下&#xff1a; import qrcode import cv2# 视频链接 video_url "…

新学期学生资料在线收集,老师用它一分钟搞定!

金秋九月&#xff0c;校园里再次迎来了新学期的热闹景象。学生们满怀期待地步入教室&#xff0c;而老师们则开始了新一学期的准备工作。在这些准备工作中&#xff0c;统计和整理学生资料是不可或缺的一环。这项工作虽然基础&#xff0c;却对教学活动的顺利开展至关重要。现在有…

【redis】redis的特性和主要应用场景

文章目录 redis 的特性在内存中存储数据可编程的扩展能力持久化集群高可用快 redis 的应用场景实时数据存储缓存消息队列 redis 的特性 redis 的一些特性&#xff08;优点&#xff09;成就了它 在内存中存储数据 In-memory data structures MySQL 主要是通过“表”的方式来…

Harbor Images Replication

文章目录 背景Add Harbor EndpointAdd Quay.io EndpointHarbor New Replication RuleHarbor Push Images To Quay.io 背景 harbor 的镜像同步至备份harbor 或者同步quay.io。实现镜像备份。 Add Harbor Endpoint Add Quay.io Endpoint Harbor New Replication Rule Harbor P…

QDesigner中的Line设置样式

在QT designer中&#xff0c;我们通常会用到线 Horizontal Line 与 Vertical Line 来代表分割线&#xff1a; 效果入下&#xff1a; 但是我们设置样式表或者设置它的其他属性的时候&#xff0c;却找不到它是哪个类&#xff0c;就连文档里面也只有跟他长得很像的QLine,但经过实验…

深度学习——pycharm配置远程服务器(蓝耘GPU智算云)

一、平台选择 一开始在网上查找资料&#xff0c;看到大量的博客文章都是关于AutoDL算力云平台的介绍&#xff0c;而且基本上都是一致好评。但是后来经过他人介绍&#xff0c;了解到蓝耘GPU智算云平台&#xff0c;最终决定采用这个平台&#xff0c;有两个原因&#xff1a;一是这…

【前端】代码打了debugger,浏览器控制打不到断点怎么解决

文章目录 一、场景二、原因三、解决 一、场景 代码中写了debugger&#xff0c;按照逻辑是要进行断点调试的&#xff0c;但是浏览器没有反应 二、原因 被浏览器忽略了 三、解决 只需要在浏览器的设置中&#xff0c;配置忽略列表 关闭也行

埃隆·马斯克表示特斯拉“没有必要”授权 xAI 模型

埃隆马斯克近日在社交媒体上对《华尔街日报》的一篇报道进行了反驳。该报道指出&#xff0c;马斯克旗下的电动汽车公司特斯拉可能与人工智能初创公司xAI达成了一项收入分享协议&#xff0c;以便特斯拉能够使用xAI的人工智能模型。据称&#xff0c;这些模型将被集成到特斯拉的全…

Semantic Kernel + Natasha:一小时快速生成100个API的奇迹

大家好&#xff0c;我今天带来了一个让人瞠目结舌的实验&#xff1a;在一小时内快速生成了100个API&#xff01; 其实如果手速高&#xff0c;可以更多。要知道&#xff0c;这得益于之前介绍过的Natasha —— 一个可以动态编译并加载代码的神奇工具。 动态编程神器! 探秘.Net…

liunx io模型多路复用

多路复用 应用程序中同时处理多路输入输出流&#xff0c;若采用阻塞模式&#xff0c;得不到预期的目的&#xff1b; 若采用非阻塞模式&#xff0c;对多个输入进行轮询&#xff0c;但又太浪费CPU时间&#xff1b; 若设置多个进程/线程&#xff0c;分别处理一条数据通路&#xff…

SQL中的外键约束

外键约束用于表示两张表中的指标连接关系。外键约束的作用主要有以下三点&#xff1a; 1.确保子表中的某个字段&#xff08;外键&#xff09;只能引用父表中的有效记录 2.主表中的列被删除时&#xff0c;子表中的关联列也会被删除 3.主表中的列更新时&#xff0c;子表中的关联…

KAN 学习 Day4 —— MultKAN 正向传播代码解读及测试

在KAN学习Day1——模型框架解析及HelloKAN中&#xff0c;我对KAN模型的基本原理进行了简单说明&#xff0c;并将作者团队给出的入门教程hellokan跑了一遍&#xff1b; 在KAN 学习 Day2 —— utils.py及spline.py 代码解读及测试中&#xff0c;我对项目的基本模块代码进行了解释…