A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 逆风TO 于 2018-3-30 09:17 编辑

分析前提,分析的是注解方式配置的源码,不同的处理方式源码不相同研究目的,探讨springmvc参数绑定我们主要研究的问题
  • springmvc怎么获取页面传入过来的数据
  • springmvc怎么把界面传入的数据绑定到对象上
    例如页面(input type="text" name="username")后台username是User的属性字段
  • springmvc Controller类中的方法怎么执行的
  • springmvc 中方法加注解和不加注解的区别
    public String index(HttpServletRequest request, HttpServletResponse response,              User user12, Person person, String keywordsa,
                   @RequestParam("keywords") String words,String keywords)


    简单的springmvc项目搭建,采用注解方式进行开发
  • 项目的下载地址
    https://github.com/wolvesleader/simplespringmvc
从springmvc的入口开始查看
代码段1
在org.springframework.web.servlet.DispatcherServlet类中
@Override
protected void doService(HttpServletRequest request,
                         HttpServletResponse response) throws Exception {
    //省略我们不研究的代码
    try {
        doDispatch(request, response);
    }
    finally {
    }
}


代码段2
在org.springframework.web.servlet.DispatcherServlet类中接着查找doDispatch方法代码如下所示
protected void doDispatch(HttpServletRequest request,
                         HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    int interceptorIndex = -1;
    try {
        ModelAndView mv;
        boolean errorView = false;
        try {
            // Determine handler adapter for the current request.
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler())
            // Actually invoke the handler.
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
        }
    }
}


代码段3
我们直接从注解类型适配器的源码中来看
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter
public final ModelAndView handle(HttpServletRequest request,
                          HttpServletResponse response, Object handler)throws Exception {
    return handleInternal(request, response, (HandlerMethod) handler);
}


代码段4
接着看handleInternal源码
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
@Override
protected final ModelAndView handleInternal(HttpServletRequest request,
                                            HttpServletResponse response,
                                            HandlerMethod handlerMethod) throws Exception {
    //忽略我们不研究的代码
    return invokeHandlerMethod(request, response, handlerMethod);
}


代码段5
到此我们来看invokeHandlerMethod做了一些什么事情
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
private ModelAndView invokeHandlerMethod(
                    HttpServletRequest request,HttpServletResponse response,
                    HandlerMethod handlerMethod) throws Exception {
    requestMappingMethod.invokeAndHandle(webRequest, mavContainer);
}


代码段6
来看这里的代码
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod类中的
requestMappingMethod.invokeAndHandle(webRequest, mavContainer);
public final void invokeAndHandle(NativeWebRequest request,
                                 ModelAndViewContainer mavContainer,
                                 Object... providedArgs) throws Exception {
    Object returnValue = invokeForRequest(request, mavContainer, providedArgs);
}


代码段7
接着走我们去看
org.springframework.web.method.support.InvocableHandlerMethod类中的
Object returnValue = invokeForRequest(request, mavContainer, providedArgs);
public Object invokeForRequest(NativeWebRequest request,
                               ModelAndViewContainer mavContainer,
                               Object... providedArgs) throws Exception {
    //获取参数并且封装
    Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
    //执行Controller中的方法
    Object returnValue = doInvoke(args);

    return returnValue;
}


代码段8
我们先看getMethodArgumentValues(request, mavContainer, providedArgs);方法
private Object[] getMethodArgumentValues(NativeWebRequest request,
                                         ModelAndViewContainer mavContainer,
                                         Object... providedArgs) throws Exception {
    MethodParameter[] parameters = getMethodParameters();
    Object[] args = new Object[parameters.length];
    for (int i = 0; i < parameters.length; i++) {
       //省略我们不研究的代码
        args = this.argumentResolvers.resolveArgument(
                        parameter, mavContainer, request, this.dataBinderFactory);
            continue;
        }
    }
    return args;
}


代码段9
@Override
public Object resolveArgument(MethodParameter parameter,
                              ModelAndViewContainer mavContainer,NativeWebRequest webRequest,
                              WebDataBinderFactory binderFactory) throws Exception {
    //根据方法中的参数获取到参数的解析器
    //在代码段2中的getHandlerAdapter方法执行的时候就会把解析器准备好
    //在次我们只要根据不同的解析器解析参数就可以了
    HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
    //用获取到的参数解析器去解析参数
    return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}


根据我们代码中的方法的参数
public String index(HttpServletRequest request,
                    HttpServletResponse response,
                    User user12, Person person,
                    String keywords,String keywordsa,
                    @RequestParam("keywords") String words)


我们结合源码可知需要以下的参数解析器,怎么是知道需要这些解析器,可以走断点调试
org.springframework.web.servlet.mvc.method.annotation.ServletRequestMethodArgumentResolver
org.springframework.web.servlet.mvc.method.annotation.ServletResponseMethodArgumentResolver
org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor
org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor
org.springframework.web.method.annotation.RequestParamMethodArgumentResolver
org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver
代码段10
我们先来看对HttpServletRequest的设置
public Object resolveArgument(
        MethodParameter parameter, ModelAndViewContainer mavContainer,
        NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
        throws IOException {
    HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
    if (ServletRequest.class.isAssignableFrom(paramType) ||
              MultipartRequest.class.isAssignableFrom(paramType)) {
        Object nativeRequest = webRequest.getNativeRequest(paramType);
        //省略不研究的代码
        return nativeRequest;
    }
}


代码段11
对HttpServletResponse的设置
public Object resolveArgument(
        MethodParameter parameter, ModelAndViewContainer mavContainer,
        NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
        throws IOException {
    HttpServletResponse response =
                       webRequest.getNativeResponse(HttpServletResponse.class);
    Class<?> paramType = parameter.getParameterType();
    if (ServletResponse.class.isAssignableFrom(paramType)) {
        Object nativeResponse = webRequest.getNativeResponse(paramType);
        return nativeResponse;
    }
}


代码段12
对User的设置,这段代码非常的重要
public final Object resolveArgument(
        MethodParameter parameter, ModelAndViewContainer mavContainer,
        NativeWebRequest request, WebDataBinderFactory binderFactory)
        throws Exception {
    //获取方法中参数的参数名,注意是参数名不是参数类型
    String name = ModelFactory.getNameForParameter(parameter);
    Object target = (mavContainer.containsAttribute(name)) ?
                    mavContainer.getModel().get(name) :
                    createAttribute(name, parameter, binderFactory, request);

    WebDataBinder binder = binderFactory.createBinder(request, target, name);
    if (binder.getTarget() != null) {
        bindRequestParameters(binder, request);
        validateIfApplicable(binder, parameter);
        if (binder.getBindingResult().hasErrors()) {
            if (isBindExceptionRequired(binder, parameter)) {
                throw new BindException(binder.getBindingResult());
            }
        }
    }

    mavContainer.addAllAttributes(binder.getBindingResult().getModel());
    return binder.getTarget();
}


代码段13
先看String name = ModelFactory.getNameForParameter(parameter);获取方法的参数名
org.springframework.web.method.annotation.ModelFactory
public static String getNameForParameter(MethodParameter parameter) {
    //根据注解获取方法的参数名,如果没有获取直接以类名首字母小写做为参数名
    //自定义的对象这个参数名没有任何影响,因为我们获取界面的参数要根据
    //类中的字段去获取可以在Conventions.getVariableNameForParameter(parameter)中查看
    ModelAttribute annot = parameter.getParameterAnnotation(ModelAttribute.class);
    String attrName = (annot != null) ? annot.value() : null;
    return StringUtils.hasText(attrName) ? attrName :  Conventions.getVariableNameForParameter(parameter);
}


代码段14
到此找到了自定义对象的参数名,在代码段12中的第7-9行中从容器中根据名字获取对象,如果获取不到会创建一个对象
@Override
protected final Object createAttribute(String attributeName,
                                       MethodParameter parameter,
                                       WebDataBinderFactory binderFactory,
                                       NativeWebRequest request) throws Exception {
    String value = getRequestValueForAttribute(attributeName, request);
    if (value != null) {
        Object attribute = createAttributeFromRequestValue(value,
                           attributeName, parameter, binderFactory, request);
        if (attribute != null) {
            return attribute;
        }
    }
    return super.createAttribute(attributeName, parameter, binderFactory, request);
}


代码段15
接着看怎么创建对象的
在org.springframework.web.method.annotation.ModelAttributeMethodProcessor类中的方法
protected Object createAttribute(String attributeName, MethodParameter parameter,
        WebDataBinderFactory binderFactory,  NativeWebRequest request) throws Exception {
    return BeanUtils.instantiateClass(parameter.getParameterType());
}


可以看到是根据类型通过反射创建出来一个对象,到此对象已经有了,我们要根据类中的字段从request中获取
代页面传入的参数并且封装,在代码段12第13行中
org.springframework.web.bind.ServletRequestDataBinder
代码段16
@Override
protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) {
    ServletRequest servletRequest = request.getNativeRequest(ServletRequest.class);
    ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder;
    servletBinder.bind(servletRequest);
}


代码段17
在走到org.springframework.web.bind.ServletRequestDataBinder
public void bind(ServletRequest request) {
    MutablePropertyValues mpvs = new ServletRequestParameterPropertyValues(request);
    MultipartRequest multipartRequest =
                     WebUtils.getNativeRequest(request, MultipartRequest.class);
    if (multipartRequest != null) {
        bindMultipart(multipartRequest.getMultiFileMap(), mpvs);
    }
    addBindValues(mpvs, request);
    doBind(mpvs);
}


代码段18
在代码段17中需要先看一下MutablePropertyValues这个对象,因为在这里做了获取页面传入的数据
public ServletRequestParameterPropertyValues(ServletRequest request) {
    this(request, null, null);
}


org.springframework.web.bind.ServletRequestParameterPropertyValues中
public ServletRequestParameterPropertyValues(ServletRequest request,
                                            String prefix, String prefixSeparator) {
    super(WebUtils.getParametersStartingWith(
            request, (prefix != null ? prefix + prefixSeparator : null)));
}


来到了核心类org.springframework.web.util.WebUtils
public static Map<String, Object> getParametersStartingWith(ServletRequest request,
                                               String prefix) {
    Assert.notNull(request, "Request must not be null");
    Enumeration paramNames = request.getParameterNames();
    Map<String, Object> params = new TreeMap<String, Object>();
    if (prefix == null) {
        prefix = "";
    }
    while (paramNames != null && paramNames.hasMoreElements()) {
        String paramName = (String) paramNames.nextElement();
        if ("".equals(prefix) || paramName.startsWith(prefix)) {
            String unprefixed = paramName.substring(prefix.length());
            String[] values = request.getParameterValues(paramName);
            if (values == null || values.length == 0) {
                // Do nothing, no values found at all.
            }
            else if (values.length > 1) {
                params.put(unprefixed, values);
            }
            else {
                params.put(unprefixed, values[0]);
            }
        }
    }
    return params;
}


到这里我们可以看到获取到了页面属性的字段名,和字段对应的值,放在了mpvs中
接着代码段17中的第9行继续走来到了org.springframework.web.bind.WebDataBinder中的方法
@Override
protected void doBind(MutablePropertyValues mpvs) {
    checkFieldDefaults(mpvs);
    checkFieldMarkers(mpvs);
    super.doBind(mpvs);
}


org.springframework.validation.DataBinder中的方法
protected void doBind(MutablePropertyValues mpvs) {
    checkAllowedFields(mpvs);
    checkRequiredFields(mpvs);
    applyPropertyValues(mpvs);
}


protected void applyPropertyValues(MutablePropertyValues mpvs) {
    try {
        // Bind request parameters onto target object.
        getPropertyAccessor().setPropertyValues(mpvs,
        isIgnoreUnknownFields(), isIgnoreInvalidFields());
    }
    catch (PropertyBatchUpdateException ex) {
    }
}


接着走会去到org.springframework.beans.AbstractPropertyAccessor类中的setPropertyValues方法
在这里我们就在不向下走了,它主要就是根据PropertyDescriptor获取到类的字段然后调用set方法设置值
对Person设置值和User相同
代码段19
对String类型的keywords设置值,首先看我们这个String类型是没有添加注解,springmvc封装原则先
根据ASM框架获取参数名,根据参数名在request对象中获取值然后放在args数组中
org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver中的解析器
public final Object resolveArgument(
        MethodParameter parameter, ModelAndViewContainer mavContainer,
        NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
        throws Exception {

    Class<?> paramType = parameter.getParameterType();
    NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
    Object arg = resolveName(namedValueInfo.name, parameter, webRequest);
    //忽略我们不研究的代码
    return arg;
}


代码段20
在同一个类中根据参数去获取
private NamedValueInfo getNamedValueInfo(MethodParameter parameter) {
    NamedValueInfo namedValueInfo = this.namedValueInfoCache.get(parameter);
    if (namedValueInfo == null) {
        namedValueInfo = createNamedValueInfo(parameter);
        namedValueInfo = updateNamedValueInfo(parameter, namedValueInfo);
        this.namedValueInfoCache.put(parameter, namedValueInfo);
    }
    return namedValueInfo;
}


代码段21
@Override
protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
    RequestParam annotation = parameter.getParameterAnnotation(RequestParam.class);
    return (annotation != null) ?
            new RequestParamNamedValueInfo(annotation) :
            new RequestParamNamedValueInfo();
}


代码段22
从上代码可以看出,如果参数没有加注解封装为了new RequestParamNamedValueInfo()对象
private NamedValueInfo updateNamedValueInfo(MethodParameter parameter,
                                  NamedValueInfo info) {
    String name = info.name;
    if (info.name.length() == 0) {
        name = parameter.getParameterName();
    }
    String defaultValue = (ValueConstants.DEFAULT_NONE.equals(info.defaultValue) ?
                           null : info.defaultValue);
    return new NamedValueInfo(name, info.required, defaultValue);
}


代码段23
在org.springframework.core.MethodParameter类中可以看到由于没有加注解,所以需要在参数列表中找参数名
public String getParameterName() {
    if (this.parameterNameDiscoverer != null) {
       //获取到参数列表
        String[] parameterNames = (this.method != null ?
                this.parameterNameDiscoverer.getParameterNames(this.method) :
                this.parameterNameDiscoverer.getParameterNames(this.constructor));
        if (parameterNames != null) {
            //获取到参数列表,根据参数索引获取到参数的名字
            this.parameterName = parameterNames[this.parameterIndex];
        }
        this.parameterNameDiscoverer = null;
    }
    return this.parameterName;
}


代码段24
获取参数列表是根据ASM,框架的org.springframework.core.LocalVariableTableParameterNameDiscoverer
public String[] getParameterNames(Method method) {
    Class<?> declaringClass = method.getDeclaringClass();
    Map<Member, String[]> map = this.parameterNamesCache.get(declaringClass);
    if (map == null) {
        // initialize cache
        map = inspectClass(declaringClass);
        this.parameterNamesCache.put(declaringClass, map);
    }
    if (map != NO_DEBUG_INFO_MAP) {
        return map.get(method);
    }
    return null;
}


到次位置获取到了参数名,我们需要根据参数名从request中获取页面传入的值,回到代码段19中的第8行
进入到org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver
我们发现,是一个抽象的方法,需要去找它的实现类
org.springframework.web.method.annotation.RequestParamMethodArgumentResolver
代码段25
protected abstract Object resolveName(String name, MethodParameter parameter,
                           NativeWebRequest request)throws Exception;


代码段26
@Override
protected Object resolveName(String name, MethodParameter parameter,
                            NativeWebRequest webRequest) throws Exception {
    Object arg;
    //忽略我们不关注的代码
    else {
        arg = null;
        if (arg == null) {
            String[] paramValues = webRequest.getParameterValues(name);
            if (paramValues != null) {
                //从请求中获取到参数所对应的值
                arg = paramValues.length == 1 ? paramValues[0] : paramValues;
            }
        }
    }
    return arg;
}


可以看到获取到了值,返回放在了args数组中,执行方法的时候作为方法的参数使用
再来看对String类型带有注解的设置@RequestParam("keywords") String words
和没有加注解不同的是在代码段21中new RequestParamNamedValueInfo(annotation)
创建了带有注解的对象,这样在代码段22中不会走第5行的代码,其他的全部相同
以上做了这么多事情主要是为了给执行方法准备方法的参数值
我们在回到代码段7的第7行Object returnValue = doInvoke(args);方法中
在org.springframework.web.method.support.InvocableHandlerMethod类中
一切准备就绪通过反射执行方法
    private Object invoke(Object... args) throws Exception {
        ReflectionUtils.makeAccessible(this.getBridgedMethod());
        try {
            return getBridgedMethod().invoke(getBean(), args);
        }
        catch (IllegalArgumentException e) {
            String msg = getInvocationErrorMessage(e.getMessage(), args);
            throw new IllegalArgumentException(msg, e);
        }
    }


小知识根据ASM获取方法的参数名
package com.quincy.demo;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public interface ParameterNameDiscoverer {
     String[] getParameterNames(Method method);
     String[] getParameterNames(Constructor ctor);
}


package com.quincy.demo;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.quincy.demo.ParameterNameDiscoverer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.asm.ClassReader;
import org.springframework.asm.Label;
import org.springframework.asm.MethodVisitor;
import org.springframework.asm.Opcodes;
import org.springframework.asm.Type;
import org.springframework.asm.commons.EmptyVisitor;
import org.springframework.util.ClassUtils;
public class LocalVariableTableParameterNameDiscoverer implements
                                            ParameterNameDiscoverer {
    private final Map<Class<?>, Map<Member, String[]>> parameterNamesCache =
            new ConcurrentHashMap<Class<?>, Map<Member, String[]>>();
    public String[] getParameterNames(Method method) {
        Class<?> declaringClass = method.getDeclaringClass();
        Map<Member, String[]> map = this.parameterNamesCache.get(declaringClass);
        if (map == null) {
            // initialize cache
            map = inspectClass(declaringClass);
            this.parameterNamesCache.put(declaringClass, map);
        }
        if (map != NO_DEBUG_INFO_MAP) {
            return map.get(method);
        }
        return null;
    }
    @SuppressWarnings("unchecked")
    public String[] getParameterNames(Constructor ctor) {
        Class<?> declaringClass = ctor.getDeclaringClass();
        Map<Member, String[]> map = this.parameterNamesCache.get(declaringClass);
        if (map == null) {
            // initialize cache
            map = inspectClass(declaringClass);
            this.parameterNamesCache.put(declaringClass, map);
        }
        if (map != NO_DEBUG_INFO_MAP) {
            return map.get(ctor);
        }
        return null;
    }
    private Map<Member, String[]> inspectClass(Class<?> clazz) {
        InputStream is =
                clazz.getResourceAsStream(ClassUtils.getClassFileName(clazz));
        if (is == null) {
            return NO_DEBUG_INFO_MAP;
        }
        try {
            ClassReader classReader = new ClassReader(is);
            Map<Member, String[]> map = new ConcurrentHashMap<Member, String[]>();
            classReader.accept(new ParameterNameDiscoveringVisitor(clazz, map),
                                                                       false);
            return map;
        }
        catch (IOException ex) {
        }
        finally {
            try {
                is.close();
            }
            catch (IOException ex) {
                // ignore
            }
        }
        return NO_DEBUG_INFO_MAP;
    }
    private static class ParameterNameDiscoveringVisitor extends EmptyVisitor {
        private static final String STATIC_CLASS_INIT = "<clinit>";
        private final Class<?> clazz;
        private final Map<Member, String[]> memberMap;
        public ParameterNameDiscoveringVisitor(Class<?> clazz,
                               Map<Member, String[]> memberMap) {
            this.clazz = clazz;
            this.memberMap = memberMap;
        }
        @Override
        public MethodVisitor visitMethod(int access, String name,
                              String desc, String signature, String[] exceptions) {
            // exclude synthetic + bridged && static class initialization
            if (!isSyntheticOrBridged(access) && !STATIC_CLASS_INIT.equals(name)) {
                return new LocalVariableTableVisitor(clazz, memberMap,
                         name, desc, isStatic(access));
            }
            return null;
        }
        private static boolean isSyntheticOrBridged(int access) {
            return (((access & Opcodes.ACC_SYNTHETIC) |
                    (access & Opcodes.ACC_BRIDGE)) > 0);
        }
        private static boolean isStatic(int access) {
            return ((access & Opcodes.ACC_STATIC) > 0);
        }
    }
    private static class LocalVariableTableVisitor extends EmptyVisitor {
        private static final String CONSTRUCTOR = "<init>";
        private final Class<?> clazz;
        private final Map<Member, String[]> memberMap;
        private final String name;
        private final Type[] args;
        private final boolean isStatic;
        private String[] parameterNames;
        private boolean hasLvtInfo = false;
        private final int[] lvtSlotIndex;
        public LocalVariableTableVisitor(Class<?> clazz, Map<Member, String[]> map,
                    String name, String desc, boolean isStatic) {
            this.clazz = clazz;
            this.memberMap = map;
            this.name = name;
            // determine args
            args = Type.getArgumentTypes(desc);
            this.parameterNames = new String[args.length];
            this.isStatic = isStatic;
            this.lvtSlotIndex = computeLvtSlotIndices(isStatic, args);
        }
        @Override
        public void visitLocalVariable(String name, String description,
                       String signature, Label start, Label end,int index) {
            this.hasLvtInfo = true;
            for (int i = 0; i < lvtSlotIndex.length; i++) {
                if (lvtSlotIndex == index) {
                    this.parameterNames = name;
                }
            }
        }
        @Override
        public void visitEnd() {
            if (this.hasLvtInfo || (this.isStatic &&
                     this.parameterNames.length == 0)) {
                memberMap.put(resolveMember(), parameterNames);
            }
        }
        private Member resolveMember() {
            ClassLoader loader = clazz.getClassLoader();
            Class<?>[] classes = new Class<?>[args.length];
            // resolve args
            for (int i = 0; i < args.length; i++) {
                classes = ClassUtils.
                             resolveClassName(args.getClassName(), loader);
            }
            try {
                if (CONSTRUCTOR.equals(name)) {
                    return clazz.getDeclaredConstructor(classes);
                }
                return clazz.getDeclaredMethod(name, classes);
            } catch (NoSuchMethodException ex) {
            }
        }
        private static int[] computeLvtSlotIndices(boolean isStatic,
                                           Type[] paramTypes) {
            int[] lvtIndex = new int[paramTypes.length];
            int nextIndex = (isStatic ? 0 : 1);
            for (int i = 0; i < paramTypes.length; i++) {
                lvtIndex = nextIndex;
                if (isWideType(paramTypes)) {
                    nextIndex += 2;
                } else {
                    nextIndex++;
                }
            }
            return lvtIndex;
        }
        private static boolean isWideType(Type aType) {
            // float is not a wide type
            return (aType == Type.LONG_TYPE || aType == Type.DOUBLE_TYPE);
        }
    }
}


测试代码
public class DemoDriver {
    public static void main(String[] args) {
        Class<User> userClass = User.class;
        LocalVariableTableParameterNameDiscoverer tableParameterNameDiscoverer =
             new LocalVariableTableParameterNameDiscoverer();
        Method[] methods = userClass.getMethods();
        for (Method m: methods) {
            System.out.println("方法");
            String[] parameterNames =
                tableParameterNameDiscoverer.getParameterNames(m);
            for (String name: parameterNames) {
                System.out.println("方法参数名称");
                System.out.println(name);
            }
        }
    }
}


总结
分析完源码我们来总结我们提出的问题
  • springmvc怎么获取页面传入过来的数据
    根据request对象来获取,和我们学习Servlet中获取参数基本相同
  • springmvc怎么把界面传入的数据绑定到对象上
    例如页面(input type="text" name="username")后台username是User的属性字段
    根据我们的参数列表的数据类型创建对象,通过反射给对象设置值
  • springmvc Controller类中的方法怎么执行的
    通过反射执行
  • springmvc 中方法加注解和不加注解的区别
    public String index(HttpServletRequest request, HttpServletResponse response,              User user12, Person person, String keywordsa,
                   @RequestParam("keywords") String words,String keywords)


    对于RequestParam注解来说需要加上,这样少走了ASM解析获取参数列表的过程,比较好

1 个回复

倒序浏览
谢谢老师分享
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马