SpringMVC 之 HandlerMethodArgumentResolver接口

在SpringMVC开发中,控制层(Controller/Action)的 handler方法能够自动进行参数封装(比如@RequestParam、@PathVariable等注解),甚至在方法参数任意位置存在Http参数(如HttpServletRequest、HttpServletResponse、HttpSession、Writer等),都可以自动进行参数赋值。辣么,SpringMVC是怎么实现的呢?用的什么方法?

1. HandlerMethodArgumentResolver

策略接口:用于在给定 请求的上下文中 将方法参数解析为参数值。简单的理解为:它负责处理你Handler方法里的所有入参:包括自动封装、自动赋值、校验等等。有了它才能会让SpringMVC处理入参这么自动化。

SpringMVC内置了非常多HandlerMethodArgumentResolver接口实现,比如上面说到的RequestParamHandlerMethodArgumentResolver、PathVariableMapMethodArgumentResolver等,并且支持自定义。

自定义解析器需要实现HandlerMethodArgumentResolver接口,HandlerMethodArgumentResolver接口包含两个接口函数:

public interface HandlerMethodArgumentResolver {

   boolean supportsParameter(MethodParameter parameter);

   @Nullable
   Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
         NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;

}
  • supportsParameter:用于判定是否需要处理该参数分解(一般都是通过 参数上面的注解、参数的类型),返回true为需要,并会去调用下面的方法resolveArgument。
  • resolveArgument:真正用于处理参数分解的方法,返回的Object就是controller方法上的形参对象。

resolveArgument参数

  • 从NativeWebRequest中获取数据;
  • ModelAndViewContainer用来提供访问Model;
  • MethodParameter请求参数;
  • WebDataBinderFactory用于创建一个WebDataBinder用于数据绑定、校验。

2. 自定义HandlerMethodArgumentResolver

使用HandlerMethodArgumentResolver给Controller注入用户信息。

2.1 创建实体类

/**
 * 用户实体类
 */
public class UserBean {
    private String id;
    private String name;
    private int age;
    private String sex;
    private String email;
    private String phone;

    public UserBean() {
    }

    public UserBean(String id, String name, int age, String sex, String email, String phone) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.email = email;
        this.phone = phone;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    @Override
    public String toString() {
        return "UserBean{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                ", email='" + email + '\'' +
                ", phone='" + phone + '\'' +
                '}';
    }
}

2.2 创建标注注解

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

/**
 * 获取登录用户信息 annotation
 */
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface CaseUser {
}

2.3 创建HandlerMethodArgumentResolver类

import com.lizq.springboot.web.annotation.CaseUser;
import com.lizq.springboot.web.bean.UserBean;
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;

@Component
public class CaseUserHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        if (methodParameter.getParameterType() == UserBean.class// 参数类型为UserBean
                && methodParameter.hasParameterAnnotation(CaseUser.class)// 参数标注注解为CaseUser
        ) {
            return true;
        }
        return false;
    }

    @Override
    public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer,
                                  NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
        // MethodParameter 请求参数信息
        // ModelAndViewContainer 用来提供访问Model
        // 从NativeWebRequest 中获取数据,如nativeWebRequest.getNativeRequest(XXX.class);nativeWebRequest.getNativeResponse(XXX.class);等
        // WebDataBinderFactory 用于创建一个WebDataBinder用于数据绑定、校验
        UserBean user = new UserBean("001", "张三", 24, "男", "test@163.com", "155xxxxx1688");
        return user;
    }
}

2.4 添加配置

2.4.1使用springboot添加
import org.springframework.beans.factory.annotation.Autowired;
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 WebConfiguration implements WebMvcConfigurer {
    @Autowired
    private CaseUserHandlerMethodArgumentResolver caseUserHandlerMethodArgumentResolver;

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        // 添加获取用户信息 HandlerMethodArgumentResolver
        resolvers.add(caseUserHandlerMethodArgumentResolver);
    }
}
2.4.2传统springmvc项目添加
<mvc:annotation-driven>
   <mvc:argument-resolvers>
      <bean class="xxx.xxx.xxx.CaseUserHandlerMethodArgumentResolver" />
   </mvc:argument-resolvers>
</mvc:annotation-driven>

2.5 测试结果

@RequestMapping("testHandlerMethodArgumentResolver.do")
public void testHandlerMethodArgumentResolver(@CaseUser UserBean user1, UserBean user2,
                                                @CaseUser String str1, String str2) {
    System.out.println(user1.toString());
    System.out.println(user2.toString());
    System.out.println(str1);
    System.out.println(str2);
}

打印结果:
在这里插入图片描述

3. 执行顺序问题

拦截器 ------>HandlerMethodArgumentResolver ------> AOP(@Aspect) ------>controller

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值