Читать конкретный лист, используя пружинную партию?
Какой способ чтения конкретного листа из файла Excel с использованием Spring-Batch-Excel?
В частности, я хочу проанализировать различные листы в файле Excel по-разному, используя org.springframework.batch.item.excel.poi.PoiItemReader
,
Я не вижу, как это сделать с PoiItemReader
, в том, что кажется, чтобы прочитать каждый лист в документе. Есть ли способ обрабатывать листы по-разному в маппере строк? Возможно ли это без написания специального считывателя POI?
2 ответа
Ни в коем случае, не написав пользовательский ридер
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.FormulaEvaluator;
import org.apache.poi.ss.usermodel.Row;
import org.springframework.batch.extensions.excel.Sheet;
import org.springframework.lang.Nullable;
public class PoiSheet implements Sheet {
private final DataFormatter dataFormatter = new DataFormatter();
private final org.apache.poi.ss.usermodel.Sheet delegate;
private final int numberOfRows;
private final String name;
private FormulaEvaluator evaluator;
/**
* Constructor which takes the delegate sheet.
* @param delegate the apache POI sheet
*/
PoiSheet(final org.apache.poi.ss.usermodel.Sheet delegate) {
super();
this.delegate = delegate;
this.numberOfRows = this.delegate.getLastRowNum() + 1;
this.name = this.delegate.getSheetName();
}
/**
* {@inheritDoc}
*/
@Override
public int getNumberOfRows() {
return this.numberOfRows;
}
/**
* {@inheritDoc}
*/
@Override
public String getName() {
return this.name;
}
/**
* {@inheritDoc}
*/
@Override
@Nullable
public String[] getRow(final int rowNumber) {
final Row row = this.delegate.getRow(rowNumber);
return map(row);
}
@Nullable
private String[] map(Row row) {
if (row == null) {
return null;
}
final List<String> cells = new LinkedList<>();
final int numberOfColumns = row.getLastCellNum();
for (int i = 0; i < numberOfColumns; i++) {
Cell cell = row.getCell(i);
CellType cellType = cell.getCellType();
if (cellType == CellType.FORMULA) {
cells.add(this.dataFormatter.formatCellValue(cell, getFormulaEvaluator()));
}
else {
cells.add(this.dataFormatter.formatCellValue(cell));
}
}
return cells.toArray(new String[0]);
}
/**
* Lazy getter for the {@code FormulaEvaluator}. Takes some time to create an
* instance, so if not necessary don't create it.
* @return the {@code FormulaEvaluator}
*/
private FormulaEvaluator getFormulaEvaluator() {
if (this.evaluator == null) {
this.evaluator = this.delegate.getWorkbook().getCreationHelper().createFormulaEvaluator();
}
return this.evaluator;
}
@Override
public Iterator<String[]> iterator() {
return new Iterator<String[]>() {
private final Iterator<Row> delegateIter = PoiSheet.this.delegate.iterator();
@Override
public boolean hasNext() {
return this.delegateIter.hasNext();
}
@Override
public String[] next() {
return map(this.delegateIter.next());
}
};
}
}
Читатель Excel
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.springframework.batch.extensions.excel.AbstractExcelItemReader;
import org.springframework.batch.extensions.excel.Sheet;
import org.springframework.core.io.Resource;
public class ExcelSheetItemReader <T> extends AbstractExcelItemReader<T> {
private Workbook workbook;
private InputStream inputStream;
private int sheetIndex = 0;
@Override
protected Sheet getSheet(final int sheet) {
return new PoiSheet(this.workbook.getSheetAt(sheetIndex));
}
@Override
protected int getNumberOfSheets() {
return 1;
}
@Override
protected void doClose() throws Exception {
super.doClose();
if (this.inputStream != null) {
this.inputStream.close();
this.inputStream = null;
}
if (this.workbook != null) {
this.workbook.close();
this.workbook = null;
}
}
/**
* Open the underlying file using the {@code WorkbookFactory}. Prefer {@code File}
* based access over an {@code InputStream}. Using a file will use fewer resources
* compared to an input stream. The latter will need to cache the whole sheet
* in-memory.
* @param resource the {@code Resource} pointing to the Excel file.
* @param password the password for opening the file
* @throws Exception is thrown for any errors.
*/
@Override
protected void openExcelFile(final Resource resource, String password) throws Exception {
try {
File file = resource.getFile();
this.workbook = WorkbookFactory.create(file, password, false);
}
catch (FileNotFoundException ex) {
this.inputStream = resource.getInputStream();
this.workbook = WorkbookFactory.create(this.inputStream, password);
}
this.workbook.setMissingCellPolicy(Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
}
public int getSheetIndex() {
return sheetIndex;
}
public void setSheetIndex(int sheetIndex) {
this.sheetIndex = sheetIndex;
}
}
Другой пример можно найти здесь
Это открытый вопрос, который на момент написания этого ответа еще не был решен.
https://github.com/spring-projects/spring-batch-extensions/issues/17