好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

详解Spring Boot中PATCH上传文件的问题

spring boot中上传multipart/form-data文件只能是post提交,而不针对patch,这个问题花了作者26个小时才解决这个问题,最后不得不调试spring源代码来解决这个问题。

需求:在网页中构建一个表单,其中包含一个文本输入字段和一个用于文件上载的输入。很简单。这是表单:

?

1

2

3

4

<form id=]data] method=]patch] action=]/f] >

   <input type= "text" required name= "company" >

   <input type= "file" required name= "definition" />

</form>

restcontroller中的方法:

?

1

2

3

4

5

@requestmapping (value = "/f" ,method = patch)

public void upload(

    @requestpart ( "definition" ) multipartfile definition,

    @requestpart ( "company" ) string company

) {...}

注意它是patch的方法(根据要求)而不是post,部分要求是提交的ajax请求,并不是表单提交,代码如下:

?

1

2

3

4

5

6

7

8

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测试数据mons测试数据monsmultipartresolver

?

1

2

3

4

5

6

7

8

@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 )。更改代码为:

?

1

2

3

4

5

6

7

8

9

10

11

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中有一行:

?

1

2

string subcontenttype = headers.getheader(content_type);

if (subcontenttype != null ... ){}

这是get的内容类型,如果它是null,则处理是通过不同的路由将我们的上传部分不是转为multipartfile,而是转换为multipartparameter(放在不同的map中,而spring没有找到它),然后spring为每个参数创建单独的实例,形成在调用rest方法时实现绑定的表单。

requestpartservletserverhttprequest构造函数中可以找到抛出异常的位置:

?

1

2

3

4

httpheaders headers = this .multipartrequest.getmultipartheaders( this .partname);

if (headers == null ) {

   throw new missingservletrequestpartexception(partname);

}

重要的是getmultipartheaders只查看multipart的文件files而不是参数parameters。

这就是为什么添加具有特定类型的blob解决了问题的原因:

?

1

2

3

var textinput = = new blob([ 'the info' ], {

   type: 'text/plain'

});

现在回过来,前面我提到我必须切换到使用post才正常,但当我改为patch时,问题又回来了。错误是一样的。

我很困惑。所以找到了源代码(毕竟这是最终的文档)。

请记住,在本文开头切换到了commonsmultipartresolver。事实证明,在请求处理期间,调用此方法:

?

1

2

3

4

5

6

7

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看起来像这样:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

@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" );

   }

 

}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

原文链接:https://HdhCmsTestjdon测试数据/51169#

查看更多关于详解Spring Boot中PATCH上传文件的问题的详细内容...

  阅读:17次