版权声明:转载请注明原创 https://blog.csdn.net/qq_42151769/article/details/89349692
定义excel注解:
package com.hf.yudemo.excel.annotation;
import java.lang.annotation.*;
/**
* @Description:
* @Date: 2019/4/16
* @Auther:
*/
@Inherited
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelFeild {
String name() default "";
}
读取excel的工具类:
package com.hf.yudemo.excel;
import com.hf.yudemo.excel.annotation.ExcelFeild;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;
/**
* @Description:
* @Date: 2019/4/16
* @Auther:
*/
@Slf4j
public class ExcelUtil {
/**
* 从excel文件流中读取每行信息,根据第一行表头与clazz类中ExcelField注解名称匹配获取相关列信息
*/
public static <T> List<T> readFromExcel(InputStream inputStream, Class<T> clazz) throws IOException, IllegalAccessException, InstantiationException {
try {
List<T> list = readFromExcel(inputStream, clazz, null);
return list;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static <T> List<T> readFromExcel(InputStream inputStream,Class<T> clzz,List<String> headList) throws Exception{
//创建文本
HSSFWorkbook workBook = new HSSFWorkbook(inputStream);
//获取到需要转换对象的所有字段
Field[] allField = CommonUtil.getAllField(clzz);
//定义Map存储 key---类的字段 value----含有ExcelField注解上面的注释 需要和headList传入的匹配(如果传入)
Map<Field, String> map = new HashMap<>();
//返回的数据
List<T> resultList = new ArrayList<>();
//判断是否有ExcelField字段,过滤static和final修饰的字段
Arrays.stream(allField).filter((Field field) -> field.isAnnotationPresent(ExcelFeild.class)
&& !Modifier.isFinal(field.getModifiers())
&& !Modifier.isStatic(field.getModifiers())).forEach(var -> {
//注解ExcelField值
String name = var.getAnnotation(ExcelFeild.class).name();
if(!CollectionUtils.isEmpty(headList)){
headList.stream().filter((String head) -> !StringUtils.isEmpty(head)).forEach(var2 -> {
if(var2.equals(name)){
map.put(var,name);
}
});
}else{
//传入headList为空,直接获取注解值
map.put(var,name);
}
});
//获取表格
Sheet sheet = workBook.getSheetAt(0);
//获取行迭代器
Iterator<Row> rowIterator = sheet.rowIterator();
//数据格式器,用来格式化cell单元格数据
DataFormatter dataFormatter = new DataFormatter();
//首行数据
List<String> excelHeadList = new ArrayList<>();
//数据处理
while(rowIterator.hasNext()){
//当前行
Row row = rowIterator.next();
//判断是否为首行
if(row.getRowNum() == 0){
//获取首行的数据
for (int i = 0; i < row.getLastCellNum(); i++) {
//格式化数据转换为String
String data = dataFormatter.formatCellValue(row.getCell(i)).trim();
if(!StringUtils.isEmpty(data)){
excelHeadList.add(data);
}
}
}
//创建对象,一行对应一个对象
T vo = clzz.newInstance();
//不是首行处理,判断excelHeadList中存入的数据和map终的value比较,得到cell的位置(也就是excelHeadList的索引)
if(!CollectionUtils.isEmpty(map)){
map.entrySet().stream().forEach(var -> {
Field field = var.getKey();
String name = var.getValue();
//使用ArraysUtil工具类,获取到指定数据所在的位置的索引
int index = ArrayUtils.indexOf(excelHeadList.toArray(), name);
//利用反射设置对象的值
try {
field.set(field,CommonUtil.castObjectToClazz(field.getType(),dataFormatter.formatCellValue(row.getCell(index))));
} catch (IllegalAccessException e) {
log.error("<readFromExcel> 将数据转化为对象失败,不能通过反射设置属性:" + field.getName(),e.getMessage(),e);
}
});
}
resultList.add(vo);
}
return resultList;
}
}
通用工具类:实现数据转换为对象,获取包括父类的所有字段:
package com.hf.yudemo.excel;
import org.springframework.util.CollectionUtils;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/**
* @Description:
* @Date: 2019/4/16
* @Auther:
*/
public class CommonUtil {
/**
* 获取指定类的所有字段,如果有父类,获取包括父类的所有字段
* @param clzz
* @return
*/
public static Field[] getAllField(Class<?> clzz){
if(null == clzz){
return null;
}
List<Field> list = new ArrayList<>();
Field[] fields = clzz.getDeclaredFields();
//获取是否有继承类的所有字段
while(null != clzz){
list.addAll(CollectionUtils.arrayToList(fields));
clzz = clzz.getSuperclass();
}
//转换为数组,注意这里不要使用list.toArray()无参的,原因你懂的
Field[] arr = new Field[list.size()];
list.toArray(arr);
return arr;
}
/**
* 将数据转换为对象
* @param clazz
* @param str
* @param <T>
* @return
*/
public static <T> T castObjectToClazz(Class<T> clazz, String str) {
T result = null;
if (clazz.equals(Integer.class)) {
result = (T) new Integer(str);
} else if (clazz.equals(String.class)) {
result = (T) str;
} else if (clazz.equals(Double.class)) {
result = (T) new Double(str);
} else if (clazz.equals(Boolean.class)) {
result = (T) new Boolean(str);
}
return result;
}
}
简单介绍下用法是:
在实体类上面字段打上@ExcelField注解,用来标识导入的字段,读取excel的时候,会判断是否有这个注解,读取excel的首行,也就是标题行,在获取传入的Class的所有字段,得到一个map,该map的key为字段Field,value为@ExcelField上面的注释(如果有),
在遍历每一行,通过首行的list集合和map的value来匹配,得到这一行单元格的位置(索引),通过反射为创建的对象设值.