1

I have created a SOAP service that correctly makes an XLSX Excel file and saves it to the server that the service is hosted on.

Relevant code here (Java):

public byte[] getFile(@WebParam(name = "arg0") String schemaName, @WebParam(name = "arg1") String tableName) {                
  FileOutputStream outputStream = new FileOutputStream("example.xlsx"); 
  workbook.write(outputStream);
  File myFile = new File("example.xlsx");
  byte[] bytesArray = new byte[(int) myFile.length()];
  FileInputStream fis = new FileInputStream(myFile);
  fis.read(bytesArray); 
  fis.close();
  return bytesArray;
}

I consume this service using the following code:

(Javascript)

function sendFileSoap() {
var xmlhttp = new XMLHttpRequest();
var responseMessage;
var fullResponse;
xmlhttp.open('POST', 'http://127.0.0.1:7101/Application3-Model-context-root/ExcelConverterPort', true);

// build SOAP request
var requestBody =
'<?xml version="1.0" encoding="utf-8"?>' +
'<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://model/">' +
   '<env:Header/>' +
   '<env:Body>' +
      '<ns1:getFile>' +
        '<arg0>' + document.getElementById('sname1').value + '<\/arg0>' +
        '<arg1>' + document.getElementById('fname1').value + '<\/arg1>' +
      '<\/ns1:getFile>' +
   '<\/env:Body>' +
'<\/env:Envelope>'

xmlhttp.onreadystatechange = function () {
    if (xmlhttp.readyState == 4) {
        if (xmlhttp.status == 200) {
            fullResponse = xmlhttp.responseText;
            alert(fullResponse);
            var xmlDoc = xmlhttp.responseXML;
            var x = xmlDoc.getElementsByTagName("return")[0];

            var y = x.childNodes[0];
           downloadFile(y.nodeValue)
        }
    }
}

xmlhttp.setRequestHeader('Content-Type', 'text/xml');
alert(requestBody);
xmlhttp.send(requestBody);

return responseMessage;
}
function downloadFile(characters) {          
        // convert base64 string to byte array
        var byteCharacters = atob(characters);
        var byteNumbers = new Array(byteCharacters.length);
        for (var i = 0; i < byteCharacters.length; i++) {
            byteNumbers[i] = byteCharacters.charCodeAt(i);
        }
        var byteArray = new Uint8Array(byteNumbers);

        // now that we have the byte array, construct the blob from it
        var blob1 = new Blob([byteCharacters], {type: "application/vnd.ms-excel"});

        var fileName1 = "table.xlsx";
        saveAs(blob1, fileName1); 
} 
...

The "saveAs" function is defined by "FileSaver.js" available here: https://github.com/eligrey/FileSaver.js/

The SOAP call is functioning correctly and returning a byte array to the soap service - however Excel is unable to open the file after the download on the browser side.

The file that is saved server-side by the FileOutputStream properly opens in Excel.

Using NotePad++ (or any editor that lets you see invisible characters), I see that some of the non-visible characters have been stripped from the resulting file.

I am guessing one or more of the functions I'm using just can't handle values and strip them out. Does anyone know if this is the case for the functions I used on the Javascript side or if there is a better way to handle this return request so that I can properly prompt the user to download the resulting soap return value (byte array) as a file?

user681574
  • 553
  • 2
  • 15

1 Answers1

0

I figured this out a couple days later:

Updated code that works:

(Java)

public byte[] getFile(@WebParam(name = "arg0") String schemaName, @WebParam(name = "arg1") String tableName) {
    Table tableData = new Table(schemaName, tableName);
    ArrayList<String> columns = tableData.getAllColumnNames();
    XSSFWorkbook workbook = new XSSFWorkbook();
    byte[] data;

    //... Create Excel using Apache POI API Here ...
    try { 
        FileOutputStream outputStream = new FileOutputStream("C:\\testPath\\test.xlsx"); 
        workbook.write(outputStream);
        Path path = Paths.get("C:\\testPath\\test.xlsx");
        data = Files.readAllBytes(path);

        return data;
    }
    catch (IOException e) {
        e.printStackTrace();
    }
    return "".getBytes();
}

(Javascript)

xmlhttp.onreadystatechange = function () {
    if (xmlhttp.readyState == 4) {

        if (xmlhttp.status == 200) {
            fullResponse = xmlhttp.responseText;
            alert(fullResponse);
            var xmlDoc = xmlhttp.responseXML;
            var x = xmlDoc.getElementsByTagName("return")[0];
            var contentType = 'vnd.ms-excel';
            var y = x.childNodes[0];
            var b64Data = y.nodeValue
            var blob = b64toBlob(b64Data, contentType)
            saveAs(blob, "text.xlsx"); 
        }
    }
}

Utilize the function "b64toBlob" that converts base 64 data to a blob here: Creating a Blob from a base64 string in JavaScript

The main difference I noticed is that the new b64toBlob function used a slice size and then pushed each slice onto a main array after converting. I do not know why that didn't work originally when converting the whole thing at once.

Community
  • 1
  • 1
user681574
  • 553
  • 2
  • 15