forked from p81075629/datagear
[analysis]完善Excel数据集类
This commit is contained in:
parent
bb30b3a1d7
commit
69dd024ef7
|
@ -111,6 +111,17 @@ public abstract class AbstractDataSet extends AbstractIdentifiable implements Da
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析属性类型。
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
protected String resolveDataType(Object value)
|
||||
{
|
||||
return DataSetProperty.DataType.resolveDataType(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定名称的{@linkplain DataNameType}对象,没找到则返回{@code null}。
|
||||
*
|
||||
|
|
|
@ -8,33 +8,57 @@
|
|||
package org.datagear.analysis.support;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.hssf.util.CellReference;
|
||||
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
|
||||
import org.apache.poi.openxml4j.opc.OPCPackage;
|
||||
import org.apache.poi.openxml4j.opc.PackageAccess;
|
||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.CellType;
|
||||
import org.apache.poi.ss.usermodel.DateUtil;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.datagear.analysis.DataSetException;
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.analysis.DataSetResult;
|
||||
import org.datagear.analysis.ResolvableDataSet;
|
||||
import org.datagear.analysis.ResolvedDataSetResult;
|
||||
import org.datagear.analysis.support.RangeExpResolver.IndexRange;
|
||||
import org.datagear.analysis.support.RangeExpResolver.Range;
|
||||
import org.datagear.util.FileUtil;
|
||||
import org.datagear.util.IOUtil;
|
||||
import org.datagear.util.StringUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 抽象Excel数据集。
|
||||
* <p>
|
||||
* 此类仅支持从Excel的单个sheet读取数据,具体参考{@linkplain #setSheetIndex(int)}。
|
||||
* </p>
|
||||
* <p>
|
||||
* 通过{@linkplain #setDataRowExp(String)}、{@linkplain #setDataColumnExp(String)}来设置读取行、列范围。
|
||||
* </p>
|
||||
* <p>
|
||||
* 通过{@linkplain #setNameRow(int)}可设置名称行。
|
||||
* </p>
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractExcelDataSet extends AbstractFmkTemplateDataSet implements ResolvableDataSet
|
||||
{
|
||||
protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractExcelDataSet.class);
|
||||
|
||||
public static final String EXTENSION_XLSX = "xlsx";
|
||||
|
||||
public static final String EXTENSION_XLS = "xls";
|
||||
|
@ -42,11 +66,11 @@ public abstract class AbstractExcelDataSet extends AbstractFmkTemplateDataSet im
|
|||
protected static final RangeExpResolver RANGE_EXP_RESOLVER = RangeExpResolver
|
||||
.valueOf(RangeExpResolver.RANGE_SPLITTER_CHAR, RangeExpResolver.RANGE_GROUP_SPLITTER_CHAR);
|
||||
|
||||
/** 是否强制作为xls文件处理 */
|
||||
private boolean forceXls = false;
|
||||
/** 此数据集所处的sheet索引号(以0计数) */
|
||||
private int sheetIndex = 0;
|
||||
|
||||
/** 作为标题行的行号 */
|
||||
private int titleRow = -1;
|
||||
/** 作为名称行的行号 */
|
||||
private int nameRow = -1;
|
||||
|
||||
/** 数据行范围表达式 */
|
||||
private String dataRowExp = null;
|
||||
|
@ -54,7 +78,11 @@ public abstract class AbstractExcelDataSet extends AbstractFmkTemplateDataSet im
|
|||
/** 数据列范围表达式 */
|
||||
private String dataColumnExp = null;
|
||||
|
||||
/** 是否强制作为xls文件处理 */
|
||||
private boolean forceXls = false;
|
||||
|
||||
private transient List<IndexRange> _dataRowRanges = null;
|
||||
private transient List<IndexRange> _dataColumnRanges = null;
|
||||
|
||||
public AbstractExcelDataSet()
|
||||
{
|
||||
|
@ -72,55 +100,51 @@ public abstract class AbstractExcelDataSet extends AbstractFmkTemplateDataSet im
|
|||
super(id, name, properties);
|
||||
}
|
||||
|
||||
public int getSheetIndex()
|
||||
{
|
||||
return sheetIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否强制作为xls文件处理。
|
||||
* 设置此数据集所处的sheet索引号。
|
||||
*
|
||||
* @param sheetIndex
|
||||
* 索引号(以{@code 0}计数)
|
||||
*/
|
||||
public void setSheetIndex(int sheetIndex)
|
||||
{
|
||||
this.sheetIndex = sheetIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否有名称行。
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isForceXls()
|
||||
public boolean hasNameRow()
|
||||
{
|
||||
return forceXls;
|
||||
return (this.nameRow > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否强制作为xls文件处理,如果为{@code false},则根据文件扩展名判断。
|
||||
*
|
||||
* @param forceXls
|
||||
*/
|
||||
public void setForceXls(boolean forceXls)
|
||||
{
|
||||
this.forceXls = forceXls;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否有标题行。
|
||||
* 获取作为名称行的行号。
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean hasTitleRow()
|
||||
public int getNameRow()
|
||||
{
|
||||
return (this.titleRow > 0);
|
||||
return nameRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取作为标题行的行号。
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getTitleRow()
|
||||
{
|
||||
return titleRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置作为标题行的行号。
|
||||
* 设置作为名称行的行号。
|
||||
*
|
||||
* @param titleRow
|
||||
* 行号,小于{@code 1}则表示无标题行。
|
||||
* 行号,小于{@code 1}则表示无名称行。
|
||||
*/
|
||||
public void setTitleRow(int titleRow)
|
||||
public void setNameRow(int titleRow)
|
||||
{
|
||||
this.titleRow = titleRow;
|
||||
this.nameRow = titleRow;
|
||||
}
|
||||
|
||||
public String getDataRowExp()
|
||||
|
@ -139,7 +163,7 @@ public abstract class AbstractExcelDataSet extends AbstractFmkTemplateDataSet im
|
|||
* {@code "1,4,8-15"}:第1、4、8至15行
|
||||
* </p>
|
||||
* <p>
|
||||
* 标题行({@linkplain #getTitleRow()})将自动被排除。
|
||||
* 标题行({@linkplain #getNameRow()})将自动被排除。
|
||||
* </p>
|
||||
* <p>
|
||||
* 注意:行号以{@code 1}开始计数。
|
||||
|
@ -151,18 +175,7 @@ public abstract class AbstractExcelDataSet extends AbstractFmkTemplateDataSet im
|
|||
public void setDataRowExp(String dataRowExp)
|
||||
{
|
||||
this.dataRowExp = dataRowExp;
|
||||
|
||||
if (!StringUtil.isEmpty(dataRowExp))
|
||||
{
|
||||
try
|
||||
{
|
||||
this._dataRowRanges = getRangeExpResolver().resolveIndex(this.dataRowExp);
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
throw new DataSetException(e);
|
||||
}
|
||||
}
|
||||
this._dataRowRanges = getRangeExpResolver().resolveIndex(this.dataRowExp);
|
||||
}
|
||||
|
||||
public String getDataColumnExp()
|
||||
|
@ -187,6 +200,27 @@ public abstract class AbstractExcelDataSet extends AbstractFmkTemplateDataSet im
|
|||
public void setDataColumnExp(String dataColumnExp)
|
||||
{
|
||||
this.dataColumnExp = dataColumnExp;
|
||||
this._dataColumnRanges = resolveDataColumnRanges(dataColumnExp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否强制作为xls文件处理。
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isForceXls()
|
||||
{
|
||||
return forceXls;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否强制作为xls文件处理,如果为{@code false},则根据文件扩展名判断。
|
||||
*
|
||||
* @param forceXls
|
||||
*/
|
||||
public void setForceXls(boolean forceXls)
|
||||
{
|
||||
this.forceXls = forceXls;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -244,9 +278,6 @@ public abstract class AbstractExcelDataSet extends AbstractFmkTemplateDataSet im
|
|||
protected ResolvedDataSetResult resolveResultForXls(Map<String, ?> paramValues, File file,
|
||||
List<DataSetProperty> properties) throws DataSetException
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = Collections.EMPTY_LIST;
|
||||
|
||||
POIFSFileSystem poifs = null;
|
||||
|
||||
try
|
||||
|
@ -254,41 +285,18 @@ public abstract class AbstractExcelDataSet extends AbstractFmkTemplateDataSet im
|
|||
poifs = new POIFSFileSystem(file, true);
|
||||
HSSFWorkbook wb = new HSSFWorkbook(poifs.getRoot(), true);
|
||||
|
||||
HSSFSheet sheet = wb.getSheetAt(0);
|
||||
Sheet sheet = wb.getSheetAt(getSheetIndex());
|
||||
|
||||
int rowIdx = 0;
|
||||
for (Row row : sheet)
|
||||
{
|
||||
if (isDataRow(rowIdx))
|
||||
{
|
||||
int cellIdx = 0;
|
||||
|
||||
for (Cell cell : row)
|
||||
{
|
||||
if (isDataColumn(cellIdx))
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rowIdx++;
|
||||
}
|
||||
return resolveResultForSheet(paramValues, sheet, properties);
|
||||
}
|
||||
catch (DataSetException e)
|
||||
catch (IOException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
throw new DataSetSourceParseException(t);
|
||||
throw new DataSetSourceParseException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtil.close(poifs);
|
||||
}
|
||||
|
||||
return new ResolvedDataSetResult(new DataSetResult(data), properties);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -304,7 +312,315 @@ public abstract class AbstractExcelDataSet extends AbstractFmkTemplateDataSet im
|
|||
protected ResolvedDataSetResult resolveResultForXlsx(Map<String, ?> paramValues, File file,
|
||||
List<DataSetProperty> properties) throws DataSetException
|
||||
{
|
||||
return null;
|
||||
OPCPackage pkg = null;
|
||||
XSSFWorkbook wb = null;
|
||||
|
||||
try
|
||||
{
|
||||
pkg = OPCPackage.open(file, PackageAccess.READ);
|
||||
wb = new XSSFWorkbook(pkg);
|
||||
|
||||
Sheet sheet = wb.getSheetAt(getSheetIndex());
|
||||
|
||||
return resolveResultForSheet(paramValues, sheet, properties);
|
||||
}
|
||||
catch (IOException | InvalidFormatException e)
|
||||
{
|
||||
throw new DataSetSourceParseException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtil.close(wb);
|
||||
IOUtil.close(pkg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析sheet结果。
|
||||
*
|
||||
* @param paramValues
|
||||
* @param sheet
|
||||
* @param properties
|
||||
* 允许为{@code null},此时会自动解析
|
||||
* @return
|
||||
* @throws DataSetException
|
||||
*/
|
||||
protected ResolvedDataSetResult resolveResultForSheet(Map<String, ?> paramValues, Sheet sheet,
|
||||
List<DataSetProperty> properties) throws DataSetException
|
||||
{
|
||||
boolean resolveProperties = (properties == null || properties.isEmpty());
|
||||
|
||||
if (resolveProperties)
|
||||
properties = new ArrayList<>();
|
||||
|
||||
List<List<Object>> data = new ArrayList<>();
|
||||
|
||||
List<String> propertyNames = null;
|
||||
|
||||
try
|
||||
{
|
||||
int rowIdx = 0;
|
||||
int dataRowIdx = 0;
|
||||
|
||||
for (Row row : sheet)
|
||||
{
|
||||
if (isNameRow(rowIdx))
|
||||
{
|
||||
if (resolveProperties)
|
||||
propertyNames = resolveDataSetPropertyNames(row, false);
|
||||
}
|
||||
else if (isDataRow(rowIdx))
|
||||
{
|
||||
if (resolveProperties && dataRowIdx == 0 && propertyNames == null)
|
||||
propertyNames = resolveDataSetPropertyNames(row, true);
|
||||
|
||||
// 名称行不一定在数据行之前,此时可能还无法确定属性名,所以暂时采用列表存储
|
||||
List<Object> rowObj = new ArrayList<>();
|
||||
|
||||
int colIdx = 0;
|
||||
int dataColIdx = 0;
|
||||
|
||||
for (Cell cell : row)
|
||||
{
|
||||
if (isDataColumn(colIdx))
|
||||
{
|
||||
DataSetProperty property = null;
|
||||
|
||||
if (!resolveProperties)
|
||||
{
|
||||
if (dataColIdx >= properties.size())
|
||||
throw new DataSetSourceParseException(
|
||||
"No property defined for column index " + dataColIdx);
|
||||
|
||||
property = properties.get(dataRowIdx);
|
||||
}
|
||||
|
||||
Object value = resolvePropertyValue(cell, property);
|
||||
|
||||
if (resolveProperties)
|
||||
{
|
||||
property = resolveDataSetProperty(row, rowIdx, dataRowIdx, cell, colIdx, dataColIdx,
|
||||
value, properties);
|
||||
}
|
||||
|
||||
rowObj.add(value);
|
||||
|
||||
dataColIdx++;
|
||||
}
|
||||
|
||||
colIdx++;
|
||||
}
|
||||
|
||||
data.add(rowObj);
|
||||
|
||||
dataRowIdx++;
|
||||
}
|
||||
|
||||
rowIdx++;
|
||||
}
|
||||
}
|
||||
catch (DataSetException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
throw new DataSetSourceParseException(t);
|
||||
}
|
||||
|
||||
if (resolveProperties)
|
||||
inflateDataSetProperties(properties, propertyNames);
|
||||
|
||||
DataSetResult result = new DataSetResult(rowListToMap(data, properties));
|
||||
|
||||
return new ResolvedDataSetResult(result, properties);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected List<Map<String, Object>> rowListToMap(List<List<Object>> data, List<DataSetProperty> dataSetProperties)
|
||||
{
|
||||
if (data == null)
|
||||
return Collections.EMPTY_LIST;
|
||||
|
||||
List<Map<String, Object>> maps = new ArrayList<>(data.size());
|
||||
|
||||
for (List<Object> row : data)
|
||||
{
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
|
||||
for (int i = 0; i < row.size(); i++)
|
||||
{
|
||||
String name = dataSetProperties.get(i).getName();
|
||||
map.put(name, row.get(i));
|
||||
}
|
||||
|
||||
maps.add(map);
|
||||
}
|
||||
|
||||
return maps;
|
||||
}
|
||||
|
||||
protected void inflateDataSetProperties(List<DataSetProperty> properties, List<String> propertyNames)
|
||||
{
|
||||
for (int i = 0; i < properties.size(); i++)
|
||||
{
|
||||
DataSetProperty property = properties.get(i);
|
||||
property.setName(propertyNames.get(i));
|
||||
|
||||
if (StringUtil.isEmpty(property.getType()))
|
||||
property.setType(DataSetProperty.DataType.UNKNOWN);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析{@linkplain DataSetProperty}并写入{@code properties}。
|
||||
*
|
||||
* @param row
|
||||
* @param rowIdx
|
||||
* @param dataRowIdx
|
||||
* @param cell
|
||||
* @param colIdx
|
||||
* @param dataColIdx
|
||||
* @param cellValue
|
||||
* @param properties
|
||||
* @return
|
||||
*/
|
||||
protected DataSetProperty resolveDataSetProperty(Row row, int rowIdx, int dataRowIdx, Cell cell, int colIdx,
|
||||
int dataColIdx, Object cellValue, List<DataSetProperty> properties)
|
||||
{
|
||||
DataSetProperty property = null;
|
||||
|
||||
if (dataRowIdx == 0)
|
||||
{
|
||||
// 空单元格先不处理数据类型,等待后续有非空单元格再判断
|
||||
String dataType = (cellValue == null ? "" : resolveDataType(cellValue));
|
||||
|
||||
// 名称行不一定在数据行之前,所以此时可能无法确定属性名
|
||||
property = new DataSetProperty("should-be-set-later", dataType);
|
||||
properties.add(property);
|
||||
}
|
||||
else
|
||||
{
|
||||
property = properties.get(dataColIdx);
|
||||
|
||||
if (StringUtil.isEmpty(property.getType()) && cellValue != null)
|
||||
property.setType(resolveDataType(cellValue));
|
||||
}
|
||||
|
||||
return property;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析属性名。
|
||||
*
|
||||
* @param nameRow
|
||||
* @return
|
||||
*/
|
||||
protected List<String> resolveDataSetPropertyNames(Row nameRow, boolean forceColumnString)
|
||||
{
|
||||
List<String> propertyNames = new ArrayList<>();
|
||||
|
||||
int colIdx = 0;
|
||||
for (Cell cell : nameRow)
|
||||
{
|
||||
if (isDataColumn(colIdx))
|
||||
{
|
||||
String name = null;
|
||||
|
||||
if (forceColumnString)
|
||||
name = CellReference.convertNumToColString(colIdx);
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
name = cell.getStringCellValue();
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
}
|
||||
|
||||
if (StringUtil.isEmpty(name))
|
||||
name = CellReference.convertNumToColString(colIdx);
|
||||
}
|
||||
|
||||
propertyNames.add(name);
|
||||
}
|
||||
|
||||
colIdx++;
|
||||
}
|
||||
|
||||
return propertyNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析单元格属性值。
|
||||
*
|
||||
* @param cell
|
||||
* @param property
|
||||
* 允许为{@code null}
|
||||
* @return
|
||||
* @throws DataSetSourceParseException
|
||||
* @throws DataSetException
|
||||
*/
|
||||
protected Object resolvePropertyValue(Cell cell, DataSetProperty property)
|
||||
throws DataSetSourceParseException, DataSetException
|
||||
{
|
||||
CellType cellType = cell.getCellTypeEnum();
|
||||
|
||||
Object cellValue = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (CellType.BLANK.equals(cellType))
|
||||
{
|
||||
cellValue = null;
|
||||
}
|
||||
else if (CellType.BOOLEAN.equals(cellType))
|
||||
{
|
||||
cellValue = cell.getBooleanCellValue();
|
||||
}
|
||||
else if (CellType.ERROR.equals(cellType))
|
||||
{
|
||||
cellValue = cell.getErrorCellValue();
|
||||
}
|
||||
else if (CellType.FORMULA.equals(cellType))
|
||||
{
|
||||
cellValue = cell.getCellFormula();
|
||||
}
|
||||
else if (CellType.NUMERIC.equals(cellType))
|
||||
{
|
||||
if (DateUtil.isCellDateFormatted(cell))
|
||||
cellValue = cell.getDateCellValue();
|
||||
else
|
||||
cellValue = cell.getNumericCellValue();
|
||||
}
|
||||
else if (CellType.STRING.equals(cellType))
|
||||
{
|
||||
cellValue = cell.getStringCellValue();
|
||||
}
|
||||
}
|
||||
catch (DataSetException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
throw new DataSetSourceParseException(t);
|
||||
}
|
||||
|
||||
return cellValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否名称行
|
||||
*
|
||||
* @param rowIndex
|
||||
* 行索引(以{@code 0}计数)
|
||||
* @return
|
||||
*/
|
||||
protected boolean isNameRow(int rowIndex)
|
||||
{
|
||||
return ((rowIndex + 1) == this.nameRow);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -316,19 +632,13 @@ public abstract class AbstractExcelDataSet extends AbstractFmkTemplateDataSet im
|
|||
*/
|
||||
protected boolean isDataRow(int rowIndex)
|
||||
{
|
||||
int row = rowIndex + 1;
|
||||
|
||||
if (hasTitleRow() && row == getTitleRow())
|
||||
if (isNameRow(rowIndex))
|
||||
return false;
|
||||
|
||||
if (this._dataRowRanges == null || this._dataRowRanges.isEmpty())
|
||||
return true;
|
||||
|
||||
for (int i = 0; i < this._dataRowRanges.size(); i++)
|
||||
if (this._dataRowRanges.get(i).inRange(row))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return IndexRange.includes(this._dataRowRanges, rowIndex + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -340,8 +650,40 @@ public abstract class AbstractExcelDataSet extends AbstractFmkTemplateDataSet im
|
|||
*/
|
||||
protected boolean isDataColumn(int columnIndex)
|
||||
{
|
||||
// TODO
|
||||
return true;
|
||||
if (this._dataColumnRanges == null || this._dataColumnRanges.isEmpty())
|
||||
return true;
|
||||
|
||||
return IndexRange.includes(this._dataColumnRanges, columnIndex);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected List<IndexRange> resolveDataColumnRanges(String dataColumnExp) throws DataSetException
|
||||
{
|
||||
List<Range> ranges = getRangeExpResolver().resolve(dataColumnExp);
|
||||
|
||||
if (ranges == null || ranges.isEmpty())
|
||||
return Collections.EMPTY_LIST;
|
||||
|
||||
List<IndexRange> indexRanges = new ArrayList<>(ranges.size());
|
||||
|
||||
for (Range range : ranges)
|
||||
{
|
||||
int from = 0;
|
||||
int to = -1;
|
||||
|
||||
String fromStr = range.trimFrom();
|
||||
String toStr = range.trimTo();
|
||||
|
||||
if (!StringUtil.isEmpty(fromStr))
|
||||
from = CellReference.convertColStringToIndex(fromStr);
|
||||
|
||||
if (!StringUtil.isEmpty(toStr))
|
||||
to = CellReference.convertColStringToIndex(toStr);
|
||||
|
||||
indexRanges.add(new IndexRange(from, to));
|
||||
}
|
||||
|
||||
return indexRanges;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.datagear.analysis.DataSet;
|
||||
import org.datagear.analysis.DataSetException;
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.util.FileUtil;
|
||||
|
||||
/**
|
||||
* 目录内Excel文件{@linkplain DataSet}。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class ExcelDirectoryFileDataSet extends AbstractExcelDataSet
|
||||
{
|
||||
/** Excel文件所在的目录 */
|
||||
private File directory;
|
||||
|
||||
/** Excel文件名 */
|
||||
private String fileName;
|
||||
|
||||
public ExcelDirectoryFileDataSet()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public ExcelDirectoryFileDataSet(String id, String name, File directory, String fileName)
|
||||
{
|
||||
super(id, name);
|
||||
this.directory = directory;
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* @param name
|
||||
* @param properties
|
||||
*/
|
||||
public ExcelDirectoryFileDataSet(String id, String name, List<DataSetProperty> properties, File directory,
|
||||
String fileName)
|
||||
{
|
||||
super(id, name, properties);
|
||||
this.directory = directory;
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected File getExcelFile(Map<String, ?> paramValues) throws DataSetException
|
||||
{
|
||||
File excelFile = FileUtil.getFile(this.directory, this.fileName);
|
||||
return excelFile;
|
||||
}
|
||||
}
|
|
@ -73,8 +73,7 @@ public class JsonDirectoryFileDataSet extends AbstractJsonFileDataSet
|
|||
@Override
|
||||
protected File getJsonFile(Map<String, ?> paramValues) throws DataSetException
|
||||
{
|
||||
String fileName = resolveTemplate(this.fileName, paramValues);
|
||||
File jsonFile = FileUtil.getFile(directory, fileName);
|
||||
File jsonFile = FileUtil.getFile(this.directory, this.fileName);
|
||||
return jsonFile;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -404,12 +404,12 @@ public class RangeExpResolver
|
|||
}
|
||||
|
||||
/**
|
||||
* 判断给定索引数值是否在此索引范围内。
|
||||
* 是否包含给定索引数值。
|
||||
*
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
public boolean inRange(int index)
|
||||
public boolean includes(int index)
|
||||
{
|
||||
if (this.from > -1 && index < this.from)
|
||||
return false;
|
||||
|
@ -452,5 +452,14 @@ public class RangeExpResolver
|
|||
{
|
||||
return getClass().getSimpleName() + " [from=" + from + ", to=" + to + "]";
|
||||
}
|
||||
|
||||
public static boolean includes(List<IndexRange> indexRanges, int index)
|
||||
{
|
||||
for (int i = 0; i < indexRanges.size(); i++)
|
||||
if (indexRanges.get(i).includes(index))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.datagear.analysis.DataSetException;
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
|
||||
/**
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class SimpleExcelDataSet extends AbstractExcelDataSet
|
||||
{
|
||||
/** Excel文件 */
|
||||
private File file;
|
||||
|
||||
public SimpleExcelDataSet()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public SimpleExcelDataSet(String id, String name, File file)
|
||||
{
|
||||
super(id, name);
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public SimpleExcelDataSet(String id, String name, List<DataSetProperty> properties, File file)
|
||||
{
|
||||
super(id, name, properties);
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected File getExcelFile(Map<String, ?> paramValues) throws DataSetException
|
||||
{
|
||||
return this.file;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.datagear.analysis.support;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.datagear.analysis.DataSetProperty;
|
||||
import org.datagear.analysis.ResolvedDataSetResult;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* {@linkplain ExcelDirectoryFileDataSet}单元测试用例。
|
||||
*
|
||||
* @author datagear@163.com
|
||||
*
|
||||
*/
|
||||
public class ExcelDirectoryFileDataSetTest
|
||||
{
|
||||
private static final File DIRECTORY = new File("src/test/resources/org/datagear/analysis/support/");
|
||||
|
||||
@Test
|
||||
public void resolveTest_xlsx()
|
||||
{
|
||||
ExcelDirectoryFileDataSet dataSet = new ExcelDirectoryFileDataSet("a", "a", DIRECTORY,
|
||||
"ExcelDirectoryFileDataSetTest-0.xlsx");
|
||||
dataSet.setNameRow(1);
|
||||
|
||||
ResolvedDataSetResult resolvedResult = dataSet.resolve(new HashMap<>());
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) resolvedResult.getResult().getData();
|
||||
List<DataSetProperty> properties = resolvedResult.getProperties();
|
||||
|
||||
{
|
||||
assertEquals(3, data.size());
|
||||
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(0);
|
||||
|
||||
assertEquals("aaa", row.get("name"));
|
||||
assertEquals(15, ((Number) row.get("value")).intValue());
|
||||
assertEquals(16, ((Number) row.get("size")).intValue());
|
||||
assertEquals("2020-08-01", dateFormat.format((Date) row.get("date")));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(1);
|
||||
|
||||
assertEquals("bbb", row.get("name"));
|
||||
assertEquals(25, ((Number) row.get("value")).intValue());
|
||||
assertEquals(26, ((Number) row.get("size")).intValue());
|
||||
assertEquals("2020-08-02", dateFormat.format((Date) row.get("date")));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(2);
|
||||
|
||||
assertEquals("ccc", row.get("name"));
|
||||
assertEquals(35, ((Number) row.get("value")).intValue());
|
||||
assertEquals(36, ((Number) row.get("size")).intValue());
|
||||
assertEquals("2020-08-03", dateFormat.format((Date) row.get("date")));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
assertEquals(4, properties.size());
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(0);
|
||||
assertEquals("name", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.STRING, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(1);
|
||||
assertEquals("value", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.DECIMAL, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(2);
|
||||
assertEquals("size", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.DECIMAL, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(3);
|
||||
assertEquals("date", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.DATE, property.getType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveTest_xls()
|
||||
{
|
||||
ExcelDirectoryFileDataSet dataSet = new ExcelDirectoryFileDataSet("a", "a", DIRECTORY,
|
||||
"ExcelDirectoryFileDataSetTest-1.xls");
|
||||
dataSet.setNameRow(1);
|
||||
|
||||
ResolvedDataSetResult resolvedResult = dataSet.resolve(new HashMap<>());
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) resolvedResult.getResult().getData();
|
||||
List<DataSetProperty> properties = resolvedResult.getProperties();
|
||||
|
||||
{
|
||||
assertEquals(3, data.size());
|
||||
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(0);
|
||||
|
||||
assertEquals("aaa", row.get("name"));
|
||||
assertEquals(15, ((Number) row.get("value")).intValue());
|
||||
assertEquals(16, ((Number) row.get("size")).intValue());
|
||||
assertEquals("2020-08-01", dateFormat.format((Date) row.get("date")));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(1);
|
||||
|
||||
assertEquals("bbb", row.get("name"));
|
||||
assertEquals(25, ((Number) row.get("value")).intValue());
|
||||
assertEquals(26, ((Number) row.get("size")).intValue());
|
||||
assertEquals("2020-08-02", dateFormat.format((Date) row.get("date")));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(2);
|
||||
|
||||
assertEquals("ccc", row.get("name"));
|
||||
assertEquals(35, ((Number) row.get("value")).intValue());
|
||||
assertEquals(36, ((Number) row.get("size")).intValue());
|
||||
assertEquals("2020-08-03", dateFormat.format((Date) row.get("date")));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
assertEquals(4, properties.size());
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(0);
|
||||
assertEquals("name", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.STRING, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(1);
|
||||
assertEquals("value", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.DECIMAL, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(2);
|
||||
assertEquals("size", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.DECIMAL, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(3);
|
||||
assertEquals("date", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.DATE, property.getType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveTest_dataRowColumnExp()
|
||||
{
|
||||
ExcelDirectoryFileDataSet dataSet = new ExcelDirectoryFileDataSet("a", "a", DIRECTORY,
|
||||
"ExcelDirectoryFileDataSetTest-0.xlsx");
|
||||
dataSet.setNameRow(1);
|
||||
dataSet.setDataRowExp("2,3-");
|
||||
dataSet.setDataColumnExp("A,C-");
|
||||
|
||||
ResolvedDataSetResult resolvedResult = dataSet.resolve(new HashMap<>());
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) resolvedResult.getResult().getData();
|
||||
List<DataSetProperty> properties = resolvedResult.getProperties();
|
||||
|
||||
{
|
||||
assertEquals(3, data.size());
|
||||
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(0);
|
||||
|
||||
assertEquals("aaa", row.get("name"));
|
||||
assertEquals(16, ((Number) row.get("size")).intValue());
|
||||
assertEquals("2020-08-01", dateFormat.format((Date) row.get("date")));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(1);
|
||||
|
||||
assertEquals("bbb", row.get("name"));
|
||||
assertEquals(26, ((Number) row.get("size")).intValue());
|
||||
assertEquals("2020-08-02", dateFormat.format((Date) row.get("date")));
|
||||
}
|
||||
|
||||
{
|
||||
Map<String, Object> row = data.get(2);
|
||||
|
||||
assertEquals("ccc", row.get("name"));
|
||||
assertEquals(36, ((Number) row.get("size")).intValue());
|
||||
assertEquals("2020-08-03", dateFormat.format((Date) row.get("date")));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
assertEquals(3, properties.size());
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(0);
|
||||
assertEquals("name", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.STRING, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(1);
|
||||
assertEquals("size", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.DECIMAL, property.getType());
|
||||
}
|
||||
|
||||
{
|
||||
DataSetProperty property = properties.get(2);
|
||||
assertEquals("date", property.getName());
|
||||
assertEquals(DataSetProperty.DataType.DATE, property.getType());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue