Comment recevoir un téléchargement de fichier au printemps mvc en utilisant à la fois multipart/form et encodage chunked?

j'essaie d'écrire une méthode MVC de printemps qui peut recevoir soit un multipart/form ou un transfert-encodage de fichier chunked upload. Je peux écrire une méthode séparée pour manipuler chaque type mais je voudrais le faire avec la même méthode donc je peux utiliser le même post uri comme:

http://host:8084/attachments/testupload

Voici ma meilleure tentative à ce jour:

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

en utilisant la méthode ci-dessus je peux télécharger un fichier multipart, mais si je télécharge un fichier chunked je reçois une exception du printemps qui dit:

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

si je supprime la requête MultipartFile param, cela fonctionne très bien pour l'encodage de transfert chunked. Si je le laisse dans Il fonctionne très bien pour les téléchargements MultipartFile. Comment puis-je le faire avec la même méthode pour gérer les deux types de téléchargement?

Cela fonctionne très bien pour chunked:

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

et cela fonctionne très bien pour 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);
}

Il devrait être possible, quelqu'un sait comment faire cela?

Merci, Steve

22
demandé sur Steve L 2013-11-23 16:47:09

2 réponses

extrait de mon code (printemps 3.2, téléchargement de fichiers blueimp avec AngularJS):

/**
 * 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);
}

cela devrait vous aider à commencer. Tests minimaux effectués sur IE8, IE9, IE10, Chrome, FF. Bien sûr, il pourrait y avoir des problèmes, et il y a probablement un moyen plus facile d'extraire des gammes de contenu, mais .. fonctionne pour moi.

23
répondu gerasalus 2014-01-15 09:23:43

Voici le contrôleur pour qu'

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();
    }
}

Vous pouvez trouver la solution complète avec le code côté client à http://faisalbhagat.blogspot.com/2014/09/springmvc-fileupload-with-ajax-and.html

3
répondu faisalbhagat 2014-09-16 11:32:31