天天看點

重構:以Java POI 導出EXCEL為例2前言正文

前言

上一篇博文已經将一些對象抽象成成員變量以及将一些代碼塊提煉成函數。這一節将會繼續重構原有的代碼,将一些函數抽象成類,增加成員變量,将傳入的參數合成類等等。

上一篇博文位址:

http://www.cnblogs.com/fixzd/p/8982739.html

正文

我們先來看看上一篇博文重構後的代碼,還是有點長

重構:以Java POI 導出EXCEL為例2前言正文
重構:以Java POI 導出EXCEL為例2前言正文
public class ExportExcel<T> {
    private HSSFWorkbook workbook;
    
    public ExportExcel() {
        this(new HSSFWorkbook());
    }

    public ExportExcel(HSSFWorkbook workbook) {
        this.workbook = workbook;
    }

    public void exportExcel(Collection<T> dataset, OutputStream out) {
        exportExcel("測試POI導出EXCEL文檔", null, dataset, out, "yyyy-MM-dd");
    }

    public void exportExcel(String[] headers, Collection<T> dataset, OutputStream out) {
        exportExcel("測試POI導出EXCEL文檔", headers, dataset, out, "yyyy-MM-dd");
    }

    public void exportExcel(String[] headers, Collection<T> dataset, OutputStream out, String pattern) {
        exportExcel("測試POI導出EXCEL文檔", headers, dataset, out, pattern);
    }

    public void exportExcel(String title, String[] headers, Collection<T> dataset, OutputStream out, String pattern) {
        // 生成一個表格
        HSSFSheet sheet = workbook.createSheet(title);
        
        // 生成資料标題和資料行樣式
        HSSFCellStyle rowTirtleStyle = getRowTitleStyle();
        HSSFCellStyle rowDataStyle = getRowDataStyle();
        
        //建立資料标題和資料行
        createRowTitle(headers, sheet, rowTirtleStyle);
        createRowData(dataset, pattern, sheet, rowDataStyle);
        
        //寫入流
        writeExecl(out);
    }

    /**
     * Description:寫入到OutputStream
     */
    private void writeExecl(OutputStream out) {
        try {
            workbook.write(out);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Description: 産生資料行
     */
    private void createRowData(Collection<T> dataset, String pattern, HSSFSheet sheet, HSSFCellStyle rowDataStyle) {
        // 周遊集合資料,産生資料行
        Iterator<T> it = dataset.iterator();
        int index = 0;
        while (it.hasNext()) {
            index++;
            HSSFRow row = sheet.createRow(index);
            T t = (T) it.next();
            // 利用反射,根據javabean屬性的先後順序,動态調用getXxx()方法得到屬性值
            Field[] fields = t.getClass().getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                HSSFCell cell = row.createCell(i);
                cell.setCellStyle(rowDataStyle);
                Field field = fields[i];
                String fieldName = field.getName();
                String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
                try {
                    Class tCls = t.getClass();
                    Method getMethod = tCls.getMethod(getMethodName, new Class[] {});
                    Object value = getMethod.invoke(t, new Object[] {});
                    // 判斷值的類型後進行強制類型轉換
                    String textValue = null;
                    if (value instanceof Boolean) {
                        boolean bValue = (Boolean) value;
                        textValue = "男";
                        if (!bValue) {
                            textValue = "女";
                        }
                    } else if (value instanceof Date) {
                        Date date = (Date) value;
                        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
                        textValue = sdf.format(date);
                    } else {
                        // 其它資料類型都當作字元串簡單處理
                        textValue = value.toString();
                    }
                    // 如果不是圖檔資料,就利用正規表達式判斷textValue是否全部由數字組成
                    if (textValue != null) {
                        Pattern p = Pattern.compile("^//d+(//.//d+)?$");
                        Matcher matcher = p.matcher(textValue);
                        if (matcher.matches()) {
                            // 是數字當作double處理
                            cell.setCellValue(Double.parseDouble(textValue));
                        } else {
                            HSSFRichTextString richString = new HSSFRichTextString(textValue);
                            HSSFFont font3 = workbook.createFont();
                            font3.setColor(HSSFColor.BLUE.index);
                            richString.applyFont(font3);
                            cell.setCellValue(richString);
                        }
                    }
                } catch (SecurityException e) {
                    e.printStackTrace();
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } finally {
                    // 清理資源
                }
            }
        }
    }

    /**
     * Description: 産生表格标題行
     */
    private void createRowTitle(String[] headers, HSSFSheet sheet, HSSFCellStyle rowTirtleStyle) {
        HSSFRow row = sheet.createRow(0);
        for (int i = 0; i < headers.length; i++) {
            HSSFCell cell = row.createCell(i);
            cell.setCellStyle(rowTirtleStyle);
            HSSFRichTextString text = new HSSFRichTextString(headers[i]);
            cell.setCellValue(text);
        }
    }

    /**
     * Description:生成資料标題樣式
     */
    private HSSFCellStyle getRowTitleStyle() {
        HSSFCellStyle style = workbook.createCellStyle();
        // 設定這些樣式
        style.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
        style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
        style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        style.setBorderRight(HSSFCellStyle.BORDER_THIN);
        style.setBorderTop(HSSFCellStyle.BORDER_THIN);
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        
        // 生成一個字型
        HSSFFont font = workbook.createFont();
        font.setColor(HSSFColor.VIOLET.index);
        font.setFontHeightInPoints((short) 12);
        font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        
        // 把字型應用到目前的樣式
        style.setFont(font);
        
        return style;
    }
    
    /**
     * Description:生成資料行樣式
     */
    private HSSFCellStyle getRowDataStyle() {
        HSSFCellStyle style = workbook.createCellStyle();
        // 設定這些樣式
        style.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
        style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
        style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        style.setBorderRight(HSSFCellStyle.BORDER_THIN);
        style.setBorderTop(HSSFCellStyle.BORDER_THIN);
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
        
        // 生成另一個字型
        HSSFFont font = workbook.createFont();
        font.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);
        
        style.setFont(font);
                
        return style;
    }

}      

View Code

那麼接下來我們要如何重構呢?我們從問題的角度來重構吧

  1. 在上面代碼中我們可以看到有兩個建立樣式的函數,這兩個函數getRowTitleStyle()和getRowDataStyle()可以說是導出execl的預設樣式。在這裡我們思考下,如果我們對導出的樣式有變動是不是又要修改ExportExcel類?
    重構:以Java POI 導出EXCEL為例2前言正文
    重構:以Java POI 導出EXCEL為例2前言正文
    /**
         * Description:生成資料标題樣式
         */
        private HSSFCellStyle getRowTitleStyle() {
            HSSFCellStyle style = workbook.createCellStyle();
            // 設定這些樣式
            style.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
            style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
            style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
            style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
            style.setBorderRight(HSSFCellStyle.BORDER_THIN);
            style.setBorderTop(HSSFCellStyle.BORDER_THIN);
            style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
            
            // 生成一個字型
            HSSFFont font = workbook.createFont();
            font.setColor(HSSFColor.VIOLET.index);
            font.setFontHeightInPoints((short) 12);
            font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
            
            // 把字型應用到目前的樣式
            style.setFont(font);
            
            return style;
        }
        
        /**
         * Description:生成資料行樣式
         */
        private HSSFCellStyle getRowDataStyle() {
            HSSFCellStyle style = workbook.createCellStyle();
            // 設定這些樣式
            style.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
            style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
            style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
            style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
            style.setBorderRight(HSSFCellStyle.BORDER_THIN);
            style.setBorderTop(HSSFCellStyle.BORDER_THIN);
            style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
            style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
            
            // 生成另一個字型
            HSSFFont font = workbook.createFont();
            font.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);
            
            style.setFont(font);
                    
            return style;
        }      
  2. 接下來我們看看導出的主方法exportExcel(String title, String[] headers, Collection<T> dataset, OutputStream out, String pattern)。有沒有覺得參數有點多了,能不能将一些參數合并成一個類或者去除沒用的參數?
  3. 我們再來看看産生資料行函數createRowData的資料處理方式,如下。雖然這裡隻有兩個if...else,但是我們能不能用什麼設計模式将他們提取出來,友善以後增加類型時不必修改原有的類?
    if (value instanceof Boolean) {
                            boolean bValue = (Boolean) value;
                            textValue = "男";
                            if (!bValue) {
                                textValue = "女";
                            }
                        } else if (value instanceof Date) {
                            Date date = (Date) value;
                            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                            textValue = sdf.format(date);
                        } else {
                            // 其它資料類型都當作字元串簡單處理
                            textValue = value.toString();
                        }      
  4. 我們在思考下第三個問題,資料的轉換不僅僅隻有上面那麼按部就班的,就好比一輛車的狀态有正常,損壞、維修中、報廢等等,但是在資料庫中是以0、1、2、3來存儲的,那麼有什麼好的方法可以在不修改原有代碼下進行轉換呢?

好了,這篇博文就圍繞着上面四個問題進行重構,大家可以試着按照這幾個問題對上面代碼進行重構,相信經過自己思考和動手後會對代碼的設計有進一步的了解。

問題1:如果我們對導出的樣式有變動是不是又要修改ExportExcel類?

針對上面問題,我們是不是可以将樣式建立抽象成類?

/**
     * Description:生成資料标題樣式
     */
    private HSSFCellStyle getRowTitleStyle() {
        HSSFCellStyle style = workbook.createCellStyle();
        // 設定這些樣式
        style.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
        style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
        style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        style.setBorderRight(HSSFCellStyle.BORDER_THIN);
        style.setBorderTop(HSSFCellStyle.BORDER_THIN);
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        
        // 生成一個字型
        HSSFFont font = workbook.createFont();
        font.setColor(HSSFColor.VIOLET.index);
        font.setFontHeightInPoints((short) 12);
        font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        
        // 把字型應用到目前的樣式
        style.setFont(font);
        
        return style;
    }      

從上面代碼可以置頂HSSFCellStyle的建立需要用到Workbook對象,是以接口就不适用。

然後上面代碼中可以看出一個整體的樣式還包含了字型,那麼就可以設計一個抽象類,如下

public abstract class AbstractCellStyle {
    HSSFWorkbook workbook;
    HSSFCellStyle style;
    HSSFFont font;

    public AbstractCellStyle(HSSFWorkbook workbook) {
        this.workbook = workbook;
        style = workbook.createCellStyle();
        font = workbook.createFont();
    }
    
    public abstract void setStyle();
    
    public abstract void setFont();

    
    public HSSFCellStyle getCellStyle() {
        style.setFont(font);
        return style;
    }
}      

該抽象類AbstractCellStyle有一個有參構造函數、三個成員變量、一個獲得樣式的方法和兩個抽象方法setStyle和setFont。

子類通過繼承AbstractCellStyle,然後重寫方法setStyle和setFont即可。

構造函數需要傳入Workbook,然後在構造函數裡建立樣式和字型對象,最後調用getCellStyle方法獲得HSSFCellStyle即可。

我這裡弄了兩個預設的樣式了,如下

預設資料行樣式類

DefaultDataCellStyle.java

重構:以Java POI 導出EXCEL為例2前言正文
重構:以Java POI 導出EXCEL為例2前言正文
public class DefaultDataCellStyle extends AbstractCellStyle{
    public DefaultDataCellStyle(HSSFWorkbook workbook) {
        super(workbook);
    }

    @Override
    public void setStyle() {
        style.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
        style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
        style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        style.setBorderRight(HSSFCellStyle.BORDER_THIN);
        style.setBorderTop(HSSFCellStyle.BORDER_THIN);
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
    }
    @Override
    public void setFont() {
        font.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);
    }

}      

預設一個資料标題樣式,

DefaultTitleCellStyle.java

重構:以Java POI 導出EXCEL為例2前言正文
重構:以Java POI 導出EXCEL為例2前言正文
public class DefaultTitleCellStyle extends AbstractCellStyle{
    public DefaultTitleCellStyle(HSSFWorkbook workbook) {
        super(workbook);
    }

    @Override
    public void setStyle() {
        style.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
        style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
        style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        style.setBorderRight(HSSFCellStyle.BORDER_THIN);
        style.setBorderTop(HSSFCellStyle.BORDER_THIN);
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
    }
    @Override
    public void setFont() {
        font.setColor(HSSFColor.VIOLET.index);
        font.setFontHeightInPoints((short) 12);
        font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
    }
}      

然後ExportExcel這個類也需要做出相應的修改,修改内容如下

  1. 删除兩個函數getRowTitleStyle()和getRowDataStyle()
  2. 增加兩個成員變量,且将Workbook也抽象成成員變量
    private HSSFWorkbook workbook;
        private AbstractCellStyle titleCellStyle;//标題行樣式
        private AbstractCellStyle dataCellStyle;//資料行樣式      
  3. 修改構造函數,如下
    public ExportExcel() {
            this(new HSSFWorkbook());
        }
    
        /**
         * 這裡可以定義兩個常量,但是這裡需要workbook,是以就沒有抽取出來
         * @param workbook
         */
        public ExportExcel(HSSFWorkbook workbook) {
            this(workbook,new DefaultTitleCellStyle(workbook),new DefaultDataCellStyle(workbook));
        }
    
        public ExportExcel(HSSFWorkbook workbook, AbstractCellStyle titleCellStyle, AbstractCellStyle dataCellStyle) {
            this.workbook = workbook;
            this.titleCellStyle = titleCellStyle;
            this.dataCellStyle = dataCellStyle;
        }      
  4. 其他調用getRowTitleStyle()和getRowDataStyle()方法的修改成調用成員變量的方法。

重構後

那麼現在我們再來看看這個問題,如果我們對導出的樣式有變動是不是又要修改ExportExcel類?

現在我們需要修改導出的标題樣式或者資料行樣式的話,我們隻需要寫個類繼承AbstractCellStyle,然後設定字型和樣式即可,是不是很友善。如果你有更好的建議在評論處留言哦

問題2:導出的主方法exportExcel參數有點多了,能不能将一些參數合并成一個類或者去除沒用的參數?

 原來的如下

public void exportExcel(String title, String[] headers, Collection<T> dataset, OutputStream out, String pattern) {...}      

現在讓我們來思考思考下execl檔案,一個execl檔案可能有多個工作簿(也就是sheet),如下

重構:以Java POI 導出EXCEL為例2前言正文

每個工作簿(sheet)都有自己的表格,每個表格都有自己的行和列

在我們到處這裡是以每一行對應資料庫中一張表的一條記錄,每一列就好比資料庫中的一張表的一個屬性。

現在我們現将每一列抽象成一個類,每一列中包含一個标題和資料所對應的實體屬性,例如,學号是标題,學号在實體Student中對應的屬性是id

重構:以Java POI 導出EXCEL為例2前言正文

抽象出來的類如下

public class CellEntity {
    private String title;
    private String filedName;
    
    //set get方法...
}      

接下來我們把每個工作簿(sheet)也抽象成一個類,這個類中包含多個列(CellEntity)、工作簿名稱(sheetName)、資料集合。

public class SheetEntity {
    private String sheetName;

    private List<CellEntity> cellEntitys;

    private Collection dataset;

    //set get方法  
}      

最後修改導出的主方法exportExcel和其他一些參數的擷取

public void exportExcel(SheetEntity sheetEntity, OutputStream out) {...}      

問題3:函數createRowData的資料處理能不能用什麼設計模式将他們提取出來,友善以後增加類型時不必修改原有的類?

String textValue = null;
    if (value instanceof Boolean) {
        boolean bValue = (Boolean) value;
        textValue = "男";
        if (!bValue) {
            textValue = "女";
        }
    } else if (value instanceof Date) {
        Date date = (Date) value;
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        textValue = sdf.format(date);
    } else {
        // 其它資料類型都當作字元串簡單處理
        textValue = value.toString();
    }      

從上面代碼中可以看出value被判斷是哪種類型,然後再進行指派操作,顯示被判斷是否是Boolean,然後判斷Date,最後都被當成字元串處理。

這裡部落客采用的是如下方法,将資料轉換抽象成一個抽象類,如下

public abstract class AbstractDataHandler {
    private AbstractDataHandler abstractDataHandler;

    public AbstractDataHandler(AbstractDataHandler abstractDataHandler) {
        this.abstractDataHandler = abstractDataHandler;
    }

    public abstract String dataHandle(Object value);

    protected String nextHandle(Object value) {
        if (abstractDataHandler != null) {
            return abstractDataHandler.dataHandle(value);
        }
        return null;
    }
}      

子類通過內建該抽象類,實作dataHandle方法,如果是目前類型,則處理後傳回,否則調用抽象類AbstractDataHandler的nextHandle方法繼續調用下個資料處理方法。現在來看看我寫的幾個資料處理類

Boolean資料處理

public class BooleanDataHandler extends AbstractDataHandler {

    public BooleanDataHandler(AbstractDataHandler abstractDataHandler) {
        super(abstractDataHandler);
    }

    @Override
    public String dataHandle(Object value) {
        if (value instanceof Boolean) {
            boolean bValue = (Boolean) value;
            String textValue = "是";
            if (!bValue) {
                textValue = "否";
            }
            return textValue;
        } else {
            return nextHandle(value);
        }
    }

}

      

Date資料處理

public class DateDataHandler extends AbstractDataHandler {
    
    public DateDataHandler(AbstractDataHandler abstractDataHandler) {
        super(abstractDataHandler);
    }

    @Override
    public String dataHandle(Object value) {
        if (value instanceof Date) {
            Date date = (Date) value;
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            return sdf.format(date);
        } else {
            return nextHandle(value);
        }
    }

}      

String資料處理

public class StringDataHandler extends AbstractDataHandler {

    public StringDataHandler(AbstractDataHandler abstractDataHandler) {
        super(abstractDataHandler);
    }

    @Override
    public String dataHandle(Object value) {
        return value.toString();
    }

}      

然後建立一個工廠類DataHandlerFactory,工具類調用這個工廠類的dataHandle方法,資料處理就會按照Boolean-->Date-->String流程走下去,都沒有處理就傳回null

public class DataHandlerFactory {

    private static AbstractDataHandler dataHandler = new BooleanDataHandler(
            new DateDataHandler(
                    new StringDataHandler(null)));

    public static String dataHandle(Object value) {
        return dataHandler.dataHandle(value);
    }
}      

 修改後的代碼如下,是不是簡便了許多

重構:以Java POI 導出EXCEL為例2前言正文

 -------------->     

重構:以Java POI 導出EXCEL為例2前言正文

現在如果需要增加預設的類型處理,隻需要增加AbstractDataHandler的子類,然後修改DataHandlerFactory工廠類即可。

問題4:資料的轉換并不是按照預期進行的那麼有什麼好的方法可以在不修改原有代碼下進行轉換呢?

關于這個問題,我們需要增加一個轉換接口,然後将資料轉換交給子類來實作即可。其實在實體類CellEntity增加一個類型轉換的成員變量即可。接口如下

public interface DataConversion {
    String transferData(Object data);
}      

實體類CellEntity也需要做相應的修改,增加一個成員變量即可

public class CellEntity {
    private String title;
    private String fieldName;
    private DataConversion conversion;
    ......
}      

然後到處工具類中也要做修改,由原先交給工廠處理的修改為判斷cellEntity對象的成員變量conversion是否為null,為null則交給預設的資料處理類處理,不為null則交給conversion處理

if (cellEntity.getConversion() == null)
        textValue = DataHandlerFactory.dataHandle(value);
    else
        textValue = cellEntity.getConversion().transferData(value);      

就按上面車輛狀态來舉個相應的例子吧,判斷傳入的類型是否為0或者1,0傳回正常,1傳回異常,其他的都傳回null,如下

public class CarStatusExportConversion implements DataExportConversion {

    @Override
    public String transferData(Object data) {
        if (data == null) return null;
        Integer carStatus = (Integer) data;
        switch (carStatus){
            case 0:
                return "正常";
            case 1:
                return "異常";
        }
        return null;
    }
}      

完整的工具類和測試代碼

ExportExecl工具類

重構:以Java POI 導出EXCEL為例2前言正文
重構:以Java POI 導出EXCEL為例2前言正文
public class ExportExcel<T> {
    private HSSFWorkbook workbook;
    private AbstractCellStyle titleCellStyle;//标題行樣式
    private AbstractCellStyle dataCellStyle;//資料行樣式

    public ExportExcel() {
        this(new HSSFWorkbook());
    }

    /**
     * 這裡可以定義兩個常量,但是這裡需要workbook,是以就沒有抽取出來
     * @param workbook
     */
    public ExportExcel(HSSFWorkbook workbook) {
        this(workbook,new DefaultTitleCellStyle(workbook),new DefaultDataCellStyle(workbook));
    }

    public ExportExcel(HSSFWorkbook workbook, AbstractCellStyle titleCellStyle, AbstractCellStyle dataCellStyle) {
        this.workbook = workbook;
        this.titleCellStyle = titleCellStyle;
        this.dataCellStyle = dataCellStyle;
    }

    public void exportExcel(SheetEntity sheetEntity, OutputStream out) {
        // 生成一個表格
        HSSFSheet sheet = workbook.createSheet(sheetEntity.getSheetName());
        // 生成資料标題和資料行樣式
        HSSFCellStyle rowTirtleStyle = titleCellStyle.getCellStyle();
        HSSFCellStyle rowDataStyle = dataCellStyle.getCellStyle();
        
        //建立資料标題和資料行
        createRowTitle(sheetEntity.getCellEntitys(), sheet, rowTirtleStyle);
        createRowData(sheetEntity.getCellEntitys(),sheetEntity.getDataset(), sheet, rowDataStyle);
        
        //寫入流
        writeExecl(out);
    }

    /**
     * Description:寫入到OutputStream
     */
    private void writeExecl(OutputStream out) {
        try {
            workbook.write(out);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Description: 産生資料行
     */
    private void createRowData(List<CellEntity> cellEntitys, Collection<T> dataset, HSSFSheet sheet, HSSFCellStyle rowDataStyle) {
        // 周遊集合資料,産生資料行
        Iterator<T> it = dataset.iterator();
        int index = 0;
        while (it.hasNext()) {
            index++;
            HSSFRow row = sheet.createRow(index);
            T t = (T) it.next();
            for (int i = 0; i < cellEntitys.size(); i++) {
                HSSFCell cell = row.createCell(i);
                cell.setCellStyle(rowDataStyle);
                try {
                    String textValue = null;

                    CellEntity cellEntity = cellEntitys.get(i);
                    Object value = PropertyUtils.getProperty(t, cellEntity.getFiledName());

                    if (cellEntity.getConversion() == null)
                        textValue = DataHandlerFactory.dataHandle(value);
                    else
                        textValue = cellEntity.getConversion().transferData(value);

                    cell.setCellValue(textValue);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * Description: 産生表格标題行
     */
    private void createRowTitle(List<CellEntity> cellEntitys, HSSFSheet sheet, HSSFCellStyle rowTirtleStyle) {
        HSSFRow row = sheet.createRow(0);
        for (int i = 0; i < cellEntitys.size(); i++) {
            HSSFCell cell = row.createCell(i);
            cell.setCellStyle(rowTirtleStyle);
            HSSFRichTextString text = new HSSFRichTextString(cellEntitys.get(i).getTitle());
            cell.setCellValue(text);
        }
    }

}      

Test導出測試類

重構:以Java POI 導出EXCEL為例2前言正文
重構:以Java POI 導出EXCEL為例2前言正文
public class Test {

    public static void main(String[] args) {
        // 測試學生
        ExportExcel<Student> ex = new ExportExcel<Student>();
        // 測試圖書
        ExportExcel<Book> ex2 = new ExportExcel<Book>();

        List<Student> studentList = getStudentList();

        try {


            OutputStream out = new FileOutputStream("E://a.xls");

            ex.exportExcel(getStudentSheetEntity("學生",studentList), out);

            out.close();
            System.out.println("excel導出成功!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static SheetEntity getStudentSheetEntity(String sheetName,List<Student> studentList){

        List<CellEntity> cellEntitys = new ArrayList<CellEntity>();
        cellEntitys.add(new CellEntity("學号","id"));
        cellEntitys.add(new CellEntity("姓名","name"));
        cellEntitys.add(new CellEntity("年齡","age"));
        cellEntitys.add(new CellEntity("性别","sex", new SexDataConversion()));
        cellEntitys.add(new CellEntity("出生日期","birthday"));

        SheetEntity entity = new SheetEntity(sheetName,cellEntitys , studentList);

        return entity;
    }

    private static List<Student> getStudentList() {
        List<Student> datas = new ArrayList<Student>();
        datas.add(new Student(10000001, "張三", 20, true, new Date()));
        datas.add(new Student(20000002, "李四", 24, false, new Date()));
        datas.add(new Student(30000003, "王五", 22, true, new Date()));
        return datas;
    }

}

class SexDataConversion implements DataConversion{

    @Override
    public String transferData(Object data) {
        if (data instanceof Boolean) {
            boolean bValue = (Boolean) data;
            String textValue = "男";
            if (!bValue) {
                textValue = "女";
            }
            return textValue;
        }
        return null;
    }
}      

這一篇修改後的github位址如下

github位址:

https://github.com/rainbowda/utils/tree/master/poi/src/main/java/com/utils/poi/update_2

後續會增加其他各種各樣的工具項目,覺得不錯的給個star,謝謝

作者: 雲枭zd

Github:

Github位址

出處:

https://www.cnblogs.com/fixzd/

版權聲明:本文歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則視為侵權。