package kr.wisestone.owl.web.view; import java.beans.PropertyDescriptor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.List; import java.util.Map; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import kr.wisestone.owl.annotation.Viewer; import kr.wisestone.owl.common.MessageAccessor; import kr.wisestone.owl.constant.Constants; import kr.wisestone.owl.util.CommonUtil; import kr.wisestone.owl.vo.*; import org.slf4j.LoggerFactory; import org.slf4j.Logger; import org.apache.poi.hssf.util.HSSFColor; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.xssf.usermodel.*; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; @Viewer public class ExcelView extends AbstractExcelView { private static final Logger log = LoggerFactory.getLogger(ExcelView.class); public static final Integer EXCEL_EXPORT_MAX_COUNT = 65000; @Autowired protected MessageAccessor messageAccessor; @SuppressWarnings({"unused", "unchecked"}) @Override protected void buildExcelDocument(Map model, XSSFWorkbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception { XSSFSheet sheet; XSSFRow mergeRow = null; XSSFRow mergeRow2 = null; XSSFRow sheetRow = null; XSSFRow sheetRow2 = null; ExportExcelVo excelInfo = (ExportExcelVo) model.get(Constants.EXCEL); String localeFileName = this.findLocaleToText(excelInfo.getFileName()); response.setContentType("application/vnd.ms-excel; charset=UTF-8"); response.setCharacterEncoding("UTF-8"); response.setHeader("Content-Disposition", "attachment; filename=" + CommonUtil.getDisposition(localeFileName, CommonUtil.getBrowser(request)) + ".xlsx"); // 총 데이터양을 뽑아 낸다. int totalCount = excelInfo.getDatas().size(); // 시트 생성 sheet = workbook.createSheet(excelInfo.getFileName()); int currentRowNum = 0; // 셀 스타일을 설정한다. XSSFCellStyle sheetTitleCellStyle = this.makeSheetTitleStyle(workbook); XSSFCellStyle gridPageCellStyle = this.makeGridPageStyle(workbook); XSSFCellStyle gridHeaderCellStyle = this.makeGridHeaderStyle(workbook); Boolean merge = Boolean.FALSE; // merge 여부 확인 int colIndex = 0; for (ExportExcelAttrVo attrInfo : excelInfo.getAttrInfos()) { if (attrInfo.getMergeCount() == 1) { merge = true; //셀 병합 if (totalCount >= 2) { totalCount = totalCount/ 2; int rowNum3 = 3 + totalCount + (totalCount - 2); for (int rowNum1 = 3; rowNum1 <= rowNum3; rowNum1 += 2) { int rowNum2 = rowNum1 + 1; sheet.addMergedRegion(new CellRangeAddress(rowNum1, rowNum2, 0, 0)); } } } sheet.setColumnWidth(colIndex++, (attrInfo.getWidth() + 1) * 2 * 256); attrInfo.setCellStyle(this.makeCellStyle(workbook, this.makeFont(workbook, XSSFFont.BOLDWEIGHT_NORMAL), attrInfo.getAlign(), XSSFCellStyle.VERTICAL_CENTER, XSSFCellStyle.BORDER_THIN)); } int size = excelInfo.getDatas().size(); // merge 를 사용할 경우 if (merge) { size = excelInfo.getDatas().size() / 2; } this.writeSheetTitle(sheet, sheetTitleCellStyle, currentRowNum++, localeFileName, excelInfo.getAttrInfos() .size() - 1, (short) 1024); // 건수 표시 제어 if (!excelInfo.getHideCount()) { this.writeGridPage(sheet, gridPageCellStyle, currentRowNum++, size, excelInfo .getAttrInfos().size() - 1); } this.writeGridHeader(sheet, gridHeaderCellStyle, currentRowNum++, excelInfo.getAttrInfos()); for (int index = 0; index < excelInfo.getDatas().size(); index++) { if (EXCEL_EXPORT_MAX_COUNT <= index) { break; } Object data = excelInfo.getDatas().get(index); XSSFRow row = sheet.createRow(currentRowNum++); int currentColNum = 0; for (ExportExcelAttrVo attrInfo : excelInfo.getAttrInfos()) { this.writeData(workbook, row, currentColNum++, data, attrInfo); } } ServletOutputStream out = null; try { out = response.getOutputStream(); workbook.write(out); } catch (Exception e) { } finally { if (out != null) { out.close(); } } } private XSSFCellStyle makeSheetTitleStyle(XSSFWorkbook workbook) { XSSFFont font = this.makeFont(workbook, XSSFFont.BOLDWEIGHT_BOLD, (short) 20); XSSFCellStyle cellStyle = this.makeCellStyle(workbook, font, XSSFCellStyle.ALIGN_CENTER, XSSFCellStyle.VERTICAL_CENTER, XSSFCellStyle.BORDER_NONE); return cellStyle; } private XSSFCellStyle makeGridPageStyle(XSSFWorkbook workbook) { XSSFFont font = this.makeFont(workbook, XSSFFont.BOLDWEIGHT_BOLD); XSSFCellStyle cellStyle = this.makeCellStyle(workbook, font, XSSFCellStyle.ALIGN_RIGHT, XSSFCellStyle.VERTICAL_CENTER, XSSFCellStyle.BORDER_NONE); return cellStyle; } private XSSFCellStyle makeGridHeaderStyle(XSSFWorkbook workbook) { XSSFFont font = this.makeFont(workbook, XSSFFont.BOLDWEIGHT_BOLD); XSSFCellStyle cellStyle = this.makeCellStyle(workbook, font, XSSFCellStyle.ALIGN_CENTER, XSSFCellStyle.VERTICAL_CENTER, XSSFCellStyle.BORDER_THIN); // 셀에 색깔 채우기 cellStyle.setFillForegroundColor(new HSSFColor.GREY_25_PERCENT().getIndex()); cellStyle.setFillPattern(XSSFCellStyle.SOLID_FOREGROUND); return cellStyle; } private XSSFCellStyle makeCellStyle(XSSFWorkbook workbook, XSSFFont font, short hAlign, short vAlign, short border) { XSSFCellStyle cellStyle = workbook.createCellStyle(); cellStyle.setFont(font); cellStyle.setAlignment(hAlign); cellStyle.setVerticalAlignment(vAlign); cellStyle.setBorderTop(border); cellStyle.setBorderLeft(border); cellStyle.setBorderBottom(border); cellStyle.setBorderRight(border); cellStyle.setWrapText(true); return cellStyle; } private XSSFFont makeFont(XSSFWorkbook workbook) { XSSFFont font = workbook.createFont(); font.setFontName("맑은 고딕"); font.setBoldweight(XSSFFont.BOLDWEIGHT_NORMAL); font.setColor(HSSFColor.BLACK.index); return font; } private XSSFFont makeFont(XSSFWorkbook workbook, short bold) { XSSFFont font = workbook.createFont(); font.setFontName("맑은 고딕"); font.setBoldweight(bold); font.setColor(HSSFColor.BLACK.index); return font; } private XSSFFont makeFont(XSSFWorkbook workbook, short bold, short size) { XSSFFont font = workbook.createFont(); font.setFontName("맑은 고딕"); font.setBoldweight(bold); font.setColor(HSSFColor.BLACK.index); font.setFontHeightInPoints(size); return font; } @SuppressWarnings("unchecked") private void writeData(XSSFWorkbook workbook, XSSFRow row, int colnum, Object data, ExportExcelAttrVo attrInfo) { XSSFCell cell = row.createCell(colnum); cell.setCellStyle(attrInfo.getCellStyle()); String cellValue = ""; if (this.getAttrValue(data, attrInfo.getName()) != null) { if (attrInfo.getI18Prefix() != null) { if (this.getAttrValue(data, attrInfo.getName()) instanceof List) { StringBuffer sb = new StringBuffer(""); List values = (List) this.getAttrValue(data, attrInfo.getName()); int idx = 0; for (String value : values) { if (idx != 0) { sb.append("\n"); } sb.append(this.messageAccessor.message(attrInfo.getI18Prefix() + value)); idx++; } cellValue = sb.toString(); } else { cellValue = this.messageAccessor.message(attrInfo.getI18Prefix() + this.getAttrValue(data, attrInfo.getName()).toString()); } } else { if (this.getAttrValue(data, attrInfo.getName()) instanceof List) { StringBuffer sb = new StringBuffer(""); List values = (List) this.getAttrValue(data, attrInfo.getName()); int idx = 0; for (Object value : values) { if (idx != 0) { sb.append("\n"); } if (value instanceof BaseVo) { sb.append(this.getAttrValue(value, attrInfo.getVoAttrName())); } else { sb.append(value); } idx++; } cellValue = sb.toString(); } else { cellValue = this.getAttrValue(data, attrInfo.getName()).toString(); } } } if (attrInfo.getReplaceWithNewlineYn()) { cellValue = CommonUtil.replaceBrWithNewline(cellValue); } cell.setCellValue(cellValue); } private void writeGridHeader(XSSFSheet sheet, XSSFCellStyle cellStyle, int rownum, List attrInfos) { XSSFRow row = sheet.createRow(rownum); int colnum = 0; for (ExportExcelAttrVo attrInfo : attrInfos) { XSSFCell cell = row.createCell(colnum++); cell.setCellStyle(cellStyle); cell.setCellValue(attrInfo.getDesc()); } } private void writeSheetTitle(XSSFSheet sheet, XSSFCellStyle cellStyle, int rownum, String title, int mergeCount, short height) { XSSFRow row = sheet.createRow(rownum); row.setHeight(height); XSSFCell cell = row.createCell(0); cell.setCellStyle(cellStyle); cell.setCellValue(title); sheet.addMergedRegion(new CellRangeAddress(rownum, rownum, 0, mergeCount)); } private void writeGridPage(XSSFSheet sheet, XSSFCellStyle cellStyle, int rownum, int size, int mergeCount) { XSSFRow row = sheet.createRow(rownum); XSSFCell cell = row.createCell(0); cell.setCellStyle(cellStyle); cell.setCellValue(size + this.messageAccessor.message("common.few")); // 건수 sheet.addMergedRegion(new CellRangeAddress(rownum, rownum, 0, mergeCount)); } /** * 총 건수를 다국어 메세지로 전환한다. * * @param string */ private String findLocaleToText(String string) { MessageVo message = this.messageAccessor.getMessage(string); return message.getMessage(); } /** * 오브젝트로 부터 attr 속성의 값을 반환한다. * * @param data * @param attr * @return * @throws IllegalAccessException * @throws InvocationTargetException */ private Object getAttrValue(Object data, String attr) { Object value = null; if (data instanceof Map) { value = ((Map) data).get(attr); } else { PropertyDescriptor descriptor = BeanUtils.getPropertyDescriptor(data.getClass(), attr); Method method = descriptor.getReadMethod(); try { value = method.invoke(data, null); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { value = ""; } } return value; } }