0

I'm building a RESTful architecture using a Java Backend and an Angular Frontend. The idea is the following: given a form with a bunch of Fields, the Frontend generates a JSON file and sends it to the Backend, where it will be processed with xdocreport along with a .docx template file in order to perform a context replacement. This pipeline generates a .docx file that I should somehow return to the Frontend, either downloading it or by returning a Response containing a byte[] entity.

So, this is my post in the Backend:

@POST
@Path("/form/{category}/export")
public Response generateDoc(JSONObject jObj) {
    Response.ResponseBuilder rb = Response.ok(Controller.generateDocument(
                                                Utils.getFileExtension(jObj.get("metadata").toString()),
                                                (ArrayList)jObj.get("data"),
                                                jObj.get("metadata").toString()
                                                ));
    rb.header("Access-Control-Allow-Origin", "*");
    rb.header("Access-Control-Allow-Methods", "POST, GET, PUT, UPDATE, OPTIONS");
    rb.header("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With");
    return rb.build();
}

where Controller.generateDocument() is a static method that actually generates the document and returns a byte[]. My request in the Frontend is:

exportToBackend(): void {
    this.fields.forEach(field=>{
      field.value = this.formGroup.value[field.label];
      if (field.label == 'image') {
        field.value = this.imgURL;
      }
    });

    let result = {metadata: this.selectedTemplate, data: this.fields};

    const httpOptions = {
      headers: new HttpHeaders({
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Methods': 'GET, POST, PUT, UPDATE, OPTIONS',
        'Access-Control-Allow-Headers': 'Content-Type, Accept, X-Requested-With'
      })
    };
    this.http.post<Uint8Array>('http://localhost:8080/ExportLibrary-BackEnd-1.0-SNAPSHOT/form/'
      .concat(this.category).concat('/export'), result, httpOptions).toPromise().then(data => {
        this.doc = data;
    });

 }

When I run it, the document is generated correctly (I create both the byte[] object and the actual .docx file as a sort of "debugging") but in the Frontend I get a Uint8Array (0) empty object, and I can't understand why. Moreover, from that array I should also create the .docx file. More precisely, the error I get is the following:

HttpResponseError

even if I don't use JSON files at all in the Backend.

So, my questions are: where am I wrong? How can I get the actual data from the Java Response object in the Frontend?

Finally, I've seen a bunch of examples (like this) that actually download the file from the Backend. How does that work? Is it a better way than getting the byte[] object?

F. Malato
  • 192
  • 2
  • 15
  • In your backend class, you are not setting response header with file info and proper content type (MediaType.APPLICATION_OCTET_STREAM) Can you take a look at below implementation for your response? https://stackoverflow.com/questions/35680932/download-a-file-from-spring-boot-rest-service – Vasif Oct 15 '20 at 12:48
  • @Vasif thanks for answering! Thing is, I can't use `.contentType()` since the `ResponseBuilder` doesn't find the method reference. Moreover, if I try to adapt my code to the answer you linked, my lib can't even find the `ResponseEntity` object. – F. Malato Oct 15 '20 at 15:00
  • what if instead builder you can use ResponseEntity in your method and generate it as ByteArrayResource resource = new ByteArrayResource(generateDocument(......)); ResponseEntity.ok() .headers(headers) .contentLength(file.length()) .contentType(MediaType.APPLICATION_OCTET_STREAM) .body(resource); – Vasif Oct 15 '20 at 15:02
  • @Vasif I tried, but I have no `ResponseEntity` in my library. Maybe it has been deprecated in an older version and it's no more available. – F. Malato Oct 15 '20 at 15:04
  • I thought you are using spring-boot but probably you are using simple jax-ws. So, anyway you can add header like rb.header("Content-Type", "application/octet-stream"); – Vasif Oct 15 '20 at 15:09
  • Yes, my bad, I forgot to specify, sorry! Anyway, I've tried to add the header, but I still get the same `HttpResponseError`. – F. Malato Oct 15 '20 at 15:22

0 Answers0