Nestjs导出Excel文件

1,003 阅读5分钟

前言

在现代Web应用中,数据导出功能是常见的需求之一。Excel文件作为一种广泛使用的格式,能够方便地在不同平台和程序间共享数据。本文将介绍服务端如何使用node 框架 NestJSexceljs 工具包返回.xls文件流,再前端通过axios,Blob处理数据流并最终通过浏览器下载excel文件

最终实现效果

1.gif

核心步骤:

  1. 创建NestJS项目和模块: 使用nest cli快速搭建项目结构,并创建专门用于导出Excel的模块和控制器。
  2. 安装exceljs: 引入exceljs库,用于创建Excel工作簿、工作表、设置样式等。
  3. 实现导出接口: 在控制器中定义一个接口,使用exceljs创建Excel文件,并将生成的文件以buffer形式返回。
  4. 配置CORS: 由于前端和后端可能运行在不同端口,需要在NestJS中配置CORS,允许跨域请求。
  5. 前端请求和下载: 使用axios发送GET请求到后端接口,设置responseTypeblob,获取返回的blob数据,并创建一个下载链接,触发浏览器下载。

后端

1. 快速创建nestjs项目和excel的module

这里通过nestjs cli快速创建项目(cli 创建项目

nest new excel-export-app

切换到项目内快速创建 export module模块 和 controller层

cd excel-export-app
nest g mo export
nest g co export

根目录下运行指令启动项目

npm run start:dev

GET 请求 :http://localhost:3000接口会返回 'Hello World'

2. 安装工具包:exceljs 和 相关导出代码

exceljs主要用于实现excel文件

npm install exceljs --save

export.controller.ts 添加导出逻辑:

// export.controller.ts

import { Controller, Get, Res } from '@nestjs/common';
import { Response } from 'express';
import * as ExcelJS from 'exceljs';

@Controller('export')
export class ExportController {

    @Get('xls')
    async exportXLS(@Res() res: Response) {
        const workbook = new ExcelJS.Workbook();
        const worksheet = workbook.addWorksheet('TestExportXLS');

        worksheet.columns = [
            { header: 'name', key: 'name' },
            { header: 'age', key: 'age' }
        ];

        worksheet.addRow({
            name: 'Neo Luo',
            age: 18
        });

        const buffer = await workbook.xlsx.writeBuffer();
        res.header('Content-Disposition', 'attachment; filename=anlikodullendirme.xlsx');
        res.type('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        res.send(buffer);
    }
}

现在访问:http://localhost:3000/export/xls 就可以访问到接口返回的buffer数据流了,再.xls文件数据中添加了一行数据name: 'Neo Luo',age: 18

3. 配置CROS

由于前端会通过http-serverweb服务启动默认 8080端口 与 netsjs 启动的 3000 端口不一致会跨域问题(Access-Control-Allow-Origin),报错内容:

Access to XMLHttpRequest at 'http://localhost:3000/export/xls' from origin 'http://127.0.0.1:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

这里在 nestjs main.ts 主入口文件配置允许跨域请求

// main.ts

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // start CORS
+  app.enableCors({
+   origin: '*',
+    methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
+   credentials: true,
+  });

  await app.listen(3000);
}

前端

由于需要请求后端接口 ,前端请求使用 axios来完成,http-server用于搭建简单web应用

1.创建简单的index.html页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Excel Export Example</title>
</head>
<body>
    <button id="exportBtn">导出Excel</button>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script src="./app.js"></script>
</body>
</html>

其中引用了 app.js为下载xls的script

// app.js

document
  .getElementById("exportBtn")
  .addEventListener("click", function () {
    axios({
      method: "get",
      url: "http://localhost:3000/export/xls",
      responseType: "blob", // 重要:指定响应类型为blob
    })
      .then((response) => {
        const url = window.URL.createObjectURL(
          new Blob([response.data])
        );
        const link = document.createElement("a");
        link.href = url;
        link.setAttribute("download", "data.xls"); // 设置下载文件名
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        window.URL.revokeObjectURL(url);
      })
      .catch((error) => {
        console.error("导出失败:", error);
      });
  });

这里需要注意的是请求返回一定要设置responseType: "blob"

  1. http-server 启动web服务

全局安装 http-server

npm i http-server -g

index.html同级目录运行 http-server启动指令

http-server ./
  1. 浏览器访问:localhost:8080 ,点击页面上的 导出ExcelButton 就可以下载成功excel,其中excel内容:
image.png

为在服务端填入的数据headerrow

导出合并单元

合并excel单元格需求日常中经常碰到,主要是通过exceljsmergeCells来实现,这里举例:导出New luo,Vates Liu的消费额度,其中合并Neo Luo的amount字段

// export.controller.ts

 async exportXLS(@Res() res: Response) {
        const workbook = new ExcelJS.Workbook();
        const worksheet = workbook.addWorksheet('TestExportXLS');

        worksheet.columns = [
            { header: 'id', key: 'id' },
            { header: 'name', key: 'name' },
            { header: 'age', key: 'age' },
            { header: 'cost', key: 'cost' },
            { header: 'amount', key: 'amount' }
        ];

        const data = [{
            id: 1,
            name: 'Neo Luo',
            age: 18,
            cost: 10,
            amount: 30
        }, {
            id: 1,
            name: 'Neo Luo',
            age: 18,
            cost: 20,
            amount: 30
        }, {
            id: 2,
            name: 'Vates Liu',
            age: 18,
            cost: 30,
            amount: 30
        }]


        for (let i = 0; i < data.length; i++) {
            worksheet.addRow(
                data[i]
            )
        }

        worksheet.mergeCells(`E${2}:E${3}`)
        const cell = worksheet.getCell(`E2`);
        cell.alignment = { vertical: 'middle' };



        const buffer = await workbook.xlsx.writeBuffer();
        res.header('Content-Disposition', 'attachment; filename=anlikodullendirme.xlsx');
        res.type('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        res.send(buffer);
    }

导出效果:

2.jpg

关键点:

  • exceljs的使用: exceljs提供了丰富的API,可以创建复杂多样的Excel文件,包括设置样式、合并单元格等。
  • CORS配置: 确保前端能够跨域访问后端接口,否则会无法下载文件。
  • responseType: "blob": 在前端请求中设置responseTypeblob,表示期望返回二进制数据。
  • 下载链接的创建: 使用createObjectURL创建一个指向blob数据的URL,然后创建一个a标签,设置href属性为该URL,触发点击事件即可下载。

扩展:

  • 数据动态生成: 可以通过数据库查询或其他方式动态生成Excel数据。
  • 复杂样式: exceljs支持设置各种样式,如字体、颜色、边框等,可以创建美观专业的Excel报表。
  • 模板化: 可以使用模板引擎来生成Excel模板,提高开发效率。
  • 大数据导出: 对于大数据集的导出,可以考虑分批导出或使用流式处理的方式。

注意事项:

  • 安全性: 如果导出数据包含敏感信息,需要进行相应的安全处理,例如加密、权限控制等。
  • 性能优化: 对于大批量数据的导出,需要优化代码,提高性能。
  • 浏览器兼容性: 不同的浏览器对blob对象的处理可能略有差异,需要进行兼容性测试。

总结

通过本文的介绍,相信读者已经掌握了使用NestJSexceljs实现Excel导出功能的基本原理和方法。在实际应用中,可以根据具体需求进行灵活扩展和优化。