package itn.com.cmm.util; import java.io.OutputStream; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; import javax.servlet.http.HttpServletResponse; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.Font; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.xssf.streaming.SXSSFWorkbook; import org.apache.poi.xssf.usermodel.XSSFCell; import org.apache.poi.xssf.usermodel.XSSFRow; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartHttpServletRequest; import itn.com.cmm.JsonResult; import itn.let.fax.user.service.FaxGroupDataVO; import itn.let.mjo.msgdata.service.PhoneVO; /** * * @author : 이호영 * @fileName : FaxUtil.java * @date : 2023.03.20 * @description : 팩스 관련 Util * =========================================================== * DATE AUTHOR NOTE * ----------------------------------------------------------- * * 2023.03.20 이호영 최초 생성 * * * */ public final class FaxUtil { public static HttpServletResponse getResponse() { ServletRequestAttributes attr = (ServletRequestAttributes)RequestContextHolder.currentRequestAttributes(); return attr.getResponse(); } /** * @methodName : checkHpNum * @author : 이호영 * @date : 2023.03.20 * @description : * @param faxConvertFilePath * @param seq * @return */ public static String makeDownloadPath(String faxConvertFilePath, String seq) { return faxConvertFilePath + "/" + seq + ".pdf"; } /** * @methodName : exelFileConvertForFax * @author : 이준호 * @date : 2023.05.08 * @description : * @param multiRequest * @return */ public static JsonResult exelFileConvertForFax(MultipartHttpServletRequest multiRequest) { JsonResult jr = new JsonResult(); jr.setSuccess(false); jr.setMessage("엑셀 파일만 업로드할 수 있습니다."); //final Map files = multiRequest.getFileMap(); List files = (List) multiRequest.getFiles("file0"); // 파일명에 .이 있을경우 오류 => Ex) 테스트6.20.xlsx int fileNameSplitCnt = 0; if(!files.isEmpty()) { fileNameSplitCnt = files.get(0).getOriginalFilename().split("[.]").length; if (files.get(0).getSize() > 0 && (files.get(0).getContentType().indexOf("spreadsheetml") > -1) || files.get(0).getContentType().indexOf("ms-excel") > -1 || files.get(0).getOriginalFilename().split("[.]")[fileNameSplitCnt-1].indexOf("xlsx") > -1 || files.get(0).getOriginalFilename().split("[.]")[fileNameSplitCnt-1].indexOf("xls") > -1) { // 엑셀 파일 용량 3MB이상 시 10만건 이상으로 서버가 다운되는 증상 발생 long fileSize = multiRequest.getFile("file0").getSize(); if(fileSize > 3374653) { jr.setMessage("엑셀 파일은 3MB를 넘을수 없습니다."); return jr; } String Ext = files.get(0).getOriginalFilename().split("[.]")[1]; String errMessage = ""; String cellValue = ""; // String phoneRegExp = "^(050[234567]{1}|01[016789]{1})-?[0-9]{3,4}-?[0-9]{4}$"; int errPhoneCnt = 0; int errNameCnt = 0; try { //엑셀 확장자에 따른 처리 로직 분리 if(Ext.equals("xls")) { HSSFWorkbook workbook = new HSSFWorkbook(files.get(0).getInputStream()); HSSFSheet sheet = workbook.getSheetAt(0); if(sheet.getLastRowNum() > 20000) { // errMessage = "20000건 이상의 업로드는 데이터 부하로 업로드 할수 없습니다."; jr.setSuccess(false); jr.setMessage(errMessage); return jr; } List> json = new ArrayList>(); PhoneVO pVO = new PhoneVO(); for(int i=2; i< sheet.getLastRowNum() + 2; i++){ //먼저 밸리데이션 체크(1줄은 생략) HSSFRow row = sheet.getRow(i); //열읽기 if(null == row) { continue; } HashMap jm = new HashMap<>(); // 행의 두번째 열(이름부터 받아오기) HSSFCell cell = null; boolean errSts = true; for(int j = 0 ; j < 2; j++){ //행읽기(6행까지나 2행까지만 필요) cellValue = ""; cell = row.getCell(j); //이름/수신번호 if(null == cell || "".equals(cell.toString().trim())) { //셀에 값이 없으면 //System.out.println("Cell 데이터가 없습니다."); if(j == 1) { if (sheet.getLastRowNum() == i) { continue; } break; } } if(null != cell){ switch(cell.getCellType()){ //숫자타임을 문자로 변환 case Cell.CELL_TYPE_NUMERIC: cell.setCellType(Cell.CELL_TYPE_STRING); } cellValue = StringUtil.getString(cell.getStringCellValue().trim()) ; } if(j == 0) { //이름 boolean nmChk = getNameRepLenChk("name", cellValue); if(nmChk && errSts) { jm.put("name", cellValue); }else { errNameCnt++; errSts = false; break; } } if(j == 1) { //전화번호 if(errSts) { jm.put("phone", cellValue); }else { errPhoneCnt++; errSts = false; break; } } } if(null != jm.get("phone") && errSts) { json.add(jm); } } int resultErrCnt = errPhoneCnt + errNameCnt; int resultErrCntExceptPhone = errPhoneCnt + errNameCnt; jr.setData(json); jr.setSuccess(true); if(resultErrCnt > 0) { jr.setMessage("유효하지 않은 형식의 전화번호 "+ errPhoneCnt +"건,\n이름 : 20byte 제한글자수 초과 "+ resultErrCntExceptPhone +"건 있습니다.\n해당 건을 제외하고 추가됩니다."); }else { jr.setMessage(""); } }else { //확장자가 xlsx OPCPackage opcPackage = OPCPackage.open(files.get(0).getInputStream()); XSSFWorkbook workbook = new XSSFWorkbook(opcPackage); XSSFSheet sheet = workbook.getSheetAt(0); // 첫번째 시트 불러오기 opcPackage.close(); if(sheet.getLastRowNum() > 20000) { // errMessage = "20000건 이상의 업로드는 데이터 부하로 업로드 할수 없습니다."; jr.setSuccess(false); jr.setMessage(errMessage); return jr; } List> json = new ArrayList>(); PhoneVO pVO = new PhoneVO(); for(int i=2; i< sheet.getLastRowNum() + 2; i++){ //먼저 밸리데이션 체크(1줄은 생략) XSSFRow row = sheet.getRow(i); //열읽기 if(null == row) { continue; } HashMap jm = new HashMap<>(); // 행의 두번째 열(이름부터 받아오기) XSSFCell cell = null; boolean errSts = true; for(int j = 0 ; j < 2; j++){ //행읽기(6행까지나 2행까지만 필요) cellValue = ""; cell = row.getCell(j); //이름/수신번호 if(null == cell || "".equals(cell.toString().trim())) { //셀에 값이 없으면 if(j == 1) { if (sheet.getLastRowNum() == i) { continue; } break; } } if(null != cell){ switch(cell.getCellType()){ //숫자타임을 문자로 변환 case Cell.CELL_TYPE_NUMERIC: cell.setCellType(Cell.CELL_TYPE_STRING); } cellValue = StringUtil.getString(cell.getStringCellValue().trim()) ; } if(j == 0) { //이름 boolean nmChk = getNameRepLenChk("name", cellValue); if(nmChk && errSts) { jm.put("name", cellValue); }else { errNameCnt++; errSts = false; break; } } if(j == 1) { //수신번호 if(errSts) { jm.put("phone", cellValue); }else { errPhoneCnt++; errSts = false; break; } } } if(null != jm.get("phone") && errSts) { json.add(jm); } } int resultErrCnt = errPhoneCnt + errNameCnt; int resultErrCntExceptPhone = errPhoneCnt + errNameCnt; jr.setData(json); jr.setSuccess(true); if(resultErrCnt > 0) { jr.setMessage("유효하지 않은 형식의 전화번호 "+ errPhoneCnt +"건,\n이름 : 20byte 제한글자수 초과 "+ resultErrCntExceptPhone +"건 있습니다.\n해당 건을 제외하고 추가됩니다."); }else { jr.setMessage(""); } } //xlsx 처리 끝 } catch (Exception e) { jr.setMessage("처리 중 오류가 발생했습니다. 관리자에게 문의하세요."); } } } return jr; } public static void getExcelForFaxSendList(List faxGroupListVO) { HttpServletResponse response =ContextUtil.getResponse(); // 메모리에 100개의 행을 유지합니다. 행의 수가 넘으면 디스크에 적습니다. SXSSFWorkbook wb = new SXSSFWorkbook(); String fileName ="팩스 발송 내역"; // 저장 파일명 String sheetTitle = "팩스 발송 내역" ; // 셀 제목 Sheet sheet = wb.createSheet(sheetTitle); Cell cell = null; Row row = null; CellStyle style = wb.createCellStyle(); style.setBorderBottom(CellStyle.BORDER_THIN); //테두리 두껍게 style.setBorderLeft(CellStyle.BORDER_THIN); style.setBorderRight(CellStyle.BORDER_THIN); style.setBorderTop(CellStyle.BORDER_THIN); // 정렬 style.setAlignment(CellStyle.ALIGN_CENTER); //가운데 정렬 style.setVerticalAlignment(CellStyle.VERTICAL_CENTER); //높이 가운데 정렬 Font font = wb.createFont(); font.setBoldweight(Font.BOLDWEIGHT_BOLD); //글씨 bold try{ //발송 성공,실패 건수 불러오기 row = sheet.createRow(0); sheet.setColumnWidth(1, 7000); // 발송형태 칼럼의 폭 조절 sheet.setColumnWidth(2, 5000); // 접수일자 칼럼의 폭 조절 //셀병합 처리 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,1,3,3)); //예약일자 세로 셀병합 sheet.addMergedRegion(new CellRangeAddress(0,1,4,4)); //형태 세로 셀병합 cell = row.createCell(0); cell.setCellValue("번호"); cell.setCellStyle(style); cell = row.createCell(1); cell.setCellValue("제목"); cell.setCellStyle(style); cell = row.createCell(2); cell.setCellValue("전송시간"); cell.setCellStyle(style); cell = row.createCell(3); cell.setCellValue("문서 매수"); cell.setCellStyle(style); cell = row.createCell(4); cell.setCellValue("발송 건수"); cell.setCellStyle(style); cell = row.createCell(5); cell.setCellValue("발송결과 건수"); sheet.addMergedRegion(new CellRangeAddress(0,0,5,6)); // 발송결과 건수 가로 셀병합 cell.setCellStyle(style); cell = row.createCell(6); cell.setCellStyle(style); row = sheet.createRow(1); cell = row.createCell(0); cell.setCellStyle(style); cell = row.createCell(1); cell.setCellStyle(style); cell = row.createCell(2); cell.setCellStyle(style); cell = row.createCell(3); cell.setCellStyle(style); cell = row.createCell(4); cell.setCellStyle(style); cell = row.createCell(5); cell.setCellValue("성공"); cell.setCellStyle(style); cell = row.createCell(6); cell.setCellValue("실패"); cell.setCellStyle(style); int rowNum = 2; for(FaxGroupDataVO faxGroupDataVO : faxGroupListVO) { row = sheet.createRow(rowNum); cell = row.createCell(0); cell.setCellStyle(style); cell.setCellValue(rowNum-1); cell = row.createCell(1); cell.setCellStyle(style); cell.setCellValue(faxGroupDataVO.getSubject()); cell = row.createCell(2); cell.setCellStyle(style); cell.setCellValue(faxGroupDataVO.getDoneDate()); cell = row.createCell(3); cell.setCellStyle(style); cell.setCellValue(faxGroupDataVO.getPage()); cell = row.createCell(4); cell.setCellStyle(style); cell.setCellValue(faxGroupDataVO.getTotalEa()); cell = row.createCell(5); cell.setCellStyle(style); cell.setCellValue(faxGroupDataVO.getSentEa()); cell = row.createCell(6); cell.setCellStyle(style); cell.setCellValue(faxGroupDataVO.getHoldEa()+faxGroupDataVO.getUnSendEa()+faxGroupDataVO.getErrorEa()); rowNum++; } response.setHeader("Set-Cookie", "fileDownload=true; path=/"); SimpleDateFormat mSimpleDateFormat = new SimpleDateFormat ( "yyyyMMdd_HHmmss", Locale.KOREA ); Date currentTime = new Date (); String mTime = mSimpleDateFormat.format ( currentTime ); fileName = fileName+"("+mTime+")"; response.setHeader("Content-Disposition", String.format("attachment; filename=\""+new String((fileName).getBytes("KSC5601"),"8859_1")+".xlsx")); wb.write(response.getOutputStream()); }catch(Exception e) { response.setHeader("Set-Cookie", "fileDownload=false; path=/"); response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); response.setHeader("Content-Type","text/html; charset=utf-8"); OutputStream out = null; try { out = response.getOutputStream(); byte[] data = new String("fail..").getBytes(); out.write(data, 0, data.length); } catch(Exception ignore) { ignore.printStackTrace(); } finally { if(out != null) try { out.close(); } catch(Exception ignore) {} } }finally { // 디스크 적었던 임시파일을 제거합니다. wb.dispose(); try { wb.close(); } catch(Exception ignore) {} } } /*==================================================================== = private function zone = ====================================================================*/ // 팩스 엑셀 업로드 이름 길이 체크 private static boolean getNameRepLenChk(String type, String value) { boolean rtnValue = true; if(type.equals("name")) { String tmpNm = value; int nmLen = tmpNm.length(); if(nmLen > 12) { rtnValue = false; } }else if(type.equals("rep")) { String tmpRep = value; int repLen = tmpRep.length(); if(repLen > 20) { rtnValue = false; } } return rtnValue; } }