사붐이개발일기
[JS/Svelte] Excel파일 다운로드 기능 구현하기 - Excel.js 본문
서론
회사 프로젝트에서 정산현황의 기간 별 데이터를 엑셀 파일로 만들어 내려받게 해달라는 요구사항이 들어왔다. 엑셀파일 변환은 처음이라 여기저기 구글링하다 xlsx 라이브러리 보단 excel.js 가 좀 더 간단한것같아서 후자로 라이브러리를 선택했다.
나중에 더 찾아보니 xlsx 라이브러리는 css가 유료라고 한다.
사용하기
1. exceljs 라이브러리 설치
npm install exceljs;
2. exceljs 객체 가져오기
import ExcelJS from 'exceljs';
3. workbook 객체 생성
엑셀파일은 여러개의 sheet를 포함한다. workbook은 worksheet를 담는 그릇이다.
const workbook = new ExcelJS.Workbook();
4. worksheet 객체 생성
worksheet는 엑셀파일에서 sheet에 해당한다.
const worksheet = workbook.addWorksheet('정산데이터');
5. worksheet 컬럼명 등록
worksheet 첫번째 줄에 컬럼명을 추가한다.
header : 컬럼명
key : 데이터 key 값
style : 데이터 포맷 or style 설정
worksheet.columns = [
{header: '순번', key: 'rowNum', style: {numFmt: '0'}},
...
{header: '승인일자', key: 'appDt'},
{header: '승인시간', key: 'appTm'},
{header: '취소일자', key: 'ccDt'},
{header: '취소시간', key: 'ccTm'},
{header: '금액', key: 'amt'},
{header: '과세', key: 'taxAmt'},
{header: '비과세', key: 'taxFreeAmt'},
{header: '일반수수료', key: 'generalFee'},
{header: '일반부가세', key: 'generalVat'},
{header: '입금금액', key: 'depositAmt'},
{header: '정산일자', key: 'settlmntDt'}
];
6. worksheet 데이터 추가
worksheet 2번째줄 부터 데이터를 추가한다.
const data = {'rowNum' = 1, 'appDt' = '20240814', 'appTm' = '164011', ... }
worksheet.insertRows(2, data);
7. workbook 객체를 Blob 객체로 변환하여 다운받기
const fileName = '파일명.xlsx';
workbook.xlsx.writeBuffer()
.then((data) => {
const blob = new Blob([data], {type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"});
const url = window.URL.createObjectURL(blob);
const anchor = document.createElement('a');
anchor.href = url;
anchor.download = fileName;
anchor.click();
window.URL.revokeObjectURL(url);
})
.catch((error) => {
console.error('Error creating Excel file:', error);
});
이슈사항
서버에서 VO 값을 String으로 뿌려주니 excel로 변환했을때도 값들이 String으로 들어가 정렬이 안되는 문제가 있었다.
number로 변경하려면 클라이언트에서 json을 int로 변경해주거나 서버에서 int로 보내주면된다. 나는 서버에서 int로 변경했다.
# 24-08-21
기존데이터를 가공해야할 일이 생겼다. 컬럼꾸미기, 정렬, 데이터 형식 변경 등 수정 요청
엑셀 컬럼 설정
worksheet.columns = [
{header: '순번', key: 'rowNum', style: {numFmt: '0', alignment: {horizontal: 'center'}}},
...
{header: '결제자명', key: 'mpayMbrName', style: {alignment: {horizontal: 'center'}}},
{header: '결제상태', key: 'padjStatDesc', style: {alignment: {horizontal: 'center'}}},
{header: '승인일자', key: 'appDtDesc', width: 15, style: {alignment: {horizontal: 'center'}}},
{header: '승인시간', key: 'appTmDesc', width: 15, style: {alignment: {horizontal: 'center'}}},
{header: '취소일자', key: 'ccDtDesc', width: 15, style: {alignment: {horizontal: 'center'}}},
{header: '취소시간', key: 'ccTmDesc', width: 15, style: {alignment: {horizontal: 'center'}}},
{header: '금액', key: 'amt', style: {numFmt: '#,##0', alignment: {horizontal: 'center'}}},
{header: '과세', key: 'taxAmt', style: {numFmt: '#,##0', alignment: {horizontal: 'center'}}},
{header: '비과세', key: 'taxFreeAmt', style: {numFmt: '#,##0', alignment: {horizontal: 'center'}}},
{header: '일반수수료', key: 'generalFee', width: 10, style: {numFmt: '#,##0', alignment: {horizontal: 'center'}}},
{header: '일반부가세', key: 'generalVat', width: 10, style: {numFmt: '#,##0', alignment: {horizontal: 'center'}}},
{header: '입금금액', key: 'depositAmt', style: {numFmt: '#,##0', alignment: {horizontal: 'center'}}},
{header: '정산일자', key: 'settlmntDtDesc', width: 15, style: {alignment: {horizontal: 'center'}}}
];
엑셀 데이터 변경
// 기존 JSON 데이터 + 가공데이터 추가
const data = excelData.map(item => {
return {
...item,
appDtDesc: changeDateForExcel(item.appDt),
appTmDesc: changeTimeForExcel(item.appTm),
ccDtDesc: changeDateForExcel(item.ccDt),
ccTmDesc: changeTimeForExcel(item.ccTm),
settlmntDtDesc: changeDateForExcel(item.settlmntDt)
};
});
컬럼 꾸미기
// 컬럼 배경색 설정
const headerFill = {
type: 'pattern',
pattern: 'solid',
fgColor: {argb: '6666ff'},
}
// 컬럼 폰트 설정
const headerFont = {bold: true, color: {argb: 'ffffff'}}
// 모든 컬럼에 적용
for (let i = 1; i <= worksheet.columnCount; i++) {
const headerEachCell = worksheet.getCell(`${String.fromCharCode(i + 64)}1`);
headerEachCell.fill = headerFill;
headerEachCell.font = headerFont;
headerEachCell.alignment = { horizontal: 'center' };
}
Reperence
1. ExcelJS 사용법
2. ExcelJS 다운로드
https://developer-talk.tistory.com/328