개발 창고/Web

[Javascript] Excel 다운로드 기능 구현하기

로이제로 2020. 8. 21. 14:41
반응형

 관리 화면들을 만들다 보면 제일 많이 요구되는 부분이 엑셀 다운입니다. 이는 아무래도 웹에 익숙하지 않은 이용자들의 경우 엑셀이 더욱 익숙한 경우도 있고, 화면에서 표현하지 못하는 많은 부분을 엑셀을 통해서 확인 가능하기도 하기 때문입니다. (웹 화면은 개발자가 요청을 수렴 또는 분석을 통해 필요 정보를 노출하게 되지만 실제로 이용자는 그 외적으로 데이터를 조작해서 보고 싶어 하는 경우가 더러 있습니다. 최근에는 빅데이터를 활용하기도 하지만, 학습이 필요한 부분이 있기 때문에 엑셀을 통한 데이터 전달하는 게 없어지는 건 아무래도 몇 년 이내에는 어려울 것으로 보입니다.)

/**
* 엑셀 다운로드
* @param fileName 엑셀파일명 (ex. excel.xls)
* @param sheetName 시트명
* @param headers 시트내용(html - table)
*/
function _excelDown(fileName, sheetName, sheetHtml) {
    var html = '';
    html += '<html xmlns:x="urn:schemas-microsoft-com:office:excel">';
    html += '    <head>';
    html += '        <meta http-equiv="content-type" content="application/vnd.ms-excel; charset=UTF-8">';
    html += '        <xml>';
    html += '            <x:ExcelWorkbook>';
    html += '                <x:ExcelWorksheets>';
    html += '                    <x:ExcelWorksheet>'
    html += '                        <x:Name>' + sheetName + '</x:Name>';   // 시트이름
    html += '                        <x:WorksheetOptions><x:Panes></x:Panes></x:WorksheetOptions>';
    html += '                    </x:ExcelWorksheet>';
    html += '                </x:ExcelWorksheets>';
    html += '            </x:ExcelWorkbook>';
    html += '        </xml>';
    html += '    </head>';
    html += '    <body>';
    
    // ----------------- 시트 내용 부분 -----------------
    html += sheetHtml;
    // ----------------- //시트 내용 부분 -----------------
    
    html += '    </body>';
    html += '</html>';
    
    // 데이터 타입
    var data_type = 'data:application/vnd.ms-excel';
    var ua = window.navigator.userAgent;
    var blob = new Blob([html], {type: "application/csv;charset=utf-8;"});
    
    if ((ua.indexOf("MSIE ") > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./)) && window.navigator.msSaveBlob) {
        // ie이고 msSaveBlob 기능을 지원하는 경우
        navigator.msSaveBlob(blob, fileName);
    } else {
        // ie가 아닌 경우 (바로 다운이 되지 않기 때문에 클릭 버튼을 만들어 클릭을 임의로 수행하도록 처리)
        var anchor = window.document.createElement('a');
        anchor.href = window.URL.createObjectURL(blob);
        anchor.download = fileName;
        document.body.appendChild(anchor);
        anchor.click();
        
        // 클릭(다운) 후 요소 제거
        document.body.removeChild(anchor);
    }
}

해당 소스는 재사용이 가능하도록 기능을 구현한 function입니다.

활용은 다음과 같이 할 수 있습니다.

다음과 같은 테이블이 있다고 가정하고 다운을 받으면 아래와 같은 엑셀이 결과로 보입니다.

다운로드된 엑셀 파일명

 

다운로드된 엑셀의 시트 명

 

다운로드된 엑셀의 내용

대상 소스는 아래와 같습니다

<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>엑셀테스트</title>
<script type="text/javascript">
/**
* 엑셀 다운로드
* @param fileName 엑셀파일명 (ex. excel.xls)
* @param sheetName 시트명
* @param headers 시트내용(html - table)
*/
function _excelDown(fileName, sheetName, sheetHtml) {
    var html = '';
    html += '<html xmlns:x="urn:schemas-microsoft-com:office:excel">';
    html += '    <head>';
    html += '        <meta http-equiv="content-type" content="application/vnd.ms-excel; charset=UTF-8">';
    html += '        <xml>';
    html += '            <x:ExcelWorkbook>';
    html += '                <x:ExcelWorksheets>';
    html += '                    <x:ExcelWorksheet>'
    html += '                        <x:Name>' + sheetName + '</x:Name>';   // 시트이름
    html += '                        <x:WorksheetOptions><x:Panes></x:Panes></x:WorksheetOptions>';
    html += '                    </x:ExcelWorksheet>';
    html += '                </x:ExcelWorksheets>';
    html += '            </x:ExcelWorkbook>';
    html += '        </xml>';
    html += '    </head>';
    html += '    <body>';
    
    // ----------------- 시트 내용 부분 -----------------
    html += sheetHtml;
    // ----------------- //시트 내용 부분 -----------------
    
    html += '    </body>';
    html += '</html>';
    
    // 데이터 타입
    var data_type = 'data:application/vnd.ms-excel';
    var ua = window.navigator.userAgent;
    var blob = new Blob([html], {type: "application/csv;charset=utf-8;"});
    
    if ((ua.indexOf("MSIE ") > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./)) && window.navigator.msSaveBlob) {
        // ie이고 msSaveBlob 기능을 지원하는 경우
        navigator.msSaveBlob(blob, fileName);
    } else {
        // ie가 아닌 경우 (바로 다운이 되지 않기 때문에 클릭 버튼을 만들어 클릭을 임의로 수행하도록 처리)
        var anchor = window.document.createElement('a');
        anchor.href = window.URL.createObjectURL(blob);
        anchor.download = fileName;
        document.body.appendChild(anchor);
        anchor.click();
        
        // 클릭(다운) 후 요소 제거
        document.body.removeChild(anchor);
    }
}

function download(){
    // 대상 테이블을 가져옴
    var table = document.getElementById("table01");
    
    if(table){
        // CASE 대상 테이블이 존재하는 경우
        
        // 엑셀다운 (엑셀파일명, 시트명, 내부데이터HTML)
        _excelDown("엑셀파일명.xls", "시트명", table.outerHTML)
    }
}
</script>
</head>
<body>
<input type="button" value="엑셀다운" onclick="download();"/>
<table id="table01"  border="1">
    <thead>
        <tr>
            <th>구분</th>
            <th>항목1</th>
            <th>항목2</th>
            <th>항목3</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>1</td>
            <td>내용1-1</td>
            <td>내용1-2</td>
            <td>내용1-3</td>
        </tr>
        <tr>
            <td>2</td>
            <td>내용2-1</td>
            <td>내용2-2</td>
            <td>내용2-3</td>
        </tr>
        <tr>
            <td>2</td>
            <td>내용3-1</td>
            <td>내용3-2</td>
            <td>내용3-3</td>
        </tr>
    </tbody>
</table>
</body>
</html>

 

function download() { ... }에 보이는 것처럼 table01이라는 테이블을 가져와서 엑셀을 다운로드하도록 진행할 수 있습니다.

 

 

※ Input을 포함하여 출력하고 싶은 경우

function download(){
    // 대상 테이블을 가져옴
    var table = document.getElementById("table01");
    
    if(table){
        // CASE 대상 테이블이 존재하는 경우
        
        // Input을 Span으로 Converting
        var inputs      = table.querySelectorAll("input");
        var orgInput    = new Array(inputs.length);         // 원본을 담아둘 Array

        // Loop를 수행하며 input을 span으로 변환
        for(var i =  0; i < inputs.length; i++){
            orgInput[i] = inputs[i].outerHTML;
            inputs[i].outerHTML = `<span class="input_org">${inputs[i].value}</span>`;
        }

        // 엑셀다운 (엑셀파일명, 시트명, 내부데이터HTML)
        _excelDown("엑셀파일명.xls", "시트명", table.outerHTML)

        // Converting 했던 Input을 복원
        var inputs = table.querySelectorAll("span.input_org");
        for(var i =  0; i < inputs.length; i++){
            inputs[i].outerHTML = orgInput[i];
        }
    }
}

input을 임시로 span으로 변경하여 출력 후 다시 input element로 원복한다.

이 경우 원래 다운되지 않던 항목 3의 마지막 줄의 AAAAA가 포함되어 출력됨을 알 수 있습니다.

반응형