1. 程式人生 > >Springboot 之 使用POI操作excel

Springboot 之 使用POI操作excel

為了方便地使用poi操作excel,在這裡,使用類BubbleSheet對Poi中的Sheet進行封裝,BubbleSheet類如下所示:

import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFPalette;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.RegionUtil;

import java.util.ArrayList;
import java.util.List;

public class BubbleSheet {

    private Sheet sheet;

    private Row nowRow;

    private Integer nowRowNo;

    private HSSFWorkbook wb;

    private List<HSSFCellStyle> cellStylesList = new ArrayList<HSSFCellStyle>();

    BubbleSheet(HSSFWorkbook wb) {
        this.wb = wb;
        this.sheet = wb.createSheet();
        createCellStyleList();
        nowRowNo = -1;
        setNowRowWithRowNo(0);
    }

    private HSSFCellStyle createCellStyle(int poiColorIndex, int r, int g, int b) {
        HSSFCellStyle cellStyle =  wb.createCellStyle();

        cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
        cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);

        cellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN); //下邊框
        cellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN); //左邊框
        cellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN); //上邊框
        cellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN); //右邊框

        HSSFPalette palette = wb.getCustomPalette();
        palette.setColorAtIndex((short)poiColorIndex, (byte) r, (byte) g, (byte) b);
        cellStyle.setFillForegroundColor((short)poiColorIndex);
        cellStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);

        return cellStyle;
    }

    private void createCellStyleList() {
        cellStylesList.add(createCellStyle(HSSFColor.LIME.index, 255, 255, 255)); // 預設的白色
        cellStylesList.add(createCellStyle(HSSFColor.BLUE.index, 211, 209, 207));  // 內容淺灰色
        cellStylesList.add(createCellStyle(HSSFColor.GREEN.index, 186, 210, 170)); // 表頭淺綠色
    }

    public void mergeCells(Integer firstRow, Integer lastRow, Integer firstCol, Integer lastCol, String content, int colorIndex) {
        CellRangeAddress cra = new CellRangeAddress(firstRow, lastRow, firstCol, lastCol);
        //在sheet裡增加合併單元格
        sheet.addMergedRegion(cra);
        Cell cell_1 = nowRow.createCell(firstCol); // 選擇第一行的第一個單元格,因為位置在這個位置,所以設定的是合併的單元格
        cell_1.setCellStyle(cellStylesList.get(colorIndex));
        // 設定單元格的內容
        cell_1.setCellValue(content);

        // 設定合併單元格的邊框
        RegionUtil.setBorderBottom(HSSFCellStyle.BORDER_THIN, cra, sheet, wb); // 下邊框
        RegionUtil.setBorderLeft(HSSFCellStyle.BORDER_THIN, cra, sheet, wb); // 左邊框
        RegionUtil.setBorderRight(HSSFCellStyle.BORDER_THIN, cra, sheet, wb); // 有邊框
        RegionUtil.setBorderTop(HSSFCellStyle.BORDER_THIN, cra, sheet, wb); // 上邊框
    }

    public void setLineValues(Integer col, String[] titleNames, int colorIndex) {
        for(String stp: titleNames) {
            Cell ctp = nowRow.createCell(col ++);
            ctp.setCellValue(stp);
            ctp.setCellStyle(cellStylesList.get(colorIndex));
        }
    }

    public void setNowRowWithRowNo(Integer rowNo) {
        // 這裡的邏輯感覺很奇怪,主要是在getRow、createRow以及樣式設定上的相互作用的結果。
        if(rowNo == null) rowNo = 0 ;
        if(nowRowNo.equals(rowNo)) { // 如果是合併單元格行後面的建立單元時,不需要重新生成這行了。
            return ;
        }
        Row row = sheet.getRow(rowNo); // 使用這個的原因是:需要設定合併單元格的外邊框樣式,如果不用這個會出錯。
        if(row == null){
            row = sheet.createRow(rowNo);
        }
        nowRowNo = rowNo;
        setNowRow(row);
    }

    private void setNowRow(Row nowRow) {
        this.nowRow = nowRow;
    }

    public void createFreezePane(int startRowNo, int endRowNo, int startColNo, int endColNo) {
        sheet.createFreezePane( startRowNo, endRowNo, startColNo, endColNo);
    }
}

接下來使用BubbleSheet方便操作表格的例子如下:

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

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;

public class bubbleSheet_ex {

    static final  private String[] titleNames = {
            "廣告位", "月度", "專案名稱", "預定量",
            "預計本月金額", "直客公司",
            "所屬區域", "對應銷售", "媒介", "當月比例"};

    public static int stepHigh = 0;

    public static void main(String[] args) {

        HSSFWorkbook wb =  new HSSFWorkbook();
        BubbleSheet bs = new BubbleSheet(wb);
        bs.setNowRowWithRowNo(0); // 設定要操作哪一行
        bs.mergeCells(0, 0, 0, 1, titleNames[0], 0); // 設定第一行第一個標題
        final String[] titleNames_temp = Arrays.copyOfRange(titleNames, 1, titleNames.length);

        bs.setNowRowWithRowNo(0); // 設定要操作哪一行
        bs.setLineValues(2, titleNames_temp, 0); // 設定第一行除第一個以外的標題

        stepHigh = 10;
        int firstRow_temp = 1;
        bs.setNowRowWithRowNo(firstRow_temp); // 設定要操作哪一行
        bs.mergeCells(firstRow_temp, firstRow_temp + stepHigh, 0, 1, "模組1", 1);

        firstRow_temp = 13;
        bs.setNowRowWithRowNo(firstRow_temp); // 設定要操作哪一行
        bs.mergeCells(firstRow_temp, firstRow_temp + stepHigh, 0, 1, "模組2", 2);

        saveexcel(wb, "e:/test_bs.xls");
    }

    private static void saveexcel(HSSFWorkbook wb, String filename) {
        // 儲存檔案
        File file = new File(filename);
        try {
            file.createNewFile(); // 建立檔案
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            FileOutputStream fos = new FileOutputStream(file);
            try {
                wb.write(fos);
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

從例子中可以看出,BubbleSheet經常用的方法有mergeCells以及setLineValues,從名字可以看出兩者的用途,在使用這兩個方法之前,都要用setNowRowWithRowNo方法,用來指明是要操作哪一行的。

在我的工作中檢驗發現,BubbleSheet是可靠的,且在操作表格時非常便捷。