分享一个工具类~用了它再也不用担心导入Excel啦

一、前言

gogogo话不多说,如果还没了解过poi的话建议小伙伴可以先了解下poi。

二、什么是POI?

POI是Apache软件基金会用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程序对Microsoft Office格式档案读和写的功能。所以POI的主要功能是可以用Java操作Microsoft Office的相关文件,但是一般我们都是用来操作Excel相关文件。

三、代码实现

1.首先呢,我们先导入坐标,引入jar

<!-- excel -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>4.0.1</version>
</dependency>
<!-- poi -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>4.0.1</version>
</dependency>

2.相关类

pojo----User

@Data
public class User {
    @FileAttributes(value = "ID")
    private String id;
    @FileAttributes(value = "名字")
    private String username;
    @FileAttributes(value = "密码")
    private String password;
}

注解----FileAttributes

/**
 * @description 用于标识对应字符对应文件上的属性
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface FileAttributes {
    String value();
    String defualtValue() default "";
    boolean isNull() default true;
    Class type() default String.class;
}

工具类---- ParsingFileUtils

/**
 * Created by gyk on 2020/9/8
 */
public class ParsingFileUtils {
    //文件后缀
    private static final String FILE_CONTENT_TYPE_XLSX="xlsx";
    private static final String FILE_CONTENT_TYPE_XLS="xls";
    private static Logger logger= LoggerFactory.getLogger(ParsingFileUtils.class);

    /**
     * 将Excel文件转换成list集合
     * @param in 文件输入流
     * @param suffix 文件后缀
     * @param clazz  文件转换对象类型
     * @return list集合
     * @throws IOException
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    public static List<Object> parsingFileXls(InputStream in,String suffix,Class clazz) throws IOException, IllegalAccessException, InstantiationException {
        //获得所有属性对象
        Field[] fields = clazz.getDeclaredFields();
        ConcurrentHashMap<String,Integer> titlesMap=new ConcurrentHashMap<>(8);
        Workbook book;
        try {
            //判断文件类型,进行对象构造
            if (FILE_CONTENT_TYPE_XLSX.equals(suffix)) {
                book = new XSSFWorkbook(in);
            } else if (FILE_CONTENT_TYPE_XLS.equals(suffix)) {
                book = new HSSFWorkbook(in);
            }else {
                throw new IllegalArgumentException("file type error!");
            }
        }catch (IOException e){
            logger.error(e.getLocalizedMessage());
            throw e;
        }
        //此处获取第一个sheet页进行操作,如需要多sheet页操作,将其变成for循环
        Sheet sheet =book.getSheetAt(0);
        //从类中属性注解进行字段-标题映射
        for (Field field:fields){
            //field 代表类的成员变量
            // getAnnotation(Class<A> annotationClass)返回该类中与参数类型匹配的公有注解对象
            FileAttributes fileAttributes = field.getAnnotation(FileAttributes.class);
            if (fileAttributes==null){
                continue;
            }
            titlesMap.put(fileAttributes.value(),-1);
        }
        //将字段对应标题所述的列进行映射   getRow(sheet.getFirstRowNum())获取第一行标题
        mappingColumns(titlesMap,sheet.getRow(sheet.getFirstRowNum()));
        List<Object> result =new ArrayList<>(8);
        //遍历所有行,进行添加值。
        for (int i=sheet.getFirstRowNum()+1;i<sheet.getLastRowNum()+1;i++){
            //获取行数
            Row row = sheet.getRow(i);
            //创建类的实例
            Object target = clazz.newInstance();
            //解析每一行,并将列属性给对象赋值
            parsingRow(titlesMap, row, fields, target);
            if(target!=null) {
                result.add(target);
            }
        }
        return result;
    }

    /**
     * @param titleMap 列与字段映射集合
     * @param row 列标题
     * @return
     */
    private static void mappingColumns(ConcurrentHashMap<String,Integer> titleMap, Row row){
        for (int i=row.getFirstCellNum();i<row.getLastCellNum();i++){
            //获取当前单元格
            Cell cell = row.getCell(i);
            Integer integer = titleMap.get(cell.getStringCellValue());
            if (integer != null){
                //重新赋值 key(标题) 的value会被重新覆盖 之前都是-1
                titleMap.put(cell.getStringCellValue(),i);
            }
        }

    }

    /**
     *
     * @param titleMap 列与字段映射集合
     * @param row 每一行数据
     * @param fields 目标对象属性集合
     * @param target 目标对象
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     */
    private static void parsingRow(ConcurrentHashMap<String,Integer> titleMap, Row row, Field[] fields, Object target) throws IllegalArgumentException, IllegalAccessException {

        for (Field field:fields){
            //field 代表类的成员变量
            FileAttributes fieldAnnotation = field.getAnnotation(FileAttributes.class);
            if (fieldAnnotation == null){
                continue;
            }
            //作用就是让我们在用反射时 可以访问private修饰的私有属性
            field.setAccessible(true);
            if (!StringUtils.isEmpty(fieldAnnotation.defualtValue())){
                field.set(target,fieldAnnotation.defualtValue());
            }
            //通过标题名拿到对应标题的value索引值
            Integer integer = titleMap.get(fieldAnnotation.value());
            if (integer==-1){
                if (!fieldAnnotation.isNull()&&StringUtils.isEmpty(fieldAnnotation.defualtValue())){
                    throw new IllegalArgumentException("we need  "+fieldAnnotation.value()+" ,but the excel doesn't!");
                }
                continue;
            }
            //根据下标获取这一行某个单元格
            Cell cell = row.getCell(integer);
            //o 接受的是匹配类型后的单元格内容
            Object o = parsingCell(cell, fieldAnnotation);
            //表格中数据会把整数读取为小数点,这里控制
			if(o!=null && o.getClass()==String.class &&((String)o).contains(".0")){
			    o=((String)o).split("\\.")[0];
			}
            if (o==null&&!fieldAnnotation.isNull()){
                throw new IllegalArgumentException("the ("+row.getRowNum()+","+integer+")cell Not allowed to be empty");
            }
	    //对target进行赋值
            field.set(target,o);
        }
    }

    /**
     *
     * @param cell 单元格
     * @param fileAttributes 注解类型
     * @return 注解中type属性类型
     */
    private static Object parsingCell(Cell cell, FileAttributes fileAttributes){
        if (cell==null){
            return null;
        }
        Class type = fileAttributes.type();
        if (type ==Date.class){
            return cell.getDateCellValue();
        }else if(type== boolean.class){
            return cell.getBooleanCellValue();
        }else if(type==double.class){
            return cell.getNumericCellValue();
        }else if(type== RichTextString.class){
            return cell.getRichStringCellValue();
        }else if(type==Integer.class){
            String stringCellValue = cell.getStringCellValue();
            return Integer.parseInt(stringCellValue);
        } else{
            try {
                return cell.getStringCellValue();
            }catch (Exception e){
                if (cell.getCellType()==CellType.NUMERIC) {
                    return ""+cell.getNumericCellValue();
                }
                return "";
            }
        }
    }
}

四、代码实现了,是不是已经迫不及待想试试水了呢

接下来我们测试一下

用户表.xlsx:

在这里插入图片描述

五、解析过程

我们来写一个优雅的main方法测试一下这个工具类行不行

  public static void main(String[] args) throws IOException, IllegalAccessException, InstantiationException {
        List<Object> objects = parsingFileXls(new FileInputStream(new File("G:\\用户表.xlsx")), FILE_CONTENT_TYPE_XLSX, User.class);
        objects.forEach(System.out::println);
    }

果然行!!!

User(id=1.0, username= 张三, password=2sd3tg5)
User(id=2.0, username= 李四, password=42freg43)
User(id=3.0, username= 王五, password=2d3d)
User(id=4.0, username= 赵六, password= asdad)
User(id=5.0, username= 刘七, password= sefwe)
User(id=6.0, username= kk, password= 21edwq)
User(id=7.0, username= sx, password= dewr3r)
User(id=8.0, username= aa, password= wegt6y)
User(id=9.0, username= bb, password= qwed2qw)
User(id=10.0, username= cc, password= 21edwq)

收好你们的对象噢

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值