mjon_git/src/main/java/itn/com/cmm/util/ExcelUploadUtil.java
2023-06-12 11:15:02 +09:00

647 lines
22 KiB
Java

package itn.com.cmm.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
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 org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.FormulaEvaluator;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.MultiValueMap;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import itn.com.cmm.service.EgovProperties;
public class ExcelUploadUtil {
private static final Logger logger = LoggerFactory.getLogger(ExcelUploadUtil.class);
/**
* 업로드 엑셀 읽기 - 파일 한 개만 지원<br>
* - 엑셀 파일의 첫 번째 레코드를 HasMap 키 이름으로 사용 - 엑셀 파일의 두 번째 레코드부터 데이터로 저장<br>
* @param request
* @param uploadFolder
* @return
* @throws Exception
*/
public static List<HashMap<String, String>> readExcel(MultipartHttpServletRequest request, String uploadFolder) throws Exception {
return readExcel(request, uploadFolder, null);
}
/**
* 업로드 엑셀 읽기 - 파일 한 개만 지원, 첫 번째 시트만 처리<br><br>
* - 지정한 배열로 HashMap key name 적용<br>
* - 엑셀 파일의 첫 번째 레코드부터 데이터로 저장<br>
* @param request
* @param uploadFolder
* @param columnNames null일 경우 엑셀 첫 레코드를 컬럼 이름으로 사용
* @return
* @throws Exception
*/
public static List<HashMap<String, String>> readExcel(MultipartHttpServletRequest request, String uploadFolder, String[] columnNames) throws Exception {
return readExcel(request, uploadFolder, columnNames, 1);
}
/**
* 업로드 엑셀 읽기 - 파일 한 개만 지원, 첫 번째 시트만 처리<br><br>
*
* @param request
* @param uploadFolder : 서브 디렉토리 : 빈 값 =/uploadRoot/com/[yyyyMMdd]/, 값이 있으면=/uploadRoot/[uploadFolder]
* @param columnNames : HasMap key name : null일 경우 엑셀 첫 레코드를 컬럼 이름으로 사용
* @param startRecord : 데이터를 가져올 시작 레코드 : 첫 레코드 = 1
* @return
* @throws Exception
*/
public static List<HashMap<String, String>> readExcel(MultipartHttpServletRequest request, String uploadFolder, String[] columnNames, int startRecord) throws Exception {
MultiValueMap<String, MultipartFile> files = request.getMultiFileMap();
//String sUploadPathProperty = "upload.path.physical." + EgovProperties.getProperty("globals.web.mode");
String sUploadPathProperty = "/temp";
String sSubDir = uploadFolder;
if (StringUtil.isEmpty(sSubDir)) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM", Locale.getDefault());
//sSubDir = EgovProperties.getProperty("upload.path.common") + "/" + sdf.format(new Date()) + "/";
sSubDir = "/test";
}
//File uploadPath = new File(EgovProperties.getProperty(sUploadPathProperty), sSubDir);
File uploadPath = new File("/usr", "temp");
if (!uploadPath.exists())
uploadPath.mkdirs();
List<HashMap<String, String>> list = null;
for (String param : files.keySet()) {
List<MultipartFile> fileList = files.get(param);
//MimeUtil mu = new MimeUtil();
//boolean isExcel = mu.isEnableMimeTypes(fileList, "application/vnd.ms-excel", "application/vnd.openxmlformats");
//if (!isExcel)
// throw new FileUploadException("지원되지 않는 형식의 파일입니다.\n엑셀 파일만 업로드할 수 있습니다.");
if (fileList.size() > 0) {
MultipartFile file = fileList.get(0);
File savedFile = new File(uploadPath, file.getOriginalFilename());
file.transferTo(savedFile);
list = readExcel(savedFile, columnNames, startRecord);
String ddd = "";
}
}
return list;
}
/**
* 업로드 엑셀 읽기 - 파일 한 개만 지원, 모든 시트 처리
* @param request
* @param uploadFolder
* @param columnNames
* @param startRecord
* @return
* @throws Exception
*/
public static HashMap<String, List<HashMap<String, String>>> readExcelSheets(MultipartHttpServletRequest request, String uploadFolder, String[] columnNames, int startRecord) throws Exception {
MultiValueMap<String, MultipartFile> files = request.getMultiFileMap();
String sUploadPathProperty = "upload.path.physical." + EgovProperties.getProperty("globals.web.mode");
String sSubDir = uploadFolder;
if (StringUtil.isEmpty(sSubDir)) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM", Locale.getDefault());
sSubDir = EgovProperties.getProperty("upload.path.common") + "/" + sdf.format(new Date()) + "/";
}
File uploadPath = new File(EgovProperties.getProperty(sUploadPathProperty), sSubDir);
if (!uploadPath.exists())
uploadPath.mkdirs();
HashMap<String, List<HashMap<String, String>>> list = null;
for (String param : files.keySet()) {
List<MultipartFile> fileList = files.get(param);
//MimeUtil mu = new MimeUtil();
//boolean isExcel = mu.isEnableMimeTypes(fileList, "application/vnd.ms-excel", "application/vnd.openxmlformats");
//if (!isExcel)
// throw new FileUploadException("지원되지 않는 형식의 파일입니다.\n엑셀 파일만 업로드할 수 있습니다.");
if (fileList.size() > 0) {
MultipartFile file = fileList.get(0);
File savedFile = new File(uploadPath, file.getOriginalFilename());
file.transferTo(savedFile);
list = readExcelSheets(savedFile, columnNames, startRecord);
}
}
return list;
}
/**
* 엑셀 파일 읽어오기 - Workbook 인터페이스 적용<br>
* - 첫 번째 시트만 처리<br>
* - 주의 : 숫자형 데이터는 기본적으로 double type으로 반환. 숫자형 데이터가 .0으로 끝날 경우 int로 변환하여 반환<br>
* - 키 이름 미지정 가능 : 엑셀 첫 레코드를 키 이름으로 사용 <br>
* @param saveFile
* @param keyNm 리턴 hashmap에 부여될 키 이름. null일 경우 엑셀 첫 레코드를 키 이름으로 사용
* @return
* @throws Exception
*/
private static List<HashMap<String, String>> readExcel(File saveFile, String[] keyNm) throws Exception {
return readExcel(saveFile, keyNm, 1);
}
/**
* 엑셀 파일 읽어오기 - Workbook 인터페이스 적용<br>
* - 첫 번째 시트만 처리<br>
* - 주의 : 숫자형 데이터는 기본적으로 double type으로 반환. 숫자형 데이터가 .0으로 끝날 경우 int로 변환하여 반환<br>
* - 키 이름 미지정 가능 : 엑셀 첫 레코드를 키 이름으로 사용 <br>
* @param saveFile
* @param keyNm 리턴 hashmap에 부여될 키 이름. null일 경우 엑셀 첫 레코드를 키 이름으로 사용
* @param startRecord 데이터를 가져올 시작 레코드 : 첫 레코드 = 1
* @return
* @throws Exception
*/
private static List<HashMap<String, String>> readExcel(File saveFile, String[] keyNm, int startRecord) throws Exception {
Workbook wb = WorkbookFactory.create(saveFile);
wb.setMissingCellPolicy(MissingCellPolicy.CREATE_NULL_AS_BLANK);
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
List<HashMap<String, String>> excelRows = new ArrayList<HashMap<String, String>>();
boolean hasKeyName = true;
if (keyNm == null)
hasKeyName = false;
try {
//hashmap용 key이름이 없을 경우 엑셀 1st row를 key 이름으로 설정
if (!hasKeyName && wb.getSheetAt(0).getLastRowNum() > 0) {
keyNm = new String[wb.getSheetAt(0).getRow(0).getLastCellNum()];
for (int i = 0; i < wb.getSheetAt(0).getRow(0).getLastCellNum(); i++)
try {
keyNm[i] = wb.getSheetAt(0).getRow(0).getCell(i).getStringCellValue();
}
catch (Exception e) {
keyNm[i] = "";
}
}
//int iRow = 0;
for (Row row : wb.getSheetAt(0)) {
//logger.debug(">>>>>>>>>>>>> excel row : {}", ++iRow);
if (!hasKeyName && row.getRowNum() == 0)
continue;
if (startRecord > row.getRowNum() + 1)
continue;
HashMap<String, String> excelCols = new HashMap<String, String>();
//주의 : foreach를 사용할 경우 컬럼이 빈 값이면 해당 컬럼 자제가 없어짐 (컬럼 인덱스가 달라짐)
for (int i = 0; i < row.getLastCellNum(); i++) {
//cell을 가져올 때 MissingCellPolicy.CREATE_NULL_AS_BLANK 옵션 사용 필수 : 빈 컬럼일 때도 빈 값을 가져옴. poi v3.16이상 지원
Cell cell = row.getCell(i, MissingCellPolicy.CREATE_NULL_AS_BLANK);
String strVal = "";
//logger.debug(">>>>> {}, {}, {}", cell.getColumnIndex(), keyNm[cell.getColumnIndex()], cell.getCellTypeEnum().equals(CellType.NUMERIC) ? cell.getNumericCellValue() : cell.getStringCellValue());
switch (cell.getCellTypeEnum()) {
case NUMERIC:
if (DateUtil.isCellDateFormatted(cell)) {
java.util.Date dateValue = cell.getDateCellValue();
SimpleDateFormat sdf = new SimpleDateFormat(EgovProperties.getProperty("common.date.type"));
strVal = sdf.format(dateValue);
}
else {
if (String.valueOf(cell.getNumericCellValue()).matches("[\\d]{1,}\\.0$"))
strVal = String.valueOf(Double.valueOf(cell.getNumericCellValue()).intValue());
else
strVal = String.valueOf(cell.getNumericCellValue());
}
break;
case FORMULA:
strVal = evaluator.evaluate(cell).getStringValue(); // .getCellFormula();
break;
case BOOLEAN:
if (cell.getBooleanCellValue())
strVal = "true";
else
strVal = "false";
break;
// case Cell.CELL_TYPE_ERROR:
// break;
//
case _NONE:
case BLANK:
strVal = "";
break;
default:
strVal = cell.getStringCellValue();
break;
}
//issue : 컬럼 헤더 개수와 레코드 컬럼 개수가 맞지 않는 문제 발생
if ((i + 1) <= keyNm.length)
excelCols.put(keyNm[cell.getColumnIndex()], strVal);
}
//logger.debug(">>>>>>>>>>>>> excelCols : {}", excelCols.toString());
excelRows.add(excelCols);
}
//logger.debug(">>>>>>>>>> saveFile : {}", saveFile.getAbsolutePath());
}
catch (Exception ex) {
logger.error(ex.getMessage(), ex);
throw ex;
}
finally {
wb.close();
if (saveFile.exists())
saveFile.delete();
}
return excelRows;
}
private static HashMap<String, List<HashMap<String, String>>> readExcelSheets(File saveFile, String[] keyNm, int startRecord) throws Exception {
HashMap<String, List<HashMap<String, String>>> excels = new HashMap<>();
Workbook wb = WorkbookFactory.create(saveFile);
wb.setMissingCellPolicy(MissingCellPolicy.CREATE_NULL_AS_BLANK);
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
boolean hasKeyName = true;
if (keyNm == null)
hasKeyName = false;
try {
//repeat sheet
for (int i = 0; i < wb.getNumberOfSheets(); i++) {
List<HashMap<String, String>> excelRows = new ArrayList<HashMap<String, String>>();
//키 이름이 없을 경우 엑셀 첫 레코드를 키 이름으로 사용
if (!hasKeyName && wb.getSheetAt(i).getLastRowNum() > 0) {
keyNm = new String[wb.getSheetAt(i).getRow(0).getLastCellNum()];
for (int j = 0; j < wb.getSheetAt(i).getRow(0).getLastCellNum(); j++)
try {
keyNm[j] = wb.getSheetAt(i).getRow(0).getCell(i).getStringCellValue();
}
catch (Exception e) {
keyNm[j] = "";
}
}
for (Row row : wb.getSheetAt(i)) {
if (!hasKeyName && row.getRowNum() == 0)
continue;
if (startRecord > row.getRowNum() + 1)
continue;
HashMap<String, String> excelCols = new HashMap<String, String>();
//주의 : foreach를 사용할 경우 컬럼이 빈 값이면 해당 컬럼 자제가 없어짐 (컬럼 인덱스가 달라짐)
for (int k = 0; k < row.getLastCellNum(); k++) {
//cell을 가져올 때 MissingCellPolicy.CREATE_NULL_AS_BLANK 옵션 사용 필수 : 빈 컬럼일 때도 빈 값을 가져옴. poi v3.16이상 지원
Cell cell = row.getCell(k, MissingCellPolicy.CREATE_NULL_AS_BLANK);
String strVal = "";
//logger.debug(">>>>> {}, {}, {}", cell.getColumnIndex(), keyNm[cell.getColumnIndex()], cell.getCellTypeEnum().equals(CellType.NUMERIC) ? cell.getNumericCellValue() : cell.getStringCellValue());
switch (cell.getCellTypeEnum()) {
case NUMERIC:
if (DateUtil.isCellDateFormatted(cell)) {
java.util.Date dateValue = cell.getDateCellValue();
SimpleDateFormat sdf = new SimpleDateFormat(EgovProperties.getProperty("common.date.type"));
strVal = sdf.format(dateValue);
}
else {
if (String.valueOf(cell.getNumericCellValue()).matches("[\\d]{1,}\\.0$"))
strVal = String.valueOf(Double.valueOf(cell.getNumericCellValue()).intValue());
else
strVal = String.valueOf(cell.getNumericCellValue());
}
break;
case FORMULA:
strVal = evaluator.evaluate(cell).getStringValue(); // .getCellFormula();
break;
case BOOLEAN:
if (cell.getBooleanCellValue())
strVal = "true";
else
strVal = "false";
break;
case ERROR:
case _NONE:
case BLANK:
strVal = "";
break;
default:
strVal = cell.getStringCellValue();
break;
}
excelCols.put(keyNm[cell.getColumnIndex()], strVal);
}
excelRows.add(excelCols);
}
excels.put(wb.getSheetName(i), excelRows);
}
}
catch (Exception ex) {
logger.error(ex.getMessage(), ex);
throw ex;
}
finally {
wb.close();
if (saveFile.exists())
saveFile.delete();
}
return excels;
}
/**
* 업로드 엑셀이 확장자가 xlsx 일경우
*
* @param savedFile
* @param keyNm
* @return
* @throws Exception
*/
@Deprecated
private static List<HashMap<String, String>> readExcelXlsx(File savedFile, String[] keyNm) throws Exception {
XSSFWorkbook wb = new XSSFWorkbook(new FileInputStream(savedFile));
List<HashMap<String, String>> excelRows = new ArrayList<HashMap<String, String>>();
try {
for (int i = 0; i < wb.getNumberOfSheets(); i++) {
for (Row row : wb.getSheetAt(i)) {
HashMap<String, String> excelCols = new HashMap<String, String>();
int cellCnt = 0;
String strVal = "";
for (Cell cell : row) {
switch (cell.getCellType()) {
case Cell.CELL_TYPE_STRING:
System.out.print(cell.getRichStringCellValue().getString());
strVal = cell.getRichStringCellValue().getString();
break;
case Cell.CELL_TYPE_NUMERIC:
if (DateUtil.isCellDateFormatted(cell)) {
java.util.Date dateValue = cell.getDateCellValue();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
System.out.print(format.format(dateValue)); // 2009-05-29
strVal = format.format(dateValue);
} else {
System.out.print(Double.valueOf(cell.getNumericCellValue()).intValue());
strVal = Double.valueOf(cell.getNumericCellValue()).intValue() + "";
}
break;
case Cell.CELL_TYPE_FORMULA:
System.out.print(cell.getCellFormula());
strVal = cell.getCellFormula();
break;
case Cell.CELL_TYPE_BOOLEAN:
System.out.print(cell.getBooleanCellValue());
if (cell.getBooleanCellValue()) {
strVal = "true";
} else {
strVal = "false";
}
break;
case Cell.CELL_TYPE_ERROR:
System.out.print(cell.getErrorCellValue());
break;
case Cell.CELL_TYPE_BLANK:
break;
default:
break;
}
excelCols.put(keyNm[cellCnt], strVal);
cellCnt++;
}
excelRows.add(excelCols);
}
}
}
catch (Exception ex) {
//ex.printStackTrace();
throw ex;
}
return excelRows;
}
/**
* 업로드 엑셀이 확장자가 xls 일경우
*
* @param savedFile
* @param keyNm
* @return
* @throws IOException
*/
@Deprecated
private static List<HashMap<String, String>> readExcelXls(File savedFile, String[] keyNm) throws Exception {
HSSFWorkbook wb = new HSSFWorkbook(new FileInputStream(savedFile));
List<HashMap<String, String>> excelDate = new ArrayList<HashMap<String, String>>();
try {
for (int i = 0; i < wb.getNumberOfSheets(); i++) {
for (Row row : wb.getSheetAt(i)) {
HashMap<String, String> dateMap = new HashMap<String, String>();
int cellCnt = 0;
String strVal = "";
for (Cell cell : row) {
switch (cell.getCellType()) {
case Cell.CELL_TYPE_STRING:
System.out.print(cell.getRichStringCellValue().getString());
strVal = cell.getRichStringCellValue().getString();
break;
case Cell.CELL_TYPE_NUMERIC:
if (DateUtil.isCellDateFormatted(cell)) {
java.util.Date dateValue = cell.getDateCellValue();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
System.out.print(format.format(dateValue)); // 2009-05-29
strVal = format.format(dateValue);
} else {
System.out.print(Double.valueOf(cell.getNumericCellValue()).intValue());
strVal = Double.valueOf(cell.getNumericCellValue()).intValue() + "";
}
break;
case Cell.CELL_TYPE_FORMULA:
System.out.print(cell.getCellFormula());
strVal = cell.getCellFormula();
break;
case Cell.CELL_TYPE_BOOLEAN:
System.out.print(cell.getBooleanCellValue());
if (cell.getBooleanCellValue()) {
strVal = "true";
} else {
strVal = "false";
}
break;
case Cell.CELL_TYPE_ERROR:
System.out.print(cell.getErrorCellValue());
break;
case Cell.CELL_TYPE_BLANK:
break;
default:
break;
}
System.out.print("\t");
dateMap.put(keyNm[cellCnt], strVal);
cellCnt++;
}
excelDate.add(dateMap);
System.out.println();
}
}
} catch (Exception ex) {
//ex.printStackTrace();
throw ex;
}
return excelDate;
}
private static List<HashMap<String, String>> readOnlyExcel(File saveFile, String[] keyNm, int startRecord) throws Exception {
Workbook wb = WorkbookFactory.create(saveFile);
wb.setMissingCellPolicy(MissingCellPolicy.CREATE_NULL_AS_BLANK);
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
List<HashMap<String, String>> excelRows = new ArrayList<HashMap<String, String>>();
boolean hasKeyName = true;
if (keyNm == null)
hasKeyName = false;
try {
//hashmap용 key이름이 없을 경우 엑셀 1st row를 key 이름으로 설정
if (!hasKeyName && wb.getSheetAt(0).getLastRowNum() > 0) {
keyNm = new String[wb.getSheetAt(0).getRow(0).getLastCellNum()];
for (int i = 0; i < wb.getSheetAt(0).getRow(0).getLastCellNum(); i++)
try {
keyNm[i] = wb.getSheetAt(0).getRow(0).getCell(i).getStringCellValue();
}
catch (Exception e) {
keyNm[i] = "";
}
}
//int iRow = 0;
for (Row row : wb.getSheetAt(0)) {
//logger.debug(">>>>>>>>>>>>> excel row : {}", ++iRow);
if (!hasKeyName && row.getRowNum() == 0)
continue;
if (startRecord > row.getRowNum() + 1)
continue;
HashMap<String, String> excelCols = new HashMap<String, String>();
//주의 : foreach를 사용할 경우 컬럼이 빈 값이면 해당 컬럼 자제가 없어짐 (컬럼 인덱스가 달라짐)
for (int i = 0; i < row.getLastCellNum(); i++) {
//cell을 가져올 때 MissingCellPolicy.CREATE_NULL_AS_BLANK 옵션 사용 필수 : 빈 컬럼일 때도 빈 값을 가져옴. poi v3.16이상 지원
Cell cell = row.getCell(i, MissingCellPolicy.CREATE_NULL_AS_BLANK);
String strVal = "";
//logger.debug(">>>>> {}, {}, {}", cell.getColumnIndex(), keyNm[cell.getColumnIndex()], cell.getCellTypeEnum().equals(CellType.NUMERIC) ? cell.getNumericCellValue() : cell.getStringCellValue());
switch (cell.getCellTypeEnum()) {
case NUMERIC:
if (DateUtil.isCellDateFormatted(cell)) {
java.util.Date dateValue = cell.getDateCellValue();
SimpleDateFormat sdf = new SimpleDateFormat(EgovProperties.getProperty("common.date.type"));
strVal = sdf.format(dateValue);
}
else {
if (String.valueOf(cell.getNumericCellValue()).matches("[\\d]{1,}\\.0$"))
strVal = String.valueOf(Double.valueOf(cell.getNumericCellValue()).intValue());
else
strVal = String.valueOf(cell.getNumericCellValue());
}
break;
case FORMULA:
strVal = evaluator.evaluate(cell).getStringValue(); // .getCellFormula();
break;
case BOOLEAN:
if (cell.getBooleanCellValue())
strVal = "true";
else
strVal = "false";
break;
// case Cell.CELL_TYPE_ERROR:
// break;
//
case _NONE:
case BLANK:
strVal = "";
break;
default:
strVal = cell.getStringCellValue();
break;
}
//issue : 컬럼 헤더 개수와 레코드 컬럼 개수가 맞지 않는 문제 발생
if ((i + 1) <= keyNm.length)
excelCols.put(keyNm[cell.getColumnIndex()], strVal);
}
//logger.debug(">>>>>>>>>>>>> excelCols : {}", excelCols.toString());
excelRows.add(excelCols);
}
//logger.debug(">>>>>>>>>> saveFile : {}", saveFile.getAbsolutePath());
}
catch (Exception ex) {
logger.error(ex.getMessage(), ex);
throw ex;
}
finally {
wb.close();
if (saveFile.exists())
saveFile.delete();
}
return excelRows;
}
}