当前位置: 首页 > article >正文

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

概述

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.kler.cn/a/303044.html

相关文章:

  • C++单例模式与多例模式
  • 01:(手撸HAL+CubeMX)时钟篇
  • 成都睿明智科技有限公司解锁抖音电商新玩法
  • python 同时控制多部手机
  • 《TCP/IP网络编程》学习笔记 | Chapter 8:域名及网络地址
  • LLMs 如何处理相互矛盾的指令?指令遵循优先级实验
  • 前端vue项目服务器部署(docker)
  • [linux 驱动]platform总线设备驱动详解与实战
  • WEB渗透Linux提权篇-MYSQL漏洞提权
  • Spring Boot实现大文件分块上传
  • woocommerce 调用当前product_tag 为标题
  • swoole协程 是单线程的,还是多线程的
  • 数学建模笔记—— 整数规划和0-1规划
  • 跟我一起写 SIPp XML scenario file 之二
  • LeetCode 每日一题 2024/9/2-2024/9/8
  • OpenAI gym: Trouble installing Atari dependency (Mac OS X)
  • CVE-2024-38063 ipv6远程蓝屏
  • 基于SpringBoot+Vue+MySQL的招聘管理系统
  • 【课程系列12】某客时间AI大模型微调训练营
  • C#中的可空类型和空合并运算符
  • Perfetto 如何查看主线程哪些操作最耗时
  • P1332 血色先锋队
  • 为什么在EffectiveJava中建议用EnumSet替代位字段,以及使用EnumMap替换序数索引
  • layui复选框删除
  • 计算机毕业设计选题推荐-流浪动物领养管理系统-Java/Python项目实战(亮点:数据可视化分析、智能推荐)
  • 开发模式和环境搭建