java后台生成中文名称可下载文件,vue3前端通过axios来实现下载。


java后端的文件生成文件的代码,这是是用来hutool生成excel文件

    @ResponseBody
    @RequestMapping(value = "/downloadDataQuery")
    public void downloadDataQuery(HttpServletRequest request, HttpServletResponse response, @RequestBody ReqDataQueryVo reqDataQueryVo) throws IOException {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        String chineseFileName = "导出数据.xlsx";
        String encodedFileName = URLEncoder.encode(chineseFileName, StandardCharsets.UTF_8.toString()).replaceAll("\\+", "%20");
        response.setHeader("Content-Disposition", "attachment;filename*=UTF-8''" + encodedFileName);
        //response.setHeader("Content-Disposition","attachment;filename=export.xlsx");
        // 需要加上下面这个,不然跨域的头拿不到这个Content-Disposition信息
        response.setHeader("Access-Control-Expose-Headers","Content-Disposition");
        OutputStream out = response.getOutputStream();

        log.info("downloadDataQuery reqDataQueryVo:" + reqDataQueryVo);
        try {
            List<DataQueryRespVo> dataQueryRespVoList = dataQueryService.queryByReqDataQuery(reqDataQueryVo);

            List<DataQueryRespExportVo> dataQueryRespExportVoList = objectMapper.convertValue(dataQueryRespVoList, objectMapper.getTypeFactory().constructCollectionType(List.class, DataQueryRespExportVo.class));

            ExcelWriter writer = ExcelUtil.getWriter(true);
            writer.write(dataQueryRespExportVoList, true);

            writer.flush(out, true);
            writer.close();
            IoUtil.close(out);

        } catch (Exception exception) {
            log.error(exception.getMessage());
        }
    }

这里是vue3前端下载文件的代码,主要是要支持utf8编码。

let handleOnExport2 = () => {
    loading.value = true;
    console.log("导出2: ");
    let reqObject = reactive({...toRefs(queryParams)});
    console.log("queryParams:"+JSON.stringify(queryParams));
    console.log("reqObject: "+JSON.stringify(reqObject));
    downloadDataQuery(reqObject).then((res)=>{
        console.log(res);
        let { data, headers } = res;
        console.log("headers:"+headers);
        console.log("headers:"+JSON.stringify(headers));
        if (res.data instanceof Blob) {
            console.log("ok1");
            let blob = new Blob([res.data], {type: headers['content-type']});
            
            // 检查Content-Disposition头来获取文件名
            let contentDisposition = res.headers['content-disposition'];
            let fileName = 'downloaded-file.xls'; // 默认文件名
            
            if (contentDisposition) {
                // 使用正则表达式匹配filename*部分
                let utf8FileNameMatch = contentDisposition.match(/filename\*=(UTF-8''|utf-8''|utf8''|UTF8'')(.+)/);
                if (utf8FileNameMatch && utf8FileNameMatch[2]) {
                    // 提取出并解码UTF-8编码的文件名
                    fileName = decodeURIComponent(utf8FileNameMatch[2].replace(/['"]/g, ''));
                } else {
                    // 如果没有filename*,尝试从传统的filename中提取(可能未编码)
                    let simpleFileNameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);
                    if (simpleFileNameMatch != null && simpleFileNameMatch[1]) {
                        fileName = simpleFileNameMatch[1].replace(/['"]/g, '');
                    }
                }
            }
    
            let link = document.createElement('a');
            link.href = window.URL.createObjectURL(blob);
            //link.download = '导出.xlsx';
            link.download = fileName;
            link.click();
            window.URL.revokeObjectURL(link.href);
            loading.value = false;
        } else {
            console.log("ok2");
            console.error(res.message || '下载失败!');
        }
    }).catch((err,res)=>{
        console.error(err || '下载失败!');
    });
}

上面使用了api目录下的情况接口方法;api接口文件内容如下

// 查询方法
export function downloadDataQuery(data) {
    return request({
        url: '/proddata/downloadDataQuery',
        method: 'post',
        data: data,
        responseType: 'blob'
    })
}

如果不喜欢这种。可以使用下面比较原始的方式。

let handleOnExport2 = () => {
    loading.value = true;
    console.log("导出2: ");
    let reqObject = reactive({...toRefs(queryParams)});
    console.log("queryParams:"+JSON.stringify(queryParams));
    console.log("reqObject: "+JSON.stringify(reqObject));
    axiosInstance.post("/proddata/downloadDataQuery",reqObject,{responseType: 'blob'}).then((res)=>{
        console.log(res);
        let { data, headers } = res;
        console.log("headers:"+headers);
        console.log("headers:"+JSON.stringify(headers));
        if (res.data instanceof Blob) {
            console.log("ok1");
            let blob = new Blob([res.data], {type: headers['content-type']});
            
            // 检查Content-Disposition头来获取文件名
            let contentDisposition = res.headers['content-disposition'];
            let fileName = 'downloaded-file.xls'; // 默认文件名
            
            if (contentDisposition) {
                // 使用正则表达式匹配filename*部分
                let utf8FileNameMatch = contentDisposition.match(/filename\*=(UTF-8''|utf-8''|utf8''|UTF8'')(.+)/);
                if (utf8FileNameMatch && utf8FileNameMatch[2]) {
                    // 提取出并解码UTF-8编码的文件名
                    fileName = decodeURIComponent(utf8FileNameMatch[2].replace(/['"]/g, ''));
                } else {
                    // 如果没有filename*,尝试从传统的filename中提取(可能未编码)
                    let simpleFileNameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);
                    if (simpleFileNameMatch != null && simpleFileNameMatch[1]) {
                        fileName = simpleFileNameMatch[1].replace(/['"]/g, '');
                    }
                }
            }
    
            let link = document.createElement('a');
            link.href = window.URL.createObjectURL(blob);
            //link.download = '导出.xlsx';
            link.download = fileName;
            link.click();
            window.URL.revokeObjectURL(link.href);
            loading.value = false;
        } else {
            console.log("ok2");
            console.error(res.message || '下载失败!');
        }
    }).catch((err,res)=>{
        console.error(err || '下载失败!');
    });
}