美文网首页
理解并手写Spring MVC框架

理解并手写Spring MVC框架

作者: 与李_han | 来源:发表于2020-08-15 09:54 被阅读0次

    一、前言

    Spring框架是大多Java程序员的必修课程,而SpringMVC是里面的重头戏,它大大的简化了Servlet的繁琐操作,让开发人员得以用更多的时间去处理业务。

    SpringMVC是一款经典的三层架构模式,M为Model(模型),V为View(视图),C为Controlle(控制器)。MVC是一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。

    二、SpringMVC流程

    流程简述:

    (1)用户通过浏览器或其他途径发起请求。

    (2)请求经过前端控制器DispatcherServlet,并根据请求的URI匹配到对应的处理映射器。

    (3)处理映射器返回HandlerExecutionChain实体给DispatcherServlet,内部封装了拦截器HandlerInterceptor、Object类型的具体处理器handler。

    (4)系统启动时,初始化了HandlerAdapter的List的集合,此步骤循环List集合,调用HandlerAdapter的support方法,找到handler支持的HandlerAdapter处理适配器。

    (5)由HandlerAdapter处理参数并调用处理器的方法。

    (6)返回结果是ModelAndView,即视图。其内部封装了view、model、status。

    (7)将处理得到的ModelAndView返回给DispatcherServlet。

    (8)将ModelAndView交由专业的视图解析器进行解析,得到页面位置。

    (9)返回结果给DispatcherServlet。

    (10)将数据渲染到页面。

    (11)响应请求。

    源码核心部分概览

    protected void initStrategies(ApplicationContext context) {
        initMultipartResolver(context);
        initLocaleResolver(context);
        initThemeResolver(context);
        initHandlerMappings(context);
        initHandlerAdapters(context);
        initHandlerExceptionResolvers(context);
        initRequestToViewNameTranslator(context);
        initViewResolvers(context);
        initFlashMapManager(context);
    }
    
    • initMultipartResolver(context)

    初始化文件上传解析功能,将普通HttpServletRequest包装成MutipartHttpServletRequest,此类可通过getFile获取到文件集合。

    • initLocaleResolver(context)

    初始化与当地区域有关的设置,如视图解析器与国际化资源的配置。

    • initThemeResolver(context)

    初始化主题解析,如消息国际话得配置,每个主题对应 一个properties文件。

    • initHandlerMappings(context)

    初始化HandlerMappings,用来获取对应的handler与interceptor。

    • initHandlerAdapters(context)

    初始化处理适配器,用来执行具体方法。

    • initHandlerExceptionResolvers(context)

    对异常情况进行处理。

    • initRequestToViewNameTranslator(context)

    从请求中获取视图名称。

    • initViewResolvers(context)

    初始化视图解析器,将ModelAndView渲染成页面。

    • initFlashMapManager(context)

    主要用处在于传递重定向参数。

    三、手写Spring MVC

    项目目录

    源码地址:

    https://github.com/hanguilin/custom-springmvc

    环境配置:

    maven项目中引入Servlet需要的jar包

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.0.1</version>
        <scope>provided</scope>
    </dependency>
    

    其他jar包(本人写代码用到的一些包)

            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
                <version>1.7.25</version>
            </dependency>
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-classic</artifactId>
                <version>1.2.3</version>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-simple</artifactId>
                <version>1.7.25</version>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.17</version>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-log4j12</artifactId>
                <version>1.7.21</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-lang3</artifactId>
                <version>3.4</version>
            </dependency>
    

    注解类:

    建立SpringMVC中常用注解@Controller、@RequstMapping、@Autowired、@Qualifier、@Service、@RequestParam的替代注解。区别为在自己的注解中给名字添加了Custom前缀。各个注解的区别在于注解地方,如类、方法、字段上不同。

    CustomController.java

    package com.hgl.mvc.annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * 控制层注解
     * @author guilin
     *
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Target(ElementType.TYPE)
    public @interface CustomController {
    
        String value() default "";
    }
    
    

    CustomRequestMapping.java

    package com.hgl.mvc.annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * 请求路径注解
     * @author guilin
     *
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Target({ElementType.TYPE, ElementType.METHOD})
    public @interface CustomRequestMapping {
    
        String value();
    }
    
    

    CustomAutowired.java

    package com.hgl.mvc.annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * 自动注入
     * @author guilin
     *
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
    public @interface CustomAutowired {
    
        String value() default "";
    }
    
    

    CustomQualifer.java

    package com.hgl.mvc.annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * 按名称自动注入
     * @author guilin
     *
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
    public @interface CustomQualifer {
    
        String value();
    }
    
    
    image.gif

    CustomService.java

    package com.hgl.mvc.annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * 业务层注解
     * @author guilin
     *
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Target(ElementType.TYPE)
    public @interface CustomService {
    
        String value() default "";
    }
    
    

    CustomRequestParam.java

    package com.hgl.mvc.annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * 参数注解
     * @author guilin
     *
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Target(ElementType.PARAMETER)
    public @interface CustomRequestParam {
    
        String value() default "";
    }
    
    

    配置文件

    在classpath下建立spring-mvc.properties,指定扫描包路径

    spring.scanner.base.package=com.hgl
    

    核心配置类

    SpringMVC核心配置类DispatcherServlet.java,替代类为CustomDispatcherServlet.java

    package com.hgl.mvc.servlet;
    
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.net.URL;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Properties;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    import javax.servlet.ServletConfig;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.apache.commons.lang3.StringUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.hgl.mvc.annotation.CustomController;
    import com.hgl.mvc.annotation.CustomQualifer;
    import com.hgl.mvc.annotation.CustomRequestMapping;
    import com.hgl.mvc.annotation.CustomService;
    import com.hgl.mvc.resolver.ArgumentResolver;
    
    public class CustomDispatcherServlet extends HttpServlet{
    
        private static final Logger LOGGER = LoggerFactory.getLogger(CustomDispatcherServlet.class);
    
        private static final long serialVersionUID = 1L;
    
        private Properties contextConfig = new Properties();
    
        // 所有扫描类
        private List<String> classes = new ArrayList<String>();
    
        // 存放bean的容器ioc
        private Map<String, Object> context = new HashMap<String, Object>();
    
        // 存放参数解析器
        private Map<String, ArgumentResolver> argumentResolverMap = new HashMap<String, ArgumentResolver>();
    
        // 根据请求url找到具体的处理器
        private List<CustomHandlerMapping> handlerMapping = new ArrayList<CustomHandlerMapping>();
    
        private List<CustomHandlerAdapter> handlerAdapter = new ArrayList<CustomHandlerAdapter>();
    
        public CustomDispatcherServlet() {
            LOGGER.info("CustomDispatcherServlet()...");
        }
    
        @Override
        public void init(ServletConfig config) throws ServletException {
            // 加载配置文件
            initConfig(config.getInitParameter("spring-mvc"));
            // 扫描类
            initBaseScanPackage(contextConfig.getProperty("spring.scanner.base.package"));
            // 生成bean实例,注入ioc
            initContext();
            // 初始化参数解析器
            initArgumentResolver();
            // 为controller层中service对象注入实例
            initInstance();
            // 建立URI与处理器的映射
            initHandlerMapping();
            // 处理器适配器
            initHandlerAdapter();
        }
    
        private void initConfig(String initParameter) {
            InputStream in = this.getClass().getClassLoader().getResourceAsStream(initParameter);
            try {
                contextConfig.load(in);
            } catch (IOException e) {
                LOGGER.error(e.getMessage(), e);
            } finally {
                if(in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        LOGGER.error(e.getMessage(), e);
                    }
                }
            }
        }
    
        private void initBaseScanPackage(String basePackage) {
            URL resource = this.getClass().getClassLoader().getResource("/" + basePackage.replaceAll("\\.", "/"));
            String packagePath = resource.getFile();
            File packageFile = new File(packagePath);
            String[] listFiles = packageFile.list();
            for (String filepPath : listFiles) {
                File file = new File(packagePath + filepPath);
                if(file.isDirectory()) {
                    initBaseScanPackage(basePackage + "." + filepPath);
                }else {
                    classes.add(basePackage + "." + file.getName());
                }
            }
        }
    
        private void initContext() {
            if(classes.isEmpty()) {
                LOGGER.error("do scan failed.");
                return;
            }
            for (String className : classes) {
                String classPath = className.substring(0, className.lastIndexOf(".class"));
                try {
                    Class<?> clazz = Class.forName(classPath);
                    String simpleName = clazz.getSimpleName();
                    if(clazz.isAnnotationPresent(CustomController.class)) {
                        CustomController controller = clazz.getAnnotation(CustomController.class);
                        String key = controller.value();
                        if(StringUtils.isBlank(key)) {
                            key = toLowerCaseFirstOne(simpleName);
                        }
                        Object instance = clazz.newInstance();
                        context.put(key, instance);
                    } else if(clazz.isAnnotationPresent(CustomService.class)) {
                        CustomService service = clazz.getAnnotation(CustomService.class);
                        String key = service.value();
                        if(StringUtils.isBlank(key)) {
                            key = toLowerCaseFirstOne(simpleName);
                        }
                        Object instance = clazz.newInstance();
                        context.put(key, instance);
                    } else {
                        continue;
                    }
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
                    LOGGER.error(e.getMessage(), e);
                }
            }
        }
    
        private void initArgumentResolver() {
            if(context.isEmpty()) {
                return;
            }
            for(Map.Entry<String, Object> entry : context.entrySet()) {
                Object bean = entry.getValue();
                // 判定此 Class 对象所表示的类或接口与指定的 Class 参数所表示的类或接口是否相同,或是否是其超类或超接口
                if(ArgumentResolver.class.isAssignableFrom(bean.getClass())) {
                    argumentResolverMap.put(entry.getKey(), (ArgumentResolver) bean);
                }
            }
        }
    
        private void initInstance() {
            if(context.isEmpty()) {
                LOGGER.error("no bean is instanced.");
                return;
            }
            for(Map.Entry<String, Object> entry : context.entrySet()) {
                Object bean = entry.getValue();
                Class<? extends Object> clazz = bean.getClass();
                if(clazz.isAnnotationPresent(CustomController.class)) {
                    Field[] declaredFields = clazz.getDeclaredFields();
                    for (Field field : declaredFields) {
                        if(field.isAnnotationPresent(CustomQualifer.class)) {
                            CustomQualifer qualifer = field.getAnnotation(CustomQualifer.class);
                            String beanName = qualifer.value();
                            Object value = context.get(beanName);
                            try {
                                if(!field.isAccessible()) {
                                    field.setAccessible(true);
                                }
                                field.set(bean, value);
                            } catch (IllegalArgumentException | IllegalAccessException e) {
                                LOGGER.error(e.getMessage(), e);
                            }
                        }
                    }
                }
            }
        }
    
        private void initHandlerMapping() {
            if(context.isEmpty()) {
                LOGGER.error("no bean is instanced.");
                return;
            }
            for(Map.Entry<String, Object> entry : context.entrySet()) {
                Object bean = entry.getValue();
                Class<? extends Object> clazz = bean.getClass();
                if(clazz.isAnnotationPresent(CustomController.class)) {
                    String classRequestMappingVal = "";
                    if(clazz.isAnnotationPresent(CustomRequestMapping.class)) {
                        CustomRequestMapping classRequestMapping = clazz.getAnnotation(CustomRequestMapping.class);
                        classRequestMappingVal = classRequestMapping.value();
                    }
                    Method[] declaredMethods = clazz.getDeclaredMethods();
                    List<String> uris = new ArrayList<String>();
                    for (Method method : declaredMethods) {
                        String methodRequestMappingVal = "";
                        if(method.isAnnotationPresent(CustomRequestMapping.class)) {
                            CustomRequestMapping methodRequestMapping = method.getAnnotation(CustomRequestMapping.class);
                            methodRequestMappingVal = classRequestMappingVal + methodRequestMapping.value();
                        }
                        if(StringUtils.isNotBlank(methodRequestMappingVal)) {
                            if(uris.contains(methodRequestMappingVal)) {
                                throw new RuntimeException("Duplicate mapping for " + methodRequestMappingVal);
                            }
                            handlerMapping.add(new CustomHandlerMapping(bean, method, Pattern.compile(methodRequestMappingVal)));
                            uris.add(methodRequestMappingVal);
                        }
                    }
                    uris = null;
                }
            }
        }
    
        private void initHandlerAdapter() {
            if(context.isEmpty()) {
                LOGGER.error("no bean is instanced.");
                return;
            }
            for(Map.Entry<String, Object> entry : context.entrySet()) {
                Object bean = entry.getValue();
                // 判定此 Class 对象所表示的类或接口与指定的 Class 参数所表示的类或接口是否相同,或是否是其超类或超接口
                if(CustomHandlerAdapter.class.isAssignableFrom(bean.getClass())) {
                    handlerAdapter.add((CustomHandlerAdapter) bean);
                }
            }
        }
    
        private String toLowerCaseFirstOne(String s){
            if(Character.isLowerCase(s.charAt(0)))
                return s;
            else
                return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
        }
    
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doPost(request, response);
        }
    
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            CustomHandlerMapping handler = getHandler(request);
            CustomHandlerAdapter handlerAdapter = getHandlerAdapter(handler);
            CustomModelAndView modelAndView = handlerAdapter.handle(request, response, handler, argumentResolverMap);
        }
    
        private CustomHandlerAdapter getHandlerAdapter(CustomHandlerMapping handler) {
            for (CustomHandlerAdapter customHandlerAdapter : handlerAdapter) {
                if(customHandlerAdapter.support(handler)) {
                    return customHandlerAdapter;
                }
            }
            throw new RuntimeException("There is no handlerAdapter for " + handler);
        }
    
        private CustomHandlerMapping getHandler(HttpServletRequest request) {
            String requestURI = request.getRequestURI();
            String path = requestURI.replaceAll(request.getContextPath(), "");
            for (CustomHandlerMapping handler : handlerMapping) {
                Pattern pattern = handler.getPattern();
                Matcher matcher = pattern.matcher(path);
                if(matcher.matches()) {
                    return handler;
                }
            }
            throw new RuntimeException("There is no mapping for " + path);
        }
    
    }
    
    

    处理映射器

    CustomHandlerMapping.java

    package com.hgl.mvc.servlet;
    
    import java.lang.reflect.Method;
    import java.util.regex.Pattern;
    
    /**
     * 自定义handlerMapping
     * 
     * @author guilin
     *
     */
    public class CustomHandlerMapping{
    
        /**
         * controller对应的bean
         */
        private Object controller;
    
        /**
         * 具体处理方法
         */
        private Method method;
    
        /**
         * 用来验证是否是当前url对应的处理方法
         */
        private Pattern pattern;
    
        public CustomHandlerMapping(Object controller, Method method, Pattern pattern) {
            super();
            this.controller = controller;
            this.method = method;
            this.pattern = pattern;
        }
    
        public Object getController() {
            return controller;
        }
    
        public void setController(Object controller) {
            this.controller = controller;
        }
    
        public Method getMethod() {
            return method;
        }
    
        public void setMethod(Method method) {
            this.method = method;
        }
    
        public Pattern getPattern() {
            return pattern;
        }
    
        public void setPattern(Pattern pattern) {
            this.pattern = pattern;
        }
    }
    

    处理适配器

    CustomHandlerAdapter.java,作为接口,由实现类实现。

    package com.hgl.mvc.servlet;
    
    import java.util.Map;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import com.hgl.mvc.resolver.ArgumentResolver;
    
    /**
     * @author guilin
     * 自定义适配器
     *
     */
    public interface CustomHandlerAdapter {
    
        /**
         * 是否支持处理
         * 是则调用本类handle方法
         * 
         * @param handler 处理器
         * @return boolean
         */
        public boolean support(Object handler);
    
        /**
         * 具体处理方法
         * 
         * @param request
         * @param response
         * @param handler
         * @param argumentResolverMap
         * @return CustomModelAndView
         */
        public CustomModelAndView handle(HttpServletRequest request, HttpServletResponse response, CustomHandlerMapping handler,
                Map<String, ArgumentResolver> argumentResolverMap);
    
    }
    
    

    实现类CustomSimpleHandlerAdapter.java

    package com.hgl.mvc.servlet;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.Map;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.hgl.mvc.annotation.CustomService;
    import com.hgl.mvc.resolver.ArgumentResolver;
    
    /**
     * 对处理适配器的实现
     * 
     * @author guilin
     *
     */
    @CustomService("customSimpleHandlerAdapter")
    public class CustomSimpleHandlerAdapter implements CustomHandlerAdapter{
    
        private static final Logger LOGGER = LoggerFactory.getLogger(CustomDispatcherServlet.class);
    
        @Override
        public CustomModelAndView handle(HttpServletRequest request, HttpServletResponse response, CustomHandlerMapping handler,
                Map<String, ArgumentResolver> argumentResolverMap) {
            Method method = handler.getMethod();
            Object controller = handler.getController();
            Class<?>[] parameterTypes = method.getParameterTypes();
            Object[] args = new Object[parameterTypes.length];
            for (int i = 0; i < parameterTypes.length; i++) {
                Class<?> parameterClass = parameterTypes[i];
                for (Map.Entry<String, ArgumentResolver> entry : argumentResolverMap.entrySet()) {
                    ArgumentResolver argumentResolver = entry.getValue();
                    if(argumentResolver.support(parameterClass, i, method)) {
                        Object resolver = argumentResolver.argumentResolver(request, response, parameterClass, i, method);
                        args[i] = resolver;
                        break;
                    }
                }
            }
            try {
                method.invoke(controller, args);
            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                LOGGER.error(e.getMessage(), e);
            }
            return new CustomModelAndView();
        }
    
        @Override
        public boolean support(Object handler) {
            // 暂定实现为true
            return true;
        }
    
    }
    
    

    参数解析器

    ArgumentResolver.java,作为上层接口,具体由实现类实现。

    package com.hgl.mvc.resolver;
    
    import java.lang.reflect.Method;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * 参数解析器
     * @author guilin
     *
     */
    public interface ArgumentResolver {
    
        public boolean support(Class<?> type, int paramIndex, Method method);
    
        public Object argumentResolver(HttpServletRequest request, HttpServletResponse response,
                Class<?> type, int paramIndex, Method method);
    }
    
    

    HttpServletRequestArgumentResolver.java,用于解析HttpServletRequest参数

    package com.hgl.mvc.resolver;
    
    import java.lang.reflect.Method;
    
    import javax.servlet.ServletRequest;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import com.hgl.mvc.annotation.CustomService;
    
    /**
     * HttpServletRequest参数解析器
     * @author guilin
     *
     */
    @CustomService("httpServletRequestArgumentResolver")
    public class HttpServletRequestArgumentResolver implements ArgumentResolver {
    
        @Override
        public boolean support(Class<?> type, int paramIndex, Method method) {
            return ServletRequest.class.isAssignableFrom(type);
        }
    
        @Override
        public Object argumentResolver(HttpServletRequest request, HttpServletResponse response, Class<?> type,
                int paramIndex, Method method) {
            return request;
        }
    
    }
    
    

    HttpServletResponseArgumentResolver.java,用于解析HttpServletResponse参数

    package com.hgl.mvc.resolver;
    
    import java.lang.reflect.Method;
    
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import com.hgl.mvc.annotation.CustomService;
    
    /**
     * HttpServletResponse参数解析器
     * @author guilin
     *
     */
    @CustomService("httpServletResponseArgumentResolver")
    public class HttpServletResponseArgumentResolver implements ArgumentResolver {
    
        @Override
        public boolean support(Class<?> type, int paramIndex, Method method) {
            return ServletResponse.class.isAssignableFrom(type);
        }
    
        @Override
        public Object argumentResolver(HttpServletRequest request, HttpServletResponse response, Class<?> type,
                int paramIndex, Method method) {
            return response;
        }
    
    }
    
    

    RequestParamArgumentResolver.java,用于解析CustomRequestParam定义的参数

    package com.hgl.mvc.resolver;
    
    import java.lang.annotation.Annotation;
    import java.lang.reflect.Method;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import com.hgl.mvc.annotation.CustomRequestParam;
    import com.hgl.mvc.annotation.CustomService;
    
    /**
     * RequestParam参数解析器
     * @author guilin
     *
     */
    @CustomService("requestParamArgumentResolver")
    public class RequestParamArgumentResolver implements ArgumentResolver {
    
        @Override
        public boolean support(Class<?> type, int paramIndex, Method method) {
            Annotation[][] annotations = method.getParameterAnnotations();
            Annotation[] currentField = annotations[paramIndex];
            for (Annotation annotation : currentField) {
                if(CustomRequestParam.class.isAssignableFrom(annotation.getClass())) {
                    return true;
                }
            }
            return false;
        }
    
        @Override
        public Object argumentResolver(HttpServletRequest request, HttpServletResponse response, Class<?> type,
                int paramIndex, Method method) {
            Annotation[][] annotations = method.getParameterAnnotations();
            Annotation[] currentField = annotations[paramIndex];
            for (Annotation annotation : currentField) {
                if(CustomRequestParam.class.isAssignableFrom(annotation.getClass())) {
                    CustomRequestParam requestParam = (CustomRequestParam) annotation;
                    String parameterName = requestParam.value();
                    String parameterVal = request.getParameter(parameterName);
                    return parameterVal;
                }
            }
            return null;
        }
    
    }
    
    

    相关文章

      网友评论

          本文标题:理解并手写Spring MVC框架

          本文链接:https://www.haomeiwen.com/subject/atnodktx.html