Spring-JSP

[Spring-JSP] 엄청쉬운 Apache Poi 데이터 Excel 다운로드 기능구현

Jeong Jeon
반응형

오늘은 저장된 데이터를 엑셀 다운로드 하는 기능을 공통화시켜서 사용할 수 있도록 만들어 놓은것을 정리 해놓으려고 한다.

 

1). JSP 

공통되게 사용할 수 있도록 정리한것이기 때문에 JSP단에서 부터 시작된다.

각각 JSP에서 사용할 메소드명과 컬럼명을 준비해놓는게 키포인트

<tr id="excelHeaderInfo" orderName="selectTestList" searchFormId="frm" saveFileName="TEST현황">
	<!-- 다운로드-->
	<th class="excel-cell" keyParam="ROWNUM" valueParam="번호">번호</th>
	<th class="excel-cell" keyParam="COMPANY_NAME" valueParam="회사명">회사명</th>
	<th class="excel-cell" keyParam="ACCOUNT_NAME" valueParam="이름">이름</th>
	<th class="excel-cell" keyParam="ADDRESS" valueParam="주소">주소</th>
	<th class="excel-cell" keyParam="PHONE" valueParam="번호">번호</th>
	<th class="excel-cell" keyParam="AGE" valueParam="나이">나이</th>
</tr>

 

2). Js

설정한 정보들을 가져온다.

여기서 엑셀의 헤더(컬럼)을 잘 정리해주자~

 

추가로 엑셀 다운로드에 필요한 form을 만들어서 붙여주고 submit을 날렸다.

function excelDownLoad(){
	$("#_excelForm").remove();
	var mapperName = $("#excelHeaderInfo").attr("mapperName");
	var searchFormId = $("#excelHeaderInfo").attr("searchFormId");
	var saveFileName = $("#excelHeaderInfo").attr("saveFileName");

	var searchInfoObjectList = $("form[name=" + searchFormId + "]").serializeArray();
	var headerInfoObjectList = new Array();
	var searchInfoObject = {};

	if(searchInfoObjectList){
		$(searchInfoObjectList).each(function() {
			searchInfoObject[this.name] = this.value;
		});
	}

	$("#excelHeaderInfo").children(".excel-cell").each(function(index){
		var keyParam = $(this).attr("keyParam");
		var valueParam = $(this).attr("valueParam");

		var obj = {
			"index"	: index + ""
			,"keyParam" : keyParam
			,"valueParam" : valueParam
		}
		headerInfoObjectList.push(obj);
	});

	var param = {
		"mapperName" : mapperName
		,"searchInfoObject" : JSON.stringify(searchInfoObject)
		,"headerInfoObjectList" : JSON.stringify(headerInfoObjectList)
		,"saveFileName" : saveFileName
	}
	html = '';
	html +='<form id="_excelForm" method="POST" action="/excel/excelDownload">';
	html +='	<input type="hidden" name="mapperName" value='+param.mapperName+'>';
	html +='	<input type="hidden" name="searchInfoObject" value=\''+param.searchInfoObject+'\'>';
	html +='	<input type="hidden" name="headerInfoObjectList" value=\''+param.headerInfoObjectList+'\'>';
	html +='	<input type="hidden" name="saveFileName" value='+param.saveFileName+'>';
	html +='</form>';
	$("body").append(html);
	$("#_excelForm").submit();
	if(typeof callback === "function"){
		callback();
	}
}

 

3). Controller

@RequestMapping(value = "/excel/excelDownload")
	public void excelDownLoad(HttpServletRequest req, HttpServletResponse response,Locale locale) throws Exception {
		excelService.downloadExcelData(req,response,locale);
	}

 

4). service

 

	@Override
	public void downloadExcelData(HttpServletRequest req, HttpServletResponse res,
			Locale locale) throws Exception {
		// TODO Auto-generated method stub
		String mapperName,searchInfoObject,headerInfoObjectList,saveFileName = null;
        
        //필수 조건 Check
		if(StringUtils.isEmpty(req.getParameter("mapperName")) || StringUtils.isEmpty(req.getParameter("searchInfoObject")) || StringUtils.isEmpty(req.getParameter("headerInfoObjectList")) || StringUtils.isEmpty(req.getParameter("saveFileName"))) {
			throw new MyBusinessException("",Constant.ERROR_500);
		}
        
		//dao 메소드
		mapperName = req.getParameter("mapperName");
		//검색폼 데이터
		searchInfoObject = req.getParameter("searchInfoObject");
		//엑셀 정보 리스트
		headerInfoObjectList = req.getParameter("headerInfoObjectList");
		//저장할 파일명
		saveFileName = req.getParameter("saveFileName");

		HashMap<String,Object> paramMap = new HashMap<String,Object>();
		Gson gson = new Gson();

		HashMap<String,Object> searchInfoObjectMap = gson.fromJson(searchInfoObject, new TypeToken<HashMap<String,Object>>(){}.getType());

		for ( String key : searchInfoObjectMap.keySet() ) {
			paramMap.put(key, searchInfoObjectMap.get(key));
		}

		//출력 범위 설정
		int start = (Integer.parseInt((String)paramMap.get("currPage")) - 1) * Integer.parseInt((String)paramMap.get("pageRow"));
		int end = Integer.parseInt((String)paramMap.get("pageRow"));

		paramMap.put("start", start);
		paramMap.put("end", end);

		if(!StringUtils.isEmpty(paramMap.get("endDate"))) {
			//비교 컬럼에 함수를 쓰지 않기위해 하루를 더함.
			paramMap.put("endDate",StringTool.getDateCalculate((String)paramMap.get("endDate"),"d",1));
		}

		
		ArrayList<HashMap<String,Object>> excelDataList = null;
		Method[] methodList = excelDao.getClass().getMethods();

		//invoke를 사용하여 실행하고자 하는 dao를 찾아 실행.
		endPoint : for(Method m : methodList) {
			if(m.getName().equals(mapperName)) {
				excelDataList = (ArrayList<HashMap<String, Object>>) m.invoke(excelDao, paramMap);
				break endPoint;
			}
		}

		ArrayList<HashMap<String,String>> headerInfoHashMapList = gson.fromJson(headerInfoObjectList, new TypeToken<ArrayList<HashMap<String,String>>>(){}.getType());

    	// 워크북 생성
		if(!StringUtils.isEmpty(headerInfoHashMapList)) {

			HashMap<String,String> keyCompareMap = new HashMap<String,String>();
			@SuppressWarnings("resource")
			SXSSFWorkbook wb = new SXSSFWorkbook();
		    SXSSFSheet sheet = wb.createSheet(saveFileName);

			Row row = null;
			Cell cell = null;
			int rowNo = 0;
			
            // 테이블 헤더용 스타일
			CellStyle headStyle = wb.createCellStyle();
			// 가는 경계선
			headStyle.setBorderTop(BorderStyle.MEDIUM);
			headStyle.setBorderBottom(BorderStyle.MEDIUM);
			headStyle.setBorderLeft(BorderStyle.MEDIUM);
			headStyle.setBorderRight(BorderStyle.MEDIUM);
			// 데이터는 가운데 정렬
			headStyle.setAlignment(HorizontalAlignment.CENTER);
            
			// 헤더 생성
			row = sheet.createRow(rowNo++);
			for(HashMap<String, String> headerMap :  headerInfoHashMapList) {
				cell = row.createCell(Integer.parseInt(headerMap.get("index")));
				cell.setCellStyle(headStyle);
				cell.setCellValue(headerMap.get("valueParam"));
				keyCompareMap.put(headerMap.get("keyParam"), headerMap.get("index"));
			}

			// 기본 셀 넓이 지정
			for (int x = 0; x < sheet.getRow(0).getPhysicalNumberOfCells(); x++) {
	            sheet.setColumnWidth(x, 20*256);
	        }

			// 데이터용 경계 스타일 테두리만 지정
			CellStyle bodyStyle = wb.createCellStyle();
			bodyStyle.setBorderTop(BorderStyle.THIN);
			bodyStyle.setBorderBottom(BorderStyle.THIN);
			bodyStyle.setBorderLeft(BorderStyle.THIN);
			bodyStyle.setBorderRight(BorderStyle.THIN);
			bodyStyle.setAlignment(HorizontalAlignment.CENTER);
			
            //엑셀화면에 뿌려질 데이터
			if(!StringUtils.isEmpty(excelDataList)) {
				for(int i = 0; i < excelDataList.size(); i++) {
					row = sheet.createRow(rowNo++);

					HashMap<String,Object> dataMap = excelDataList.get(i);
					Set<String> set = dataMap.keySet();
					Iterator<String> iterator = set.iterator();
					while(iterator.hasNext()){
						String key = iterator.next();
						if(!StringUtils.isEmpty(keyCompareMap.get(key))) {
							cell = row.createCell(Integer.parseInt(keyCompareMap.get(key)));
							cell.setCellStyle(bodyStyle);
							cell.setCellValue(dataMap.get(key) == null? "" : dataMap.get(key).toString());
						}
					}
				}
			}

			// 컨텐츠 타입과 파일명 지정
			res.setHeader("Set-Cookie", "fileDownload=true; path=/");
			res.setHeader("Content-Disposition", String.format("attachment; filename=\""+new String((saveFileName).getBytes("KSC5601"),"8859_1")+".xlsx\""));
			wb.write(res.getOutputStream());
			wb.dispose();
		}
	}

 

 

추가 설명

=> Front단에서 엑셀 화면에 출력하고 싶은 컬럼들을 미리 설정해두고, Dao(메소드명)을 함께보내 해당 엑셀파일에 출력하고 싶은 데이터를 뽑아올 Dao를 실행시키는것이 키포인트

 

이로써 Controller 및 Service는 동일하게 사용할 수 있는것이 장점이다.

다른 데이터를 엑셀로 다운로드 할때면 간단하게 JSP만 변경해서 사용하면 된다.

 

 

오늘도 화이팅!

반응형