
[SPRING/Mybatis] POI를 이용한 대용량 데이터 추출 (엑셀 다운) -1
오랜만에 티스토리에 개발관련 기록을 남기는 것같다. 디비의 값을 엑셀로 다운로드을 수 있도록 해달라는 요청이 있었다. (요즘은 Android를 파는 중이지만...) 요청은 하나의 대상 테이블에 대한
kyome.tistory.com
이전 게시글에 이어서,
이제 ResultHandler 를 작성한다.
0. ResultHandler (ExcelHandler.java)
ResultHandler는 handleResult라는 메서드를
Override 하기만 하면 쉽게 사용할 수 있다.
handleResult는 데이터가 들어오는대로
건마다 호출되는 걸로 보인다.
1. 변수 및 생성자 선언
ResultHandler는 Generic으로 선언할 수 있고
내가 만들 ExcelHandler는 Map으로 받아져야하기 때문에
Generic 변수 T는 Map을 상속받는 변수야한다는 조건을 걸었다.
ResultHandler를 통해 다운로드를 받을 수 있도록 할 계획이기 때문에
생성자로 Response를 받으며 파일명이나
컬럼 순서를 받을 수 있도록 생성자를 추가했다.
import ... public class ExcelHandler<T extends Map<String,Object>> implements ResultHandler<T> { public static final Logger LOGGER = LoggerFactory.getLogger(ExcelHandler.class); private T result; private String title; private String filename; private SXSSFWorkbook workbook; private SXSSFSheet sheet; private HttpServletResponse response; private ResultContext<? extends T> context; private List<String> columnTitleList; private int rownum; final int TITLE = 0; final int BODY = 1; private ExcelHandler() { super(); rownum = 0; } public ExcelHandler(HttpServletResponse response, String filename) { this(); this.response = response; this.title = filename; try { this.filename = URLEncoder.encode(filename.replace(" ", "_"),"UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); }; workbook = new SXSSFWorkbook(10000); sheet = workbook.createSheet(title); } public ExcelHandler(HttpServletResponse response, String filename,List<String> orderedColumnTitleList) { this(response,filename); this.columnTitleList = orderedColumnTitleList; } ...
2. 엑셀에 쓰기 메서드 구현
DB 에서 조회한 결과의 Column이 몇 개이고 이름이 무엇이든 상관없이
독립적으로 실행이 되어야 재사용이 가능해지기 때문에
엑셀에 입력하는 기능에만 집중했고
나머지는 파라미터로 받도록 했다.
private void write(int type,int currentRow,CellStyle style) { if (columnTitleList == null) { columnTitleList = new ArrayList<String>(context.getResultObject().keySet()); } SXSSFRow row = sheet.createRow(currentRow); if(columnTitleList.size() == 0 ) { return; } for(int i = 0 ; i < columnTitleList.size() ; i++) { SXSSFCell cell = row.createCell(i); String tempValue = ""; switch (type) { case TITLE: tempValue = columnTitleList.get(i); break; case BODY: if(context.getResultObject().containsKey(columnTitleList.get(i))) { tempValue = context.getResultObject().get(columnTitleList.get(i)).toString(); } break; } // 스타일 객체가 없다면 기본으로 if(style != null) { cell.setCellStyle(style); } cell.setCellValue(tempValue); } }
3. handleResult Override
데이터가(한개의 행이) 호출 될 때마다 workbook에 입력해주고
현재의 행을 나타내는 변수를 ++ 해준다.
헤더전용 CellStyle 과 내용전용 CellStyle을
미리 선언해두어서 write에 마지막 파라미터로 넣어주면
필요에 따라 셀스타일을 변경하면서 입력할 수도 있다.
... @Override public void handleResult(ResultContext<? extends T> resultContext) { if(resultContext.getResultObject() == null) { return; } this.context = resultContext; result = context.getResultObject(); Font headerFont = workbook.createFont(); headerFont.setFontName("맑은 고딕"); headerFont.setBold(true); CellStyle headerStyle = workbook.createCellStyle(); headerStyle.setBorderTop(BorderStyle.THIN); headerStyle.setBorderBottom(BorderStyle.THIN); headerStyle.setBorderLeft(BorderStyle.THIN); headerStyle.setBorderRight(BorderStyle.THIN); headerStyle.setAlignment(HorizontalAlignment.CENTER); headerStyle.setVerticalAlignment(VerticalAlignment.CENTER); headerStyle.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex()); headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); headerStyle.setFont(headerFont); Font bodyFont = workbook.createFont(); bodyFont.setFontName("맑은 고딕"); CellStyle bodyStyle= workbook.createCellStyle(); bodyStyle.setBorderTop(BorderStyle.THIN); bodyStyle.setBorderBottom(BorderStyle.THIN); bodyStyle.setBorderLeft(BorderStyle.THIN); bodyStyle.setBorderRight(BorderStyle.THIN); bodyStyle.setAlignment(HorizontalAlignment.LEFT); bodyStyle.setFont(bodyFont); if(rownum == 0 ) { write(TITLE, rownum,headerStyle); write(BODY, rownum+1,bodyStyle); }else { write(BODY, rownum+1,bodyStyle); } rownum++; } ...
4. 엑셀 다운로드
생성자로 Response 객체를 받는 이유는 여기에 있다.
Response 객체의 헤더에 첨부파일을 넣어서
OutStream으로 파일을 내보낸다.
파일 처리는 항상 그렇듯 예외처리를 성실하게 해줘야하고
종료시에 close 를 호출해줘야한다.
... public void download() throws IOException{ LOGGER.debug("## start excel download : "+filename); response.setHeader("Content-Disposition", "attachment; filename=" + filename.replaceAll(" ", "_") + ".xlsx;"); response.setCharacterEncoding(Constants.ENCODING); ServletOutputStream stream = response.getOutputStream(); OutputStream out = new BufferedOutputStream(stream); try { response.resetBuffer(); response.setBufferSize(1024 * 4); workbook.write(out); } catch (Exception e) { out.flush(); out.close(); stream.close(); } finally { out.flush(); out.close(); stream.close(); } if (workbook != null) { try { workbook.dispose(); } catch (Exception e) { workbook.close(); } finally { workbook.close(); } } workbook.close(); } public void close() { workbook.dispose(); try { workbook.close(); } catch (IOException e) { e.printStackTrace(); } } ...
도움이 되었다면
로그인이 필요 없는 공감 버튼 꾹 눌러주세요!
'Web 개발 > Java Web' 카테고리의 다른 글
[SPRING/Mybatis] POI를 이용한 대용량 데이터 추출 (엑셀 다운) -1 (0) | 2020.07.08 |
---|---|
문자열을 날짜로 변환하기 (String to Date) (0) | 2019.08.21 |
[log4j] 설정 및 사용방법 (0) | 2019.06.13 |
[log4j ] Log4j 구조 (0) | 2019.06.12 |
[log4j ] Log4j 란 (0) | 2019.06.11 |