详解Spring Boot中PATCH上传文件的问题
spring boot中上传multipart/form-data文件只能是post提交,而不针对patch,这个问题花了作者26个小时才解决这个问题,最后不得不调试spring源代码来解决这个问题。
需求:在网页中构建一个表单,其中包含一个文本输入字段和一个用于文件上载的输入。很简单。这是表单:
<form id=”data” method=”patch” action=”/f” > <input type="text" required name="company" > <input type="file" required name="definition" /> </form>
restcontroller中的方法:
@requestmapping(value = "/f",method = patch) public void upload( @requestpart("definition") multipartfile definition, @requestpart("company") string company ) {...}
注意它是patch的方法(根据要求)而不是post,部分要求是提交的ajax请求,并不是表单提交,代码如下:
var fileinput = ...; //this is html element that holds the files var textinput = ...; //thi is the string var fd = new formdata(); fd.append('definition',fileinput.files[0]); fd.append('name', textinput ); xhr = new xmlhttprequest(); xhr.open( 'patch', uploadform.action, true ); xhr.send( fd );
但无论怎么做,我都无法让它发挥作用。总是遇到以下异常:
missingservletrequestpartexception: required request part ‘definition' is not present
我做的第一件事就是将这个问题分解为最简单的问题。所以我将请求类型更改为post,并删除了textinput。将multipart解析器的实现进行更改,从org.springframework.web.multipart.support.standardservletmultipartresolver 改为org.springframework.web.multipart.commons.commonsmultipartresolver
@configuration public class myconfig { @bean public multipartresolver multipartresolver() { return new commonsmultipartresolver(); } }
这还需要将commons-fileupload库添加到类路径中。
但每当我添加一个字符串变量返回错误:the string field not the file field
这说明multi part request resolver 没有发现这部分字段。
这是由于javascript的formdata问题,在formdata对象上调用的append方法接受两个参数name和value(有第三个但不重要),该value字段可以是一个 usvstring或blob(包括子类等file)。更改代码为:
var fileinput = ...; //this is html element that holds the files var textinput = = new blob(['the info'], { type: 'text/plain' }); ; //thi is the string var fd = new formdata(); fd.append('definition',fileinput.files[0]); fd.append('name', textinput ); xhr = new xmlhttprequest(); xhr.open( 'patch', uploadform.action, true ); xhr.send( fd );
它突然开始工作:)。
看一下浏览器发送的内容:
— — — webkitformboundaryhgn3yjdgselbgmzh
content-disposition: form-data; name=”definition”; filename=”test.csv” content-type: text/csv
this is the content of a file, browser hides it.
— — — webkitformboundaryhgn3yjdgselbgmzh content-disposition: form-data; name=”name”
this is the string
— — — webkitformboundaryhgn3yjdgselbgmzh —
你能注意到内容处置标题中缺少的内容吗?文件名和内容类型。在servlet处理期间,multi-part表单变成multipartfile。在commons-fileupload中有一行:
string subcontenttype = headers.getheader(content_type); if (subcontenttype != null ... ){}
这是get的内容类型,如果它是null,则处理是通过不同的路由将我们的上传部分不是转为multipartfile,而是转换为multipartparameter(放在不同的map中,而spring没有找到它),然后spring为每个参数创建单独的实例,形成在调用rest方法时实现绑定的表单。
requestpartservletserverhttprequest构造函数中可以找到抛出异常的位置:
httpheaders headers = this.multipartrequest.getmultipartheaders(this.partname); if (headers == null) { throw new missingservletrequestpartexception(partname); }
重要的是getmultipartheaders只查看multipart的文件files而不是参数parameters。
这就是为什么添加具有特定类型的blob解决了问题的原因:
var textinput = = new blob(['the info'], { type: 'text/plain' });
现在回过来,前面我提到我必须切换到使用post才正常,但当我改为patch时,问题又回来了。错误是一样的。
我很困惑。所以找到了源代码(毕竟这是最终的文档)。
请记住,在本文开头切换到了commonsmultipartresolver。事实证明,在请求处理期间,调用此方法:
public static final boolean ismultipartcontent( httpservletrequest request) { if (!post_method.equalsignorecase(request.getmethod())) { return false; } return fileuploadbase.ismultipartcontent(new servletrequestcontext(request)); }
如果它不是post请求,则立即确定该请求没有multipart内容。
那么久通过覆盖调用上面静态方法的方法解决了这个问题。
所以现在config bean看起来像这样:
@bean public multipartresolver multipartresolver() { return new commonsmultipartresolvermine(); } public static class commonsmultipartresolvermine extends commonsmultipartresolver { @override public boolean ismultipart(httpservletrequest request) { final string header = request.getheader("content-type"); if(header == null){ return false; } return header.contains("multipart/form-data"); } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: ASP.NET从字符串中查找字符出现次数的具体实现方法
下一篇: 深入了解MyBatis二级缓存
推荐阅读
-
spring boot使用i18n时properties文件中文乱码问题的解决方法
-
详解Spring Boot中PATCH上传文件的问题
-
关于旗正规则引擎规则中的上传和下载问题 博客分类: 旗正4.0 jsp文件上传文件下载压缩
-
PHP中TP5 上传文件的实例详解
-
详解spring mvc(注解)上传文件的简单例子
-
详解spring mvc(注解)上传文件的简单例子
-
Spring中属性文件properties的读取与使用详解
-
Spring Boot中扩展XML请求与响应的支持详解
-
Spring中属性文件properties的读取与使用详解
-
解决spring-boot2.0.6中webflux无法获得请求IP的问题