javascript - 如何从 javascript 中的服务器响应下载 XLSX 文件?

标签 javascript groovy xmlhttprequest apache-poi micronaut

我有一个使用 Micronaut 框架的 React 前端和 Java 服务器。在 BaseController在我的 Micronaut 框架中,我正在创建一个 XLSX 文件,然后发送响应,以便在从前端代码调用时下载它。

基础 Controller

@Inject ExportService exportService

@Controller('/abc/api/v1')
@Slf4j
class BaseController implements CachingHandler, CommonUtils {
    @Post('/export/{name}')
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.ALL)
    executeExporter(String name, @Nullable @Body LinkedHashMap payload) {
        def handler = { LinkedHashMap paramMap ->
            List paramMapList = paramMap.get("data") as List
            Byte[] resultBytes = exportService.exportToXLSX(paramMapList, getFileName(getLookupValue(name), paramMap.get("key") as String), true)
            log.info String.format("About to return XLSX file %s for %s",getFileName(getLookupValue(name), paramMap.get("key") as String), name)
            return resultBytes
        }
        def results = handler.call(payload)
        InputStream inputStream = new ByteArrayInputStream(results)
        return new StreamedFile(inputStream, getFileName(getLookupValue(name), payload["key"] as String))
    }
}

导出服务

注意:使用这个类的 main 方法,我可以创建一个 TestReport.xlsx文件。 XLSXExporter类用途 Apache POI生成 XLSX 文件的库。
@Prototype
@Slf4j
class ExportService implements CommonUtils {

    Byte[] exportToXLSX(List response, String fileName, boolean isDelete) {
        def headers = []
        try {
            headers = response[0].keySet()
        } catch(Exception e) {
            e.printStackTrace()
        }
        Map params = [:]
        params[Constants.HEADERS] = headers
        params[Constants.DATA] = response

        XLSXExporter xlsxExporter = new XLSXExporter()
        boolean fileCreated = xlsxExporter.writeData(Constants.DEFAULT_SHEET_NAME, fileName, params)
        if (fileCreated) {
            Byte[] workbookContent = xlsxExporter.getFile(fileName, isDelete)
            return workbookContent
        } else {
            return new Byte[0]
        }
    }

    static void main(String[] args) {
        def param = []
        for (int i in 1..5) {
            def paramMap = [:]
            paramMap["key1"] = "data"+i
            paramMap["key2"] = "data"+i
            paramMap["key3"] = "data"+i
            param.add(paramMap)
        }
        ExportService exportService = new ExportService()
        Byte[] resultBytes = exportService.exportToXLSX(param, "TestReport.xlsx", false)

        /**
            I am able to create a proper TestReport.xlsx file using this main method
        **/
    }
}

我从 Postman 测试了上述 API,它能够下载 XLSX 文件。
enter image description here
enter image description here

当我使用我的应用程序 (javascript) 调用上述导出 API 时,它能够下载 xlsx 文件,但无法打开。

调用导出 API 的 Javascript 代码
const exportData = (filteredRows, activity) => {
    let filename = "TestReport.xlsx";
    return axios({
        headers: {
            'Content-type': 'application/json'
         },
        accept:'application/x-www-form-urlencoded',
        url: '/abc/api/v1/export/'+ activity,
        method: 'post',
        data: {
            "key": "8575",
            "type":"userdetails",
            "data":filteredRows
        }
    }).then(resp => {
        var blob = resp.data;
        if(window.navigator.msSaveOrOpenBlob) {
            window.navigator.msSaveBlob(blob, filename);
        }
        else{
            var downloadLink = window.document.createElement('a');
            downloadLink.href = window.URL.createObjectURL(new Blob([blob], {type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}));
            downloadLink.download = filename;
            document.body.appendChild(downloadLink);
            downloadLink.click();
            document.body.removeChild(downloadLink);
           }
    });
}

enter image description here
enter image description here
一旦我在上面的对话框上单击是,我就会收到以下错误,并且与从 Postman 下载的文件相反,没有任何显示。
enter image description here

最佳答案

您的 MS Excel (XLSX) 文件在服务器上生成并通过您的 API 发送回客户端。您可以使用 responseType = blob 将响应下载为文件。 .您还应该在浏览器上设置文件名,以便为下载的文件命名。

试试下面的片段。

const exportData = (filteredRows,activity) => {
    let filename = "TestReport.xlsx";
    let xmlHttpRequest = new XMLHttpRequest();
    xmlHttpRequest.onreadystatechange = function() {
        var a;
        if (xmlHttpRequest.readyState === 4 && xmlHttpRequest.status === 200) {
            a = document.createElement('a');
            a.href = window.URL.createObjectURL(xmlHttpRequest.response);
            a.download = filename;
            a.style.display = 'none';
            document.body.appendChild(a);
            a.click();
        }
    };
    xmlHttpRequest.open("POST", '/abc/api/v1/export/'+ activity);
    xmlHttpRequest.setRequestHeader("Content-Type", "application/json");
    xmlHttpRequest.responseType = 'blob';
    xmlHttpRequest.send(JSON.stringify({
        "key": "8575",
        "type":"userdetails",
        "data":filteredRows
    }));
}

关于javascript - 如何从 javascript 中的服务器响应下载 XLSX 文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60810249/

相关文章:

javascript - 无法在 vuejs 中传递/接收 Prop 值

javascript - Highcharts 栏边框

javascript - XMLHttpRequest 抛出 InvalidStateError 说 "Object state must be opened"

C++ "HTTP"服务器 - 分块数据传输

javascript - 如何在后台添加音频,如谷歌追踪圣诞老人

javascript - 如何在将ajax数据放入div之前预加载它?

javascript - jQuery 按首字母过滤帖子 - 按字母顺序

groovy - 从 Groovy 中的字符串加载闭包代码

Groovy 子类称为访问闭包的父类(super class)方法

gradle - Groovy 中的测试类在 Kotlin 中看不到测试类