이전 게시글에 이어서,
이제 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 |