手把手教学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.Sheets[workbook.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';
  }

至此都已搞定

相关推荐
Cache技术分享7 分钟前
148. Java Lambda 表达式 - 捕获局部变量
前端·后端
YGY Webgis糕手之路11 分钟前
Cesium 快速入门(二)底图更换
前端·经验分享·笔记·vue
神仙别闹39 分钟前
基于JSP+MySQL 实现(Web)毕业设计题目收集系统
java·前端·mysql
前端李二牛40 分钟前
Web字体使用最佳实践
前端·http
YGY_Webgis糕手之路41 分钟前
Cesium 快速入门(六)实体类型介绍
前端·gis·cesium
Jacob023441 分钟前
UI 代码不写也行?我用 MCP Server 和 ShadCN 自动生成前端界面
前端·llm·ai编程
爱泡脚的鸡腿42 分钟前
Vue第五次笔记
前端·vue.js
PineappleCoder44 分钟前
用 “餐厅模型” 吃透事件循环:同步、宏任务、微任务谁先执行?
前端·javascript·面试
ls_qq_267081347044 分钟前
cocos打包web - ios设备息屏及前后台切换音频播放问题
前端·ios·音视频·cocos-creator
YGY_Webgis糕手之路1 小时前
Cesium 快速入门(四)相机控制完全指南
前端·gis·cesium