更新Rouyi的ExcelUtil读取,兼容多行表头的情况

This commit is contained in:
panshuling321 2021-12-29 11:43:06 +08:00
parent b111ca56df
commit c5fab8d7f4
3 changed files with 138 additions and 35 deletions

View File

@ -1,5 +1,7 @@
package com.xhpc.common.core.annotation; package com.xhpc.common.core.annotation;
import com.xhpc.common.core.utils.poi.ExcelHandlerAdapter;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
@ -103,7 +105,17 @@ public @interface Excel
/** /**
* 导出字段对齐方式0默认1靠左2居中3靠右 * 导出字段对齐方式0默认1靠左2居中3靠右
*/ */
Align align() default Align.AUTO; public Align align() default Align.AUTO;
/**
* 自定义数据处理器
*/
public Class<?> handler() default ExcelHandlerAdapter.class;
/**
* 自定义数据处理器参数
*/
public String[] args() default {};
public enum Align public enum Align
{ {

View File

@ -0,0 +1,18 @@
package com.xhpc.common.core.utils.poi;
/**
* Excel数据格式处理适配器
*
* @author ruoyi
*/
public interface ExcelHandlerAdapter {
/**
* 格式化
*
* @param value 单元格数据值
* @param args excel注解args参数组
*
* @return 处理后的值
*/
Object format(Object value, String[] args);
}

View File

@ -4,6 +4,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.ArrayList; import java.util.ArrayList;
@ -149,33 +150,37 @@ public class ExcelUtil<T>
*/ */
public List<T> importExcel(InputStream is) throws Exception public List<T> importExcel(InputStream is) throws Exception
{ {
return importExcel(StringUtils.EMPTY, is); return importExcel(StringUtils.EMPTY, is, 0);
}
/**
* 对excel表单默认第一个索引名转换成list
*
* @param is 输入流
* @param titleNum 标题占用行数
* @return 转换后集合
*/
public List<T> importExcel(InputStream is, int titleNum) throws Exception
{
return importExcel(StringUtils.EMPTY, is, titleNum);
} }
/** /**
* 对excel表单指定表格索引名转换成list * 对excel表单指定表格索引名转换成list
* *
* @param sheetName 表格索引名 * @param sheetName 表格索引名
* @param titleNum 标题占用行数
* @param is 输入流 * @param is 输入流
* @return 转换后集合 * @return 转换后集合
*/ */
public List<T> importExcel(String sheetName, InputStream is) throws Exception public List<T> importExcel(String sheetName, InputStream is, int titleNum) throws Exception
{ {
this.type = Type.IMPORT; this.type = Type.IMPORT;
this.wb = WorkbookFactory.create(is); this.wb = WorkbookFactory.create(is);
List<T> list = new ArrayList<T>(); List<T> list = new ArrayList<T>();
Sheet sheet = null; // 如果指定sheet名,则取指定sheet中的内容 否则默认指向第1个sheet
if (StringUtils.isNotEmpty(sheetName)) Sheet sheet = StringUtils.isNotEmpty(sheetName) ? wb.getSheet(sheetName) : wb.getSheetAt(0);
{
// 如果指定sheet名,则取指定sheet中的内容.
sheet = wb.getSheet(sheetName);
}
else
{
// 如果传入的sheet名不存在则默认指向第1个sheet.
sheet = wb.getSheetAt(0);
}
if (sheet == null) if (sheet == null)
{ {
throw new IOException("文件sheet不存在"); throw new IOException("文件sheet不存在");
@ -189,40 +194,40 @@ public class ExcelUtil<T>
// 定义一个map用于存放excel列的序号和field. // 定义一个map用于存放excel列的序号和field.
Map<String, Integer> cellMap = new HashMap<String, Integer>(); Map<String, Integer> cellMap = new HashMap<String, Integer>();
// 获取表头 // 获取表头
Row heard = sheet.getRow(0); Row heard = sheet.getRow(titleNum);
for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++) for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++)
{ {
Cell cell = heard.getCell(i); Cell cell = heard.getCell(i);
if (StringUtils.isNotNull(cell)) if (StringUtils.isNotNull(cell))
{ {
String value = this.getCellValue(heard, i).toString(); String value = this.getCellValue(heard, i).toString();
/**
* 当存在两列标题是一样的时候以最先存在的一列为准
* 主要针对快电的对账单
*/
if (!cellMap.containsKey(value)){
cellMap.put(value, i); cellMap.put(value, i);
} }
}
else else
{ {
cellMap.put(null, i); cellMap.put(null, i);
} }
} }
// 有数据时才处理 得到类的所有field. // 有数据时才处理 得到类的所有field.
Field[] allFields = clazz.getDeclaredFields(); List<Object[]> fields = this.getFields();
// 定义一个map用于存放列的序号和field. Map<Integer, Object[]> fieldsMap = new HashMap<Integer, Object[]>();
Map<Integer, Field> fieldsMap = new HashMap<Integer, Field>(); for (Object[] objects : fields)
for (int col = 0; col < allFields.length; col++)
{ {
Field field = allFields[col]; Excel attr = (Excel) objects[1];
Excel attr = field.getAnnotation(Excel.class);
if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
{
// 设置类的私有字段属性可访问.
field.setAccessible(true);
Integer column = cellMap.get(attr.name()); Integer column = cellMap.get(attr.name());
if (column != null) if (column != null)
{ {
fieldsMap.put(column, field); fieldsMap.put(column, objects);
} }
} }
} for (int i = titleNum + 1; i <= rows; i++)
for (int i = 1; i <= rows; i++)
{ {
// 从第2行开始取数据,默认第一行是表头. // 从第2行开始取数据,默认第一行是表头.
Row row = sheet.getRow(i); Row row = sheet.getRow(i);
@ -232,14 +237,15 @@ public class ExcelUtil<T>
continue; continue;
} }
T entity = null; T entity = null;
for (Map.Entry<Integer, Field> entry : fieldsMap.entrySet()) for (Map.Entry<Integer, Object[]> entry : fieldsMap.entrySet())
{ {
Object val = this.getCellValue(row, entry.getKey()); Object val = this.getCellValue(row, entry.getKey());
// 如果不存在实例则新建. // 如果不存在实例则新建.
entity = (entity == null ? clazz.newInstance() : entity); entity = (entity == null ? clazz.newInstance() : entity);
// 从map中得到对应列的field. // 从map中得到对应列的field.
Field field = fieldsMap.get(entry.getKey()); Field field = (Field) entry.getValue()[0];
Excel attr = (Excel) entry.getValue()[1];
// 取得类型,并根据对象类型设置值. // 取得类型,并根据对象类型设置值.
Class<?> fieldType = field.getType(); Class<?> fieldType = field.getType();
if (String.class == fieldType) if (String.class == fieldType)
@ -299,7 +305,6 @@ public class ExcelUtil<T>
} }
if (StringUtils.isNotNull(fieldType)) if (StringUtils.isNotNull(fieldType))
{ {
Excel attr = field.getAnnotation(Excel.class);
String propertyName = field.getName(); String propertyName = field.getName();
if (StringUtils.isNotEmpty(attr.targetAttr())) if (StringUtils.isNotEmpty(attr.targetAttr()))
{ {
@ -309,6 +314,10 @@ public class ExcelUtil<T>
{ {
val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator()); val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator());
} }
else if (!attr.handler().equals(ExcelHandlerAdapter.class))
{
val = dataFormatHandlerAdapter(val, attr);
}
ReflectUtils.invokeSetter(entity, propertyName, val); ReflectUtils.invokeSetter(entity, propertyName, val);
} }
} }
@ -318,6 +327,48 @@ public class ExcelUtil<T>
return list; return list;
} }
/**
* 获取字段注解信息
*/
public List<Object[]> getFields()
{
List<Object[]> fields = new ArrayList<Object[]>();
List<Field> tempFields = new ArrayList<>();
tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
for (Field field : tempFields)
{
// 单注解
if (field.isAnnotationPresent(Excel.class))
{
Excel attr = field.getAnnotation(Excel.class);
if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
{
field.setAccessible(true);
fields.add(new Object[] { field, attr });
}
}
// 多注解
if (field.isAnnotationPresent(Excels.class))
{
Excels attrs = field.getAnnotation(Excels.class);
Excel[] excels = attrs.value();
for (Excel attr : excels)
{
if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
{
field.setAccessible(true);
fields.add(new Object[] { field, attr });
}
}
}
}
return fields;
}
/** /**
* 对list数据源将其里面的数据导入到excel表单 * 对list数据源将其里面的数据导入到excel表单
* *
@ -427,6 +478,28 @@ public class ExcelUtil<T>
} }
} }
/**
* 数据处理器
*
* @param value 数据值
* @param excel 数据注解
* @return
*/
public String dataFormatHandlerAdapter(Object value, Excel excel)
{
try
{
Object instance = excel.handler().newInstance();
Method formatMethod = excel.handler().getMethod("format", new Class[] { Object.class, String[].class });
value = formatMethod.invoke(instance, value, excel.args());
}
catch (Exception e)
{
log.error("不能格式化数据 " + excel.handler(), e.getMessage());
}
return Convert.toStr(value);
}
/** /**
* 创建表格样式 * 创建表格样式
* *