Search code examples
angularspring-bootfile-uploadhttp-post

Post a file together with an object in Angular/Springboot application


I am currently building on a simple web application where I want to upload a file (or multiple files) together with an options-object from an Angular-Frontend and receive both on the SpringBoot-Backend. The Backend should convert the options-object to an EnumerateOptions object (see below).

I managed to upload the file/files and the object separately but I cant find a solution to post them together successfully.

Angular Frontend:

uploadOptions(): Observable<Blob>{

  return this.httpClient.post(this.baseuri + "/test1", {
    position: "left", 
    fontStyle: "bold", 
    fontSize: "12",
    changes: [1, 2, 3, 4, 5]
  }, {responseType: 'blob'});
}

uploadPdf(file: File): Observable<Blob>{

  const formData: FormData = new FormData();
  formData.append('file', file, file.name);

  //formData.append('file', file, file.name); 
  //... For multiple Files

  return this.httpClient.post(this.baseuri + "/test2", formData, {responseType: 'blob'});
}

Spring Boot Backend:

@PostMapping("/test1")
public ResponseEntity<String> test1(@RequestParam("file") MultipartFile file) {

    LOGGER.info(file.getName());

    return ResponseEntity
            .ok().body("done");
}

@PostMapping("/test2")
public ResponseEntity<String> test2(@RequestBody EnumerateOptions options) {

    LOGGER.info(options.toString());
    LOGGER.info(options.getFontSize());
    LOGGER.info(options.getFontStyle());
    LOGGER.info(options.getFontSize());
    LOGGER.info(String.valueOf(options.getChanges()[0]));

    return ResponseEntity
            .ok().body("done");
}

Class EnumerateOptions:

public class EnumerateOptions {

    @JsonProperty("position")
    private String position;

    @JsonProperty("fontStyle")
    private String fontStyle;

    @JsonProperty("fontSize")
    private String fontSize;

    @JsonProperty("changes")
    private int[] changes;

    //getter, setter ...

I already tried many things but there was always a Problem with converting the options-object. For example I successfully uploaded both from the frontend like this:

uploadBoth(file: File, options: EnumerateOptions): Observable<Blob>{

const formData: FormData = new FormData();
formData.append('file', file, file.name);
formData.append('options', JSON.stringify(options));
  
return this.httpClient.post(this.baseuri + "/test", formData, {responseType: 'blob'});
}

But in the backend Spring was not able to convert the options object.

Thank you in advance for your help!


Solution

  • In your question you have two different controllers for 2 different data types, so I guess you showing us a working example. Your question should include 1 contrller with two objects that you tried to post and it fail.

    When you use RequestBody you trigger jsonmapping for the body which means if you don't include only body the mapping will fail, and when you use formdata from the frontend the corresponding spring object as RequestParameter. My suggestion is to send post request with RequestParameters:

    Angular

    const formData: FormData = new FormData();
    formData.append('file', file, file.name);
    formData.append('options', JSON.stringify(options));
    

    Controller

    @PostMapping("/test1")
    public ResponseEntity<String> test1(@RequestParam("file") MultipartFile file,
    @RequestParam("options")) {
    

    You might need to do the mapping yourself.

    If I were you I might split the request to two dependent requests, first send the RequestBody and then the file (or vise-versa) on the subscribe block.