[DEV] 기록

[Java] 엑셀 데이터 읽어오는 코드

꾸준함. 2022. 10. 15. 02:53

개요

기존에 Apache Poi 라이브러리를 활용해 업로드된 엑셀 데이터를 읽은 뒤 처리하는 코드가 있었는데 fastexcel 라이브러리로 생성된 엑셀을 읽어오지 못하는 문제가 발생했습니다.

이에 따라 fastexcel 라이브러리를 활용해 엑셀 데이터를 읽어오는 코드를 구현했고 테스트한 결과 모든 엑셀을 읽어올 수 있었습니다.

fastexcel 라이브러리 관련해서는 아래 글을 참고해주세요.

https://jaimemin.tistory.com/2191

 

[SpringBoot + Fastexcel] 대용량 엑셀 생성 및 다운로드

개요 여태까지 엑셀 생성 및 다운로드 기능을 구현할 때 Apache Poi 라이브러리를 사용했었고 이와 관련하여 게시글을 여러 번 남겼습니다. https://jaimemin.tistory.com/2069 [SpringBoot] 대용량 엑셀 파일 생

jaimemin.tistory.com

 

코드

모든 엑셀 파일에 대해서 읽어올 수 있어야하므로 자바 Generic을 적용하여 코드를 작성했습니다.

코드가 정상적으로 작동하기 위해서는 아래의 fastexcel-reader 라이브러리가 추가되어 있어야 합니다!

<dependency>
    <groupId>org.dhatim</groupId>
    <artifactId>fastexcel-reader</artifactId>
    <version>0.12.3</version>
</dependency>

 

FastExcelReader.java

 

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.dhatim.fastexcel.reader.Cell;
import org.dhatim.fastexcel.reader.ReadableWorkbook;
import org.dhatim.fastexcel.reader.Row;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
@Slf4j
public class FastExcelReader {
public static <E> List<E> read(InputStream is, ExcelReadOption excelReadOption, Class<E> classType) {
List<E> result = new ArrayList<>();
if (ObjectUtils.isEmpty(is)) {
return result;
}
try (ReadableWorkbook wb = new ReadableWorkbook(is)) {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false);
objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
final Map<String, Type> cells = excelReadOption.getOutputColumns();
int startRow = excelReadOption.getStartRow() < 0 ? 0 : excelReadOption.getStartRow();
wb.getSheets().forEach(sheet -> {
try (Stream<Row> rows = sheet.openStream()) {
/**
* 각 sheet당 첫 번째 row는 header
*/
rows.skip(startRow).forEach(row -> {
AtomicInteger index = new AtomicInteger();
/**
* 각 row마다의 값을 저장할 맵 객체 저장되는 형식은 다음과 같다. put("A", "이름"); put("B", "게임명");
*/
Map<String, Object> rowData = new LinkedHashMap<>();
cells.forEach((key, val) -> {
Object refVal;
if (val.equals(Integer.class)
|| val.equals(Double.class)
|| val.equals(Long.class)) {
BigDecimal bigDecimal = row.getCellAsNumber(index.getAndIncrement()).orElse(null);
refVal = getRefVal(val, bigDecimal);
} else if (val.equals(LocalDateTime.class) || val.equals(Date.class)) {
refVal = row.getCellAsDate(index.getAndIncrement()).orElse(null);
} else if (val.equals(Boolean.class)) {
refVal = row.getCellAsBoolean(index.getAndIncrement()).orElse(null);
} else {
Cell cell = row.getCell(index.getAndIncrement());
refVal = cell.getValue() + "";
// [FastExcelReader.read] ERROR Wrong cell type NUMBER, wanted STRING
// refVal = row.getCellAsString(index.getAndIncrement()).orElse("-");
}
rowData.put(key, refVal);
});
E o = objectMapper.convertValue(rowData, classType);
result.add(o);
});
} catch (IOException e) {
log.error("[FastExcelReader.read] ERROR {}", e.getMessage());
}
});
return result;
} catch (Exception e) {
log.error("[FastExcelReader.read] ERROR {}", e.getMessage());
}
return result;
}
private static Object getRefVal(Type val, BigDecimal bigDecimal) {
Object refVal;
if (bigDecimal == null) {
refVal = 0;
} else {
if (val.equals(Integer.class)) {
refVal = bigDecimal.intValue();
} else if (val.equals(Double.class)) {
refVal = bigDecimal.doubleValue();
} else if (val.equals(Long.class)) {
refVal = bigDecimal.longValue();
} else {
refVal = 0;
}
}
return refVal;
}
}
view raw .java hosted with ❤ by GitHub

 

ExcelReadOption.java


@Data
@Builder
public class ExcelReadOption {
/**
* 추출할 컬럼 명
*/
private Map<String, Type> outputColumns;
/**
* 추출을 시작할 행 번호
*/
private int startRow;
}
view raw .java hosted with ❤ by GitHub

 

예시 코드


// 칼럼이 총 6개 존재하는 엑셀을 읽어오는
private List<Sample> convertMultipartFileToExcelList(MultipartFile excelFile) {
ExcelReadOption option = ExcelReadOption.builder()
.startRow(1)
.outputColumns(Sample.getColumnMap())
.build();
List<Sample> inputList = new ArrayList<>();
try {
inputList = FastExcelReader.read(excelFile.getInputStream(), option, Sample.class);
} catch (Exception e) {
log.error("[convertMultipartFileToExcelList] ERROR {}", e.getMessage());
}
return inputList;
}
@Getter
@Setter
public class Sample {
private String a;
private String b;
private String c;
private String d;
private String e;
private String f;
public Sample() {
}
public static Map<String, Type> getColumnMap() {
Map<String, Type> map = new LinkedHashMap<>();
map.put("a", String.class);
map.put("b", String.class);
map.put("c", String.class);
map.put("d", String.class);
map.put("e", String.class);
map.put("f", String.class);
return map;
}
}
view raw .java hosted with ❤ by GitHub

 

반응형