NestJS excel 업로드/다운로드

Peter·2020년 10월 24일
11

nestjs

목록 보기
9/11
post-thumbnail

1. 패키지 설치

> yarn add xlsx fs

엑셀을 다루는 xlsx 패키지와, 파일을 다루는 fs 패키지를 설치합니다.

2. excel 업로드

1) sample 파일 준비

엑셀 업로드 테스트를 위한 엑셀파일을 준비합니다.
위와 같은 엑셀파일을 업로드하면, 서버에서 엑셀파일을 파싱해서 json형태로 만들어줄 수 있습니다.
이 때, 최상단 row에 있는 name, age, phone이 key가 되고 그 하단 row들이 각각의 value로 매핑된 json array가 생성되도록 셋팅할 수 있습니다.

2) 업로드 & json 변환

import { Controller, Get, Header, Post, Res, UploadedFile, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { MyLogger } from '../../logger/logger.service';
import * as XLSX from 'xlsx';

...(생략)

  @Post()
  @UseInterceptors(FileInterceptor('file'))
  async handleExcel(@UploadedFile() file) {
    const workbook = XLSX.read(file.buffer, { type: 'buffer' });

    // 첫번째 sheet 의 이름을 조회합니다.
    const sheetName = workbook.SheetNames[0];

    // 첫번째 sheet 를 사용합니다.
    const sheet = workbook.Sheets[sheetName];

    // sheet 의 정보를 json array 로 변환합니다.
    const rows = XLSX.utils.sheet_to_json(sheet, {
      // cell 에 값이 비어있으면 '' 을 기본값으로 설정합니다.
      defval: null,
    });

    this.logger.debug(rows);

    for (const row of rows) {
      const values = Object.keys(row).map(key => row[key]);
      const [name, age, phone] = values;
      this.logger.debug(`name : ${name}, age : ${age}, phone : ${phone}`);
    }

    return true;
  }

XLSX.utils.sheet_to_json 함수를 이용하여 엑셀 시트 내용을 json으로 변환 가능 합니다.
이렇게 json으로 변환한 뒤 원하는대로 가공하여 사용할 수 있습니다.
rows 로그 내용

[
  {
    "name": "John",
    "age": 27,
    "phone": "010-1111-1111"
  },
  {
    "name": "Peter",
    "age": 23,
    "phone": "010-2222-2222"
  },
  {
    "name": "Grace",
    "age": 25,
    "phone": "010-3333-3333"
  },
  {
    "name": "Paul",
    "age": 26,
    "phone": "010-4444-4444"
  },
  {
    "name": "David",
    "age": 27,
    "phone": "010-5555-5555"
  }
] 

3) 파일 업로드 테스트 (w/포스트맨)

아래와 같이 Body의 form-date에 엑셀파일을 셋팅해서 전송하는 방식을 이용하여 간단하게 테스트를 진행할 수 있습니다.

3. excel 다운로드


private readonly users = [
    {
      name: 'John',
      age: 27,
      phone: '010-1111-1111',
    },
    {
      name: 'Peter',
      age: 23,
      phone: '010-2222-2222',
    },
    {
      name: 'Grace',
      age: 25,
      phone: '010-3333-3333',
    },
    {
      name: 'Paul',
      age: 26,
      phone: '010-4444-4444',
    },
    {
      name: 'David',
      age: 27,
      phone: '010-5555-5555',
    },
  ];

... (생략)

  @Get()
  @Header('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
  @Header('Content-Disposition', 'attachment; filename=users.xlsx')
  async makeExcel(@Res() res) {

    // step 1. workbook 생성
    const wb = XLSX.utils.book_new();

    // step 2. 시트 만들기
    const newWorksheet = XLSX.utils.json_to_sheet(this.users);

    // step 3. workbook에 새로만든 워크시트에 이름을 주고 붙임.
    XLSX.utils.book_append_sheet(wb, newWorksheet, '연락처');

    const wbOptions = { bookType: 'xlsx', type: 'binary' };

    const filename = 'users.xlsx';
    // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
    // @ts-ignore
    // step 4. 파일을 로컬에 생성합니다.
    XLSX.writeFile(wb, filename, wbOptions); // write workbook file

    // step 5. 생성된 파일을 client 에 전송합니다.
    const stream = fs.createReadStream(filename); // create read stream
    stream.pipe(res);
  }

DB로부터 사용자 정보를 쿼리한 결과를 users에 저장했다고 가정해봅니다.
XLSX.utils.json_to_sheet 함수를 이용하여 json을 sheet로 변환할 수 있습니다.
생성한 sheet를 workbook에 append한 뒤, XLSX.writeFile 함수를 이용하여 엑셀 파일을 생성할 수 있습니다.
생성한 파일을 client로 전송하면 excel 다운로드가 완성됩니다!
(web 브라우져에서 해당 url을 입력하고 실행하면 다운로드가 진행됩니다.)

3-2. excel 다운로드 (파일생성 없이)

로컬에 파일을 생성하지 않고 client에 바로 내려주고 싶을 수도 있습니다.

  @Get()
  @Header('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
  @Header('Content-Disposition', 'attachment; filename=users.xlsx')
  async makeExcel(@Res() res) {

    // step 1. workbook 생성
    const wb = XLSX.utils.book_new();

    // step 2. 시트 만들기
    const newWorksheet = XLSX.utils.json_to_sheet(this.users);

    // step 3. workbook에 새로만든 워크시트에 이름을 주고 붙인다.
    XLSX.utils.book_append_sheet(wb, newWorksheet, '연락처');

    const wbOptions = { bookType: 'xlsx', type: 'base64' };

    // step 4. 파일을 생성한다. (메모리에만 저장)
    const wbout = XLSX.write(wb, wbOptions);

    // step 5. 파일을 response 한다.
    res.end(Buffer.from(wbout, 'base64'));
  }

XLSX.write 함수를 이용하여 메모리에 생성한 파일을 내려주면 로컬에 파일 생성 없이 excel 다운로드 기능을 구현할 수 있습니다.

참고 : https://github.com/SheetJS/sheetjs/issues/122

0개의 댓글