ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • XMLHttpRequest로 excel(.xlsx) download하기 (로딩바)
    회사/사내개발 2020. 9. 4. 10:09

    고객사의 요청 : 엑셀 다운로드 하는동안에 로딩바가 보이게 해주세요

     

    POST로 SUBMIT은 힘들겠고, 화면에서 ajax로 엑셀 다운로드하는 방법을 찾아보았다.

    처음에는 누군가가 제공해놓은 라이브러리가 있더라. 이름하여 jquery.fileDownload.js

     

    해당 라이브러리는 누군가가 ajax로 blob으로 response받을 때 문제가 있다는 것을 감안하여 파일 다운로드의 편의성을 제공한 라이브러리이다. 공식 라이브러리는 아닌것 같고 그냥 개발 좀 하는 외국분이 올려놓은것 같다.

     

    먼저 jquery.fileDownload.js 를 사용하여 다운로드를 구현해보았다.

    http://johnculviner.com/jquery-file-download-plugin-for-ajax-like-feature-rich-file-downloads/

    	<form id="excelForm" action="/marketing/mpk_sale_excel">
    		<input type="hidden" id="hiddenBranchId" name="hiddenBranchId" th:value="${branchId}"/>
    		<input type="hidden" id="hiddenBranchNameKor" name="hiddenBranchNameKor" th:value="${branchNameKor}"/>
    		<input type="hidden" id="hiddenStartDate" name="hiddenStartDate" th:value="${startDate}"/>
    		<input type="hidden" id="hiddenEndDate" name="hiddenEndDate" th:value="${endDate}"/>
    	</form>

    html 코드

               $.fileDownload( $("#excelForm").prop('action'),{
                    httpMethod: "POST",
                    data: $("#excelForm").serialize(),
                    successCallback: function( url ){
                        $("#div_load_image").hide();
                    },
                    failCallback: function(responseHtml,excelUrl){
                        console.log( "에러콜백" )
                        $("#div_load_image").hide();
                        alert("오류가 발생하였습니다.");
                    }
                });

    javascript 코드

     

    wow 이건너무 간단한거 아닌가? 이렇게 적용하고 실행했더니 바로 된다..

    기뻐하면서 commit을 하려는데 ie에서 동작을 안하는것... 일이 잘풀린다 했다.

     

    라이브러리 소스분석도 해보고 하다가 복잡해서 그냥 다른 방법을 찾기로 했다.

    jquery ajax로 blob로 응답받아 파일 다운로드하기.

    검색하고 적용하고 하는데 파일은 다운로드 되나 파일이 깨져있거나 하는 문제들이 있다.

     

    마지막 방법 XMLHttpRequest로 호출하기!

                var excelUrl = "/marketing/mpk_sale_excel";
    
    			var request = new XMLHttpRequest();
                request.open('POST', excelUrl, true);
                request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
                request.responseType = 'blob';
    
                request.onload = function(e) {
    
                    $("#div_load_image").hide();
    
                    var filename = "";
                    var disposition = request.getResponseHeader('Content-Disposition');
                    if (disposition && disposition.indexOf('attachment') !== -1) {
                        var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
                        var matches = filenameRegex.exec(disposition);
                        if (matches != null && matches[1])
                            filename = decodeURI( matches[1].replace(/['"]/g, '') );
                    }
                    console.log("FILENAME: " + filename);
    
                    if (this.status === 200) {
                        var blob = this.response;
                        if(window.navigator.msSaveOrOpenBlob) {
                            window.navigator.msSaveBlob(blob, filename);
                        }
                        else{
                            var downloadLink = window.document.createElement('a');
                            var contentTypeHeader = request.getResponseHeader("Content-Type");
                            downloadLink.href = window.URL.createObjectURL(new Blob([blob], { type: contentTypeHeader }));
                            downloadLink.download = filename;
                            document.body.appendChild(downloadLink);
                            downloadLink.click();
                            document.body.removeChild(downloadLink);
                        }
                    }
                };
    
                var hiddenBranchId = $( "#hiddenBranchId" ).val();
                var hiddenBranchNameKor = $( "#hiddenBranchNameKor" ).val();
                var hiddenStartDate = $( "#hiddenStartDate" ).val();
                var hiddenEndDate = $( "#hiddenEndDate" ).val();
                var params = 'hiddenBranchId=' + hiddenBranchId + '&hiddenBranchNameKor=' + hiddenBranchNameKor +
                    '&hiddenStartDate=' + hiddenStartDate + '&hiddenEndDate=' + hiddenEndDate;
                request.send( params);

    된다.. 잘 다운로드 되고 파일이 깨지지도 않는다.. 그리고 ie에서도 아주 잘된다!!!

     

     

    서버단 소스

    @Override
    	public Map<String, String> getViSMSaleInfoExcel(HttpServletResponse response, String startDate, String endDate, String branchId, String branchNameKor, String userId) {        
            
            FileOutputStream fos = null;
            SXSSFWorkbook workbook = null;
            SXSSFRow row = null;							// 행
    		SXSSFCell cell = null;							// 셀
    		CellStyle styleMoneyFormat = null;				// 샐 스타일
            
            
            
            try {
            
    			// ... dao 호출하여 데이터 가져오는 소스 ...
    
    			// 워크북 생성
    			workbook = new SXSSFWorkbook();
    			workbook.setCompressTempFiles(true);
    
    			// SXSSFSheet 생성
    			SXSSFSheet sheet = (SXSSFSheet) workbook.createSheet("판매속보");
    			sheet.setRandomAccessWindowSize(100); // 메모리 행 100개로 제한, 초과 시 Disk로 flush
                
                
                //... 엑셀 내용 작성 ...
    
                
                        
            
                String filename = "test";
    
                response.reset();
    
                response.setContentType( "application/vnd.ms-excel" );
                //response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
                response.addHeader("Content-Disposition","attachment;filename=\"" + URLEncoder.encode(filename, "UTF-8") + ".xlsx\"");
    
                log.debug( "출력 -------------" + filename );
                workbook.write(response.getOutputStream());
                response.getOutputStream().flush();
            
           } catch (Exception e) {
    			e.printStackTrace();
    			if(fos != null) try { fos.close(); } catch(Exception ignore) {}
    		} finally {
    			try {
    				//response.getOutputStream().close();
    				workbook.close();
    				workbook.dispose();
    				if(fos != null) try { fos.close(); } catch(Exception ignore) {}
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
            
    
            
            
    }

    대용량 엑셀파일이라 xlsx로 작업했다.

    검색했을 때 xlsx는 contentType을 application/vnd.openxmlformats-officedocument.spreadsheetml.sheet 이걸로 해야한다했는데 그냥 일반 엑셀파일에 대한 contentType인 application/vnd.ms-excel 로해도 따로 문제없었다.

    삽질끝

     

Designed by Tistory.