sheetjs로 Excel upload, download 구현하기(with antd upload component)

Maliethy·2021년 10월 13일
1

react

목록 보기
3/7

1. Excel Upload

import { Upload, message, ... } from 'antd';
import * as XLSX from 'xlsx';


function UploadOrderList() {
 const [uploadFileName, setUploadFileName] = useState('');


 const handleBeforeUpload = useCallback((file) => {
 ...자세한 로직은 아래에
 }, []);
 
 const handleOnChange = useCallback(
    (info) => {
      const status = info.file.status;
      
      if (status === 'done') {
        setUploadFileName(info.file.name);

             ....파일 업로드 성공 후 작업

             
      } else if (status === 'error') {
        message.error(`${info.file.name} 파일 업로드에 실패하였습니다. 다시 시도해주세요.`);
      }
    },
    [],
  );

  useEffect(() => {
    if (uploadFileName) {
      message.success(`${uploadFileName} 파일 업로드에 성공하였습니다.`);
    }
  }, [uploadFileName]);

  const props = {
    name: 'file',
    multiple: true,
    showUploadList: false,
    maxCount: 1,
    beforeUpload: handleBeforeUpload,
    onChange: handleOnChange,
  };
  
  return(
    <Dragger {...props}>
     
     ...
     
    </Dragger>
  );
  
  }
  
  export default UploadOrderList;

File 객체를 읽는 handleBeforeUpload를 자세히 살펴보자.
File객체에 숨어있는 데이터를 FileReader API를 통해 읽는다.
new FileReader()를 통해 파일리더를 만들고,
onload 이벤트 핸들러를 붙여서 콜백으로 파일을 다 읽었다는 것을 알려주도록 하고 있다.
다음은 파일을 읽는 방법 중 readAsArrayBuffer를 사용한 예시이다.
ArrayBuffer 객체는 데이터를 일정한 크기로 조금 조금씩 서버로 보낼 때 사용한다.

const handleBeforeUpload = useCallback(
    (file) => {
      let fileExt = file.name.split('.');
      fileExt = fileExt[fileExt.length - 1];

      const reader = new FileReader();
      if (fileExt === 'xlsx' || fileExt === 'xls' || fileExt === 'csv') {
        reader.readAsArrayBuffer(file);

        reader.onload = (evt) => {
          // evt = on_file_select event
          const bstr = evt.target.result;//file data
          console.log('bstr', bstr);
       
          const wb = XLSX.read(bstr, { type: 'array', cellDates: true });
      
          const firstSheetName = wb.SheetNames[0];

          if (firstSheetName) {
            const firstSheet = wb.Sheets[firstSheetName];
            const range = XLSX.utils.decode_range(firstSheet['!ref']);//엑셀 열의 갯수를 파악하기

 ...엑셀데이터를 가지고 원하는 작업 진행하기 
 
          } else {
            //엑셀파일양식 중 fileData가 html으로 읽혀서 들어오는 경우가 있어 readAsBinaryString로 처리해준다.
            
            reader.readAsBinaryString(file);//이진데이터로 반환하기
            reader.onload = () => {
              const bstr = reader.result;
              const wb = XLSX.read(bstr, { type: 'binary' });
              const firstSheetName = wb.SheetNames[0]; // 첫번째 시트명
              const firstSheet = wb.Sheets[firstSheetName]; // 첫번째 시트
              const range = XLSX.utils.decode_range(firstSheet['!ref']);//엑셀 열의 갯수를 파악하기

            ...엑셀데이터를 가지고 원하는 작업 진행하기 
            };
          }
        };
      } else {
      //확장자가 xlsx, xls, csv가 아닌 경우 에러 처리하기
        return false;
      }
    },
    [],
  );

구현된 화면은 다음과 같다.

sheetjs bstr wb console

2. Excel download

Button을 클릭하면 handleDownloadInvoice함수가 실행되고 GetBatchInfos요청이 서버로 간다.(redux-toolkit 사용함)
요청이 성공했을 때 서버로부터 받아온 응답값이 BatchInfosList에 담긴다.
이 데이터를 makeInvoiceExcelDataLists 함수에서 엑셀형식에 맞게 invoiceData에 담는다.
아래의 예시에서는 xls, csv, xlsx 세가지 형식으로 엑셀파일이 다운받아진다.

import * as XLSX from 'xlsx';


const BatchOrderStatusLists = ()=>{


const makeInvoiceExcelDataLists = (BatchInfosList) => {
  let invoiceData = [];

  if (openmarketKind === 'cafe24') {
    for (let i = 0; i < BatchInfosList.length; i++) {
      invoiceData.push({
          주문번호: BatchInfosList[i].Order.OrderID,
        품목번호: BatchInfosList[i].ProductOrder.ProductID,
        '품목별 주문번호': `${BatchInfosList[i].Order.OrderID}+${i % 10 ? '0' + i : i}`,
        운송장번호: BatchInfosList[i].trackingNumber,
      });
    }
    return invoiceData;
  }
  
  
    useEffect(() => {
   
      const invoiceData = makeInvoiceExcelDataLists(BatchInfosList);
     
      if (invoiceData) {
        /* make the worksheet */
        const ws = XLSX.utils.json_to_sheet(invoiceData);

        /* add to workbook */
        const wb = XLSX.utils.book_new();
        XLSX.utils.book_append_sheet(wb, ws, '발송처리');//시트 이름을 '발송처리'로 한다.

       XLSX.writeFile(wb, `modument_${BatchInfosList[0]?.openmarketKind.toLowerCase()}_invoice.xls`, {
              bookType: 'biff8', //Microsoft Office Excel 97-2003 Binary File Format, xls
            })
          
       XLSX.writeFile(wb, `modument_${BatchInfosList[0]?.openmarketKind.toLowerCase()}_invoice.csv`, {
              bookType: 'csv',
            })
     
     XLSX.writeFile(wb, `modument_${BatchInfosList[0]?.openmarketKind.toLowerCase()}_invoice.xlsx`);
       
      }
    }
  }, [ BatchInfosList]);
  
  
  
    const handleDownloadInvoice = useCallback(
    (batchNumber) => (e) => {
      dispatch(GetBatchInfos({ batchNumber }));//서버에 요청보내기
    },
    [],
  );
  
  return(
  
    <Button onClick={handleDownloadInvoice(text.batchNumber)}>송장번호 일괄등록 엑셀다운로드</Button>
    );
  
...

}

export default BatchOrderLists;

다운로드된 csv형식의 엑셀은 다음과 같은 모양이 된다.

cafe24 invoice download excel

출처:
https://eblo.tistory.com/83
https://www.zerocho.com/category/HTML&DOM/post/592827558653d6001804a0a5
https://developer.mozilla.org/ko/docs/Web/API/FileReader

profile
바꿀 수 있는 것에 주목하자

0개의 댓글