5

How to implement multiple file upload feature, with each of file have it own extra field (eg. comment, documentType) in Spring Boot?

This answer might be related but it's for single file only: Spring boot controller - Upload Multipart and JSON to DTO

duccom
  • 134
  • 2
  • 16
  • Follow this link https://www.callicoder.com/spring-boot-file-upload-download-rest-api-example/ that help which include complete front end , back end and tested response from postman – DHARMENDRA SINGH Feb 14 '19 at 04:15
  • @DHARMENDRASINGH Thank you! But in example the multi-file upload without extra fields for each file. – duccom Feb 14 '19 at 06:57
  • Have you check postman hit(screen-shot) for multiple hit in that json he is sending many things like type, name and size – DHARMENDRA SINGH Feb 14 '19 at 07:33
  • @DHARMENDRASINGH Nope, they are the responses from server (after uploaded) not the request, :) – duccom Feb 14 '19 at 13:51
  • There is no difference between multiple files and single files upload, just add another form file input with name `file2`, and receive it with `@RequestParam("file2")` in spring. And there is no ready way to resolve "List of DTO" in spring – tianzhipeng Feb 17 '19 at 17:06

2 Answers2

4

Html side

<input id="files" type="file" name="files[]"  multiple />

Upload

<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.min.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script type="text/javascript">
function uploadFiles(){
    var form = new FormData();
    var i=0;
    $.each($("input[type='file']")[0].files, function(i, file) {
        form.append('file', file);
        form.append('extradata','ola'+i);
        i++;
    });

    // send form data with ajax
    $.ajax({
        type: 'POST',
        url: '/uploadFiles',
        cache: false,
        contentType: false,
        processData: false,
        data : form,
        success: function(result){
            console.log(result);
            alert('upload success');
        },
        error: function(err){
            console.log(err);
        }
    })
}
</script>

and server side

@PostMapping("/uploadFiles")
public String uploadFiles(@RequestParam("file") MultipartFile[] files,
                          @RequestParam("extradata") String[] extras) throws Exception {
    int i = 0;
    Files.createDirectories(Paths.get("./uploaded/"));
    for (MultipartFile f : files) {
        Files.copy(f.getInputStream(), Paths.get("./uploaded/" + extras[i] + f.getOriginalFilename()));
        i++;
    }
    return "success";
}

you can find running example here https://github.com/ozkanpakdil/spring-examples/tree/master/demoMultiFileUpload

ozkanpakdil
  • 3,199
  • 31
  • 48
2

You can encode multiple request parts in the POST payload and process that with Spring Boot.

Let's say you need to pass in two things per file:

  • Blob with the file contents
  • metadata - an object that can hold whatever - title/comments - you name it.

FrontEnd

You can use anything to simulate FormData params, this is in TypeScript:

let's say a document looks like this:

export interface NewDocument {
  title: string,
  comment: string,
  author: string,
  file: File
}

So the generating of the FormData might be like:

private getFormData(doc: NewDocument): FormData {
  let formData: FormData = new FormData();
  const json: Blob = new Blob([JSON.stringify(doc)], {type: 'application/json'});
  formData.append('metadata', json); //adding the metadata
  const blob: Blob = new Blob([doc.file[0]], {type: doc.file[0].type});
  formData.append('file', blob); //adding the file contents
  return formData;
}

You can then POST the form data to a given endpoint.

BackEnd

You can specify the different RequestParts you're expecting in the request

@PostMapping
public ResponseEntity<Void> uploadFile(@RequestPart("metadata") FileMetadata metadata,
@RequestPart("file") MultipartFile file) {
   //process
}

FileMetadata here is a custom Java POJO into which you can deserialize the JSON representation of the FrontEnd's NewDocument

You should be able to turn this into a multiples version.

@PostMapping
public ResponseEntity<Void> uploadFile(@RequestPart("metadata") FileMetadata[] metadatas,
@RequestPart("file") MultipartFile[] files) {
   //process
}

The problem now is how to identify which metadata is for which file.

A simple way would be to have the filename encoded in the metadata object and use that for mapping.

Community
  • 1
  • 1
hovanessyan
  • 30,580
  • 6
  • 55
  • 83