如何使用多部分/表单和分块编码在 spring mvc 中接收文件上传?

     2023-02-24     206

关键词:

【中文标题】如何使用多部分/表单和分块编码在 spring mvc 中接收文件上传?【英文标题】:How do I receive a file upload in spring mvc using both multipart/form and chunked encoding? 【发布时间】:2013-12-08 08:57:05 【问题描述】:

我正在尝试编写一个 spring mvc 方法,该方法可以接收多部分/表单或传输编码分块文件上传。我可以编写一个单独的方法来处理每种类型,但我想用相同的方法来做,所以我可以使用相同的 REST POST uri,例如:

http://host:8084/attachments/testupload

这是我迄今为止最好的尝试:

@RequestMapping(value =  "/testupload" , method = RequestMethod.POST, produces = 
  "application/json")
public @ResponseBody
ResponseEntity<MessageResponseModel> testUpload(
  @RequestParam(value = "filedata", required = false) MultipartFile filedata,
  final HttpServletRequest request) throws IOException 

  InputStream is = null;
  if (filedata == null) 
    is = request.getInputStream();
  
  else 
    is = filedata.getInputStream();
  
  byte[] bytes = IOUtils.toByteArray(is);
  System.out.println("read " + bytes.length + " bytes.");

  return new ResponseEntity<MessageResponseModel>(null, null, HttpStatus.OK);

使用上述方法我可以上传一个多部分文件,但是如果我上传一个分块文件,我会从 spring 中得到一个异常:

org.springframework.web.multipart.MultipartException: \
The current request is not a multipart request

如果我删除 MultipartFile 请求参数,它非常适合传输编码分块。如果我把它留在里面,它非常适合 MultipartFile 上传。如何使用相同的方法来处理两种上传类型?

这适用于分块:

@RequestMapping(value =  "/testupload" , method = RequestMethod.POST, produces = 
  "application/json")
public @ResponseBody
ResponseEntity<MessageResponseModel> testUpload(
  final HttpServletRequest request) throws IOException 

  InputStream is = null;
  is = request.getInputStream();
  byte[] bytes = IOUtils.toByteArray(is);
  System.out.println("read " + bytes.length + " bytes.");

  return new ResponseEntity<MessageResponseModel>(null, null, HttpStatus.OK);

这对 MultipartFile 非常有用:

@RequestMapping(value =  "/testupload" , method = RequestMethod.POST, produces = 
  "application/json")
public @ResponseBody
ResponseEntity<MessageResponseModel> testUpload(
  @RequestParam MultipartFile filedata) throws IOException 

  InputStream is = null;
  is = filedata.getInputStream();
  byte[] bytes = IOUtils.toByteArray(is);
  System.out.println("read " + bytes.length + " bytes.");

  return new ResponseEntity<MessageResponseModel>(null, null, HttpStatus.OK);

应该是可以的,有人知道怎么做吗?

谢谢, 史蒂夫

【问题讨论】:

你想要一个端点,并且不介意有两个控制器方法吗?或者你想要单个端点和单个控制器方法? 如果有办法让 2 个控制器方法使用相同的 URI,并且 spring 可以根据是否存在多部分内容来选择调用哪个方法。 【参考方案1】:

摘自我的代码(Spring 3.2,使用 AngularJS 上传 blueimp 文件):

/**
 * Handles chunked file upload, when file exceeds defined chunked size.
 * 
 * This method is also called by modern browsers and IE >= 10
 */
@RequestMapping(value = "/content-files/upload/", method = RequestMethod.POST, headers = "content-type!=multipart/form-data")
@ResponseBody
public UploadedFile uploadChunked(
        final HttpServletRequest request,
        final HttpServletResponse response) 

    request.getHeader("content-range");//Content-Range:bytes 737280-819199/845769
    request.getHeader("content-length"); //845769
    request.getHeader("content-disposition"); // Content-Disposition:attachment; filename="Screenshot%20from%202012-12-19%2017:28:01.png"
    request.getInputStream(); //actual content.

    //Regex for content range: Pattern.compile("bytes ([0-9]+)-([0-9]+)/([0-9]+)");
    //Regex for filename: Pattern.compile("(?<=filename=\").*?(?=\")");

    //return whatever you want to json
    return new UploadedFile();


/**
 * Default Multipart file upload. This method should be invoked only by those that do not
 * support chunked upload.
 * 
 * If browser supports chunked upload, and file is smaller than chunk, it will invoke
 * uploadChunked() method instead.
 * 
 * This is instead a fallback method for IE <=9
 */
@RequestMapping(value = "/content-files/upload/", method = RequestMethod.POST, headers = "content-type=multipart/form-data")
@ResponseBody
public HttpEntity<UploadedFile> uploadMultipart(
        final HttpServletRequest request,
        final HttpServletResponse response,
        @RequestParam("file") final MultipartFile multiPart) 

    //handle regular MultipartFile

    // IE <=9 offers to save file, if it is returned as json, so set content type to plain.
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.TEXT_PLAIN);
    return new HttpEntity<>(new UploadedFile(), headers);

这应该可以帮助您入门。在 IE8、IE9、IE10、Chrome、FF 上进行的测试最少。当然可能存在问题,并且可能有一种更简单的提取内容范围的方法,但是 .. 对我有用。

【讨论】:

很棒的解决方案!一旦我完成、签入并清理到足以在此处发布的解决方案,我也会发布我的解决方案。不过你的解决方案更好。 我无法使用第一种方法让 blueimp(使用 AngularJS)上传分块。它总是调用uploadMultipart(通过发送多部分标头)。请问有什么特别的 blueimp 配置可以分享吗? 据我记忆,没什么特别的。你使用的是什么浏览器?将哪些标头发送到服务器端?【参考方案2】:

这是控制器

package com.faisalbhagat.web.controller;

@Controller
@RequestMapping(value =  "" )
public class UploadController 

    @RequestMapping(value = "/uploadMyFile", method = RequestMethod.POST)
    @ResponseBody
    public String handleFileUpload(MultipartHttpServletRequest request)
            throws Exception 
        Iterator<String> itrator = request.getFileNames();
        MultipartFile multiFile = request.getFile(itrator.next());
                try 
            // just to show that we have actually received the file
            System.out.println("File Length:" + multiFile.getBytes().length);
            System.out.println("File Type:" + multiFile.getContentType());
            String fileName=multiFile.getOriginalFilename();
            System.out.println("File Name:" +fileName);
            String path=request.getServletContext().getRealPath("/");

            //making directories for our required path.
            byte[] bytes = multiFile.getBytes();
            File directory=    new File(path+ "/uploads");
            directory.mkdirs();
            // saving the file
            File file=new File(directory.getAbsolutePath()+System.getProperty("file.separator")+picture.getName());
            BufferedOutputStream stream = new BufferedOutputStream(
                    new FileOutputStream(file));
            stream.write(bytes);
            stream.close();
         catch (Exception e) 
            // TODO Auto-generated catch block
            e.printStackTrace();
            throw new Exception("Error while loading the file");
        
        return toJson("File Uploaded successfully.")
    

    public String toJson(Object data)
    
        ObjectMapper mapper=new ObjectMapper();
        StringBuilder builder=new StringBuilder();
        try 
            builder.append(mapper.writeValueAsString(data));
         catch (Exception e) 
            // TODO Auto-generated catch block
            e.printStackTrace();
        
        return builder.toString();
    

您可以使用客户端代码在以下位置找到完整的解决方案 http://faisalbhagat.blogspot.com/2014/09/springmvc-fileupload-with-ajax-and.html

【讨论】:

我建议不要使用multiFile.getBytes(),因为它将整个字节数组加载到内存中

如何在 GlassFish 3.1.1 上运行的应用程序中使用多部分/表单数据编码

】如何在GlassFish3.1.1上运行的应用程序中使用多部分/表单数据编码【英文标题】:Howtousemultipart/form-dataencodinginapplicationrunningonGlassFish3.1.1【发布时间】:2012-02-2221:09:04【问题描述】:我有一个在GlassFish3.1.1下运行的JSF2.0应用程序... 查看详情

如何使用 Spring MockMvc 放置多部分/表单数据?

】如何使用SpringMockMvc放置多部分/表单数据?【英文标题】:HowtoPUTmultipart/form-datausingSpringMockMvc?【发布时间】:2016-11-2900:42:39【问题描述】:我有一个带有PUT方法的控制器方法,它接收multipart/form-data:@RequestMapping(value="/putIn",meth... 查看详情

如何发布具有多部分/表单数据编码的数组?

】如何发布具有多部分/表单数据编码的数组?【英文标题】:HowdoIPOSTanarraywithmultipart/form-dataencoding?【发布时间】:2012-04-1716:06:35【问题描述】:在GET参数字符串或“x-www-form-urlencoded”POST请求中,可以通过用括号命名参数来指定... 查看详情

多部分和分块协议之间的区别

...解释一下两者的区别吗?分块是流协议而多部分不是吗?使用multipart有什么好处?【问题讨论】:只是一个猜测,但我希望multipart包含多个单独的部分,用于多个不同的内容等-而chunked为同一实体提供多个块。在等待更有知识的... 查看详情

在 iphone 中使用多部分表单数据发布图像和其他数据

...ata向服务器发送一些数据和图像。请给我一些PHP代码,我如何将图像保存在服务器上,我能够在服务器上获取与图像一起传递的其他变量。请查看我的objC代码和p 查看详情

Retrofit - @Body 参数不能与表单或多部分编码一起使用

】Retrofit-@Body参数不能与表单或多部分编码一起使用【英文标题】:Retrofit-@Bodyparameterscannotbeusedwithformormulti-partencoding【发布时间】:2015-02-0316:39:57【问题描述】:我正在尝试发出要包含Header、form-urlencoded字段和json正文的请求。... 查看详情

发布多部分表单数据问题

...aIssue【发布时间】:2019-11-1914:55:10【问题描述】:我正在使用HttpWebRequest发布到MMSAPI。帖子的正文包含有关交付的XML数据和作为MIME多部分附件的MMS消息,需要进行Base64编码。发帖成功,但我只收到文字,没有图片。在查看我的代... 查看详情

如何使用 URLSessionStreamTask 和 URLSession 进行分块编码传输

】如何使用URLSessionStreamTask和URLSession进行分块编码传输【英文标题】:HowtouseURLSessionStreamTaskwithURLSessionforchunked-encodingtransfer【发布时间】:2017-11-1923:53:07【问题描述】:我正在尝试连接到Twitter流API端点。看起来URLSession支持通过U... 查看详情

禁用传输编码:在 Spring Webflux 响应中分块

...luxresponses【发布时间】:2018-07-1211:55:36【问题描述】:我使用SpringWebflux响应式库创建了一堆RESTAPI端点。我现在面临的问题是SpringWebflux返回的响应具有transfer-encoding:chunkedHTTP标头。由于 查看详情

如何在邮递员的同一请求中发送多部分/表单数据和嵌套 json?

】如何在邮递员的同一请求中发送多部分/表单数据和嵌套json?【英文标题】:Howtosendmultipart/form-dataandnestedjsoninthesamerequestinpostman?【发布时间】:2021-10-2214:13:51【问题描述】:我有一个RESTapi,它获取嵌套json的数据,包括多部分... 查看详情

如何在 Spring App 中接收多部分请求

】如何在SpringApp中接收多部分请求【英文标题】:HowtoreceivemultipartrequestinSpringApp【发布时间】:2022-01-0400:27:34【问题描述】:我已经看到了很多来源,也看到了一些关于SO的问题,但没有找到解决方案。我想向我的Spring应用发送... 查看详情

如何在不模拟多部分表单的情况下发布图像[重复]

】如何在不模拟多部分表单的情况下发布图像[重复]【英文标题】:Howtopostimagewithoutsimulatemultipartform[duplicate]【发布时间】:2013-04-1711:26:03【问题描述】:我正在与一个php开发人员一起工作,他希望我向他发布一张图片。但我什... 查看详情

如何在 SMTP 的多部分 MIME 消息中使用 8 位编码?

】如何在SMTP的多部分MIME消息中使用8位编码?【英文标题】:Howtouse8bitencodinginmultipartMIMEmessagesinSMTP?【发布时间】:2015-01-0609:42:57【问题描述】:我有一个关于如何在SMTP的多部分MIME中使用8位编码的问题。根据MIMEWiki,我们可以... 查看详情

如何从反应提交多部分/表单数据到表达?

】如何从反应提交多部分/表单数据到表达?【英文标题】:Howtosubmitmultipart/form-datafromreacttoexpress?【发布时间】:2020-04-0620:16:20【问题描述】:我正在尝试提交带有Image和Name类别的表单。但是在我的ExpressJS(后端)中,我无法获... 查看详情

如何在 NestJS 中为采用多部分表单数据的 OpenAPI 注释端点

】如何在NestJS中为采用多部分表单数据的OpenAPI注释端点【英文标题】:HowdoIannotateanendpointinNestJSforOpenAPIthattakesMultipartFormData【发布时间】:2021-03-1222:03:26【问题描述】:我的NestJS服务器有一个接受文件和其他表单数据的端点例如... 查看详情

如何在烧瓶中读取多部分/表单数据[重复]

】如何在烧瓶中读取多部分/表单数据[重复]【英文标题】:howtoreadmultipart/form-datainflask[duplicate]【发布时间】:2017-03-1719:21:30【问题描述】:我在读取通过XMLHttpRequest发布的烧瓶中的数据时遇到问题。我正在使用这个jquery插件来裁... 查看详情

Spring Batch - 分块和多线程步骤 - RowMapper 中的 Nullpointer 异常

】SpringBatch-分块和多线程步骤-RowMapper中的Nullpointer异常【英文标题】:SpringBatch-Chunking&Multithreadedsteps-NullpointerexceptioninRowMapper【发布时间】:2020-01-2507:36:45【问题描述】:当我在多个线程中运行我的步骤时,我在处理结果集时... 查看详情

如何在 Jetty HttpClient 中进行多部分/表单数据发布

】如何在JettyHttpClient中进行多部分/表单数据发布【英文标题】:Howtodomultipart/form-datapostinJettyHttpClient【发布时间】:2011-08-3110:13:44【问题描述】:我想知道是否有人可以帮助我。对于Java项目,我想使用JettyHttpClient将数据发送到Re... 查看详情