美文网首页
理解并手写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