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

      

  • 相关阅读:
    poj 2488 DFS
    畅通工程 并查集模版
    KMP 模板
    poj 1426 DFS
    poj 2528 线段数
    poj 3468 线段数 修改区间(点)
    CVPR2012文章阅读(2)A Unified Approach to Salient Object Detection via Low Rank Matrix Recovery
    如何制定目标
    Saliency Map 最新综述
    计算机视觉模式识别重要会议杂志
  • 原文地址:https://www.cnblogs.com/wangjing666/p/10770726.html
Copyright © 2011-2022 走看看