自定义HandlerMethodArgumentResolver参数解析器和源码分析
在初学springmvc框架时,我就一直有一个疑问,为什么controller方法上竟然可以放这么多的参数,而且都能得到想要的对象,比如HttpServletRequest或HttpServletResponse,各种注解@RequestParam
、@RequestHeader
、@RequestBody
、@PathVariable
、@ModelAttribute
等。相信很多初学者都曾经感慨过。
这一章就是讲解处理这方面工作的
org.springframework.web.method.support.HandlerMethodArgumentResolver
接口。
springmvc自带的一些实现:
ServletRequestMethodArgumentResolver
和ServletResponseMethodArgumentResolver
处理了自动绑定HttpServletRequest和HttpServletResponseRequestParamMapMethodArgumentResolver
处理了@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参数解析器和源码分析的更多相关文章
- 一步一步自定义SpringMVC参数解析器
随心所欲,自定义参数解析器绑定数据. 题图:from Zoommy 干货 SpringMVC解析器用于解析request请求参数并绑定数据到Controller的入参上. 自定义一个参数解析器需要实现 ...
- springMVC源码分析--HandlerMethodArgumentResolver参数解析器(一)
HandlerMethodArgumentResolver是用来为处理器解析参数的,主要用在HandlerMethod中,每个Resolver对应一种类型的参数,其实现类特别的多. HandlerMe ...
- 实现自定义的参数解析器——HandlerMethodArgumentResolver
1.为什么需要自己实现参数解析器 我们都知道在有注解的接口方法中加上@RequestBody等注解,springMVC会自动的将消息体等地方的里面参数解析映射到请求的方法参数中. 如果我们想要的信息不 ...
- HandlerMethodArgumentResolver 参数解析器
关于springMvc中的参数解析器 springMvc中的HandlerAdapter会检测所有的 HandlerMethodArgumentResolver(对参数的解析器) HandlerMet ...
- 自定义springmvc参数解析器
实现spring HandlerMethodArgumentResolver接口 通过使用@JsonArg自定义注解来解析json数据(通过fastjson的jsonPath),支持多个参数(@Req ...
- Spring boot中自定义Json参数解析器
转载请注明出处... 一.介绍 用过springMVC/spring boot的都清楚,在controller层接受参数,常用的都是两种接受方式,如下 /** * 请求路径 http://127.0. ...
- layoutInflater参数解析与源码分析
关于LayoutInflater方法,无论是在listview的适配器中,还是在动态添加view的时候,都会出现它的身影,最开始我在看<第一行代码>时,不知道这个方法实际的参数到底指的是什 ...
- Django 之 restframework 解析器源码分析
解析器分类: 1. JSONPaser ----> 解析 JSON-serialized data (解析JSON序列化的数据) 2.FormParser ---->解析form 表单中 ...
- springmvc 源码分析(三) -- 自定义处理器映射器和自定义处理器适配器,以及自定义参数解析器 和错误跳转自定页面
测试环境搭建: 本次搭建是基于springboot来实现的,代码在码云的链接:https://gitee.com/yangxioahui/thymeleaf.git DispatcherServlet ...
随机推荐
- Object Detection: Face Detection using Haar Cascades
目录 利用基于Haar特征的级联分类器实现人脸检测:官方教程 目标 学习基于Haar特征的级联分类器(Cascade Callifiers)实现人脸检测: 扩展到人眼检测: 基础知识 Paul V ...
- b,u,i,s,这些被删除的标签以及用来替换他们的标签
加粗文字 给文字加下划线 倾斜文字 给文字加删除线 这些是以前的HTML语言修饰文字用的,没有语义,所以被删除,不到万不得已 不能使用,HTML给了新的标签替换他们,并且有语义 定义重要性强调的文字 ...
- 【bzoj1965】: [Ahoi2005]SHUFFLE 洗牌 数论-快速幂-扩展欧几里得
[bzoj1965]: [Ahoi2005]SHUFFLE 洗牌 观察发现第x张牌 当x<=n/2 x=2x 当x>n/2 x=2x-n-1 好像就是 x=2x mod (n+1) 就好 ...
- luogu P3811线性求逆元
首先扩O:T了一个点(因为上界松),83分. #include <cstdio> using namespace std; int n, p; void exgcd(int a, int ...
- 转载《centos6安装nginx最详细步骤》
出处:https://www.cnblogs.com/hltswd/p/6956264.html 第一步:在centos下面下载 nginx wget http://nginx.or ...
- CLH同步队列
原文链接:https://blog.csdn.net/chenssy/article/details/60781148 AQS内部维护着一个FIFO队列,该队列就是CLH同步队列. CLH同步队列是一 ...
- 树状数组 P3605 [USACO17JAN]Promotion Counting晋升者计数
P3605 [USACO17JAN]Promotion Counting晋升者计数 题目描述 奶牛们又一次试图创建一家创业公司,还是没有从过去的经验中吸取教训--牛是可怕的管理者! 为了方便,把奶牛从 ...
- luogu4449 于神之怒加强版(莫比乌斯反演)
link 给定n,m,k,计算\(\sum_{i=1}^n\sum_{j=1}^m\gcd(i,j)^k\)对1000000007取模的结果 多组数据,T<=2000,1<=N,M,K&l ...
- Mybatis学习笔记(三) —— DAO开发方法
一.SqlSession的使用范围 SqlSession中封装了对数据库的操作,如:查询.插入.更新.删除等. SqlSession通过SqlSessionFactory创建. SqlSessionF ...
- H - 逆序数(树状数组)
在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数. 如2 4 3 1中,2 1,4 3,4 1,3 1是逆序 ...