You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

116 lines
3.8 KiB
Java

package egovframework.util.excel;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
@Slf4j
public class ExcelHandler<T> {
public List<T> handleExcelUpload(List<MultipartFile> mFiles, Class<T> clazz) {
List<T> dataList = new ArrayList<>();
mFiles.forEach(file -> {
try (InputStream inputStream = file.getInputStream()) {
dataList.addAll(parseExcel(inputStream, clazz));
} catch (IOException e) {
throw new RuntimeException(e);
}
});
return dataList;
}
private List<T> parseExcel(InputStream inputStream, Class<T> clazz) throws IOException {
Workbook workbook = new XSSFWorkbook(inputStream);
Sheet sheet = workbook.getSheetAt(0); // 첫 번째 시트를 가져옴
// 헤더 정보 추출
Row headerRow = sheet.getRow(0);
List<String> headers = StreamSupport.stream(headerRow.spliterator(), false)
.map(Cell::getStringCellValue)
.collect(Collectors.toList());
List<T> dataList = StreamSupport.stream(sheet.spliterator(), false)
.skip(1) // 첫 번째 행은 헤더이므로 건너뜁니다.
.filter(this::isRowNotEmpty) // 빈 행이 아닌 경우에만 처리합니다.
.map(row -> mapRowToDto(row, clazz, headers))
.collect(Collectors.toList());
workbook.close();
return dataList;
}
private boolean isRowNotEmpty(Row row) {
Iterator<Cell> cellIterator = row.cellIterator();
while (cellIterator.hasNext()) {
Cell cell = cellIterator.next();
if (cell.getCellType() != CellType.BLANK) {
return true; // 빈 셀이 아닌 경우에만 true를 반환합니다.
}
}
return false; // 모든 셀이 비어 있으면 false를 반환합니다.
}
private T mapRowToDto(Row row, Class<T> clazz, List<String> excelHeaderList) {
T dataDto;
try {
dataDto = clazz.getDeclaredConstructor().newInstance();
Iterator<Cell> cellIterator = row.cellIterator();
while (cellIterator.hasNext()) {
Cell cell = cellIterator.next();
String excelHeaderName = excelHeaderList.get(cell.getColumnIndex());
//각 필드를 순회하며 커스텀 어노테이션인 ExcelHeader값에 맞게 값을 넣어줌
Field[] dtoFields = clazz.getDeclaredFields();
for (Field field : dtoFields) {
if (field.isAnnotationPresent(ExcelColumn.class)) {
ExcelColumn annotation = field.getAnnotation(ExcelColumn.class);
if (Objects.requireNonNull(annotation).headerName().equals(excelHeaderName)) {
field.setAccessible(true);
setFieldValue(field, dataDto, cell);
break;
}
}
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return dataDto;
}
private void setFieldValue(Field field, T dataDto, Cell cell) throws IllegalAccessException {
Class<?> fieldType = field.getType();
field.setAccessible(true);
if (fieldType == int.class || fieldType == Integer.class) {
field.set(dataDto, (int)cell.getNumericCellValue());
} else if (fieldType == long.class || fieldType == Long.class) {
field.set(dataDto, (long)cell.getNumericCellValue());
} else if (fieldType == double.class || fieldType == Double.class) {
field.set(dataDto, cell.getNumericCellValue());
} else if (fieldType == boolean.class || fieldType == Boolean.class) {
field.set(dataDto, cell.getBooleanCellValue());
} else {
// if (fieldType == String.class) {
DataFormatter formatter = new DataFormatter();
field.set(dataDto, formatter.formatCellValue(cell));
}
// 다른 타입에 따른 맵핑을 추가할 수 있습니다.
}
}