2025-12-17 07:34:15 +00:00
|
|
|
|
package geoinfo.util;
|
|
|
|
|
|
|
2026-02-20 00:18:09 +00:00
|
|
|
|
import java.io.ByteArrayOutputStream;
|
2025-12-17 07:34:15 +00:00
|
|
|
|
import java.io.IOException;
|
|
|
|
|
|
import java.io.PrintWriter;
|
|
|
|
|
|
import java.net.URLEncoder;
|
|
|
|
|
|
import java.time.LocalDate;
|
|
|
|
|
|
import java.time.LocalDateTime;
|
|
|
|
|
|
import java.time.format.DateTimeFormatter;
|
|
|
|
|
|
import java.util.Date;
|
|
|
|
|
|
import java.util.List;
|
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
|
|
|
|
|
|
|
import javax.servlet.http.HttpServletRequest;
|
|
|
|
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
|
|
|
|
|
|
|
|
|
import org.apache.poi.ss.usermodel.BorderStyle;
|
|
|
|
|
|
import org.apache.poi.ss.usermodel.Cell;
|
|
|
|
|
|
import org.apache.poi.ss.usermodel.CellStyle;
|
|
|
|
|
|
import org.apache.poi.ss.usermodel.FillPatternType;
|
2025-12-29 07:54:20 +00:00
|
|
|
|
import org.apache.poi.ss.usermodel.Font;
|
2025-12-17 07:34:15 +00:00
|
|
|
|
import org.apache.poi.ss.usermodel.HorizontalAlignment;
|
|
|
|
|
|
import org.apache.poi.ss.usermodel.IndexedColors;
|
|
|
|
|
|
import org.apache.poi.ss.usermodel.Row;
|
|
|
|
|
|
import org.apache.poi.ss.usermodel.Sheet;
|
|
|
|
|
|
import org.apache.poi.ss.usermodel.VerticalAlignment;
|
|
|
|
|
|
import org.apache.poi.ss.util.CellRangeAddress;
|
|
|
|
|
|
import org.apache.poi.xssf.usermodel.XSSFDataFormat;
|
|
|
|
|
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
|
|
|
|
|
|
|
|
|
|
|
import egovframework.rte.psl.dataaccess.util.EgovMap;
|
|
|
|
|
|
|
|
|
|
|
|
public class ExcelMergeHeaderUtil {
|
|
|
|
|
|
|
2026-02-20 00:18:09 +00:00
|
|
|
|
public static boolean isEmpty(final Object obj) {
|
|
|
|
|
|
return !isNotEmpty(obj);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static boolean isNotEmpty(final Object obj) {
|
|
|
|
|
|
if (null == obj)
|
|
|
|
|
|
return false;
|
|
|
|
|
|
else {
|
|
|
|
|
|
if (obj instanceof String)
|
|
|
|
|
|
return "".equals(obj) ? false : true;
|
|
|
|
|
|
else if (obj instanceof List)
|
|
|
|
|
|
return !((List<?>) obj).isEmpty();
|
|
|
|
|
|
else if (obj instanceof Map)
|
|
|
|
|
|
return !((Map<?, ?>) obj).isEmpty();
|
|
|
|
|
|
// else if(obj instanceof Object[]) return 0 == Array.getLength(obj) ? false :
|
|
|
|
|
|
// true;
|
|
|
|
|
|
else if (obj instanceof Integer)
|
|
|
|
|
|
return !(null == obj);
|
|
|
|
|
|
else if (obj instanceof Long)
|
|
|
|
|
|
return !(null == obj);
|
|
|
|
|
|
else if (obj instanceof LocalDate)
|
|
|
|
|
|
return !(null == obj);
|
|
|
|
|
|
else
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static String getTimeStampString(final String format) {
|
|
|
|
|
|
return getTimeStampString(new Date(), format);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static String getTimeStampString(final Date date) {
|
|
|
|
|
|
return getTimeStampString(date, "yyyyMMddHHmmss");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static String getTimeStampString(final Date date, final String format) {
|
|
|
|
|
|
java.text.SimpleDateFormat formatter = new java.text.SimpleDateFormat(format, java.util.Locale.KOREA);
|
|
|
|
|
|
return formatter.format(date);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static String getTimeStampString(String date, final String format) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
if (null == date || "".equals(date))
|
|
|
|
|
|
return "";
|
|
|
|
|
|
|
|
|
|
|
|
Date d = null;
|
|
|
|
|
|
date = date.replaceAll("-", "");
|
|
|
|
|
|
|
|
|
|
|
|
switch (date.length()) {
|
|
|
|
|
|
case 14:
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 12:
|
|
|
|
|
|
date += "00";
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 10:
|
|
|
|
|
|
date += "0000";
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 8:
|
|
|
|
|
|
date += "000000";
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 6:
|
|
|
|
|
|
date += "01000000";
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 4:
|
|
|
|
|
|
date += "0101000000";
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
return "";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
java.text.SimpleDateFormat tmpFormat = new java.text.SimpleDateFormat("yyyyMMddHHmmss",
|
|
|
|
|
|
java.util.Locale.KOREA);
|
|
|
|
|
|
|
|
|
|
|
|
if ("".equals(date))
|
|
|
|
|
|
d = new Date();
|
|
|
|
|
|
else {
|
|
|
|
|
|
tmpFormat.setLenient(true);
|
|
|
|
|
|
d = tmpFormat.parse(date);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return getTimeStampString(d, format);
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
|
return "";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static String getFileExtention(final String filename) {
|
|
|
|
|
|
if (null == filename || "".equals(filename))
|
|
|
|
|
|
return "";
|
|
|
|
|
|
|
|
|
|
|
|
return -1 < filename.lastIndexOf(".") ? filename.substring(filename.lastIndexOf(".") + 1).toLowerCase() : "";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static String generationSaveName() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
Thread.sleep(100);
|
|
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
|
}
|
|
|
|
|
|
return ExcelMergeHeaderUtil.getTimeStampString("yyyyMMdd_HHmmss_SSS");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static void listToExcel(List<EgovMap> list, HttpServletResponse response, String[] headers,
|
|
|
|
|
|
String[] headerNames, String[] columnType, String sheetName, String excelFileName) throws IOException {
|
|
|
|
|
|
if (ExcelMergeHeaderUtil.isNotEmpty(list)) {
|
|
|
|
|
|
// 메모리에 100개의 행을 유지합니다. 행의 수가 넘으면 디스크에 적습니다.
|
|
|
|
|
|
XSSFWorkbook wb = new XSSFWorkbook();
|
|
|
|
|
|
Sheet sheet = wb.createSheet(sheetName);
|
|
|
|
|
|
Row headerRow = sheet.createRow(0);
|
|
|
|
|
|
CellStyle cellStyle1 = wb.createCellStyle(); // 쉼표들어간 숫자 양식
|
|
|
|
|
|
CellStyle cellStyle2 = wb.createCellStyle(); // 숫자양식
|
|
|
|
|
|
CellStyle headerStyle = wb.createCellStyle(); // 헤더 스타일
|
|
|
|
|
|
CellStyle borderStyle = wb.createCellStyle(); // 기본 검정 테두리 스타일
|
|
|
|
|
|
|
|
|
|
|
|
// 기본 검정 테두리 스타일 설정
|
|
|
|
|
|
borderStyle.setBorderTop(BorderStyle.THIN);
|
|
|
|
|
|
borderStyle.setBorderBottom(BorderStyle.THIN);
|
|
|
|
|
|
borderStyle.setBorderLeft(BorderStyle.THIN);
|
|
|
|
|
|
borderStyle.setBorderRight(BorderStyle.THIN);
|
|
|
|
|
|
|
|
|
|
|
|
// 글꼴 색상 흰색으로 설정
|
|
|
|
|
|
Font headerFont = wb.createFont();
|
|
|
|
|
|
headerFont.setColor(IndexedColors.WHITE.getIndex()); // 글씨 색상 흰색
|
|
|
|
|
|
headerStyle.setFont(headerFont); // 헤더 스타일에 적용
|
|
|
|
|
|
|
|
|
|
|
|
XSSFDataFormat format = wb.createDataFormat();
|
|
|
|
|
|
cellStyle1.setDataFormat(format.getFormat("#,##0"));
|
|
|
|
|
|
cellStyle2.setDataFormat(format.getFormat("#"));
|
|
|
|
|
|
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.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
|
|
|
|
|
headerStyle.setFillForegroundColor((short) 3);
|
|
|
|
|
|
headerStyle.setFillForegroundColor(IndexedColors.GREY_40_PERCENT.getIndex());
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < list.size(); i++) {
|
|
|
|
|
|
EgovMap rowData = list.get(i);
|
|
|
|
|
|
Row row = sheet.createRow(i + 1);
|
|
|
|
|
|
|
|
|
|
|
|
for (int j = 0; j < headers.length; j++) {
|
|
|
|
|
|
Cell cell = row.createCell(j);
|
|
|
|
|
|
|
|
|
|
|
|
Object value = rowData.get(headers[j]);
|
|
|
|
|
|
// Money 타입
|
|
|
|
|
|
if ("Money".equalsIgnoreCase(columnType[j])) {
|
|
|
|
|
|
if (value instanceof Number) {
|
|
|
|
|
|
cell.setCellValue(((Number) value).doubleValue());
|
|
|
|
|
|
} else {
|
|
|
|
|
|
cell.setCellValue(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
cell.setCellStyle(cellStyle1);
|
|
|
|
|
|
|
|
|
|
|
|
// Int 타입
|
|
|
|
|
|
} else if ("Int".equalsIgnoreCase(columnType[j])) {
|
|
|
|
|
|
if (value instanceof Number) {
|
|
|
|
|
|
cell.setCellValue(((Number) value).doubleValue());
|
|
|
|
|
|
} else {
|
|
|
|
|
|
cell.setCellValue(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
cell.setCellStyle(cellStyle2);
|
|
|
|
|
|
|
|
|
|
|
|
// String 타입
|
|
|
|
|
|
} else {
|
|
|
|
|
|
cell.setCellValue(value == null ? "" : String.valueOf(value));
|
|
|
|
|
|
}
|
|
|
|
|
|
// 검정 테두리 적용
|
|
|
|
|
|
cell.setCellStyle(borderStyle);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (int j = 0; j < headerNames.length; j++) {
|
|
|
|
|
|
Cell cell = headerRow.createCell(j);
|
|
|
|
|
|
cell.setCellValue(headerNames[j]);
|
|
|
|
|
|
cell.setCellStyle(headerStyle);
|
|
|
|
|
|
sheet.autoSizeColumn(j);
|
|
|
|
|
|
sheet.setColumnWidth(j, (sheet.getColumnWidth(j)) + 1000);
|
|
|
|
|
|
}
|
|
|
|
|
|
// 엑셀이름 한글깨짐방지
|
|
|
|
|
|
String outputFileName = new String(excelFileName.getBytes("KSC5601"), "8859_1");
|
|
|
|
|
|
|
|
|
|
|
|
response.setHeader("Set-Cookie", "fileDownload=true; path=/");
|
|
|
|
|
|
response.setHeader("Content-Disposition", String.format("attachment; filename=\"" + outputFileName + "_"
|
|
|
|
|
|
+ ExcelMergeHeaderUtil.getTimeStampString("yyyyMMdd_HHmm") + ".xlsx\""));
|
|
|
|
|
|
|
|
|
|
|
|
wb.write(response.getOutputStream());
|
|
|
|
|
|
wb.close();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
createNoDataAlert(response);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static void listToExcelMergeHeader(List<EgovMap> list, HttpServletResponse response, String[] headers,
|
|
|
|
|
|
String[][] headerNames, int[] headerWidths, String[] columnType, String sheetName, String excelFileName)
|
|
|
|
|
|
throws IOException {
|
|
|
|
|
|
if (ExcelMergeHeaderUtil.isNotEmpty(list)) {
|
|
|
|
|
|
// 메모리에 100개의 행을 유지합니다. 행의 수가 넘으면 디스크에 적습니다.
|
|
|
|
|
|
XSSFWorkbook wb = new XSSFWorkbook();
|
|
|
|
|
|
Sheet sheet = wb.createSheet(sheetName);
|
|
|
|
|
|
Row headerRow = sheet.createRow(headerNames.length);
|
|
|
|
|
|
CellStyle cellStyle1 = wb.createCellStyle(); // 쉼표들어간 숫자 양식
|
|
|
|
|
|
CellStyle cellStyle2 = wb.createCellStyle(); // 숫자양식
|
|
|
|
|
|
CellStyle headerStyle = wb.createCellStyle(); // 헤더 스타일
|
|
|
|
|
|
CellStyle borderStyle = wb.createCellStyle(); // 기본 검정 테두리 스타일
|
|
|
|
|
|
|
|
|
|
|
|
// 기본 검정 테두리 스타일 설정
|
|
|
|
|
|
borderStyle.setBorderTop(BorderStyle.THIN);
|
|
|
|
|
|
borderStyle.setBorderBottom(BorderStyle.THIN);
|
|
|
|
|
|
borderStyle.setBorderLeft(BorderStyle.THIN);
|
|
|
|
|
|
borderStyle.setBorderRight(BorderStyle.THIN);
|
|
|
|
|
|
|
|
|
|
|
|
// 글꼴 색상 흰색으로 설정
|
|
|
|
|
|
Font headerFont = wb.createFont();
|
|
|
|
|
|
headerFont.setColor(IndexedColors.WHITE.getIndex()); // 글씨 색상 흰색
|
|
|
|
|
|
headerStyle.setFont(headerFont); // 헤더 스타일에 적용
|
|
|
|
|
|
|
|
|
|
|
|
XSSFDataFormat format = wb.createDataFormat();
|
|
|
|
|
|
cellStyle1.setDataFormat(format.getFormat("#,##0"));
|
|
|
|
|
|
cellStyle2.setDataFormat(format.getFormat("#"));
|
|
|
|
|
|
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.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
|
|
|
|
|
// headerStyle.setFillForegroundColor((short)3);
|
|
|
|
|
|
headerStyle.setFillForegroundColor(IndexedColors.GREY_40_PERCENT.getIndex());
|
|
|
|
|
|
|
|
|
|
|
|
// 바디 스타일
|
|
|
|
|
|
CellStyle bodyStyle = wb.createCellStyle();
|
|
|
|
|
|
bodyStyle.setAlignment(HorizontalAlignment.CENTER);
|
|
|
|
|
|
// ---------- 헤더구성 ------------------------------------
|
|
|
|
|
|
Row hRow = null;
|
|
|
|
|
|
// rows
|
|
|
|
|
|
int rowCnt = 0;
|
|
|
|
|
|
|
|
|
|
|
|
// 헤더 셀 병합
|
|
|
|
|
|
// === 세로 병합 (단일 컬럼) ===
|
|
|
|
|
|
sheet.addMergedRegion(new CellRangeAddress(0, 1, 0, 0)); // 연번
|
|
|
|
|
|
sheet.addMergedRegion(new CellRangeAddress(0, 1, 1, 1)); // 사업명
|
|
|
|
|
|
sheet.addMergedRegion(new CellRangeAddress(0, 1, 2, 2)); // 입력상태
|
|
|
|
|
|
|
|
|
|
|
|
// === 가로 병합 (대분류) ===
|
|
|
|
|
|
sheet.addMergedRegion(new CellRangeAddress(0, 0, 3, 4)); // 사업내용
|
|
|
|
|
|
sheet.addMergedRegion(new CellRangeAddress(0, 0, 5, 8)); // 발주기관현황
|
|
|
|
|
|
sheet.addMergedRegion(new CellRangeAddress(0, 0, 9, 11)); // 건설사현황
|
|
|
|
|
|
|
|
|
|
|
|
// 헤더 정보 구성
|
|
|
|
|
|
for (int i = 0; i < headerNames.length; i++) {
|
|
|
|
|
|
hRow = sheet.createRow(rowCnt++);
|
|
|
|
|
|
for (int j = 0; j < headerNames[i].length; j++) {
|
|
|
|
|
|
Cell cell = headerRow.createCell(j);
|
|
|
|
|
|
cell = hRow.createCell(j);
|
|
|
|
|
|
cell.setCellStyle(headerStyle);
|
|
|
|
|
|
cell.setCellValue(headerNames[i][j]);
|
|
|
|
|
|
sheet.setColumnWidth(j, (sheet.getColumnWidth(j)) + 1000);
|
|
|
|
|
|
sheet.setColumnWidth(j, headerWidths[j]);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ---------- 헤더구성 끝------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < list.size(); i++) {
|
|
|
|
|
|
EgovMap rowData = list.get(i);
|
|
|
|
|
|
Row row = sheet.createRow(i + 2);
|
|
|
|
|
|
|
|
|
|
|
|
for (int j = 0; j < headers.length; j++) {
|
|
|
|
|
|
Cell cell = row.createCell(j);
|
|
|
|
|
|
|
|
|
|
|
|
// 특정 컬럼 중앙 정렬 -----참고용------------
|
|
|
|
|
|
// if ("lvl1_rate".equals(headers[j]) ||
|
|
|
|
|
|
// "lvl2_rate".equals(headers[j]) ||
|
|
|
|
|
|
// "lvl3_rate".equals(headers[j]) ||
|
|
|
|
|
|
// "lvl2_organ_up".equals(headers[j]) ||
|
|
|
|
|
|
// "lvl3_organ_up".equals(headers[j])) {
|
|
|
|
|
|
// cell.setCellStyle(bodyStyle);
|
|
|
|
|
|
// } -----참고용------------
|
|
|
|
|
|
|
|
|
|
|
|
Object value = rowData.get(headers[j]);
|
|
|
|
|
|
|
|
|
|
|
|
// Money 타입
|
|
|
|
|
|
if ("Money".equalsIgnoreCase(columnType[j])) {
|
|
|
|
|
|
if (value instanceof Number) {
|
|
|
|
|
|
cell.setCellValue(((Number) value).doubleValue());
|
|
|
|
|
|
} else {
|
|
|
|
|
|
cell.setCellValue(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
cell.setCellStyle(cellStyle1);
|
|
|
|
|
|
|
|
|
|
|
|
// Int 타입
|
|
|
|
|
|
} else if ("Int".equalsIgnoreCase(columnType[j])) {
|
|
|
|
|
|
if (value instanceof Number) {
|
|
|
|
|
|
cell.setCellValue(((Number) value).doubleValue());
|
|
|
|
|
|
} else {
|
|
|
|
|
|
cell.setCellValue(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
cell.setCellStyle(cellStyle2);
|
|
|
|
|
|
|
|
|
|
|
|
// String 타입
|
|
|
|
|
|
} else {
|
|
|
|
|
|
cell.setCellValue(value == null ? "" : String.valueOf(value));
|
|
|
|
|
|
}
|
|
|
|
|
|
// 검정 테두리 적용
|
|
|
|
|
|
cell.setCellStyle(borderStyle);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 엑셀이름 한글깨짐방지
|
|
|
|
|
|
String outputFileName = new String(excelFileName.getBytes("KSC5601"), "8859_1");
|
|
|
|
|
|
|
|
|
|
|
|
response.setHeader("Set-Cookie", "fileDownload=true; path=/");
|
|
|
|
|
|
response.setHeader("Content-Disposition", String.format("attachment; filename=\"" + outputFileName + "_"
|
|
|
|
|
|
+ ExcelMergeHeaderUtil.getTimeStampString("yyyyMMdd_HHmm") + ".xlsx\""));
|
|
|
|
|
|
|
|
|
|
|
|
wb.write(response.getOutputStream());
|
|
|
|
|
|
wb.close();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
createNoDataAlert(response);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 로딩바 표시를 위하여 응답을 return함
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param response
|
|
|
|
|
|
* @throws IOException
|
|
|
|
|
|
*/
|
|
|
|
|
|
// public static byte[] listToExcelMergeHeaderByteArray(List<EgovMap> list,
|
|
|
|
|
|
// String[] headers, String[][] headerNames, int[] headerWidths, String[]
|
|
|
|
|
|
// columnType, String sheetName) throws IOException {
|
|
|
|
|
|
public static byte[] listToExcelMergeHeaderByteArray(List<EgovMap> list, String[] headers, String[][] headerNames,
|
|
|
|
|
|
int[] headerWidths, String[] columnType, String sheetName, ExcelJobManager.ProgressCallback callback)
|
|
|
|
|
|
throws IOException {
|
|
|
|
|
|
|
|
|
|
|
|
if (!ExcelMergeHeaderUtil.isNotEmpty(list)) {
|
|
|
|
|
|
return new byte[0];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
XSSFWorkbook wb = new XSSFWorkbook();
|
|
|
|
|
|
Sheet sheet = wb.createSheet(sheetName);
|
|
|
|
|
|
|
|
|
|
|
|
CellStyle headerStyle = wb.createCellStyle();
|
|
|
|
|
|
CellStyle borderStyle = wb.createCellStyle();
|
|
|
|
|
|
CellStyle cellStyle1 = wb.createCellStyle();
|
|
|
|
|
|
CellStyle cellStyle2 = wb.createCellStyle();
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 스타일 설정 =====
|
|
|
|
|
|
borderStyle.setBorderTop(BorderStyle.THIN);
|
|
|
|
|
|
borderStyle.setBorderBottom(BorderStyle.THIN);
|
|
|
|
|
|
borderStyle.setBorderLeft(BorderStyle.THIN);
|
|
|
|
|
|
borderStyle.setBorderRight(BorderStyle.THIN);
|
|
|
|
|
|
|
|
|
|
|
|
Font headerFont = wb.createFont();
|
|
|
|
|
|
headerFont.setColor(IndexedColors.WHITE.getIndex());
|
|
|
|
|
|
headerStyle.setFont(headerFont);
|
|
|
|
|
|
headerStyle.cloneStyleFrom(borderStyle);
|
|
|
|
|
|
headerStyle.setAlignment(HorizontalAlignment.CENTER);
|
|
|
|
|
|
headerStyle.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
|
|
|
|
headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
|
|
|
|
|
headerStyle.setFillForegroundColor(IndexedColors.GREY_40_PERCENT.getIndex());
|
|
|
|
|
|
|
|
|
|
|
|
XSSFDataFormat format = wb.createDataFormat();
|
|
|
|
|
|
cellStyle1.setDataFormat(format.getFormat("#,##0"));
|
|
|
|
|
|
cellStyle2.setDataFormat(format.getFormat("#"));
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 헤더 병합 =====
|
|
|
|
|
|
sheet.addMergedRegion(new CellRangeAddress(0, 1, 0, 0));
|
|
|
|
|
|
sheet.addMergedRegion(new CellRangeAddress(0, 1, 1, 1));
|
|
|
|
|
|
sheet.addMergedRegion(new CellRangeAddress(0, 1, 2, 2));
|
|
|
|
|
|
sheet.addMergedRegion(new CellRangeAddress(0, 0, 3, 4));
|
|
|
|
|
|
sheet.addMergedRegion(new CellRangeAddress(0, 0, 5, 8));
|
|
|
|
|
|
sheet.addMergedRegion(new CellRangeAddress(0, 0, 9, 11));
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 헤더 생성 =====
|
|
|
|
|
|
for (int i = 0; i < headerNames.length; i++) {
|
|
|
|
|
|
Row row = sheet.createRow(i);
|
|
|
|
|
|
for (int j = 0; j < headerNames[i].length; j++) {
|
|
|
|
|
|
Cell cell = row.createCell(j);
|
|
|
|
|
|
cell.setCellValue(headerNames[i][j]);
|
|
|
|
|
|
cell.setCellStyle(headerStyle);
|
|
|
|
|
|
sheet.setColumnWidth(j, headerWidths[j]);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 바디 =====
|
|
|
|
|
|
for (int i = 0; i < list.size(); i++) {
|
|
|
|
|
|
EgovMap rowData = list.get(i);
|
|
|
|
|
|
Row row = sheet.createRow(i + 2);
|
|
|
|
|
|
|
|
|
|
|
|
for (int j = 0; j < headers.length; j++) {
|
|
|
|
|
|
Cell cell = row.createCell(j);
|
|
|
|
|
|
Object value = rowData.get(headers[j]);
|
|
|
|
|
|
|
|
|
|
|
|
if ("Money".equalsIgnoreCase(columnType[j])) {
|
|
|
|
|
|
cell.setCellValue(value instanceof Number ? ((Number) value).doubleValue() : 0);
|
|
|
|
|
|
cell.setCellStyle(cellStyle1);
|
|
|
|
|
|
} else if ("Int".equalsIgnoreCase(columnType[j])) {
|
|
|
|
|
|
cell.setCellValue(value instanceof Number ? ((Number) value).doubleValue() : 0);
|
|
|
|
|
|
cell.setCellStyle(cellStyle2);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
cell.setCellValue(value == null ? "" : String.valueOf(value));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
cell.setCellStyle(borderStyle);
|
|
|
|
|
|
// 진행률 계산 (중간중간 콜백 호출)
|
|
|
|
|
|
if (callback != null) {
|
|
|
|
|
|
int percent = (int) (((i + 1) / (double) list.size()) * 100);
|
|
|
|
|
|
callback.update(percent);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
|
|
|
|
wb.write(bos);
|
|
|
|
|
|
wb.close();
|
|
|
|
|
|
|
|
|
|
|
|
return bos.toByteArray();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void createNoDataAlert(HttpServletResponse response) throws IOException {
|
|
|
|
|
|
response.setHeader("Content-Type", "text/html; charset=UTF-8");
|
|
|
|
|
|
PrintWriter out = response.getWriter();
|
|
|
|
|
|
|
|
|
|
|
|
out.write(
|
|
|
|
|
|
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">");
|
|
|
|
|
|
out.write("<html lang=\"ko\">");
|
|
|
|
|
|
out.write("<head>");
|
|
|
|
|
|
out.write("<script type=\"text/javascript\">");
|
|
|
|
|
|
out.write("alert('데이터가 없습니다.');");
|
|
|
|
|
|
out.write("history.back(-1);");
|
|
|
|
|
|
out.write("</script>");
|
|
|
|
|
|
out.write("</head>");
|
|
|
|
|
|
out.write("</html>");
|
|
|
|
|
|
|
|
|
|
|
|
out.flush();
|
|
|
|
|
|
out.close();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static void setDisposition(String filename, HttpServletRequest request, HttpServletResponse response)
|
|
|
|
|
|
throws IOException {
|
|
|
|
|
|
String browser = getBrowser(request);
|
|
|
|
|
|
|
|
|
|
|
|
String dispositionPrefix = "attachment; filename=";
|
|
|
|
|
|
String encodedFilename = null;
|
|
|
|
|
|
|
|
|
|
|
|
if (browser.equals("MSIE")) {
|
|
|
|
|
|
encodedFilename = URLEncoder.encode(filename, "UTF-8").replaceAll("\\+", "%20");
|
|
|
|
|
|
} else if (browser.equals("Trident")) { // IE11 문자열 깨짐 방지
|
|
|
|
|
|
encodedFilename = URLEncoder.encode(filename, "UTF-8").replaceAll("\\+", "%20");
|
|
|
|
|
|
} else if (browser.equals("Firefox")) {
|
|
|
|
|
|
encodedFilename = "\"" + new String(filename.getBytes("UTF-8"), "8859_1") + "\"";
|
|
|
|
|
|
} else if (browser.equals("Opera")) {
|
|
|
|
|
|
encodedFilename = "\"" + new String(filename.getBytes("UTF-8"), "8859_1") + "\"";
|
|
|
|
|
|
} else if (browser.equals("Chrome")) {
|
|
|
|
|
|
StringBuffer sb = new StringBuffer();
|
|
|
|
|
|
for (int i = 0; i < filename.length(); i++) {
|
|
|
|
|
|
char c = filename.charAt(i);
|
|
|
|
|
|
if (c == ',') {
|
|
|
|
|
|
sb.append(URLEncoder.encode(",", "UTF-8"));
|
|
|
|
|
|
} else if (c > '~') {
|
|
|
|
|
|
sb.append(URLEncoder.encode("" + c, "UTF-8"));
|
|
|
|
|
|
} else {
|
|
|
|
|
|
sb.append(c);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
encodedFilename = sb.toString();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
throw new IOException("Not supported browser");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
response.setHeader("Content-Disposition", dispositionPrefix + encodedFilename);
|
|
|
|
|
|
|
|
|
|
|
|
if ("Opera".equals(browser)) {
|
|
|
|
|
|
response.setContentType("application/octet-stream;charset=UTF-8");
|
|
|
|
|
|
}
|
|
|
|
|
|
if (filename.contains("zip")) {
|
|
|
|
|
|
response.setContentType("application/zip");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static String getBrowser(HttpServletRequest request) {
|
|
|
|
|
|
String header = request.getHeader("User-Agent");
|
|
|
|
|
|
if (header.indexOf("MSIE") > -1) {
|
|
|
|
|
|
return "MSIE";
|
|
|
|
|
|
} else if (header.indexOf("Trident") > -1) { // IE11 문자열 깨짐 방지
|
|
|
|
|
|
return "Trident";
|
|
|
|
|
|
} else if (header.indexOf("Chrome") > -1) {
|
|
|
|
|
|
return "Chrome";
|
|
|
|
|
|
} else if (header.indexOf("Opera") > -1) {
|
|
|
|
|
|
return "Opera";
|
|
|
|
|
|
}
|
|
|
|
|
|
return "Firefox";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static String LocalDateTimeToStringDate(LocalDateTime localDateTime) {
|
|
|
|
|
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
|
|
|
String formattedDate = localDateTime.toLocalDate().format(formatter);
|
|
|
|
|
|
return formattedDate;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static void listToExcelMergeHeaderForLoginHistory(List<EgovMap> list, HttpServletResponse response,
|
|
|
|
|
|
String[] headers, String[] headerNames, int[] headerWidths, String[] columnType, String sheetName,
|
|
|
|
|
|
String excelFileName) throws IOException {
|
|
|
|
|
|
if (ExcelMergeHeaderUtil.isNotEmpty(list)) {
|
|
|
|
|
|
// 메모리에 100개의 행을 유지합니다. 행의 수가 넘으면 디스크에 적습니다.
|
|
|
|
|
|
XSSFWorkbook wb = new XSSFWorkbook();
|
|
|
|
|
|
Sheet sheet = wb.createSheet(sheetName);
|
|
|
|
|
|
Row headerRow = sheet.createRow(headerNames.length);
|
|
|
|
|
|
CellStyle cellStyle1 = wb.createCellStyle(); // 쉼표들어간 숫자 양식
|
|
|
|
|
|
CellStyle cellStyle2 = wb.createCellStyle(); // 숫자양식
|
|
|
|
|
|
CellStyle headerStyle = wb.createCellStyle(); // 헤더 스타일
|
|
|
|
|
|
CellStyle borderStyle = wb.createCellStyle(); // 기본 검정 테두리 스타일
|
|
|
|
|
|
|
|
|
|
|
|
// 기본 검정 테두리 스타일 설정
|
|
|
|
|
|
borderStyle.setBorderTop(BorderStyle.THIN);
|
|
|
|
|
|
borderStyle.setBorderBottom(BorderStyle.THIN);
|
|
|
|
|
|
borderStyle.setBorderLeft(BorderStyle.THIN);
|
|
|
|
|
|
borderStyle.setBorderRight(BorderStyle.THIN);
|
|
|
|
|
|
|
|
|
|
|
|
// 글꼴 색상 흰색으로 설정
|
|
|
|
|
|
Font headerFont = wb.createFont();
|
|
|
|
|
|
headerFont.setColor(IndexedColors.WHITE.getIndex()); // 글씨 색상 흰색
|
|
|
|
|
|
headerStyle.setFont(headerFont); // 헤더 스타일에 적용
|
|
|
|
|
|
|
|
|
|
|
|
XSSFDataFormat format = wb.createDataFormat();
|
|
|
|
|
|
cellStyle1.setDataFormat(format.getFormat("#,##0"));
|
|
|
|
|
|
cellStyle2.setDataFormat(format.getFormat("#"));
|
|
|
|
|
|
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.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
|
|
|
|
|
// headerStyle.setFillForegroundColor((short)3);
|
|
|
|
|
|
headerStyle.setFillForegroundColor(IndexedColors.GREY_40_PERCENT.getIndex());
|
|
|
|
|
|
|
|
|
|
|
|
// 바디 스타일
|
|
|
|
|
|
CellStyle bodyStyle = wb.createCellStyle();
|
|
|
|
|
|
bodyStyle.setAlignment(HorizontalAlignment.CENTER);
|
|
|
|
|
|
// ---------- 헤더구성 ------------------------------------
|
|
|
|
|
|
Row hRow = null;
|
|
|
|
|
|
// rows
|
|
|
|
|
|
int rowCnt = 0;
|
|
|
|
|
|
|
|
|
|
|
|
// 헤더 정보 구성
|
|
|
|
|
|
hRow = sheet.createRow(rowCnt++);
|
|
|
|
|
|
for (int i = 0; i < headerNames.length; i++) {
|
|
|
|
|
|
Cell cell = headerRow.createCell(i);
|
|
|
|
|
|
cell = hRow.createCell(i);
|
|
|
|
|
|
cell.setCellStyle(headerStyle);
|
|
|
|
|
|
cell.setCellValue(headerNames[i]);
|
|
|
|
|
|
sheet.setColumnWidth(i, (sheet.getColumnWidth(i)) + 1000);
|
|
|
|
|
|
sheet.setColumnWidth(i, headerWidths[i]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ---------- 헤더구성 끝------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < list.size(); i++) {
|
|
|
|
|
|
EgovMap rowData = list.get(i);
|
|
|
|
|
|
Row row = sheet.createRow(i + 1);
|
|
|
|
|
|
|
|
|
|
|
|
for (int j = 0; j < headers.length; j++) {
|
|
|
|
|
|
Cell cell = row.createCell(j);
|
|
|
|
|
|
|
|
|
|
|
|
Object value = rowData.get(headers[j]);
|
|
|
|
|
|
|
|
|
|
|
|
// Money 타입
|
|
|
|
|
|
if ("Money".equalsIgnoreCase(columnType[j])) {
|
|
|
|
|
|
if (value instanceof Number) {
|
|
|
|
|
|
cell.setCellValue(((Number) value).doubleValue());
|
|
|
|
|
|
} else {
|
|
|
|
|
|
cell.setCellValue(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
cell.setCellStyle(cellStyle1);
|
|
|
|
|
|
|
|
|
|
|
|
// Int 타입
|
|
|
|
|
|
} else if ("Int".equalsIgnoreCase(columnType[j])) {
|
|
|
|
|
|
if (value instanceof Number) {
|
|
|
|
|
|
cell.setCellValue(((Number) value).doubleValue());
|
|
|
|
|
|
} else {
|
|
|
|
|
|
cell.setCellValue(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
cell.setCellStyle(cellStyle2);
|
|
|
|
|
|
|
|
|
|
|
|
// String 타입
|
|
|
|
|
|
} else {
|
|
|
|
|
|
cell.setCellValue(value == null ? "" : String.valueOf(value));
|
|
|
|
|
|
}
|
|
|
|
|
|
// 검정 테두리 적용
|
|
|
|
|
|
cell.setCellStyle(borderStyle);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 엑셀이름 한글깨짐방지
|
|
|
|
|
|
String outputFileName = new String(excelFileName.getBytes("KSC5601"), "8859_1");
|
|
|
|
|
|
|
|
|
|
|
|
response.setHeader("Set-Cookie", "fileDownload=true; path=/");
|
|
|
|
|
|
response.setHeader("Content-Disposition", String.format("attachment; filename=\"" + outputFileName + "_"
|
|
|
|
|
|
+ ExcelMergeHeaderUtil.getTimeStampString("yyyyMMdd_HHmm") + ".xlsx\""));
|
|
|
|
|
|
|
|
|
|
|
|
wb.write(response.getOutputStream());
|
|
|
|
|
|
wb.close();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
createNoDataAlert(response);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2025-12-17 07:34:15 +00:00
|
|
|
|
|
|
|
|
|
|
}
|