JavaWEB--POI之EXCEL操作、优化、封装详解系列(三)--万能POI之EXCEL导出工具--PoiExportUtil入门篇

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Jack__Frost/article/details/77510892

前面讲完概述、原理以及helloworld,现在就讲下怎样的POI的EXCEL导出工具可以适用于各种情况吧。后面再做个优化分页的万能POI之EXCEL导出工具,本篇章先做个简单的万能POI之EXCEL导出工具(博主已经抽象成库,请于文末前去使用)。

文章结构:(1)面向JavaBean的导出工具;(2)面向List-Map结构的导出工具。

大家阅读了前篇就知道Excel报表导出之JSP方式就是这么简单了,查出数据直接对到jsp处理,样式也可以在制作excel模板时自定义,相当简单。但是我们要想当要导出大量数据的时候呢??难道我们也这样实时导出??这样一个正常系统而且在大量人使用的时候,对于系统的负载会非常非常高的,所以前篇我也给出了另一种方式:Excel报表导出之上传文件流方式。在这样的方式下,如何做出一个公用的适应各种情况的设计,这就是往后几篇文章要探讨的。

一、面向JavaBean的导出工具:

(一)设计的关键:

(1)兼容普通JavaBean;

(2)接口方法易用性;

(3)导出数据准确性;

(4)扩展性。

(二)基于POI抽象的关键步骤:

(1)设置表格标题

(2)设置标题栏

(3)设置内容栏(为了精确比对,需要给出标题栏对应的字段—DTO类(普通javabean)的属性)

(4)导出写入到流对象

(三)核心代码与demo:

准备实体:(一个普通的JavaBean)

package com.fuzhu.model;

/**
 * Created by 符柱成 on 2017/8/24.
 */
public class Student {
    private int id;
    private String name;
    private String sex;

    public Student(int id, String name, String sex) {
        this.id = id;
        this.name = name;
        this.sex = sex;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}

工具代码:


package com.fuzhu.utils;

/**
 * Created by 符柱成 on 2017/8/23.
 */

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;


import com.fuzhu.entity.Student;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;


public class ExportBeanExcel<T> {

    /**
     * 这是一个通用的方法,利用了JAVA的反射机制,可以将放置在JAVA集合中并且符号一定条件的数据以EXCEL 的形式输出
     *
     * title         表格标题名
     * headersName  表格属性列名数组
     * headersId    表格属性列名对应的字段---你需要导出的字段名(为了更灵活控制你想要导出的字段)
     *  dtoList     需要显示的数据集合,集合中一定要放置符合javabean风格的类的对象
     *  out         与输出设备关联的流对象,可以将EXCEL文档导出到本地文件或者网络中
     */
    public  void exportExcel(String title, List<String> headersName,List<String> headersId,
                            List<T> dtoList) {
        /*(一)表头--标题栏*/
        Map<Integer, String> headersNameMap = new HashMap<>();
        int key=0;
        for (int i = 0; i < headersName.size(); i++) {
            if (!headersName.get(i).equals(null)) {
                headersNameMap.put(key, headersName.get(i));
                key++;
            }
        }
        /*(二)字段*/
        Map<Integer, String> titleFieldMap = new HashMap<>();
        int value = 0;
        for (int i = 0; i < headersId.size(); i++) {
            if (!headersId.get(i).equals(null)) {
                titleFieldMap.put(value, headersId.get(i));
                value++;
            }
        }
        /* (三)声明一个工作薄:包括构建工作簿、表格、样式*/
        HSSFWorkbook wb = new HSSFWorkbook();
        HSSFSheet sheet = wb.createSheet(title);
        sheet.setDefaultColumnWidth((short)15);
        // 生成一个样式
        HSSFCellStyle style = wb.createCellStyle();
        HSSFRow row = sheet.createRow(0);
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        HSSFCell cell;
        Collection c = headersNameMap.values();//拿到表格所有标题的value的集合
        Iterator<String> it = c.iterator();//表格标题的迭代器
        /*(四)导出数据:包括导出标题栏以及内容栏*/
        //根据选择的字段生成表头
        short size = 0;
        while (it.hasNext()) {
            cell = row.createCell(size);
            cell.setCellValue(it.next().toString());
            cell.setCellStyle(style);
            size++;
        }
        //表格标题一行的字段的集合
        Collection zdC = titleFieldMap.values();
        Iterator<T> labIt = dtoList.iterator();//总记录的迭代器
        int zdRow =0;//列序号
        while (labIt.hasNext()) {//记录的迭代器,遍历总记录
            int zdCell = 0;
            zdRow++;
            row = sheet.createRow(zdRow);
            T l = (T) labIt.next();
            // 利用反射,根据javabean属性的先后顺序,动态调用getXxx()方法得到属性值
            Field[] fields = l.getClass().getDeclaredFields();//获得JavaBean全部属性
            for (short i = 0; i < fields.length; i++) {//遍历属性,比对
                Field field = fields[i];
                String fieldName = field.getName();//属性名
                Iterator<String> zdIt = zdC.iterator();//一条字段的集合的迭代器
                while (zdIt.hasNext()) {//遍历要导出的字段集合
                    if (zdIt.next().equals(fieldName)) {//比对JavaBean的属性名,一致就写入,不一致就丢弃
                        String getMethodName = "get"
                                + fieldName.substring(0, 1).toUpperCase()
                                + fieldName.substring(1);//拿到属性的get方法
                        Class tCls = l.getClass();//拿到JavaBean对象
                        try {
                            Method getMethod = tCls.getMethod(getMethodName,
                                    new Class[] {});//通过JavaBean对象拿到该属性的get方法,从而进行操控
                            Object val = getMethod.invoke(l, new Object[] {});//操控该对象属性的get方法,从而拿到属性值
                            String textVal = null;
                            if (val!= null) {
                                textVal = String.valueOf(val);//转化成String
                            }else{
                                textVal = null;
                            }
                            row.createCell((short) zdCell).setCellValue(textVal);//写进excel对象
                            zdCell++;
                        } catch (SecurityException e) {
                            e.printStackTrace();
                        } catch (IllegalArgumentException e) {
                            e.printStackTrace();
                        } catch (NoSuchMethodException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        try {
            FileOutputStream exportXls = new FileOutputStream("E://工单信息表.xls");
            wb.write(exportXls);
            exportXls.close();
            System.out.println("导出成功!");
        } catch (FileNotFoundException e) {
            System.out.println("导出失败!");
            e.printStackTrace();
        } catch (IOException e) {
            System.out.println("导出失败!");
            e.printStackTrace();
        }
    }
    /*
        使用例子
    */
    public static void main(String [] args){
        List<String> listName = new ArrayList<>();
        listName.add("id");
        listName.add("名字");
        listName.add("性别");
        List<String> listId = new ArrayList<>();
        listId.add("id");
        listId.add("name");
        listId.add("sex");
        List<Student> list = new ArrayList<>();
        list.add(new Student(111,"张三asdf","男"));
        list.add(new Student(111,"李四asd","男"));
        list.add(new Student(111,"王五","女"));


        ExportBeanExcel<Student> exportBeanExcelUtil = new ExportBeanExcel();
        exportBeanExcelUtil.exportExcel("测试POI导出EXCEL文档",listName,listId,list);

    }
}

(四)工具注意点:

(1)应用泛型,代表任意一个符合javabean风格的类

(2)注意这里为了简单起见,boolean型的属性xxx的get器方式为getXxx(),而不是isXxx()

(3) T这里代表一个不确定是实体类,即参数实体


二、面向List-Map结构的导出工具:

(一)设计的关键:

(1)兼容普通List-Map结构;

(2)接口方法易用性;

(3)导出数据准确性;

(4)扩展性。

(二)基于POI抽象的关键步骤:

(1)设置表格标题

(2)设置标题栏

(3)设置内容栏(为了精确比对,需要给出标题栏对应的字段—dtoList(List-Map结构中的key))

(4)导出写入到流对象

(三)核心代码与demo:

package com.fuzhu.utils;

import org.apache.poi.hssf.usermodel.*;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;

/**
 * Created by 符柱成 on 2017/8/24.
 */
public class ExportMapExcel {
    public void exportExcel(String title, List<String> headersName, List<String> headersId,
                            List<Map<String, Object>> dtoList) {
        /*
               (一)表头--标题栏
         */
        Map<Integer, String> headersNameMap = new HashMap<>();
        int key = 0;
        for (int i = 0; i < headersName.size(); i++) {
            if (!headersName.get(i).equals(null)) {
                headersNameMap.put(key, headersName.get(i));
                key++;
            }
        }
        /*
                (二)字段---标题的字段
         */
        Map<Integer, String> titleFieldMap = new HashMap<>();
        int value = 0;
        for (int i = 0; i < headersId.size(); i++) {
            if (!headersId.get(i).equals(null)) {
                titleFieldMap.put(value, headersId.get(i));
                value++;
            }
        }
       /*
                (三)声明一个工作薄:包括构建工作簿、表格、样式
       */
        HSSFWorkbook wb = new HSSFWorkbook();
        HSSFSheet sheet = wb.createSheet(title);
        sheet.setDefaultColumnWidth((short) 15);
        // 生成一个样式
        HSSFCellStyle style = wb.createCellStyle();
        HSSFRow row = sheet.createRow(0);
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        HSSFCell cell;
        Collection c = headersNameMap.values();//拿到表格所有标题的value的集合
        Iterator<String> headersNameIt = c.iterator();//表格标题的迭代器
        /*
                (四)导出数据:包括导出标题栏以及内容栏
        */
        //根据选择的字段生成表头--标题
        short size = 0;
        while (headersNameIt.hasNext()) {
            cell = row.createCell(size);
            cell.setCellValue(headersNameIt.next().toString());
            cell.setCellStyle(style);
            size++;
        }
        //表格一行的字段的集合,以便拿到迭代器
        Collection zdC = titleFieldMap.values();
        Iterator<Map<String, Object>> titleFieldIt = dtoList.iterator();//总记录的迭代器
        int zdRow = 1;//真正的数据记录的列序号
        while (titleFieldIt.hasNext()) {//记录的迭代器,遍历总记录
            Map<String, Object> mapTemp = titleFieldIt.next();//拿到一条记录
                row = sheet.createRow(zdRow);
                zdRow++;
                int zdCell = 0;
                Iterator<String> zdIt = zdC.iterator();//一条记录的字段的集合的迭代器
                while (zdIt.hasNext()) {
                    String tempField =zdIt.next();//字段的暂存
                    if (mapTemp.get(tempField) != null) {
                        row.createCell((short) zdCell).setCellValue(String.valueOf(mapTemp.get(tempField)));//写进excel对象
                        zdCell++;
                    }
                }
        }
        try {
            FileOutputStream exportXls = new FileOutputStream("E://工单信息表Map.xls");
            wb.write(exportXls);
            exportXls.close();
            System.out.println("导出成功!");
        } catch (FileNotFoundException e) {
            System.out.println("导出失败!");
            e.printStackTrace();
        } catch (IOException e) {
            System.out.println("导出失败!");
            e.printStackTrace();
        }
    }
    public static void main(String [] args) {

        List<String> listName = new ArrayList<>();
        listName.add("id");
        listName.add("名字");
        listName.add("性别");
        List<String> listId = new ArrayList<>();
        listId.add("id");
        listId.add("name");
        listId.add("sex");

        List<Map<String,Object>> listB = new ArrayList<>();
        for (int t=0;t<6;t++){
            Map<String,Object> map = new HashMap<>();
            map.put("id",t);
            map.put("name","abc"+t);
            map.put("sex","男"+t);
            listB.add(map);
        }
        System.out.println("listB  : "+listB.toString());
        ExportMapExcel exportExcelUtil = new ExportMapExcel();
        exportExcelUtil.exportExcel("测试POI导出EXCEL文档",listName,listId,listB);

    }
}

(四)工具注意点:

(1)面向的是List-Map数据结构,请不要注入别的数据结构

(2)方法参数说明:

1)title是:表格的名称
2)headersName标题栏的文字
3)headersId:对应标题栏的字段,为了准确导出到对应列而设计
4)dtoList:我们要导出的所有数据(把数据封装在dtoList数据传输对象中)

(3)此处的入门篇工具兼容性并不很好,只是讲解了工具的核心。博客抽象的工具是已这两个demo工具为基准点去设计的。


本篇的demo源码下载:JavaWEB–POI之EXCEL操作、优化、封装详解系列(三)万能POI之EXCEL导出工具–PoiExportUtil入门篇

POI辅助库:POI辅助库

好了,JavaWEB–POI之EXCEL操作、优化、封装详解系列(三)万能POI之EXCEL导出工具–PoiExportUtil入门篇讲完了,这是自己设计的第一个java工具库,并且抽象作为开源工具了,在这里写出来记录,这是积累的必经一步,我会继续出这个系列文章,分享经验给大家。欢迎在下面指出错误,共同学习!!你的点赞是对我最好的支持!!!

更多内容,可以访问JackFrost的博客

猜你喜欢

转载自blog.csdn.net/Jack__Frost/article/details/77510892