在初学springmvc框架时,我就一直有一个疑问,为什么controller方法上竟然可以放这么多的参数,而且都能得到想要的对象,比如HttpServletRequest或HttpServletResponse,各种注解@RequestParam@RequestHeader@RequestBody@PathVariable@ModelAttribute等。相信很多初学者都曾经感慨过。

这一章就是讲解处理这方面工作的

org.springframework.web.method.support.HandlerMethodArgumentResolver接口。

springmvc自带的一些实现:

  • ServletRequestMethodArgumentResolverServletResponseMethodArgumentResolver处理了自动绑定HttpServletRequest和HttpServletResponse
  • RequestParamMapMethodArgumentResolver处理了@RequestParam
  • RequestHeaderMapMethodArgumentResolver处理了@RequestHeader
  • PathVariableMapMethodArgumentResolver处理了@PathVariable
  • ModelAttributeMethodProcessor处理了@ModelAttribute
  • RequestResponseBodyMethodProcessor处理了@RequestBody
  • 整体的spring实现为以下:
  • private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
    List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>(); // Annotation-based argument resolution
    resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
    resolvers.add(new RequestParamMapMethodArgumentResolver());
    resolvers.add(new PathVariableMethodArgumentResolver());
    resolvers.add(new PathVariableMapMethodArgumentResolver());
    resolvers.add(new MatrixVariableMethodArgumentResolver());
    resolvers.add(new MatrixVariableMapMethodArgumentResolver());
    resolvers.add(new ServletModelAttributeMethodProcessor(false));
    resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters()));
    resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters()));
    resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
    resolvers.add(new RequestHeaderMapMethodArgumentResolver());
    resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
    resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory())); // Type-based argument resolution
    resolvers.add(new ServletRequestMethodArgumentResolver());
    resolvers.add(new ServletResponseMethodArgumentResolver());
    resolvers.add(new HttpEntityMethodProcessor(getMessageConverters()));
    resolvers.add(new RedirectAttributesMethodArgumentResolver());
    resolvers.add(new ModelMethodProcessor());
    resolvers.add(new MapMethodProcessor());
    resolvers.add(new ErrorsMethodArgumentResolver());
    resolvers.add(new SessionStatusMethodArgumentResolver());
    resolvers.add(new UriComponentsBuilderMethodArgumentResolver()); // Custom arguments
    if (getCustomArgumentResolvers() != null) {
    resolvers.addAll(getCustomArgumentResolvers());
    } // Catch-all
    resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
    resolvers.add(new ServletModelAttributeMethodProcessor(true)); return resolvers;
    }

      

我们可以模仿springmvc的源码,实现一些我们自己的实现类,而方便我们的代码开发。

接口说明

package org.springframework.web.method.support;

import org.springframework.core.MethodParameter;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest; public interface HandlerMethodArgumentResolver {
//用于判定是否需要处理该参数分解,返回true为需要,并会去调用下面的方法resolveArgument(可通过参数类型或注解等等)。
boolean supportsParameter(MethodParameter parameter);
//真正用于处理参数分解的方法,返回的Object就是controller方法上的形参对象。
Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception; }

自定义实现

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; /**
* 用于绑定@CurrentUser的方法参数解析器
*
* @author lism
*/
public class CurrentUserMethodArgumentResolver implements HandlerMethodArgumentResolver { public CurrentUserMethodArgumentResolver() {
} @Override
public boolean supportsParameter(MethodParameter parameter) {
if (parameter.getParameterType().isAssignableFrom(UserBean.class) && parameter.hasParameterAnnotation(CurrentUser.class)) {
return true;
}
return false;
} @Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
CurrentUser currentUserAnnotation = parameter.getParameterAnnotation(CurrentUser.class);
//从Session 获取用户
Object object = webRequest.getAttribute(currentUserAnnotation.value(), NativeWebRequest.SCOPE_SESSION);
//从 accessToken获得用户信息
if (object == null) {
String token = webRequest.getHeader("Authorization");
if (token == null) {
token = webRequest.getParameter("accessToken");
}
//为了测试先写死用户名
//TODO: 取真实用户
return new UserBean(1L,"admin");
}
return object;
}
}

  

import java.lang.annotation.*;

/**
* <p>绑定当前登录的用户</p>
* <p>不同于@ModelAttribute</p>
*
* @author lism
*/
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CurrentUser { /**
* 当前用户在request中的名字
*
* @return
*/
String value() default "user"; }

  

@RestController
@RequestMapping(value = "/test")
public class TestController { /**
* 根据name查询
*
* @param request
* @return
*/
@RequestMapping(value = "/testCurrentUser", method = RequestMethod.POST, produces = "application/json", consumes = "application/json")
@ResponseBody
public void test(@CurrentUser UserBean userBean, @RequestBody SubjectRequest request) {
String createdBy = userBean.getUsername();
log.info(createdBy);
}
}

 

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor; import java.io.Serializable; @Data
@NoArgsConstructor
@AllArgsConstructor
public class UserBean implements Serializable {
private Long id;
private String username;
}

另外,我需要将他配置到spring context中。 

	<!--自定义controller接受参数进行解析  -->
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean
class="com.common.util.CurrentUserMethodArgumentResolver" />
</mvc:argument-resolvers>
</mvc:annotation-driven>

或者中配置的方式:

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="synchronizeOnSession" value="true" />
<property name="customArgumentResolvers">
<list>
<bean class="com.common.util.CurrentUserMethodArgumentResolver" />
</list>
</property>
</bean>

spring-boot方式配置

package com.demo;

import java.util.List;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; import com.demo.mvc.component.MultiPersonArgumentResolver;
import com.demo.mvc.component.PersonArgumentResolver; @SpringBootApplication
public class WebMvcConfiguration extends WebMvcConfigurationSupport { @Override
protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { // 注册Person的参数分解器
argumentResolvers.add(new PersonArgumentResolver());
}
}

  

自定义HandlerMethodArgumentResolver参数解析器和源码分析的更多相关文章

  1. 一步一步自定义SpringMVC参数解析器

    随心所欲,自定义参数解析器绑定数据. 题图:from Zoommy 干货 SpringMVC解析器用于解析request请求参数并绑定数据到Controller的入参上. 自定义一个参数解析器需要实现 ...

  2. springMVC源码分析--HandlerMethodArgumentResolver参数解析器(一)

    HandlerMethodArgumentResolver是用来为处理器解析参数的,主要用在HandlerMethod中,每个Resolver对应一种类型的参数,其实现类特别的多. HandlerMe ...

  3. 实现自定义的参数解析器——HandlerMethodArgumentResolver

    1.为什么需要自己实现参数解析器 我们都知道在有注解的接口方法中加上@RequestBody等注解,springMVC会自动的将消息体等地方的里面参数解析映射到请求的方法参数中. 如果我们想要的信息不 ...

  4. HandlerMethodArgumentResolver 参数解析器

    关于springMvc中的参数解析器 springMvc中的HandlerAdapter会检测所有的 HandlerMethodArgumentResolver(对参数的解析器) HandlerMet ...

  5. 自定义springmvc参数解析器

    实现spring HandlerMethodArgumentResolver接口 通过使用@JsonArg自定义注解来解析json数据(通过fastjson的jsonPath),支持多个参数(@Req ...

  6. Spring boot中自定义Json参数解析器

    转载请注明出处... 一.介绍 用过springMVC/spring boot的都清楚,在controller层接受参数,常用的都是两种接受方式,如下 /** * 请求路径 http://127.0. ...

  7. layoutInflater参数解析与源码分析

    关于LayoutInflater方法,无论是在listview的适配器中,还是在动态添加view的时候,都会出现它的身影,最开始我在看<第一行代码>时,不知道这个方法实际的参数到底指的是什 ...

  8. Django 之 restframework 解析器源码分析

    解析器分类: 1. JSONPaser ----> 解析 JSON-serialized data (解析JSON序列化的数据) 2.FormParser ---->解析form 表单中 ...

  9. springmvc 源码分析(三) -- 自定义处理器映射器和自定义处理器适配器,以及自定义参数解析器 和错误跳转自定页面

    测试环境搭建: 本次搭建是基于springboot来实现的,代码在码云的链接:https://gitee.com/yangxioahui/thymeleaf.git DispatcherServlet ...

随机推荐

  1. 洛谷P4074 [WC2013]糖果公园(莫队)

    传送门 总算会树形莫队了…… 上次听说树形莫队是给树分块,实在看不懂.然后用括号序列的方法做总算能弄明白了 先说一下什么是括号序列,就是在$dfs$的时候,进入的时候记录一下,出去的时候也记录一下 拿 ...

  2. Jmeter-响应结果unicode转成中文显示

    本文为转载微信公众号文章,如作者发现后不愿意,请联系我进行删除 原文链接:http://mp.weixin.qq.com/s?__biz=MjM5OTI2MTQ3OA==&mid=265217 ...

  3. Kruskal算法 克鲁斯卡尔

    30行 #include <iostream> #include <algorithm> using namespace std; int f[5001],n,m,ans=0, ...

  4. 谁能赢呢? BZOJ 2463

    题目描述 小明和小红经常玩一个博弈游戏.给定一个n×n的棋盘,一个石头被放在棋盘的左上角.他们轮流移动石头.每一回合,选手只能把石头向上,下,左,右四个方向移动一格,并且要求移动到的格子之前不能被访问 ...

  5. HDU - 6416 :Rikka with Seam(DP & 前缀和 & 数学)

    pro:给定N*M的矩阵,现在让你在每一行删去一个位置,然后形成新N*(M-1)的矩阵,问有多少种不同的新的矩阵.需要满足相邻行删去的位置不大于K. (题目是01矩阵,其实任意矩阵都可以做,本题算法里 ...

  6. springcloud系列五 feign远程调用服务

    一:Feign简介 Feign 是一种声明式.模板化的 HTTP 客户端,在 Spring Cloud 中使用 Feign,可以做到使用 HTTP请求远程服务时能与调用本地方法一样的编码体验,开发者完 ...

  7. thinkphp 3.0 核心函数U的一个致命bug

    最近在玩thinkphp,感觉内置函数 U 挺强大的! 传递多个参数时,出乱子了(window环境下,xampp) 例如 echo U('Blog/cate',array('cate_id'=> ...

  8. N - 嘤嘤嘤 (并查集+枚举)

    Our lovely KK has a difficult Social problem. A big earthquake happened in his area. N(2≤N≤2000)N(2≤ ...

  9. P2575 高手过招

    传送门 直接搞好像搞不了 考虑转换模型 显然每一行棋子不会跑到其他行.. 所以可以把每一行的情况看成一个子博弈 显然整个答案就是每一行的SG值的异或和 不懂的回去学SG函数... 考虑怎么分析一行的状 ...

  10. Realm数据库的使用

    https://github.com/lipanquan/Realm/tree/master