package com.interplug.qcast.util; import com.fasterxml.jackson.databind.exc.InvalidFormatException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.io.*; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.text.DecimalFormat; import java.util.*; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import net.sf.jxls.exception.ParsePropertyException; import org.jxls.common.Context; import org.jxls.util.JxlsHelper; import org.springframework.stereotype.Component; @Slf4j @Component @RequiredArgsConstructor public class ExcelUtil { // DecimalFormat 인스턴스를 미리 생성 private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#,##0.000"); /** * jxls을 이용한 엑셀데이터 축출 * * @param request HttpServletRequest * @param response HttpServletResponse * @param map 엑셀 출력데이터 * @param list 엑셀 출력 목록 데이터 * @param templateFileName 템플릿 파일명 * @throws ParsePropertyException * @throws InvalidFormatException */ public byte[] download( HttpServletRequest request, HttpServletResponse response, Map map, List> list, String templateFileName) throws ParsePropertyException, InvalidFormatException { byte[] excelBytes = null; try { String templateFilePath = "template/excel/" + templateFileName; InputStream templateStream = PdfUtil.class.getClassLoader().getResourceAsStream(templateFilePath); try (InputStream is = new BufferedInputStream(templateStream)) { Context context = new Context(); context.putVar("data", map); context.putVar("list", list); // 포맷팅 함수를 컨텍스트에 추가 context.putVar("formatNumber", new FormatNumberFunction()); context.putVar("decimalFormat", DECIMAL_FORMAT); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); JxlsHelper.getInstance().processTemplate(is, byteArrayOutputStream, context); excelBytes = byteArrayOutputStream.toByteArray(); } } catch (Exception e) { log.debug(e.getMessage()); } return excelBytes; } /** * jxls을 이용한 엑셀다운로드 * * @param request HttpServletRequest * @param response HttpServletResponse * @param map 엑셀 출력데이터 * @param list 엑셀 출력 목록 데이터 * @param fileName 다운로드 파일명 * @param templateFileName 템플릿 파일명 * @throws ParsePropertyException * @throws InvalidFormatException */ public void download( HttpServletRequest request, HttpServletResponse response, Map map, List> list, String fileName, String templateFileName) throws ParsePropertyException, InvalidFormatException { try { String templateFilePath = "template/excel/" + templateFileName; InputStream templateStream = PdfUtil.class.getClassLoader().getResourceAsStream(templateFilePath); InputStream is = new BufferedInputStream(templateStream); response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + ".xlsx\""); response.addHeader("Access-Control-Expose-Headers", "Content-Disposition"); try (OutputStream os = response.getOutputStream()) { Context context = new Context(); context.putVar("data", map); context.putVar("list", list); // 포맷팅 함수를 컨텍스트에 추가 context.putVar("formatNumber", new FormatNumberFunction()); context.putVar("decimalFormat", DECIMAL_FORMAT); JxlsHelper.getInstance().processTemplate(is, os, context); } } catch (Exception e) { log.debug(e.getMessage()); } } /** * Object => Map 변환 함수 * * @param vo Object * @return Map Map 변환 정보 */ public Map convertVoToMap(Object vo) { Map result = new HashMap(); try { BeanInfo info = Introspector.getBeanInfo(vo.getClass()); for (PropertyDescriptor pd : info.getPropertyDescriptors()) { Method reader = pd.getReadMethod(); if (reader != null) { result.put(pd.getName(), reader.invoke(vo)); } } } catch (Exception e) { log.error("convertVoToMap >>> " + e.getMessage()); } return result; } /** * List => List 변환 함수 * * @param target List * @return List> List 변환 정보 */ public static List> convertListToMap(Collection target) { List> resultList = new ArrayList>(); for (T element : target) { Map resultMap = new HashMap(); Field[] fieldList = element.getClass().getDeclaredFields(); if (fieldList != null && fieldList.length > 0) { try { for (int i = 0; i < fieldList.length; i++) { String curInsName = fieldList[i].getName(); Field field = element.getClass().getDeclaredField(curInsName); field.setAccessible(true); Object targetValue = field.get(element); resultMap.put(curInsName, targetValue); } resultList.add(resultMap); } catch (Exception e) { log.error("convertListToMap >>> " + e.getMessage()); } } } return resultList; } /** * JXLS 템플릿에서 사용할 수 있는 포맷팅 함수 클래스 */ public static class FormatNumberFunction { /** * 숫자 포맷팅을 위한 헬퍼 메서드 */ public static String formatNumber(Object amount, Object grossWt) { try { if (amount != null && grossWt != null) { double amountValue = Double.parseDouble(amount.toString()); double grossWtValue = Double.parseDouble(grossWt.toString()); return DECIMAL_FORMAT.format(amountValue * grossWtValue); } } catch (NumberFormatException e) { log.warn("Number formatting error: {}", e.getMessage()); } return "0.000"; } public String format(Object amount, Object grossWt) { return formatNumber(amount, grossWt); } // 합계 계산을 위한 숫자 값 반환 메서드 public Double calculate(Object amount, Object grossWt) { try { if (amount != null && grossWt != null) { double amountValue = Double.parseDouble(amount.toString()); double grossWtValue = Double.parseDouble(grossWt.toString()); return amountValue * grossWtValue; } } catch (NumberFormatException e) { log.warn("Number calculation error: {}", e.getMessage()); } return 0.0; } // 리스트의 합계를 계산하고 포맷팅하는 메서드 public String formatSum(List> items) { double sum = 0.0; for (Map item : items) { sum += calculate(item.get("amount"), item.get("grossWt")); } return DECIMAL_FORMAT.format(sum); } } }