SheetJS를 이용한 html table을 엑셀 xlsx로 다운로드 하는 방법

<% 
  response.setHeader("Content-Type", "application/vnd.ms-xls");
  response.setHeader("Content-Disposition", "inline; filename=viewcount-excel.xls");
%>

jsp에서 html table을 excel 파일로 변환하는 것은 매우 간단하다.
상단에 헤더값 Content-Type을 application/vnd.ms.[원하는 엑셀확장자]으로 선언하고 Content-Disposition값에 다운로드할 파일의 이름(filename=)을 적어주면 해결된다.
 
하지만 엑셀 형식 중 .xlsx파일의 경우에는 파일이 깨졌다는 메시지와 함께 다운로드가 제대로 되지 않는다.

일반적인 MIME 유형

.aac AAC audio audio/aac
.abw AbiWord document application/x-abiword
.apng Animated Portable Network Graphics (APNG) image image/apng
.arc Archive document (multiple files embedded) application/x-freearc
.avif AVIF image image/avif
.avi AVI: Audio Video Interleave video/x-msvideo
.azw Amazon Kindle eBook format application/vnd.amazon.ebook
.bin Any kind of binary data application/octet-stream
.bmp Windows OS/2 Bitmap Graphics image/bmp
.bz BZip archive application/x-bzip
.bz2 BZip2 archive application/x-bzip2
.cda CD audio application/x-cdf
.csh C-Shell script application/x-csh
.css Cascading Style Sheets (CSS) text/css
.csv Comma-separated values (CSV) text/csv
.doc Microsoft Word application/msword
.docx Microsoft Word (OpenXML) application/vnd.openxmlformats-officedocument.wordprocessingml.document
.eot MS Embedded OpenType fonts application/vnd.ms-fontobject
.epub Electronic publication (EPUB) application/epub+zip
.gz GZip Compressed Archive application/gzip
.gif Graphics Interchange Format (GIF) image/gif
.htm, .html HyperText Markup Language (HTML) text/html
.ico Icon format image/vnd.microsoft.icon
.ics iCalendar format text/calendar
.jar Java Archive (JAR) application/java-archive
.jpeg, .jpg JPEG images image/jpeg
.js JavaScript text/javascript
.json JSON format application/json
.jsonld JSON-LD format application/ld+json
.mid, .midi Musical Instrument Digital Interface (MIDI) audio/midi, audio/x-midi
.mjs JavaScript module text/javascript
.mp3 MP3 audio audio/mpeg
.mp4 MP4 video video/mp4
.mpeg MPEG Video video/mpeg
.mpkg Apple Installer Package application/vnd.apple.installer+xml
.odp OpenDocument presentation document application/vnd.oasis.opendocument.presentation
.ods OpenDocument spreadsheet document application/vnd.oasis.opendocument.spreadsheet
.odt OpenDocument text document application/vnd.oasis.opendocument.text
.oga Ogg audio audio/ogg
.ogv Ogg video video/ogg
.ogx Ogg application/ogg
.opus Opus audio in Ogg container audio/ogg
.otf OpenType font font/otf
.png Portable Network Graphics image/png
.pdf Adobe Portable Document Format (PDF) application/pdf
.php Hypertext Preprocessor (Personal Home Page) application/x-httpd-php
.ppt Microsoft PowerPoint application/vnd.ms-powerpoint
.pptx Microsoft PowerPoint (OpenXML) application/vnd
.rar RAR archive application/vnd.rar
.rtf Rich Text Format (RTF) application/rtf
.sh Bourne shell script application/x-sh
.svg Scalable Vector Graphics (SVG) image/svg+xml
.tar Tape Archive (TAR) application/x-tar
.tif, .tiff Tagged Image File Format (TIFF) image/tiff
.ts MPEG transport stream video/mp2t
.ttf TrueType Font font/ttf
.txt Text, (generally ASCII or ISO 8859-n) text/plain
.vsd Microsoft Visio application/vnd.visio
.wav Waveform Audio Format audio/wav
.weba WEBM audio audio/webm
.webm WEBM video video/webm
.webp WEBP image image/webp
.woff Web Open Font Format (WOFF) font/woff
.woff2 Web Open Font Format (WOFF) font/woff2
.xhtml XHTML application/xhtml+xml
.xls Microsoft Excel application/vnd.ms-excel
.xlsx Microsoft Excel (OpenXML) application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
.xml XML application/xml
.xul XUL application/vnd.mozilla.xul+xml
.zip ZIP archive application/zip
.3gp 3GPP audio/video container video/3gpp
.3g2 3GPP2 audio/video container video/3gpp2
.7z 7-zip archive application/x-7z-compressed

 
MIME 미디어 유형의 공식 레지스트리를 살펴보니 엑셀 형식중 xlsx는 Content-Type을 application/vnd.openxmlformats-officedocument.spreadsheetml.sheet으로 변경해야 했다.
그러나 실제로 적용을 하고 다운로드를 해봤지만 형식이 잘못 되었다는 메시지와 함께 파일이 올바르게 열리지 않았다.
그래서 나는 javascript로 html을 xlsx로 변환하는 방법을 찾아보게 되었다.
 

SheetJS를 이용한 HTML을 EXCEL 파일로 변환하는 방법

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Html Table to Excel xlsx</title>
    <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.14.3/xlsx.full.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.8/FileSaver.min.js"></script>
    <script>
        function s2ab(s) {
            var buf = new ArrayBuffer(s.length); //convert s to arrayBuffer
            var view = new Uint8Array(buf);  //create uint8array as viewer
            for (var i=0; i<s.length; i++) view[i] = s.charCodeAt(i) & 0xFF; //convert to octet
            return buf;
        }
        function exportExcel(){
            var wb = XLSX.utils.book_new();

            var newWorksheet = excelHandler.getWorksheet();

            XLSX.utils.book_append_sheet(wb, newWorksheet, excelHandler.getSheetName());

            var wbout = XLSX.write(wb, {bookType:'xlsx',  type: 'binary'});

            saveAs(new Blob([s2ab(wbout)],{type:"application/octet-stream"}), excelHandler.getExcelFileName());
        }
        $(document).ready(function() {
            $("#excelFileExport").click(function(){
                exportExcel();
            });
        });
    </script>
    <script>
        var excelHandler = {
            getExcelFileName : function(){
                return 'excel_download.xlsx';
            },
            getSheetName : function(){
                return 'Html Table to Excel';
            },
            getExcelData : function(){
                return document.getElementById('tableData');
            },
            getWorksheet : function(){
                return XLSX.utils.table_to_sheet(this.getExcelData());
            }
        }
    </script>
</head>
<body>
<input type="button" id="excelFileExport" value="엑셀 다운로드" />
<table id="tableData" border="1" >
    <thead>
    <tr>
        <th style="text-align: center; width: 200px;">이름</th>
        <th style="text-align: center; width: 200px;">국어</th>
        <th style="text-align: center; width: 200px;">영어</th>
        <th style="text-align: center; width: 200px;">합계</th>
    </tr>
    </thead>
    <tbody>
    <tr>
        <td style="text-align: right">철수</td>
        <td style="text-align: right">90</td>
        <td style="text-align: right">80</td>
        <td style="text-align: right"><b>170</b></td>
    </tr>
    <tr>
        <td style="text-align: right">영이</td>
        <td style="text-align: right">50</td>
        <td style="text-align: right">40</td>
        <td style="text-align: right"><b>90</b></td>
    </tr>
    <tr>
        <td style="text-align: right">희철</td>
        <td style="text-align: right">100</td>
        <td style="text-align: right">40</td>
        <td style="text-align: right"><b>140</b></td>
    </tr>
    </tbody>
</table>
</body>
</html>

SheetJs는 복잡한 스프레드 시트에서 데이터를 추출해  최신 소프트웨어에서 모두 작동하게끔 도와주는 오픈 소스이다.


먼저 html table을 만든 후에 id값을 주고 다운로드 버튼을 누르면 테이블의 셀값을 읽어서 blob형식으로 파일저장을 한다.
셀마다 스타일링을 하고 싶어 옵션을 찾아봤는데 프로 버전을 사용해야 셀에 스타일링을 주거나 성능향상이 가능하다고 하니 이점은 참고 하기 바란다.
 

 

참고한 글

https://eblo.tistory.com/84
https://git.sheetjs.com/SheetJS/sheetjs