使用poi包解析excel

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.16</version>
</dependency>

一个excel内容包括:sheet-->row-->cell (这时应该打开新建或打开一个excel看看)

  1. 先跑一个导入excel的小例子(先导入poi的包)
    目的:输出 shafish 到新建的excel中并命名该excel为student.xls

    //1. 创建工作簿(excel)
    HSSFWorkbook workbook = new HSSFWorkbook();
    //2. 创建sheet,命名为学生信息
    HSSFSheet hssfSheet = workbook.createSheet("学生信息");
    //3. 创建行
    HSSFRow hssfRow = hssfSheet.createRow(0);
    //4. 创建列
    HSSFCell hssfCell = hssfRow.createCell(0);
    //5. 填充数据(输出到excel的数据)
    hssfCell.setCellValue("shafish");
    //6. 创建excel输出流
    try {
        OutputStream out = new FileOutputStream("d://student.xls");
    //7. 使用workbook实现输出
        workbook.write(out);
    //8. 关闭输出流
        out.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    总结:1.首先创建一个excel对象
    2.生成sheet了解一个excel可以存多大数据
    3.生成一行,再指定一列--行列定位出一个单元格
    4.最后写入数据-->数据持久化(就是写进硬盘)

  2. 导出excel例子
    把上面保存在excel中的shafish导入程序中,应用场景:导入excel数据到数据库

    try {
    //1. 取得excel工作簿
    HSSFWorkbook workbook = new HSSFWorkbook(new FileInputStream("d://students.xls"));
    //2. 迭代每一个sheet(考虑某个sheet为空的情况)
    for(int i=0;i<workbook.getNumberOfSheets();i++) {
        HSSFSheet sheet = workbook.getSheetAt(i);
        if(sheet == null) {
            continue;
        }
    //3. 循环获取每一行
        for(int j=1;j<sheet.getLastRowNum();j++) {
            //得到当前行(也要考虑当前行是否为空的情况)
            HSSFRow row = sheet.getRow(j);
            if(row == null) {
                continue;
            }
            System.our.println(row.getCell(0).getStringCellValue()));
        }
    }
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    } catch (IOException e) {
    e.printStackTrace();
    }

    总结:
    先取得excel,一步步定位到保存数据的单元格,最后获取

  3. 将第一个把数据导入excel的例子封装成util方便使用
    需要先定义传入的参数(先看一遍有大概印象,不用太纠结,看完代码就会了解全部流程)

    data:一个List集合,包含T(泛型)类型的数据--比如下面用到的Student类
    out:一个文件输出流(FileOutputStream)--指定输出的路径和文件名
    fields:从Student中指定需要输出的东吸(Map<key,value>)--比如说Student类中有age,name,no三个属性。现在只需要把age和name保存在excel中。Map<类属性,在excel表头显示内容>--会使用到反射

    先定义Student类

    /**
    * 
    * @ClassName: Student 
    * @Description: 学生实体类测试ExcelUtil导入
    * @author shafish
    * @date 2018年5月2日 下午1:40:16 
    *
    */
    public class Student {
    private String name;
    private String no;
    private String sex;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getNo() {
        return no;
    }
    public void setNo(String no) {
        this.no = no;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    }

    设置util工具类,处理传进的参数--data,out,fields

    /**
    * 
    * @ClassName: ExcelUtil 
    * @Description: 封装一个传入数据生成excel表格的工具类
    * @author shafish
    * @date 2018年5月2日 下午12:34:27 
    *
    */
    public class ExcelUtil {
    /**
    * @throws Exception 
    * 
    * @Title: listToExcel 
    * @Description: TODO(这里用一句话描述这个方法的作用) 
    * @param @param data  要导出的数据
    * @param @param out   输出位置
    * @param @param fields  属性对应的表头
    * @return void    返回类型 
    * @throws
     */
    public static <T> void listToExcel(List<T> data,OutputStream out,Map<String, String> fields) throws Exception {
        int sheetSize = 6000;//定义一个sheet最大的行数 03版的excel行数不能超过65536
        if(data==null||data.size()==0) {
            throw new Exception("传入数据源为空");
        }
    //1. 创建一个工作簿--sheet中的数据不能超过65536(需要做限制)
        HSSFWorkbook hssfWorkbook = new HSSFWorkbook();
    //2. 计算一共可分多少个sheet--sheetNum 
        int sheetNum = data.size()/sheetSize;
        if(data.size()%sheetSize!=0) {
            sheetNum += 1;
        }
    //3. 拿出实体中表头和对应数据 储存在数组中
        String[] fieldNames = new String[fields.size()];
        String[] chinaNames = new String[fields.size()];
        int count = 0;
        for(Entry<String, String> entry:fields.entrySet()) {
            String fieldName = entry.getKey();
            String chinaName = entry.getValue();
            fieldNames[count] = fieldName;
            chinaNames[count] = chinaName;
            count++;
        }
    //4. 在每一个sheet中填充内容--每个sheet都需要定义表头chinaName和它的数据fieldName
        for(int i=0;i<sheetNum;i++) {
            int rowCount = 0;
            HSSFSheet hssfSheet = hssfWorkbook.createSheet();
            int startIndex = i*sheetSize;
            //数据的终结点需要跟data中数据size比较
            int endIndex = ((i+1)*sheetSize>data.size())?data.size()-1:(i+1)*sheetSize-1;
    //4.1 创建表头行
            HSSFRow hssfRow = hssfSheet.createRow(rowCount);
    //4.2 在表头填充完所有表头数据
            for(int j=0;j<chinaNames.length;j++) {
                HSSFCell hssfCell = hssfRow.createCell(j);
                hssfCell.setCellValue(chinaNames[j]);
            }
            rowCount++;
    //4.3 在表内容中填充对应数据(值)
            for(int index=startIndex;index<=endIndex;index++) {
        //4.3.1 先取得当前数据实体
                T item = data.get(index);
        //4.3.2 当前sheet在当前行显示数据
                hssfRow = hssfSheet.createRow(rowCount);
        //4.3.3 输出与表头对应的数据
                for(int j=0;j<chinaNames.length;j++) {
                    //反射获取当前属性值
                    Field field = item.getClass().getDeclaredField(fieldNames[j]);
                    field.setAccessible(true);
                    Object object =field.get(item);
                    String value = object==null?"":object.toString();
                    //设置单元格内容(某行某列确定一个单元格)
                    HSSFCell hssfCell = hssfRow.createCell(j);
                    hssfCell.setCellValue(value);
                }
                //循环构造下一行
                rowCount ++;
            }
            hssfWorkbook.write(out);
        }
    }
    }

    写入数据,数据源可以从数据库中读(先挖个坑)

    public static void main(String[] args) {
        List<Student> data = new ArrayList<Student>();
        Student student = new Student();
        student.setAge(19);
        student.setName("fish");
        student.setNo("007");
        student.setSex("男");
        data.add(student);
    
        student = new Student();
        student.setAge(12);
        student.setName("as");
        student.setNo("008");
        student.setSex("男");
        data.add(student);
    
        student = new Student();
        student.setAge(20);
        student.setName("zx");
        student.setNo("009");
        student.setSex("男");
        data.add(student);
    
        student = new Student();
        student.setAge(21);
        student.setName("qw");
        student.setNo("010");
        student.setSex("女");
        data.add(student);
    
        student = new Student();
        student.setAge(22);
        student.setName("po");
        student.setNo("011");
        student.setSex("女");
        data.add(student);
    
        OutputStream out;
        try {
            out = new FileOutputStream("d://students.xls");
            Map<String,String> fields = new HashMap<String, String>();//new LinkedHashMap<String, String>();
            fields.put("age", "年龄");
            fields.put("no", "学号");
            fields.put("name", "姓名");
            fields.put("sex", "性别");
            ExcelUtil.listToExcel(data, out, fields);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    总结:
    1. 判断传入data有没有数据
    2. 创建一个工作簿
    3. 判断sheet
    4. 在sheet中填充数据
    4.1 每个sheet都需要填充表头(使用fields中的value)
    4.2 在表头的下一行开始填充对应的数据(根据fields中的key,使用反射获取data中当前对象的属性)
    重点
    5. 填充数据

    HSSFCell hssfCell = hssfRow.createCell(index);
    hssfCell.setCellValue(value);

    6. 其中需要用到的计算(计算一个sheet的起始和结束)

    //sheetSize是之前定义的sheet最大行数(03版sheet不能超过65536行)
    //0~5999、6000~1199、1200~1799、....
    int startIndex = i*sheetSize;
    int endIndex = ((i+1)*sheetSize>data.size())?data.size()-1:(i+1)*sheetSize-1;

result