JavaScript/JavaScript 문법

[JavaScript]exceljs 사용방법 및 엑셀 다운로드(내보내기)

DevStory 2022. 1. 25.

이번 포스팅은 exceljs 라이브러리를 사용하여 엑셀 다운로드(내보내기)하는 방법을 소개합니다.

 

exceljs를 사용하는 이유

JavaScript에서 엑셀 다운로드를 지원하는 다양한 라이브러리가 존재하지만, exceljs 라이브러리는 엑셀의 모든 셀을 접근하여 커스텀할 수 있다는 장점이 있습니다. font, border, fill 등... 특정 행의 셀마다 스타일을 설정할 수 있으며 이미지도 엑셀로 내보낼 수 있습니다.

 

자세한 사용 방법은 exceljs 공식 문서에서 확인할 수 있습니다.


엑셀 다운로드 구현 방법

예제는 react에서 구현하였지만, JavaScript를 사용하는 다른 웹 프레임워크에서도 사용할 수 있습니다.

 

※ 주의사항

exceljs의 주의사항으로 행과 셀은 0이 아닌 1부터 시작합니다.

 

exceljs는 외부 라이브러리이므로 npm을 통해 다운로드합니다.

npm install express exceljs

 

라이브러리를 다운로드하였다면, require() 함수를 사용하여 excel.js 종속성을 추가합니다.

const Excel = require('exceljs');

 

엑셀 객체(workbook)를 생성합니다.

const workbook = new Excel.Workbook();

 

workbook이라는 엑셀 객체를 생성 후 생성자, 수정자, 생성일, 수정자 속성에 값을 설정합니다.

  • creator: 생성자
  • lastModifiedBy: 최종 수정자
  • created: 생성일
  • modified: 수정일
// 생성자
workbook.creator = '작성자';
 
// 최종 수정자
workbook.lastModifiedBy = '최종 수정자';
 
// 생성일(현재 일자로 처리)
workbook.created = new Date();
 
// 수정일(현재 일자로 처리)
workbook.modified = new Date();

 

addWorksheet() 함수를 사용하여 엑셀 시트를 추가합니다.

workbook.addWorksheet('Sheet One');
workbook.addWorksheet('Sheet Two');
workbook.addWorksheet('Sheet Three');

 

엑셀 시트를 접근하기 위해서는 getWorksheet() 함수를 사용하거나 배열 타입인 worksheets 속성으로 접근합니다.

// 1. getWorksheet() 함수에서 시트 명칭 전달
const sheetOne = workbook.getWorksheet('Sheet One');
 
// 2. getWorksheet() 함수에서 시트 인덱스 전달
const sheetTwo = workbook.getWorksheet(1);
 
// 3. 대괄호 표기법
const sheetThree = workbook.worksheets[2];

 

엑셀 시트 생성과 동시에 시트를 접근하고 싶은 경우 addWorksheet() 함수의 리턴 값을 받는 객체를 설정합니다.

const sheetOne = workbook.addWorksheet('Sheet One');
const sheetTwo = workbook.addWorksheet('Sheet Two');
const sheetThree = workbook.addWorksheet('Sheet Three');

 

엑셀 시트를 삭제하는 경우 removeWorksheet() 함수에 엑셀 시트 객체의 id를 전달합니다.

// 세 번째 엑셀 시트를 제거
workbook.removeWorksheet(sheetThree.id);

 

다음은 엑셀 시트의 셀(첫 번째 행)을 설정합니다. 가장 기본적인 속성은 header와 key 속성이며 2가지 속성 이외에도 여러 가지 속성이 존재합니다.

  • header: 엑셀(첫 번째 행)에 표기되는 이름
  • key: 셀에 접근하기 위한 고유한 값
// 엑셀 시트 접근(어떤 워크시트에서 작업할 건지...)
const sheetOne = workbook.getWorksheet('Sheet One');
 
// 컬럼 설정
// header: 엑셀에 표기되는 이름
// key: 컬럼을 접근하기 위한 key
// hidden: 숨김 여부
// width: 컬럼 넓이
// style: 셀 스타일 설정
sheetOne.columns = [
  {header: '이름', key: 'name', width: 40},
  {header: '성별', key: 'gender', hidden:false, width: 30},
  {header: '부서코드', key: 'deptCode', width: 60},
  {header: '부서명', key: 'deptName', width: 100,
    // 스타일 설정
    style: {
      // Font 설정
      font: {name: 'Arial Black', size: 20},
      // Borders 설정
      border: {
        top: {style:'thin', color: {argb:'FF00FF00'}},
        left: {style:'thin', color: {argb:'FF00FF00'}},
        bottom: {style:'thin', color: {argb:'FF00FF00'}},
        right: {style:'thin', color: {argb:'FF00FF00'}},
      },
      // Fills 설정
      fill: {
        type: 'pattern'
        fgColor: {argb: 'FFFFFF00'},
        bgColor: {argb: 'FF0000FF'}
      }
    }
  }
]

 

셀에 접근해야 하는 경우 getColumn() 함수에 셀의 고유한 값인 key 또는 셀 순서를 전달합니다. getColumn() 함수의 리턴 값을 이용하여 셀의 속성을 변경할 수 있습니다.

// 컬럼 접근 방법
// 1. getColumn() 함수에 key를 전달
const colName = worksheet.getColumn('name');
 
// 2. getColumn() 함수에 컬럼 순서를 전달(1부터 시작함)
const colGender = worksheet.getColumn(2);
 
// 컬럼 접근 후 속성 변경
colGender.width = 40;
colGender.hidden = true;

 

엑셀에 행을 추가하는 경우 addRow() 함수를 사용합니다. 다음은 샘플 데이터를 순회하여 item을 추가하고 추가된 행의 셀 속성을 변경합니다.

// 객체의 key와 컬럼 헤더의 key와 매핑되는 데이터만 엑셀에 출력된다.
// 컬럼 헤더의 key는 name, gender, deptCode, deptName 총 4개가 존재하며, code와 entryDate는 컬럼 헤더에 없으므로 엑셀에 출력되지 않는다.
const sampleData = [
  { name: '홍길동', code: 'A100', gender: 'F', entryDate: '20200101', deptCode: 'A1000', deptName: '금융팀' },
  { name: '마이콜', code: 'A200', gender: 'F', entryDate: '20200201', deptCode: 'A2000', deptName: '자산팀' },
  { name: '둘리', code: '9999991234567', gender: 'M', entryDate: '20200301', deptCode: 'A1000', deptName: '금융팀' },
  { name: '또치', code: '9999992234567', gender: 'M', entryDate: '20200401', deptCode: 'A2000', deptName: '자산팀' }
];
 
const borderStyle = {
  top: { style: 'thin' },
  left: { style: 'thin' },
  bottom: { style: 'thin' },
  right: { style: 'thin' }
};

// 샘플 데이터 순회
sampleData.map((item, index) => {
  // 행 추가
  sheetOne.addRow(item);
 
  // 추가된 행의 컬럼 설정(헤더와 style이 다를 경우)
  // 컬럼 갯수만큼 루프
  for(let loop = 1; loop <= 4; loop++) {
    // 로우와 행은 0이 아닌 1부터 시작한다.
    // 행은 헤더를 제외한 행부터 시작해야하므로 "index + 2"
    const col = sheetOne.getRow(index + 2).getCell(loop);
    col.border = borderStyle; 
  }
});

 

Blob 객체를 사용하여 엑셀을 다운로드합니다.

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 = `테스트.xlsx`;
  anchor.click();
  window.URL.revokeObjectURL(url);
})

 

다음은 예제 코드입니다.

// 버튼 클릭한 경우
handleClick = ({ target, event }) => {
  try {
    // 엑셀 생성
    const workbook = new Excel.Workbook();
   
    // 생성자
    workbook.creator = '작성자';
   
    // 최종 수정자
    workbook.lastModifiedBy = '최종 수정자';
   
    // 생성일(현재 일자로 처리)
    workbook.created = new Date();
   
    // 수정일(현재 일자로 처리)
    workbook.modified = new Date();
 
 
    // addWorksheet() 함수를 사용하여 엑셀 시트를 추가한다.
    // 엑셀 시트는 순차적으로 생성된다.
    workbook.addWorksheet('Sheet One');
    workbook.addWorksheet('Sheet Two');
    workbook.addWorksheet('Sheet Three');
   
    // 엑셀 시트를 접근하는 방법은 세 가지 방법이 존재한다.
    // 1. getWorksheet() 함수에서 시트 명칭 전달
    const sheetOne = workbook.getWorksheet('Sheet One');
   
    // 2. getWorksheet() 함수에서 시트 인덱스 전달
    const sheetTwo = workbook.getWorksheet(1);
   
    // 3. 대괄호 표기법
    const sheetThree = workbook.worksheets[2];
   
    // removeWorksheet() 함수를 사용하여 엑셀 시트를 제거한다.
    workbook.removeWorksheet(sheetThree.id);
 
    // 컬럼 설정
    // header: 엑셀에 표기되는 이름
    // key: 컬럼을 접근하기 위한 key
    // hidden: 숨김 여부
    // width: 컬럼 넓이
    sheetOne.columns = [
      {header: '이름', key: 'name', width: 40},
      {header: '성별', key: 'gender', hidden:false, width: 30},
      {header: '부서코드', key: 'deptCode', width: 60},
      {header: '부서명', key: 'deptName', width: 100,
        // 스타일 설정
        style: {
          // Font 설정
          font: {name: 'Arial Black', size: 20},
          // Borders 설정
          border: {
            top: {style:'thin', color: {argb:'FF00FF00'}},
            left: {style:'thin', color: {argb:'FF00FF00'}},
            bottom: {style:'thin', color: {argb:'FF00FF00'}},
            right: {style:'thin', color: {argb:'FF00FF00'}},
          },
          // Fills 설정
          fill: {
            type: 'pattern',
            fgColor: {argb: 'FFFFFF00'},
            bgColor: {argb: 'FF0000FF'}
          }
        }
      }
    ]
 
    const sampleData = [
      { name: '홍길동', code: 'A100', gender: 'F', entryDate: '20200101', deptCode: 'A1000', deptName: '금융팀' },
      { name: '마이콜', code: 'A200', gender: 'F', entryDate: '20200201', deptCode: 'A2000', deptName: '자산팀' },
      { name: '둘리', code: '9999991234567', gender: 'M', entryDate: '20200301', deptCode: 'A1000', deptName: '금융팀' },
      { name: '또치', code: '9999992234567', gender: 'M', entryDate: '20200401', deptCode: 'A2000', deptName: '자산팀' }
    ];
   
    const borderStyle = {
      top: { style: 'thin' },
      left: { style: 'thin' },
      bottom: { style: 'thin' },
      right: { style: 'thin' }
    };
   
    sampleData.map((item, index) => {
      sheetOne.addRow(item);
   
      // 추가된 행의 컬럼 설정(헤더와 style이 다를 경우)
      for(let loop = 1; loop <= 4; loop++) {
        const col = sheetOne.getRow(index + 2).getCell(loop);
        col.border = borderStyle;
        col.font = {name: 'Arial Black', size: 40};
      }
    });
 
    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 = `테스트.xlsx`;
      anchor.click();
      window.URL.revokeObjectURL(url);
    })
  } catch(error) {
    console.error(error);
  }
}
반응형

댓글