🚀Nest.js实现Excel上传并解析数据存入数据库

NestJS 在构建高效且可扩展的 Node.js 服务器端应用程序方面别具优势,越来越多的团队在大型 Node.js 服务端项目中使用 NestJS,非常值得前端学习。

本文主要记录一下对一个小功能的实现,也是日常开发比较实用的功能,就是通过Nest来实现一个接口,读取客户端上传的文件保存到本地,并且解析excel将文件中的每一列存入到数据库中

接口Controller层实现

js 复制代码
@Controller('stockx')
@UseGuards(JwtGuard, RoleGuard)
export class StockxController {
  constructor(private readonly stockxService: StockxService) {}
  @Post('updateSPGFromExcel')
    @UseInterceptors(FileInterceptor('file'))
    updateSPGFromExcel(@UploadedFile() file: Express.Multer.File) {
      return this.stockxService.updateSPGFromExcel(file);
    }
  
  1. Controller 装饰器 : @Controller('stockx'): 这个装饰器用于在 /stockx 下设置控制器的基本路由。

  2. Guard 装饰器 : @UseGuards(JwtGuard, RoleGuard): 这个装饰器将守卫应用于控制器,以基于 JWT 认证 (JwtGuard) 和角色授权 (RoleGuard) 限制访问。

  3. 构造函数 : 构造函数注入了一个 StockxService 的实例,这个服务负责处理与 StockX 服务相关的业务逻辑。我们直接在函数中调用service的updateSPGFromExcel

这里的@UploadedFile() 是 NestJS 的装饰器,用于从 HTTP 请求中提取上传的文件。它告诉 NestJS 在处理 HTTP 请求时将上传的文件绑定到被装饰的参数上。在这个特定的情况下,file 参数被装饰为 Express.Multer.File 类型,这是 Multer 中间件提供的类型,表示上传的文件对象的类型。

在postman中这样去调用请求即可

接口Service层实现

由于需要先将文件保存到本地,接着对文件的数据进行解析,先完成文件保存,一个文件可能被上传多次,这里使用了uuid来给每个文件命名成唯一的名字,防止文件名冲突,通过fs来讲

js 复制代码
async updateSPGFromExcel(file) {
      try {
      // 将上传的文件保存到本地
      const uuid = uuidv4()
      let filename = `${uuid}_spg.xlsx`
      const filePath = path.join('/home/www/nestjs-admin/uploads',filename);
      const writeStream = fs.createWriteStream(filePath);
    //   // 将上传的文件写入到可写流中
      writeStream.write(file.buffer);
      return { message: 'File uploaded and processed successfully' };
    } catch (err) {
      console.error('Error processing file:', err);
      return { message: 'Error processing file' };
    }
    //
  }

创建了一个写入流 (writeStream),它将数据写入到指定的文件路径中,传入要写入的文件的路径作为参数,这里使用path.join来拼接一下路径即可

解析传入的excel

这里可以多学习一个知识点就是解析excel,所以我把这两步分开写了,先保存文件,在对保存好的文件进行解析

有个需要注意的地方就是这里是一个函数中执行两步操作

第一个是保存文件

第二个是解析保存的文件

那么就会出现一种情况就是文件还没保存好,就已经开始解析,所以这种情况下要利用end操作,准确的知道写入文件完成的时候,再去执行解析操作,并且在finish中去执行解析。

writeStream.end() 是用于结束写入流的方法。在 Node.js 中,当使用可写流时,必须调用 .end() 方法来明确地标记写入操作的结束。这样做有几个目的:

  1. 确保所有数据都已写入 :调用 .end() 方法会将所有数据写入到流中,然后关闭流,这样可以确保所有数据都已成功写入到文件中。
  2. 触发 'finish' 事件 :当写入操作完成时,可写流会触发 'finish' 事件。通过调用 .end() 方法,可以确保在数据全部写入后触发这个事件,从而执行相应的后续操作。
js 复制代码
 // 明确结束写入操作,以确保触发 'finish' 事件
        writeStream.end();
      // 监听可写流的 'finish' 事件,表示写入操作完成
        writeStream.on('finish',async () => {
          console.log('Write operation finished.');
          // 执行其他处理,比如解析 Excel 文件等
           const workbook = xlsx.readFile(filePath);
           const worksheet = workbook.Sheets[workbook.SheetNames[0]];
           const excelData = xlsx.utils.sheet_to_json(worksheet, { header: 1 });
           let data: any = excelData.slice(1)
           console.log(data,'dadadadada')
            
            }catch(e){
                console.log('errr',e)
            }
        });

上面的代码的一些解析

  1. const workbook = xlsx.readFile(filePath);

    • 使用 xlsx 库的 readFile 方法读取指定路径下的 Excel 文件。
  2. const worksheet = workbook.Sheets[workbook.SheetNames[0]];

    • excel表格可能存在多个工作表,SheetNames【0】读取的是第一个工作表
  3. const excelData = xlsx.utils.sheet_to_json(worksheet, { header: 1 });

    • 将数据转换成json格式,并且使用 { header: 1 } 配置,表示将工作表中的第一行作为 JSON 对象的属性名。
  4. let data: any = excelData.slice(1);

    • 将 Excel 数据存储在变量 data 中,并排除了第一行标题行。

存入数据库

js 复制代码
try{
let spg  = []
for (const item of data) {
    let obj = {
        spgId:'12312312',//唯一id编号
        spid:item[1],
        sname:item[2],
        surl:item[3],
    }
    spg.push(obj)

}
console.log(spg,'spg')
await this.spgRepo.save(spg);

生成了data数据后可以通过下标的方式来访问data中拿到的数据,比如0下标则是表格的第一列

由于excel的数据量可能会比较多,所以对解析后的data循环并且做好数据格式放到数组中,保存成一个数据,再通过save的格式存到对应的表中

如果觉得有趣或有收获,请关注我的更新,给个喜欢和分享。您的支持是我写作的最大动力!

往期好文推荐

相关推荐
金灰几秒前
HTML5--裸体回顾
java·开发语言·前端·javascript·html·html5
茶卡盐佑星_3 分钟前
说说你对es6中promise的理解?
前端·ecmascript·es6
bug菌27 分钟前
Java GUI编程进阶:多线程与并发处理的实战指南
java·后端·java ee
Манго нектар31 分钟前
JavaScript for循环语句
开发语言·前端·javascript
蒲公英100139 分钟前
vue3学习:axios输入城市名称查询该城市天气
前端·vue.js·学习
天涯学馆1 小时前
Deno与Secure TypeScript:安全的后端开发
前端·typescript·deno
以对_1 小时前
uview表单校验不生效问题
前端·uni-app
Zheng1132 小时前
【可视化大屏】将柱状图引入到html页面中
javascript·ajax·html
夜月行者2 小时前
如何使用ssm实现基于SSM的宠物服务平台的设计与实现+vue
java·后端·ssm
程序猿小D2 小时前
第二百六十七节 JPA教程 - JPA查询AND条件示例
java·开发语言·前端·数据库·windows·python·jpa