Search code examples
angularspring-bootmultipartfile

MultipartFile with additional properties from Angular to Spring Boot


I have the following spring-boot function that works and is able to read MultipartFiles that is sent from Angular front-end code.

@PostMapping(value = "/upload")
@Operation(summary = "Upload Files")
public ResponseEntity<Map<String, List<String>>> uploadFiles(@RequestParam("files") MultipartFile[] files) {

    List<String> exceptions = new ArrayList<>();
    List<String> fileNames = new ArrayList<>();
    
    for (MultipartFile file : files) {
        try {
            Path fileStorage = get(DIRECTORY, fileName).toAbsolutePath().normalize();
            copy(file.getInputStream(), fileStorage, true);
            fileNames.add(fileName);
        } catch (Exception e) {
            exceptions.add(e.getClass().getName() + ": " + e.getMessage());
        }
    }

    Map<String, List<String>> map = new HashMap<>();
    map.put("data", fileNames);
    map.put("errors", exceptions);
    return ResponseEntity.ok().body(map);

}

My problem is, I have a couple of properties (checksum and author) that I need to get on each file. This is the sample of the file object that gets added as FormData. enter image description here

How will I be able to get them in my backend code?

Here's the Request Payload enter image description here

Here's the Request Header coming from Angular enter image description here


Solution

  • I found this article that helped me fix my problem: https://blogs.perficient.com/2020/07/27/requestbody-and-multipart-on-spring-boot/

    @PostMapping(value = "/upload", consumes = { MediaType.APPLICATION_JSON, MediaType.MULTIPART_FORM_DATA })
    @Operation(summary = "Upload Files")
    public ResponseEntity<Map<String, List<String>>> uploadFiles(@RequestPart("files") MultipartFile[] files,
            @RequestPart("fileUploadMetadataList") String inputFileUploadMetadataList) {
    
        ObjectMapper mapper = new ObjectMapper();
        CollectionType listType = mapper.getTypeFactory().constructCollectionType(ArrayList.class,
                FileUploadMetadataEntity.class);
        try {
            List<FileUploadMetadata> fileUploadMetadataList = mapper.readValue(inputFileUploadMetadataList, listType);
            /*** fileUploadMetadataList => CONTAINS EXACTLY WHAT I NEEDED ***/
        
        } catch (JsonMappingException jsonMappingError) {
            jsonMappingError.printStackTrace();
        } catch (JsonProcessingException jsonProcessingError) {
            jsonProcessingError.printStackTrace();
        }
    
        // ... some other statements
    
    }
    

    And in Angular, this is what I needed to do:

    // ... some other statements
    
    const formData = new FormData();
    const fileUploadMetaDataList: FileUploadMetadata[] = [];
    
    for (const file of this.files) {
      const fileUploadMetadata: FileUploadMetadata = {
        fileName: file.name,
        checksum: file.checksum,
        author: file.author,
        fileSize: file.size,
        lastModifiedDate: file.lastModifiedDate,
        uploadDate: new Date(),
      };
      formData.append('files', file);
      fileUploadMetaDataList.push(fileUploadMetadata);
    }
    
    formData.append(
      'fileUploadMetadataList',
      JSON.stringify(fileUploadMetaDataList)
    );
    
    // ... some other statements