根据源码用HttpServletRequest获取MultipartFile的问题
问题
由于某些原因,现在需要这样的一个文件上传接口,这个接口type(String)是必传参数,photoFile(MultipartFile)是非必传参数,即一般情况下需要接受两个参数,分别为photoFile和type,但是偶尔只接受type参数,不需要起到上传作用。
按常规写法,photoFile参数的required配置设置为了false。
奈何调试时发现,photoFile的required配置是失效的。即下面的接口写法,photoFile成了必传参数。
@ResponseBody
@RequestMapping(value = "/upload")
public String uploadPics(@RequestPart(value = "photoFile", required = false) MultipartFile photoFile,
@RequestParam(value = "type", required = true) String type, HttpServletRequest request) throws Exception {
。。。
}
当模拟upload接口请求时,如果不携带photoFile参数,如上接口写法报错如下
org.springframework.web.multipart.MultipartException: The current request is not a multipart request
at org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver.assertIsMultipartRequest(RequestPartMethodArgumentResolver.java:178) ~[spring-webmvc-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver.resolveArgument(RequestPartMethodArgumentResolver.java:116) ~[spring-webmvc-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:79) ~[spring-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:157) ~[spring-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:124) ~[spring-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) ~[spring-webmvc-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:749) ~[spring-webmvc-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:690) ~[spring-webmvc-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83) ~[spring-webmvc-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:945) ~[spring-webmvc-4.0.2.RELEASE.jar:4.0.2.RELEASE]
...
方案
required配置失效,估计是没有走required的相关流程。
我们根据所报的第三行错误,进入RequestPartMethodArgumentResolver.class的源码的116行查看。
111 @Override
112 public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
113 NativeWebRequest request, WebDataBinderFactory binderFactory) throws Exception {
114
115 HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
116 assertIsMultipartRequest(servletRequest);
117
118 MultipartHttpServletRequest multipartRequest =
119 WebUtils.getNativeRequest(servletRequest, MultipartHttpServletRequest.class);
120
121 String partName = getPartName(parameter);
122 Object arg;
123
124 if (MultipartFile.class.equals(parameter.getParameterType())) {
125 Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?");
126 arg = multipartRequest.getFile(partName);
}
.....
再点击116行,进入assertIsMultipartRequest方法
175 private static void assertIsMultipartRequest(HttpServletRequest request) {
176 String contentType = request.getContentType();
177 if (contentType == null || !contentType.toLowerCase().startsWith("multipart/")) {
178 throw new MultipartException("The current request is not a multipart request");
179 }
}
很明显,错误就是178行触发的。而且在上层的几个调用中也没有涉及到required的流程。
那么问题来了, 接口偶尔需要起到上传作用,如果不改变接口传参形式,就只能改源码了,很明显,这不是好的方案。
那答案肯定就在源码里了,我们很容易就想到可以在接口处完全去掉photoFile(MultipartFile)参数,然后把模仿源码,从request里去获取MultipartFile对象。
下面是根据源码118-126行、176-179行修改的接口,经测试是可行的:
@ResponseBody
@RequestMapping(value = "/upload")
public String uploadPics(@RequestParam(value = "type", required = true) String type,
HttpServletRequest request) {
....
// 检测是否为上传请求
String contentType = request.getContentType();
if (contentType != null && contentType.toLowerCase().startsWith("multipart/")) {
MultipartHttpServletRequest multipartRequest =
WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class);
MultipartFile file = multipartRequest.getFile("file");
....
}
....
}
后记
问题的处理其实很简单,但是这边文章的记录是为了另一件事。
当时实现这个功能时,发现常规写法走不通,又不好改源码,内心是有草泥马奔腾而过的。
知道答案可能在源码里,猜想可以去用request获取MultipartFile对象,但是又觉得麻烦,不想去干这事,想着可能有更好的办法,然后这事就拖着。
到后来问同事怎么解决,同事说那就从request获取MultipartFile对象咯。
根据源码用HttpServletRequest获取MultipartFile的问题的更多相关文章
- Flink 源码解析 —— 如何获取 ExecutionGraph ?
https://t.zsxq.com/UnA2jIi 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- Mac 上搭建 Flink 1.6. ...
- Flink 源码解析 —— 如何获取 JobGraph?
JobGraph https://t.zsxq.com/naaMf6y 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- Mac 上搭建 F ...
- Flink 源码解析 —— 如何获取 StreamGraph?
StreamGraph https://t.zsxq.com/qRFIm6I 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- Mac 上搭 ...
- 33、[源码]-AOP原理-获取拦截器链-MethodInterceptor
33.[源码]-AOP原理-获取拦截器链-MethodInterceptor
- springMVC源码分析--AbstractHandlerMethodMapping获取url和HandlerMethod对应关系(十)
在之前的博客springMVC源码分析--AbstractHandlerMapping(二)中我们介绍了AbstractHandlerMethodMapping的父类AbstractHandlerMa ...
- UiAutomator源码分析之获取控件信息
根据上一篇文章<UiAutomator源码分析之注入事件>开始时提到的计划,这一篇文章我们要分析的是第二点: 如何获取控件信息 我们在测试脚本中初始化一个UiObject的时候通常是像以下 ...
- lodash源码分析之获取数据类型
所有的悲伤,总会留下一丝欢乐的线索,所有的遗憾,总会留下一处完美的角落,我在冰峰的深海,寻找希望的缺口,却在惊醒时,瞥见绝美的阳光! --几米 本文为读 lodash 源码的第十八篇,后续文章会更新到 ...
- Kafka源码研究--Comsumer获取partition下标
背景 由于项目上Flink在设置parallel多于1的情况下,job没法正确地获取watermark,所以周末来研究一下一部分,大概已经锁定了原因: 虽然我们的topic只设置了1的partitio ...
- springMVC源码学习之获取参数名
1.入口到参数处理调用流程 入口为spring-webmvc-4.3.18.RELEASE.jar中org.springframework.web.servlet.DispatcherServlet. ...
随机推荐
- JS常用特效方法总结
1.按Ctrl提交 <body onkeydown="if(event.ctrlKey&&event.keyCode=='13') form1.submit.click ...
- 微信小程序,前端大梦想(二)
微信小程序的视图与渲染 今天我们从四个方面来了解小程序: •组件的基本使用 •数据绑定 •渲染标签 •模板的使用 一.组件的基本使用: 微信小程序为我们的开发提供了丰富的UI组件 ...
- 原生JS跨浏览器事件封装处理
引子:用javascript给元素绑定事件,我们可以用addEventListener这个方法,然而这个方法有兼容问题,比如在IE浏览器上面就无效,在IE上面要用attachEvent这个方法 一.a ...
- 串口屏Modbus协议,串口屏的modbus协议资料,串口屏modbus通讯协议开发,串口屏之modbus协议使用技巧
串口屏Modbus协议,串口屏的modbus协议资料,串口屏modbus通讯协议开发,串口屏之modbus协议使用技巧 本例程中用51单片机作为Modbus从机,从机的设备地址为2,从机有4个寄存器, ...
- Java 8 Lambda 表达式
Lambda 是啥玩意 简单来说,Lambda 就是一个匿名的方法,就这样,没啥特别的.它采用一种非常简洁的方式来定义方法.当你想传递可复用的方法片段时,匿名方法非常有用.例如,将一个方法传递给另外一 ...
- GreenDao教程1
最近项目重构,涉及到了数据库和文件下载,发现GreenDao这个框架还是不错的.直接面向对象的,可以通过对对象的操作,实现数据的存储. 但是官网上的API是在不敢恭维,文档写的很糙,看了半天,才搞懂一 ...
- Go - 第一个 go 程序 -- helloworld
创建程序目录 接着上一节的内容,在我们的workspace (D:\Gopher) 里面创建子目录 hello,他的绝对路径为:D:\Gopher\src\github.com\tuo\hello 创 ...
- LRU Cache java实现
要求: get(key):如果key在cache中,则返回对应的value值,否则返回null set(key,value):如果key不在cache中,则将该(key,value)插入cache中( ...
- Java计算两个程序运行时间
一.获取系统当前时间 long startTime = System.currentTimeMillis(); //获取开始时间 doSomething(); //测试的代码段 long endTim ...
- PHP环境搭建之PHPstorm9+PHP5开发环境配置
以前写过一篇zend studio+WAMP的:点这里,个人感觉写得不怎么好可是阅读数却上千了... 不过笔者身边好多人开始用PHPStrom了,所以就简单的写个教程 一.下载安装 PHPStrom下 ...