搭建一个新工程时,想使用最新稳当版的springmvc,所以选择了最新的版本

            <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.1.RELEASE</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>

  

然后用以往的经验写了一个极其简单的Controller方法

    @ResponseBody
@RequestMapping(value = "/cates")
public Object cates(@PathVariable Long pageId, @PathVariable Long moduleId,
String goodIds, Goods goods) {
Map<String,Object> map = new HashMap<String, Object>();
map.put("1","1");
return map;
}

  

然而,奇怪的事情发生了。

参入参数:http://localhost:8088/1/2/cates.json?goodIds=2,3

运行时goodIds始终为null,而如果用bean属性的方式解析则正常,即goods.goodIds是可以正常解析到的。

我首先想到的是,给goodIds加上RequestParam注解。

    
@ResponseBody
@RequestMapping(value = "/cates")
public Object cates(@PathVariable Long pageId, @PathVariable Long moduleId,
@RequestParam(value = "goodIds", required = false) String goodIds, Goods goods) {
Map<String,Object> map = new HashMap<String, Object>();
map.put("1","1");
return map;
}

  

这样试了一下,还是不行,网上简单的搜了一下资料,并没有搜到这种情况,只能打断点看看问题出在哪里。

由于spring-mvc.xml里面,我写死了使用RequestMappingHandlerAdapter来处理方法级的相关操作。进入这个类,有一个spring的初始化对象接口的实现

@Override
public void afterPropertiesSet() {
// Do this first, it may add ResponseBody advice beans
initControllerAdviceCache(); if (this.argumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}

  

可以清晰的看见getDefaultArgumentResolvers()方法就是默认的参数解析器。

/**
* Return the list of argument resolvers to use including built-in resolvers
* and custom resolvers provided via {@link #setCustomArgumentResolvers}.
*/
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());
....

  

这里就不截该方法的全部代码了,我们把关注点集中到

RequestParamMethodArgumentResolver

这个解析器,由于代码层级太深,有兴趣的同学可以自己打断点一步一步的走,总之,最后可以走到这里来MultipartResolutionDelegate。

isPartCollection是用来判断参数是否为进行文件上传相关的方法参数

private static boolean isPartCollection(MethodParameter methodParam) {
return (servletPartClass == getCollectionParameterType(methodParam));
}
private static Class<?> getCollectionParameterType(MethodParameter methodParam) {
Class<?> paramType = methodParam.getNestedParameterType();
if (Collection.class == paramType || List.class.isAssignableFrom(paramType)){
Class<?> valueType = GenericCollectionTypeResolver.getCollectionParameterType(methodParam);
if (valueType != null) {
return valueType;
}
}
return null;
}

  

由于goodIds是String对象,调用getCollectionParameterType方法后,返回的无疑是null,而最终isPartCollection方法返回的竟然是true,这点无疑是我们无法接受的。细磕原因,我们会发现servletPartClass值为null,因此返回了true。

再看它的初始化方式

/**
* A common delegate for {@code HandlerMethodArgumentResolver} implementations
* which need to resolve {@link MultipartFile} and {@link Part} arguments.
*
* @author Juergen Hoeller
* @since 4.3
*/
public abstract class MultipartResolutionDelegate { public static final Object UNRESOLVABLE = new Object(); private static Class<?> servletPartClass = null; static {
try {
servletPartClass = ClassUtils.forName("javax.servlet.http.Part",
MultipartResolutionDelegate.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
// Servlet 3.0 javax.servlet.http.Part type not available -
// Part references simply not supported then.
}
}

  

需要指出的是,MultipartResolutionDelegate是spring-web在4.3版本才出现的,因此在某些低版本的springmvc下,我们出现的问题不是一定能重现的,具体看框架实现的方式。

从这里可以看到servletPartClass是javax.servlet.http.Part的类型对象。同时catch块也分明注释了

javax.servlet.http.Part是serlvet 3.0才支持的对象,因此要想servletPartClass不为null,应该使用serlvet3.0的版本依赖,因此我头脑一热,马上吧serlvet-api从2.5升级到了3.0.1

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

  

     

现在,在ide里面,能搜索到javax.servlet.http.Part这个类了,火速重启工程,然而,servletPartClass依然是null,坚强的null。

旋即,我才想起,启动工程用的是tomcat6,火速想到tomcat6有可能不支持serlvet3.0规范。

tomcat官网http://tomcat.apache.org/whichversion.html页的tomcat7描述中,有这么一段话

Apache Tomcat 7.x
Apache Tomcat 7.x builds upon the improvements made in
Tomcat 6.0.x and implements the Servlet 3.0,JSP 2.2, EL 2.2 andWeb Socket 1.1 specifications. In addition
to that, it includes the following improvements:
Web application memory leak detection and prevention
Improved security for the Manager and Host Manager applications
Generic CSRF protection
Support for including external content directly in a web application
Refactoring (connectors, lifecycle) and lots of internal code clean-up
Apache Tomcat 6.x
Apache Tomcat 6.x builds upon the improvements made in
Tomcat 5.5.x and implements the Servlet 2.5 andJSP 2.1 specifications. In addition to that, it includes the
following improvements:

  

tomcat7.x支持serlvet3.0规范,而tomcat6并不支持,火速下载tomcat7,应用后,servletPartClass不在为null,终于哦了,成功获取到goodIds

总结:

1.springmvc 4.3版本新增的很多类,如MultipartResolutionDelegate,他们是基于servlet 3.0规范实现的,如果使用旧的serlvet2.5规范,是无法正常工作的,同时,tomcat也需要同时支持serlvet3.0,最低版本的tomcat也需要是7.x

2.其实在看spring mvc 4.3的maven版本依赖时,里面就有这块依赖

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

人家也不是写着玩的,这意味着,要想用spring mvc 4.3,那么你就应该使用serlvet3.0规范,tomcat至少使用7.x

3.MultipartResolutionDelegate本身是一个抽象类,用来解析判断MultipartFile和Part类型的方法参数的,如果无法获取到Part类型对象,则无法正确执行它应有的功能,在使用新的工具或版本时,难免会出现无法理解的事,找到原因,分析解决后会有一种豁然开朗的感觉

springmvc 4.3,RequestParamMethodArgumentResolver无法正常解析String参数问题解决的更多相关文章

  1. (转)springMVC框架下JQuery传递并解析Json数据

    springMVC框架下JQuery传递并解析Json数据 json作为一种轻量级的数据交换格式,在前后台数据交换中占据着非常重要的地位.Json的语法非常简单,采用的是键值对表示形式.JSON 可以 ...

  2. SpringMVC系列(七)视图解析器和视图

    在springmvc.xml里面配置视图解析器 <!-- 配置视图解析器: 如何把 handler 方法返回值解析为实际的物理视图 --> <bean class="org ...

  3. SpringMVC中的视图和视图解析器

    对于控制器的目标方法,无论其返回值是String.View.ModelMap或是ModelAndView,SpringMVC都会在内部将它们封装为一个ModelAndView对象进行返回.  Spri ...

  4. 模仿GsonConverter 写的StringConverter 解析String字符串

    使用自己写的StringConverter 来封装的 Converter 来解析String private static final RestAdapter CAMERA_CLIENT_NETWOR ...

  5. springMVC框架下JQuery传递并解析Json数据

    springMVC框架下JQuery传递并解析Json数据

  6. springMVC源码解析--HandlerMethodArgumentResolverComposite参数解析器集合(二)

    上一篇博客springMVC源码分析--HandlerMethodArgumentResolver参数解析器(一)中我们已经介绍了参数解析相关的东西,并且也提到了HandlerMethodArgume ...

  7. SpringMvc CharacterEncodingFilter 解析 encoding 参数并初始化参数

    SpringMvc CharacterEncodingFilter 解析 encoding 参数并初始化参数:

  8. SpringMVC的应用与工作流程解析

    一:SpringMVC是什么 SpringMVC只是Spring的一个子框架,作用学过Struts2的应该很好理解,他们都是MVC的框架.学他就是用来代替Struts2的,那么为什么不用Struts2 ...

  9. 深入解析String#intern

    转自:https://tech.meituan.com/in_depth_understanding_string_intern.html 深入解析String#intern john_yang ·2 ...

随机推荐

  1. 关于Python输出时间戳的问题

    在我们的程序中,有时候想要知道程序的执行时间或者准确的停止时间,这时候就需要我们自己添加一个时间戳,以便我们做出判断和相应的处理. 下面是我亲测并收集的资料,菜鸟一枚,不全之处大神可给予补充和指正. ...

  2. Vue源码后记-更多options参数(2)

    写起来感觉都是老三套,AST => render => VNode => patch 之前是把AST弄完了,对事件和过滤器处理如图: render函数也只看这两部分的转换吧! 首先是 ...

  3. C++STL之双端队列容器

    C++STL之双端队列容器 deque双端队列容器与vector很类似,采用线性表顺序存储结构.但与vector区别,deque采用分块的线性存储结构来存储数据,每块的大小一般为512B,将之称为de ...

  4. Python 解决面试题47 不用加减乘除做加法

    在看<剑指Offer>过程中,面试题47不用加减乘除做加法,给出的思路是使用二进制的异或以及与运算,总之就是使用二进制.但是在使用Python实现的过程中,对于正整数是没有问题的,但是对于 ...

  5. Docker安装Mysql数据库容器(zz)

    zz自:http://blog.csdn.net/chengxuyuanyonghu/article/details/54380032 1.下载mysql的镜像: sudo docker pull m ...

  6. 用大白话扯扯那"神奇"的面向对象编程思维(一)

    前言: 每当提到面向对象的时候,初学者肯定都是一脸懵逼的状态,到底什么是面向对象?会用面向对象后有什么牛逼之处吗?不会用是不是就会死掉?答案肯定不会死掉,我们可以来简单的举一 个栗子 1.当你想到熊猫 ...

  7. 极简版ASP.NET Core学习路径及教程

    绝承认这是一个七天速成教程,即使有这个效果,我也不愿意接受这个名字.嗯. 这个路径分为两块: 实践入门 理论延伸 有了ASP.NET以及C#的知识以及项目经验,我们几乎可以不再需要了解任何新的知识就开 ...

  8. python基础阶段练习题 拾英札记(1)

    python很灵活,学起来有人机交互的快乐感,贵在坚持. 做题对自学python很有帮助,融汇贯通-查漏补缺-巩固提高. 写了一些注释,希望能对您有所帮助. #1.输入一个3位数,计算个位.百位.十位 ...

  9. [转载] zookeeper 分布式锁服务

    转载自http://www.cnblogs.com/shanyou/archive/2012/09/22/2697818.html 分布式锁服务在大家的项目中或许用的不多,因为大家都把排他放在数据库那 ...

  10. Json字符串解析原理、超大json对象的解析

    概述 附上完整的代码:https://pan.baidu.com/s/1dEDmGz3(入口类是Json)JSON:JavaScript 对象表示法(JavaScript Object Notatio ...