1. 程式人生 > >JavaWEB--POI之EXCEL操作、優化、封裝詳解系列(三)--萬能POI之EXCEL匯出工具--PoiExportUtil入門篇

JavaWEB--POI之EXCEL操作、優化、封裝詳解系列(三)--萬能POI之EXCEL匯出工具--PoiExportUtil入門篇

前面講完概述、原理以及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工具為基準點去設計的。

好了,JavaWEB–POI之EXCEL操作、優化、封裝詳解系列(三)萬能POI之EXCEL匯出工具–PoiExportUtil入門篇講完了,這是自己設計的第一個java工具庫,並且抽象作為開源工具了,在這裡寫出來記錄,這是積累的必經一步,我會繼續出這個系列文章,分享經驗給大家。歡迎在下面指出錯誤,共同學習!!你的點贊是對我最好的支援!!!