本文接上一篇繼續探究POI組件的使用。
現在來看看Excel的基本設置問題,以2007爲例,先從工作簿來說,設置列寬,因爲生成表格列應該固定,而行是遍歷生成的,所以可以在工作簿級別來設置列寬,那麼可以如下來進行。
首先是創建工作簿和工作表了:
// 創建Excel2007工作簿對象
XSSFWorkbook workbook2007 = new XSSFWorkbook();
// 創建工作表對象並命名
XSSFSheet sheet = workbook2007.createSheet("學生信息統計表");
之後是設置格式:
// 設置行列的默認寬度和高度
sheet.setColumnWidth(0, 32 * 80);// 對A列設置寬度爲80像素
sheet.setColumnWidth(1, 32 * 80);
sheet.setColumnWidth(2, 32 * 80);
sheet.setColumnWidth(3, 32 * 80);
sheet.setColumnWidth(4, 32 * 80);
在這之前要先創建一個工作表sheet,然後就可以對每列設置列寬了。而行高一般針對不同的行有不同的設置,比如表頭行,合計行,數據行等,那麼分別設置會比較好。設置完列寬和行高,剩下就是對單元格的設置,比如居中,邊框,字體等。設置好樣式後將樣式應用於所需要的單元格,就得到了整體的效果,比如:
// 創建樣式
XSSFFont font = workbook2007.createFont();
XSSFCellStyle headerStyle = workbook2007.createCellStyle();
// 設置垂直居中
headerStyle.setAlignment(HorizontalAlignment.CENTER);
headerStyle.setVerticalAlignment(VerticalAlignment.CENTER);
// 設置邊框
headerStyle.setBorderTop(BorderStyle.THIN);
headerStyle.setBorderBottom(BorderStyle.THIN);
headerStyle.setBorderLeft(BorderStyle.THIN);
headerStyle.setBorderRight(BorderStyle.THIN);
// 字體加粗
font.setBold(true);
// 設置長文本自動換行
headerStyle.setWrapText(true);
headerStyle.setFont(font);
這裏我們定義的是表頭的樣式,其中垂直居中時的設置要設置兩次,而且方法名不同,要注意。邊框就很簡單了,上下左右設置四次,字體加粗就是布爾值設定了,之後是文本自動換行,意思就是在固定單元格長度不變時是否自動折行。然後將字體樣式加入到單元格樣式中即可。
下面針對之前的例子設計表頭,如下:
// 創建表頭
XSSFRow headerRow = sheet.createRow(0);
headerRow.setHeightInPoints(25f);// 設置行高度
XSSFCell nameHeader = headerRow.createCell(0);
nameHeader.setCellValue("姓名");
nameHeader.setCellStyle(headerStyle);
XSSFCell genderHeader = headerRow.createCell(1);
genderHeader.setCellValue("性別");
genderHeader.setCellStyle(headerStyle);
XSSFCell ageHeader = headerRow.createCell(2);
ageHeader.setCellValue("年齡");
ageHeader.setCellStyle(headerStyle);
XSSFCell classHeader = headerRow.createCell(3);
classHeader.setCellValue("班級");
classHeader.setCellStyle(headerStyle);
XSSFCell scoreHeader = headerRow.createCell(4);
scoreHeader.setCellValue("成績");
scoreHeader.setCellStyle(headerStyle);
這裏的代碼會有大段的重複,因爲都是一個套路下來的,最後別忘加入樣式就行了,這樣表格頭部就做好了。剩下的是遍歷數據出行。
for (int i = 0; i < studentList.size(); i++) {
XSSFRow row = sheet.createRow(i + 1);
row.setHeightInPoints(20f);
Student student = studentList.get(i);
XSSFCell nameCell = row.createCell(0);
nameCell.setCellValue(student.getName());
nameCell.setCellStyle(cellStyle);
XSSFCell genderCell = row.createCell(1);
genderCell.setCellValue(student.getGender());
genderCell.setCellStyle(cellStyle);
XSSFCell ageCell = row.createCell(2);
ageCell.setCellValue(student.getAge());
ageCell.setCellStyle(cellStyle);
XSSFCell classCell = row.createCell(3);
classCell.setCellValue(student.getSclass());
classCell.setCellStyle(cellStyle);
XSSFCell scoreCell = row.createCell(4);
scoreCell.setCellValue(student.getScore());
scoreCell.setCellStyle(cellStyle);
}
用for循環就可以完成任務,需要注意的是循環變量仍然從0開始走,這是爲了遍歷集合的方便,而創建行就是從i+1開始走了,因爲0行是表頭,已經佔用了。下面就是先設定行高,之後開始取值,賦值,設定格式,結構也很統一。
完成遍歷後,來看看合併,Excel中的合併單元格也是很常用的操作,比如本例中,將班級都設置成一班後,那麼就想讓班級這列合併,該如何操作呢?
// 合併班級
sheet.addMergedRegion(new CellRangeAddress(1, 4, 3, 3));
這是對sheet級別的操作,因爲是在sheet上合併單元格,就是加一個合併的區域,這個區域接收四個參數,就是開始的行,結束的行,開始的列,結束的列,這個位置一般比較確定,或者用循環變量計算得出。班級,從第二行開始,第五行結束,對應索引是1,4,而列不變,就是在列上合併,就都是3即可。
至此我們已經將數據遍歷得出生成了Excel表格,設置了單元格樣式也進行了合併,那麼還有合計沒有說,用合計可以直接設置公式,也可以程序計算好後直接填充,後者一般用於比較複雜的報表,就不用在POI中設置合併的位置,減少複雜度。結合本例,我們來計算平均年齡和成績之和。如下:
// 數據分析行
int dadaRowNum = sheet.getLastRowNum();
XSSFRow totalRow = sheet.createRow(dadaRowNum + 1);// 獲取已有的行數,加1再出新行
totalRow.setHeightInPoints(25f);
XSSFCell analyticsCell = totalRow.createCell(0);
analyticsCell.setCellValue("數據分析");
analyticsCell.setCellStyle(headerStyle);
XSSFCell avgAgeCell = totalRow.createCell(1);
avgAgeCell.setCellValue("平均年齡");
avgAgeCell.setCellStyle(headerStyle);
XSSFCell avgAgeValueCell = totalRow.createCell(2);
avgAgeValueCell.setCellStyle(headerStyle);
avgAgeValueCell.setCellFormula("AVERAGE(C2:C" + (dadaRowNum + 1) + ")");
XSSFCell sumScoreCell = totalRow.createCell(3);
sumScoreCell.setCellValue("總成績");
sumScoreCell.setCellStyle(headerStyle);
XSSFCell sumScoreValueCell = totalRow.createCell(4);
sumScoreValueCell.setCellStyle(headerStyle);
sumScoreValueCell.setCellFormula("SUM(E2:E" + (dadaRowNum + 1) + ")");
這裏使用Excel函數的時候我們已經知道數據所在的位置,就直接使用了單元格的代號進行運算了,要注意使用公式時的方法中不用寫=號,POI會自動爲我們添加進去,這裏就直接寫公式的內容即可。在實際中可能會有動態計算的任務,那麼就根據業務複雜度來選擇是用Excel公式進行運算還是程序運算好後直接賦值顯示。
最後是生成文件的步驟,這已經介紹過了,都很簡單:
// 生成文件
File file = new File(filePath);
OutputStream os = null;
try {
os = new FileOutputStream(file);
workbook2007.write(os);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
}
}
}
最後是執行測試了,寫個主函數來運行:
public static void main(String[] args) {
long start = System.currentTimeMillis();
generateExcel2007(xlsx2007);
long end = System.currentTimeMillis();
System.out.println((end - start) + " ms done!");
}
將以上所有內容封裝在靜態方法generateExcel2007(String filePath)中,執行即可得到生成的Excel報表了,我們得到了這樣的一個報表:
這就是最終得到的結果了。POI操作Excel的基本設置就基本涵蓋了,剩下的就是靈活運用,生成符合自己需求的報表了。