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
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));
|
|
}
|
|
// 다른 타입에 따른 맵핑을 추가할 수 있습니다.
|
|
}
|
|
|
|
}
|