手把手教学Nestjs对excel的增删改查

背景:最近经常要给业务方拉数据生成表格、修改表格,遂记录下研究结果。

  1. node框架用的Nestjs
  2. 常用的excel库有xlsx、exceljs, 对于简单表格,两者差别不大,xlsx写起来更简洁,可以用这个。
  3. 快的话1小时可以搞定。

一、生成excel - xlsx

先看成果 装包 pnpm i xlsx

服务

typescript 复制代码
import { Injectable } from '@nestjs/common';
import * as XLSX from 'xlsx';

@Injectable()
export class ExcelService {

  // 创建Excel
  async create() {
    const users = [
      { id: 1, name: '张三2', age: 25, email: 'zhangsan@example.com' },
      { id: 2, name: '李四', age: 30, email: 'lisi@example.com' },
      { id: 3, name: '王五', age: 28, email: 'wangwu@example.com' },
    ];
    const worksheet = XLSX.utils.json_to_sheet(users);

    // 新建表格
    const workbook = XLSX.utils.book_new();
    XLSX.utils.book_append_sheet(workbook, worksheet);
    // 指定路径和文件名
    XLSX.writeFile(workbook, `${process.cwd()}/public/excel/user.xlsx`);
    return 'Excel文件创建成功!'
  }

}

控制器

less 复制代码
  @Get('create')
  @ApiOperation({ summary: '创建Excel' })
  async create() {
    return await this.excelService.create();
  }

二、生成excel方式2-exceljs

比较繁琐但是对样式控制更高,可以了解下 先看成果 装包 pnpm i exceljs fs

服务

typescript 复制代码
import { Injectable } from '@nestjs/common';
import * as ExcelJS from 'exceljs';
import { join } from 'path';
import { existsSync, mkdirSync } from 'fs';

@Injectable()
export class ExcelService {

  // 创建Excel
  async create() {
    // 创建工作簿和工作表
    const workbook = new ExcelJS.Workbook();
    // 指定sheet名
    const worksheet = workbook.addWorksheet('用户数据');

    // 设置表头
    worksheet.columns = [
      { header: 'ID', key: 'id', width: 20 },
      { header: '姓名', key: 'name', width: 20 },
      { header: '年龄', key: 'age', width: 10 },
      { header: '邮箱', key: 'email', width: 30 },
    ];

    // 添加数据
    const users = [
      { id: 1, name: '张三2', age: 25, email: 'zhangsan@example.com' },
      { id: 2, name: '李四', age: 30, email: 'lisi@example.com' },
      { id: 3, name: '王五', age: 28, email: 'wangwu@example.com' },
    ];

    // 添加行,方式1
    // worksheet.addRows(users);
    // 方式2
    users.forEach((item) => worksheet.addRow(item))

    // 设置表头样式
    worksheet.getRow(1).eachCell((cell) => {
      cell.font = { bold: true };
      cell.alignment = { horizontal: 'center' };
      cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFCCCCCC' }, };
    });

    // 确保保存目录存在:根目录下uploads文件夹
    const publicDir = join(process.cwd(), 'public/excel');
    if (!existsSync(publicDir)) mkdirSync(publicDir, { recursive: true });

    // 生成文件名(包含时间戳避免重复)
    const timestamp = new Date().getTime();
    const fileName = `users_${timestamp}.xlsx`;
    const filePath = join(publicDir, fileName);

    // 保存 Excel 文件
    await workbook.xlsx.writeFile(filePath);

    // 返回文件路径和 URL
    return { path: filePath };
  }

}

控制器

less 复制代码
  @Get('create')
  @ApiOperation({ summary: '创建Excel' })
  async create() {
    return await this.excelService.create();
  }

三、修改excel

注意:wps不会自动更新表格,修改完后需要在wps中重新打开excel。 需求:修改用户表中2条数据的名字;

  1. 获取所有sheet的名字: workbook.SheetNames
  2. 操控某个sheet: workbook.Sheets'用户数据'或workbook.Sheetsworkbook.SheetNames\[0];
  3. 先装包 pnpm i xlsx

服务

typescript 复制代码
import { Injectable } from '@nestjs/common';
import { existsSync } from 'fs';
import * as XLSX from 'xlsx';

@Injectable()
export class ExcelService {
  
  edit() {
    // 1.找到文件
    const filePath = `${process.cwd()}/public/excel/users.xlsx`;
    if (!existsSync(filePath)) return (`文件不存在: ${filePath}`);
    // 读取文件内容
    const workbook = XLSX.readFile(filePath);
    // 获取第一个工作表
    const firstSheetName = workbook.SheetNames[0];
    const worksheet = workbook.Sheets[firstSheetName];
    // 数据转化
    const tableData = XLSX.utils.sheet_to_json(worksheet);
    console.log('tableData: ', tableData);

    // 2.修改数据
    const newTableData = tableData.map((row: any) => {
      if (row['姓名'] === '张三2') row['姓名'] = '张三3';
      if (row['ID'] === 2) row['姓名'] = '李四3';
      return row
    })
    console.log('newTableData: ', newTableData);

    // 3.替换工作簿中的工作表
    workbook.Sheets[firstSheetName] = XLSX.utils.json_to_sheet(newTableData);

    // 4. 写回文件
    XLSX.writeFile(workbook, filePath);
    return '更新完毕';
  }

}

控制器中使用

less 复制代码
  @Get('edit')
  @ApiOperation({ summary: '修改Excel' })
  edit() {
    return this.excelService.edit();
  }

四、删除excel文件

核心 fs.unlinkSync(文件路径);

比较简单直接看代码

typescript 复制代码
import * as fs from 'fs';

  @Get('del')
  @ApiOperation({ summary: '删除Excel' })
  async del() {
    const filePath = `${process.cwd()}/public/excel/yuanGong.xlsx`;
    await fs.unlinkSync(filePath);
    return '删除Excel';
  }

至此都已搞定

相关推荐
kyriewen5 小时前
我手写了一个 EventEmitter,面试官追问了 6 个问题——第 4 个我没答上来
前端·javascript·面试
IT_陈寒5 小时前
Java的Date类又坑了我一次,改用时间戳真香
前端·人工智能·后端
小林攻城狮6 小时前
使用 Transport 节流解决 Vercel AI SDK 流式渲染卡死问题
前端·react.js
前端缘梦6 小时前
告别 TS 运行时类型漏洞!Zod 完整入门实战教程(前端 / 全栈必备)
前端·react.js·全栈
the_answer6 小时前
Webpack vs Vite 深度对比分析
前端·webpack
转转技术团队6 小时前
验证码识别实战:前端不写页面,改训模型了?
前端
MomentYY6 小时前
Temperature:AI 的“脑洞旋钮”
前端·llm·ai编程
远航_7 小时前
OpenSpec 完整详细介绍
前端·后端
召钱熏7 小时前
状态枚举正确≠渲染正确:一个语音按钮的状态机边界修复实录
android·前端
SkyWalking中文站7 小时前
认识 Horizon UI · 1/17:SkyWalking 新一代可观测性控制台
运维·前端·监控