前言
在现代Web应用中,数据导出功能是常见的需求之一。Excel文件作为一种广泛使用的格式,能够方便地在不同平台和程序间共享数据。本文将介绍服务端如何使用node 框架 NestJS,exceljs 工具包返回.xls文件流,再前端通过axios,Blob处理数据流并最终通过浏览器下载excel文件
最终实现效果
核心步骤:
- 创建NestJS项目和模块: 使用
nest cli快速搭建项目结构,并创建专门用于导出Excel的模块和控制器。 - 安装
exceljs: 引入exceljs库,用于创建Excel工作簿、工作表、设置样式等。 - 实现导出接口: 在控制器中定义一个接口,使用
exceljs创建Excel文件,并将生成的文件以buffer形式返回。 - 配置CORS: 由于前端和后端可能运行在不同端口,需要在
NestJS中配置CORS,允许跨域请求。 - 前端请求和下载: 使用
axios发送GET请求到后端接口,设置responseType为blob,获取返回的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"
http-server启动web服务
全局安装 http-server
npm i http-server -g
在index.html同级目录运行 http-server启动指令
http-server ./
- 浏览器访问:
localhost:8080,点击页面上的导出ExcelButton 就可以下载成功excel,其中excel内容:
为在服务端填入的数据header 和 row
导出合并单元
合并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);
}
导出效果:
关键点:
exceljs的使用:exceljs提供了丰富的API,可以创建复杂多样的Excel文件,包括设置样式、合并单元格等。- CORS配置: 确保前端能够跨域访问后端接口,否则会无法下载文件。
responseType: "blob": 在前端请求中设置responseType为blob,表示期望返回二进制数据。- 下载链接的创建: 使用
createObjectURL创建一个指向blob数据的URL,然后创建一个a标签,设置href属性为该URL,触发点击事件即可下载。
扩展:
- 数据动态生成: 可以通过数据库查询或其他方式动态生成Excel数据。
- 复杂样式:
exceljs支持设置各种样式,如字体、颜色、边框等,可以创建美观专业的Excel报表。 - 模板化: 可以使用模板引擎来生成Excel模板,提高开发效率。
- 大数据导出: 对于大数据集的导出,可以考虑分批导出或使用流式处理的方式。
注意事项:
- 安全性: 如果导出数据包含敏感信息,需要进行相应的安全处理,例如加密、权限控制等。
- 性能优化: 对于大批量数据的导出,需要优化代码,提高性能。
- 浏览器兼容性: 不同的浏览器对
blob对象的处理可能略有差异,需要进行兼容性测试。
总结
通过本文的介绍,相信读者已经掌握了使用NestJS和exceljs实现Excel导出功能的基本原理和方法。在实际应用中,可以根据具体需求进行灵活扩展和优化。