zoukankan      html  css  js  c++  java
  • 自定义HandlerMethodArgumentResolver参数解析器和源码分析

    在初学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());
    	}
    }
    

      

  • 相关阅读:
    25、Base64
    24、AES RSA加密处理记录
    23、获取app所占据的内存
    22、DDMS(转载)
    21、HierarchyViewer使用记录
    kubernetes 操作 serviceaccounts
    删除dashboard
    数据库建库指定UTF-8和jdbc连接字符串
    apt 被卸载
    EasyReport报表工具部署
  • 原文地址:https://www.cnblogs.com/wangjing666/p/10770726.html
Copyright © 2011-2022 走看看