com.orion.office.excel.reader.ExcelBeanReader Maven / Gradle / Ivy
Show all versions of orion-office Show documentation
package com.orion.office.excel.reader;
import com.orion.lang.utils.Exceptions;
import com.orion.lang.utils.Objects1;
import com.orion.lang.utils.Strings;
import com.orion.lang.utils.Valid;
import com.orion.lang.utils.codec.Base64s;
import com.orion.lang.utils.reflect.Annotations;
import com.orion.lang.utils.reflect.Constructors;
import com.orion.lang.utils.reflect.Fields;
import com.orion.lang.utils.reflect.Methods;
import com.orion.office.excel.Excels;
import com.orion.office.excel.annotation.ImportField;
import com.orion.office.excel.annotation.ImportIgnore;
import com.orion.office.excel.option.CellOption;
import com.orion.office.excel.option.ImportFieldOption;
import com.orion.office.excel.type.ExcelReadType;
import org.apache.poi.ss.usermodel.*;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
/**
* excel bean 读取器
*
* 支持高级数据类型
*
* {@link Excels#getCellValue(Cell, ExcelReadType, CellOption)}
*
* @author Jiahang Li
* @version 1.0.0
* @since 2021/1/6 17:10
*/
public class ExcelBeanReader extends BaseExcelReader {
private final Class targetClass;
private final Constructor constructor;
private final Map setters;
/**
* 如果列为null是否调用setter(null)
*/
private boolean nullInvoke;
/**
* 如果行为null是否添加一个新的实例对象
*/
private boolean nullAddEmptyBean;
public ExcelBeanReader(Workbook workbook, Sheet sheet, Class targetClass) {
this(workbook, sheet, targetClass, new ArrayList<>(), null);
}
public ExcelBeanReader(Workbook workbook, Sheet sheet, Class targetClass, List store) {
this(workbook, sheet, targetClass, store, null);
}
public ExcelBeanReader(Workbook workbook, Sheet sheet, Class targetClass, Consumer consumer) {
this(workbook, sheet, targetClass, null, consumer);
}
protected ExcelBeanReader(Workbook workbook, Sheet sheet, Class targetClass, List rows, Consumer consumer) {
super(workbook, sheet, rows, consumer);
this.targetClass = Valid.notNull(targetClass, "target class is null");
this.constructor = Valid.notNull(Constructors.getDefaultConstructor(targetClass), "target class not found default constructor");
this.setters = new HashMap<>();
this.options = new HashMap<>();
this.analysisField();
this.init = false;
}
/**
* 如果列为null是否调用setter(null)
*
* @return this
*/
public ExcelBeanReader nullInvoke() {
this.nullInvoke = true;
return this;
}
/**
* 如果行为null是否添加实例对象
*
* @return this
*/
public ExcelBeanReader nullAddEmptyBean() {
this.nullAddEmptyBean = true;
return this;
}
/**
* 添加配置
*
* @param field field
* @param option 配置
* @return this
*/
public ExcelBeanReader option(String field, ImportFieldOption option) {
this.addOption(field, option);
return this;
}
/**
* 添加配置
*
* @param column 列
* @param field field
* @param type 类型
* @return this
*/
public ExcelBeanReader option(int column, String field, ExcelReadType type) {
this.addOption(field, new ImportFieldOption(column, type));
return this;
}
/**
* 添加配置
*
* @param field field
* @param option 配置
*/
@Override
protected void addOption(String field, ImportFieldOption option) {
Valid.notNull(option, "field option is null");
Valid.notNull(setters.get(field), "not found setter method ({}) in {}", field, targetClass);
super.addOption(field, option);
}
@Override
protected T parserRow(Row row) {
if (row == null) {
if (nullAddEmptyBean) {
return Constructors.newInstance(constructor);
}
return null;
}
T t = Constructors.newInstance(constructor);
options.forEach((field, option) -> {
Method setter = setters.get(field);
int index = option.getIndex();
Cell cell = row.getCell(index);
Object value;
if (option.getType().equals(ExcelReadType.PICTURE)) {
// 图片
value = this.getPicture(setter, row.getRowNum(), index);
} else {
// 值
value = Excels.getCellValue(cell, option.getType(), option.getCellOption());
}
if (value != null) {
if (trim && value instanceof String) {
value = ((String) value).trim();
}
// 调用setter
try {
Methods.invokeSetterInfer(t, setter, value);
} catch (Exception e) {
// ignore
}
} else if (nullInvoke) {
Methods.invokeMethod(t, setter, (Object) null);
}
});
return t;
}
/**
* 读取图片
*
* @param setter setter
* @param row row
* @param col col
* @return value
*/
private Object getPicture(Method setter, int row, int col) {
if (pictureParser == null) {
return null;
}
// 获取图片
PictureData picture = pictureParser.getPicture(row, col);
if (picture == null) {
return null;
}
Class> parameterType = setter.getParameterTypes()[0];
if (parameterType == String.class) {
return Base64s.img64Encode(picture.getData(), picture.getMimeType());
} else if (parameterType == byte[].class) {
return picture.getData();
} else if (parameterType == OutputStream.class || parameterType == ByteArrayOutputStream.class) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
out.write(picture.getData());
} catch (Exception e) {
throw Exceptions.ioRuntime(e);
}
return out;
}
return null;
}
/**
* 解析field
*/
private void analysisField() {
// setter cache
List setterMethodList = Methods.getSetterMethodsByCache(targetClass);
// 扫描field
List fieldList = Fields.getFieldsByCache(targetClass);
for (Field field : fieldList) {
this.analysisColumn(Annotations.getAnnotation(field, ImportField.class),
Annotations.getAnnotation(field, ImportIgnore.class),
Methods.getSetterMethodByField(targetClass, field), field.getName());
}
// 扫描setter
for (Method method : setterMethodList) {
String fieldName = Fields.getFieldNameByMethod(method);
setters.put(fieldName, method);
// 解析
this.analysisColumn(Annotations.getAnnotation(method, ImportField.class),
Annotations.getAnnotation(method, ImportIgnore.class),
method, fieldName);
}
}
/**
* 解析 field ignore
*
* @param field field
* @param ignore ignore
* @param method method
* @param fieldName fieldName
*/
private void analysisColumn(ImportField field, ImportIgnore ignore,
Method method, String fieldName) {
if (field == null || ignore != null) {
return;
}
ImportFieldOption option = new ImportFieldOption();
option.setIndex(field.index());
option.setType(field.type());
String parseFormat = field.parseFormat();
if (!Strings.isEmpty(parseFormat)) {
option.setCellOption(new CellOption(parseFormat));
}
// 解析
this.analysisColumn(option, fieldName, method);
}
/**
* 解析option
*
* @param option option
* @param fieldName fieldName
* @param method method
*/
private void analysisColumn(ImportFieldOption option, String fieldName, Method method) {
Valid.notNull(option, "option is null");
Valid.notNull(method, fieldName + " setter method not found from " + targetClass);
Valid.gte(option.getIndex(), 0, "index must >= 0");
// check
ExcelReadType type = Objects1.def(option.getType(), ExcelReadType.TEXT);
option.setType(type);
// 判断是否支持流式操作
this.checkStreamingSupportType(type);
Class> parameterType = method.getParameterTypes()[0];
switch (type) {
case LINK_ADDRESS:
// 超链接
if (!parameterType.equals(String.class)) {
throw Exceptions.parse("read hyperlink address parameter type must be String");
}
break;
case PICTURE:
// 图片
if (!parameterType.equals(byte[].class)
&& !parameterType.equals(String.class)
&& !parameterType.equals(OutputStream.class)
&& !parameterType.equals(ByteArrayOutputStream.class)) {
throw Exceptions.parse("read picture parameter type must be byte[], String, OutputStream or ByteArrayOutputStream");
}
break;
case TEXT:
default:
break;
}
options.put(fieldName, option);
}
}