使用Java POI读Excel文档

2,879 阅读2分钟

Poi介绍

Poi是由apache公司提供的Java编写的免费开源跨平台的Java API,提供让Java程序对Microsoft Office档案读和写的功能。也是目前针对Excel读写比较常用的实现方案。

poi分为2003版(.xls文件)和2007版(.xlsx文件),本次只介绍07版Excel的基础操作

导入相关的jar

    <dependency> 
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.9</version>
    </dependency> 
    <dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId> 
    <version>3.9</version>
    </dependency>

Poi包结构:

HSSF —— 读写 Microsoft Excel xls(07版本之前的Excel)

XSSF —— 读写 Microsoft Excel OOXML XLSX(07版本之后的Excel)

HWPF —— 读写 Word

HSLF —— 读写 PowerPoint(PPT)

其实我们主要用的就是XSSF

读取Excel

Poi如何读取操作表格?其实在Poi内部封装了一些对象

XSSFWorkbook:工作簿

XSSFSheet:工作表

Row:行

Cell:单元格

1662553810345.png

具体使用

那这里我做了一个简答的表格来模仿,如何将表格中的数据读取出来,并且放入到实体类中,后续用于写入数据库

image.png

首先创建一个product的实体类

/**
 * 此类型用户测试poi读取Excel表格功能
 * 将读取的数据,存入到当前Product类型的属性中
 * Excel中的每一条数据为一个Product实列
 */
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Product {
    private Integer id;
    private String name;
    private Double price;
    private Integer count;
}

然后创建具体的测试类来读取表格中的数据

/** 
 * 利用Poi读取excel表格数据
 */
public class ReadDemo {
    public static void main(String[] args) {

        try {
            List<Product> products = read("D:\JAVA_\a.xlsx");
            for (Product product : products) {
                System.out.println(product);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    public static List<Product> read(String path) throws Exception{
        //最后输出的实体类的集合
        List<Product> products = new ArrayList<>();
        // 1. 创建输入流
        FileInputStream fip = new FileInputStream(path);
        // 2. 在输入流中获取工作簿(excel表格)
        XSSFWorkbook workbook = new XSSFWorkbook(fip);
        // 3. 在目标工作簿中获取目标工作表 0:表示第一个工作表
        Sheet sheet = workbook.getSheetAt(0);
        // 4. 获取工作表的行数(有数据的)
        int rowNum = sheet.getPhysicalNumberOfRows();
        // 除去第一行,有效数据从第二行开始
        for (int i = 1; i < rowNum; i++) {
            // 5. 获取除第一行以外的所有行
            Row row = sheet.getRow(i);
            if(row!=null){
                //用于保存每一行数据的集合
                List<String> list = new ArrayList<>();
                for (Cell cell : row) {
                    if(cell!=null){
                        // 6. 把一行中所有的数据转化为String,方便数据处理
                        cell.setCellType(Cell.CELL_TYPE_STRING);
                        // 7. 获取所有单元格的数据
                        String value = cell.getStringCellValue();
                        if(value !=null && !value.equals("")){
                            // 8. 将每一个单元格的数据放入到list集合中
                            list.add(value);
                        }
                    }
                }
                // 9. 把获取的每一行数据封装成product对象
                if(list.size()>0){
                    Product product = new Product(Integer.parseInt(list.get(0)), list.get(1), Double.parseDouble(list.get(2)), Integer.parseInt(list.get(3)));
                    // 将product对象放入products对象中
                    products.add(product);
                }
            }
        }
        return products;
    }
}

测试

image.png

当遇到实体类中对象数据较多时 用list封装就比较麻烦,此时可以采用Map来封装数据,但是第一列的数据要与实体类中的属性值相对应

image.png

image.png


/**
 * 解析表格的工具类
 */
public class ExcelUtil {

    /**
     * 解析表格的方法(通用)
     * @param stream 文件的输入流
     * @param clazz 实体类类型
     * @param <T> 任何数据类型
     * @return 解析表格的数据
     */
    public static <T>List<T> readExcel (FileInputStream stream,Class<T> clazz) throws Exception {
        List<T> result = new ArrayList<>();
        //从输入流中获取工作簿
        XSSFWorkbook workbook = new XSSFWorkbook(stream);
        //在工作簿中获取目标工作表
        Sheet sheet = workbook.getSheetAt(0);
        //获取工作表中的行数
        int rowNums = sheet.getPhysicalNumberOfRows();
        //获取第一行数据,因为Excel表格中第一行数据包含对应要映射的属性
        Row row = sheet.getRow(0);
        //遍历第一行的数据,遍历出的数据就是所需要新增数据的所有属性,并且把这些数据放入到key集合中
        List<String> key = new ArrayList<>();
        // 遍历第一行数据,遍历出所有需要新增的属性,并把这些属性放入key中
        for (Cell cell : row) {
            cell.setCellType(Cell.CELL_TYPE_STRING);
            key.add(cell.getStringCellValue());
        }
        // 遍历所有的正式数据,但是要跳过第二行标题数据,所以下标要从2开始;
        for(int i=2;i<rowNums;i++){
            // 获取所有行
            row = sheet.getRow(i);
            if(row!=null){
                // 遍历所有单元格中的数据,并且把key和value(单元格的数据),放入到excelMap中映射
                //计数器用于映射数据使用
                int count = 0;
                //用于保存每条数据的Map,并且在Map中建立属性与对应关系的映射关系
                Map<String,String> excelMap = new HashMap<>();
                for (Cell cell : row) {
                    if(cell != null){
                        cell.setCellType(Cell.CELL_TYPE_STRING);
                        //获取每个单元格的数据
                        String value = cell.getStringCellValue();
                        if(value!=null && !value.equals("")){
                            // 将每个单元格的数据,存储到集合中
                            excelMap.put(key.get(count),value);
                            count++;
                        }
                    }
                }
                //创建对应的实体类类型
                T t =clazz.newInstance();
                /**
                 * Spring 提供的BeanMap,它可以通过反射的形式把Map中的数据映射到实体类中
                 */
                BeanMap beanMap = BeanMap.create(t);
                beanMap.putAll(excelMap);
                result.add(t);
            }
        }
        return result;
    }
}

此工具类就可以处理任何的excel表格