Skip to content

文件下载

在很多场景下,我们需要导出文件,例如导出 Excel 文件,导出 Word 文件,导出 PDF 文件等等。当我们需要导出功能时,我们只需要给导出按钮配置一个点击事件,通过事件流找到请求模块,选择文件下载节点即可。

文件下载要求配置第三方API接口,第三方接口无论是基于什么语言开发,都必须返回一个二进制数据流给前端,才能实现下载或导出功能。

Java 示例

java
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

@WebServlet("/download-excel")
public class ExcelDownloadServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1. 创建 Excel 工作簿和工作表
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("Sheet1");

        // 2. 添加表头
        Row headerRow = sheet.createRow(0);
        String[] headers = {"姓名", "年龄", "城市"};
        for (int i = 0; i < headers.length; i++) {
            Cell cell = headerRow.createCell(i);
            cell.setCellValue(headers[i]);
        }

        // 3. 添加数据行
        String[][] data = {
            {"张三", "28", "北京"},
            {"李四", "32", "上海"},
            {"王五", "25", "广州"}
        };
        for (int i = 0; i < data.length; i++) {
            Row row = sheet.createRow(i + 1);
            for (int j = 0; j < data[i].length; j++) {
                row.createCell(j).setCellValue(data[i][j]);
            }
        }

        // 4. 写入到 ByteArrayOutputStream
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        workbook.write(bos);
        byte[] excelBytes = bos.toByteArray();

        // 5. 设置响应头
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("Content-Disposition", "attachment; filename=\\"example.xlsx\\"");
        response.setContentLength(excelBytes.length);

        // 6. 写入到响应输出流
        try (OutputStream out = response.getOutputStream()) {
            out.write(excelBytes);
            out.flush();
        }

        // 7. 关闭资源
        bos.close();
        workbook.close();
    }
}

Node.js 示例

javascript
import { Router } from 'express';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import ExcelJS from 'exceljs';

router.get('/download-csv', (req, res) => {
  const csvData = `Name,Email,Phone
  John Doe,john@example.com,123-456-7890
  Jane Smith,jane@example.com,987-654-3210`;

  const buffer = Buffer.from(csvData);

  res.setHeader('Content-Type', 'text/csv');
  res.setHeader('Content-Disposition', 'attachment; filename="example.csv"');
  res.setHeader('Content-Length', buffer.length);

  res.end(buffer);
});

前端实现

javascript
async download(url: string, method: string, params: any = {}, config: any = {}) {
    const reqMethod = method.toLowerCase() as 'get' | 'post';
    let response: AxiosResponse;
    if (reqMethod === 'get') {
      response = await axios.get(url, {
        params,
        ...config,
        responseType: 'blob',
      });
    } else {
      response = await axios.post(url, params, {
        ...config,
        responseType: 'blob',
      });
    }

    const blob = response.data;
    const link = document.createElement('a');
    const contentDisposition = response.headers['content-disposition'];
    const fileName = config.filename || 'fileName.xls';

    link.download = fileName;
    link.href = URL.createObjectURL(blob);
    document.body.appendChild(link);
    link.click(); //点击下载
    document.body.removeChild(link); //下载完成移除元素
    setTimeout(() => {
      URL.revokeObjectURL(link.href); //清除引用
    }, 100);
  },

Released under the MIT License.