poi读取excel,动态返回对象list

版权声明:转载请注明原创 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来匹配,得到这一行单元格的位置(索引),通过反射为创建的对象设值.

猜你喜欢

转载自blog.csdn.net/qq_42151769/article/details/89349692