관리 메뉴

개발이야기

[ Node.js 기본 ] Node.js로 엑셀 파일 데이터 입력 및 파일 다운로드 하는 방법 (with Ajax) 본문

node js/node js 기본

[ Node.js 기본 ] Node.js로 엑셀 파일 데이터 입력 및 파일 다운로드 하는 방법 (with Ajax)

안성주지몬 2020. 5. 26. 00:00

안녕하세요. 오랜만에 돌아온 개발이야기입니다.

오늘은 Node.js로 엑셀 파일에 데이터를 입력하고 파일을 다운로드 하는 방법에 대해서 알아보겠습니다. 

* 특히, 클라이언트단에서 엑셀 아이콘을 클릭했을때 파일을 다운로드 하는 방법에 대해서 알아보겠습니다.

 

 

1. 라이브러리 선택

엑셀 관련 Node.js 라이브러리는 exceljs, excel4node, node-excel-export 등 여러개가 존재합니다. 저는 이 중 ajax로 엑셀을 다운 받는 레퍼런스가 있었던 node-excel-export를 사용했습니다. 

 

2. Ajax에서 파일 다운로드 하는 방법

 

< js >

      $.ajax({
        type: "POST",
        url: url, // 엑셀 다운로드 관련 미들웨어로 url 
        success: function(resp){
          if(!resp.result) {
            alert('엑셀 다운로드 중 문제가 발생했습니다.');
            return false;
          }
          let excelUri = "data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,";
          let excelUrl = excelUri + resp.content; // resp.content는 엑셀 데이터입니다. 
          let filename = 'ExcelDownLaod-File' // 다운받는 파일의 이름 지정 
          setTimeout(function () {
            var a = document.createElement("a");
            a.href = excelUrl;
            a.download = filename;
            a.click();
          }, 100);
        }
    });

* setTimeout 함수는 용량이 큰 문제를 다운로드 받을때 "about:blank#blocked" 이슈가 발생해 이를 해결하기 위해 추가했습니다. 

 

3. 엑셀 데이터 입력 

export async function makeExcelFile(res) {
  const excel = require('node-excel-export');
 
  let dailySpecification = { // 헤더 역할을 합니다. 
    days: {
      displayName: '날짜', // 헤더의 표시되는 이름 
      headerStyle: {},
      cellStyle: {}, 
      width: 120
    }
  };

  
  let dailyDataSet = [];
  const dailyDatas = dataSe;

  // 헤더를 추가할일이 있다면 아래와 같이 추가해줍니다. 
  for(let idx=0; idx<dailyDatas.length; idx++) {
    let tempKey = 'excelTest' + idx;
    let tempObj = new Object();
    tempObj[tempKey] = new Object();
    tempObj[tempKey]['displayName'] = dailyDatas[idx]['name'];
    tempObj[tempKey]['headerStyle'] = {};
    tempObj[tempKey]['cellStyle'] = {}; 
    tempObj[tempKey]['width'] = 120;
    Object.assign(dailySpecification, tempObj)
  }

// 각각의 헤더별로 데이터를 넣어주면 됩니다. 
  for(let idx=0; idx<dailyDatas.length; idx++) {
    let data = dailyDatas[idx]['data']
    let tempKey = 'excelTest' + idx;
    for(let j=0; j<data.length; j++) {
      let tempData = data[j] // format [timestamp, profit];
      let tempObj = new Object();
      if (idx === 0) {
        tempObj['days'] = moment(tempData[0]).format("YYYY.MM.DD");
        tempObj[tempKey] = tempData[1]
        // tempObj 예시 : {'days': '2019.01.01', 'excelTest0': 'data0', 'excelTest1', 'data0'} 
        dailyDataSet.push(tempObj);
      }
      else {
        let targetObj = dailyDataSet[j]
        targetObj[tempKey] = tempData[1]
      }
    }
  }

  
  let exportData = [ 
    {
        name: '첫번째시트', // 시트 이름입니다. 
        specification: dailySpecification, // 위에서 만든 헤더들입니다.
        data: dailyDataSet // 시트에 들어가는 데이터들입니다. 
    }
    /*
	,{
      name: '두번채시트', 
      specification: monthlySpecification,
      data: monthlyDataSet 
    }
    */
  ];
  // exportData 역시 specification 처럼 for문을 통해 추가가능합니다. 
  let report = excel.buildExport(exportData);
  return report  
}

 

1) 헤더 부분 = specification

헤더의 개수가 데이터 값에 따라 유동적으로 변경된다면 아래와 같이 for문을 통해 specification 값을 추가해 대응할 수 있습니다.

위에서 선언한 'days'와 같이 Object 타입으로 새롭게 만들어 기존의 dailySpecification 값에 추가해주면 됩니다.

  // 헤더를 추가할일이 있다면 아래와 같이 추가해줍니다. 
  for(let idx=0; idx<dailyDatas.length; idx++) {
    let tempKey = 'excelTest' + idx;
    let tempObj = new Object();
    tempObj[tempKey] = new Object();
    tempObj[tempKey]['displayName'] = dailyDatas[idx]['name'];
    tempObj[tempKey]['headerStyle'] = {};
    tempObj[tempKey]['cellStyle'] = {}; 
    tempObj[tempKey]['width'] = 120;
    Object.assign(dailySpecification, tempObj)
  }

 

2) 데이터 입력 

데이터를 입력할 때는 위에서 선언한 dailySpecificaion의 키 값들에 접근해서 데이터를 추가해야합니다.

{'days': '2019.01.01', 'excelTest0': 'data0', 'excelTest1', 'data1'} 이와 같이 모든 키값에 대응하는 데이터를 추가해주고 이들을 배열 형태에 dailyDataSet에 넣어줍니다. 위 데이터가 시트상에서 하나의 줄을 채워주게 됩니다.  

// 각각의 헤더별로 데이터를 넣어주면 됩니다. 
  for(let idx=0; idx<dailyDatas.length; idx++) {
    let data = dailyDatas[idx]['data']
    let tempKey = 'excelTest' + idx;
    for(let j=0; j<data.length; j++) {
      let tempData = data[j] // format [timestamp, profit];
      let tempObj = new Object();
      if (idx === 0) {
        tempObj['days'] = moment(tempData[0]).format("YYYY.MM.DD");
        tempObj[tempKey] = tempData[1]
        // tempObj 예시 : {'days': '2019.01.01', 'excelTest0': 'data0', 'excelTest1', 'data1'} 
        dailyDataSet.push(tempObj);
      }
      else {
        let targetObj = dailyDataSet[j]
        targetObj[tempKey] = tempData[1]
      }
      
    }
  }

 

< 라우터 >

export async function saveAsExcel(req: express.Request, res: express.Response) {
  const report = await makeExcelFile(res);
  res.send({content: report.toString('base64'), filename: 'testFile', result:true});
}

 

4. 맺음말

 

ajax를 통해서 클라이언트단으로 엑셀 파일을 다운로드하는 레퍼런스가 많이 부족해 어려움을 겪었습니다. 여러 레퍼런스를 통해 이를 구현할 수 있었습니다. 이 글을 보고 이해가 안되시거나 궁금하신게 있으면 댓글을 달아주시면 제가 아는한에서 최대한 도움을 드리겠습니다.

또한 피드백이 있으시다면 언제나 환영입니다!

 

 

참고자료

1) Ajax Download

https://gist.github.com/umidjons/b47d0fbf538e432bbd4e1760816447f6

 

Generate Excel file via AJAX

Generate Excel file via AJAX. GitHub Gist: instantly share code, notes, and snippets.

gist.github.com

2) https://www.npmjs.com/package/node-excel-export

 

node-excel-export

Node-Excel-Export

www.npmjs.com

 

Comments