> yarn add xlsx fs
엑셀을 다루는 xlsx 패키지와, 파일을 다루는 fs 패키지를 설치합니다.
엑셀 업로드 테스트를 위한 엑셀파일을 준비합니다.
위와 같은 엑셀파일을 업로드하면, 서버에서 엑셀파일을 파싱해서 json형태로 만들어줄 수 있습니다.
이 때, 최상단 row에 있는 name, age, phone이 key가 되고 그 하단 row들이 각각의 value로 매핑된 json array가 생성되도록 셋팅할 수 있습니다.
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"
}
]
아래와 같이 Body의 form-date에 엑셀파일을 셋팅해서 전송하는 방식을 이용하여 간단하게 테스트를 진행할 수 있습니다.
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을 입력하고 실행하면 다운로드가 진행됩니다.)
로컬에 파일을 생성하지 않고 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 다운로드 기능을 구현할 수 있습니다.