本篇面向對象為Java的初學者,從下載必備軟件到創建一個空白的POI工程,已經熟練掌握環境搭建的請跳過此文。
開發環境為windowsXP-SP2,Eclipse3.2,JDK1.5.07,其實差不多都行,不會有太大的差異。本文從POI下載開始講解,前提是開發環境包括系統變量等等已經正確設置完畢。
1.POI的下載
截至本文發表,POI最新版本是3.0.1,距離上一個Final版本有3年了吧,以至于我差點兒就把他放棄了——以為沒人管了。官方的公告講,這一版主要是追加了一些新的特性和BUG修正,不過稍微有點兒遺憾的是,還不能很好的操作Excel2007。
-
POI官方網址:
- http://poi.apache.org/
下載上面的JAR和源碼(源碼不是必須的,但是為了早日修得正果,深入系統的看看POI代碼還是有必要的)并解壓待用。
2.用Eclipse搭建項目
- 打開Eclipse
- 依次點擊File->New->Java Project
- 輸入項目名稱,本例中設置為POI
- 單擊完成
- 在項目上點擊右鍵->New->Folder
- 輸入文件夾名稱lib
- 把剛才解壓的poi-3.0.1-FINAL-20070705.jar復制過來
- 右鍵點擊項目,選擇Properties
- 在左側列表里選中Java Build Path,右側選中Libraries
- 點擊Add JARs,選擇POI項目的lib下的所有文件
- 兩次OK確認,回到Eclipse界面
小技巧,快捷操作:可以用鼠標左鍵選中poi-3.0.1-FINAL-20070705.jar但不松開,拖到任務欄的Eclipse圖標上等候1秒左右,Eclipse會自動彈起來,依然不松開移動到lib文件夾上,這個時候鼠標后面跟個十字符號,松開左鍵,就完成了復制動作。這個是對整個windows系統都好用的快捷復制方式,視源盤符和目標盤符的不同偶爾會用到Ctrl鍵。
到此為止,我們做好了POI學習的前提準備,接下來將從最簡單的文檔創建開始一步一步學習怎樣讓POI更好的為我們工作。
第一講:基本的Excel讀寫
本文主要演示一下POI的基本操作,例如怎樣讀取和創建一個具體的Excel文件。按照慣例,拿HelloWorld說事兒。
說明:本文主要內容皆包含于 官方幫助手冊 ,之所以要拿出來,出于兩個原因,手冊是英文的+手冊是對應2.5.1的。
核心代碼如下,注釋部分為講解。這里只挑干的講,完整的代碼請參考 (下載代碼) 。
//創建一個空白的WorkBook
HSSFWorkbook wb = new HSSFWorkbook();
//基于上面的WorkBook創建屬于此WorkBook的Sheet,
//3.0.1版在使用全角Sheet名的時候不必再setEncdoing了,個人感覺方便了許多。
HSSFSheet st = wb.createSheet("測試頁");
//創建屬于上面Sheet的Row,參數0可以是0~65535之間的任何一個,
//注意,盡管參數是Int類型,但是Excel最多支持65536行
HSSFRow row = st.createRow(0);
//創建屬于上面Row的Cell,參數0可以是0~255之間的任何一個,
//同樣,是因為Excel最大支持的列數為256列
HSSFCell cell = row.createCell((short) 0);
//設置此單元格的格式為文本,此句可以省略,Excel會自動識別。
//其他還有幾種常用的格式,請參考本文底部的補充部分。
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
//此處是3.0.1版的改進之處,上一版可以直接setCellValue("Hello, World!"),
//但是在3.0.1里,被deprecated了。
cell.setCellValue(new HSSFRichTextString("Hello, World!"));
//創建一個文件輸出流,指定到C盤根目錄下(C盤都有吧?)
//xls是Excel97-2003的標準擴展名,2007是xlsx,目前的POI能直接生產的還是xls格式,
//如果此處把擴展名改成xlsx,在用Excel2007打開此文件時會報錯。
FileOutputStream writeFile = new FileOutputStream("c:/helloworld.xls");
//把WorkBook寫到流里
wb.write(writeFile);
//記得手動關閉流,官方文檔已經做了特別說明,說POI不負責關閉用戶打開的流。所以...
writeFile.close();
上面就是創建一個新文檔的簡易代碼,下面的例子是讀取剛才創建的Excel并把讀取到的內容顯示在控制臺上。
//指定要讀取的文件,本例使用上面生成的helloworld.xls
FileInputStream readFile = new FileInputStream("c:/helloworld.xls");
//創建一個WorkBook,從指定的文件流中創建,即上面指定了的文件流
HSSFWorkbook wb = new HSSFWorkbook(readFile);
//獲取名稱為“測試頁”的sheet
//注意,如果不能確定具體的名稱,可以用getSheetAt(int)方法取得Sheet
HSSFSheet st = wb.getSheet("測試頁");
//獲得第一行,同上,如果此行沒有被創建過則拋出異常
HSSFRow row = st.getRow(0);
//獲取第一個單元格,如果沒有被創建過則拋出異常
HSSFCell cell = row.getCell((short) 0);
//把cell中的內容按字符串方式讀取出來,并顯示在控制臺上
//注意,getRichStringCellValue()方法是3.0.1新追加的,
//老版本中的getStringCellValue()方法被deprecated了
System.out.println(cell.getRichStringCellValue());
//記得關閉流
readFile.close();
上面對創建和讀取分別舉例說明,回顧兩段代碼,不難看出POI操作Excel的“套路”:
- 獲得一個WorkBook(準確說是HSSFWorkBook,對于POI來說,WorkBook是“另有其類”,以下類同)
- 獲得要讀/寫的Sheet對象
- 獲得要操作的Row對象
- 獲得最小單位——Cell對象
然后就可以隨意的讀取、寫入了。
關于單元格格式的補充:
-
單元格一共有如下幾種格式, 都是HSSFCell類的靜態共有屬性,
- CELL_TYPE_NUMERIC - 數字格式
- CELL_TYPE_STRING - 字符串(默認)
- CELL_TYPE_FORMULA - 公式
- CELL_TYPE_BLANK - 空白
- CELL_TYPE_BOOLEAN - 布爾
- CELL_TYPE_ERROR - 錯誤
第二講:單元格邊框、字體及顏色
此文概要性的講述了一下單元格的邊框、字體以及顏色的設置方式,在POI中,這一切都是通過實例化HSSFCellStyle對象來實現的,HSSFCellStyle類還有很多其他實際有用方法,本例中只是取平時用的比較普遍的一些設置來做演示的。好,開始講解了……
// 設置行號
row.setHeightInPoints((short) 50);
// 設置列寬,(256 * 50)這種寫法是因為width參數單位是單個字符的256分之一
st.setColumnWidth(cell.getCellNum(), (short) (256 * 50));
// 讓HSSFWorkbook創建一個單元格樣式的對象
// 小技巧:在多處用到完全一樣的樣式的時候可以用工廠模式生產
HSSFCellStyle cellStyle = wb.createCellStyle();
// 設置單元格的橫向和縱向對齊方式,具體參數就不列了,參考HSSFCellStyle
cellStyle.setAlignment(HSSFCellStyle.ALIGN_JUSTIFY);
cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
// 這個地方是用來在單元格里畫斜線的
// 原理是在指定的兩個點之間畫線,然后默認情況此線會隨著單元格的變化而變化
// 類似Excel那種設置邊框的方式達到的斜線效果目前好像POI不支持
// 如果是我疏忽了請記得告訴我一些,先行謝過啦
HSSFPatriarch patriarch = st.createDrawingPatriarch();
HSSFClientAnchor anchor = new HSSFClientAnchor();
anchor.setAnchor(cell.getCellNum(), row.getRowNum(), 0, 0, (short) (cell.getCellNum() + 1),
row.getRowNum() + 1, 0, 0);
patriarch.createSimpleShape(anchor);
// 設置單元格的文本方式為可多行編寫方式
cellStyle.setWrapText(true);
// 設置單元格的填充方式,以及前景顏色和背景顏色
// 三點注意:
// 1.如果需要前景顏色或背景顏色,一定要指定填充方式,兩者順序無所謂;
// 2.如果同時存在前景顏色和背景顏色,前景顏色的設置要寫在前面;
// 3.前景顏色不是字體顏色。
cellStyle.setFillPattern(HSSFCellStyle.DIAMONDS);
cellStyle.setFillForegroundColor(HSSFColor.RED.index);
cellStyle.setFillBackgroundColor(HSSFColor.LIGHT_YELLOW.index);
// 設置單元格底部的邊框及其樣式和顏色
// 這里僅設置了底邊邊框,左邊框、右邊框和頂邊框同理可設
cellStyle.setBorderBottom(HSSFCellStyle.BORDER_SLANTED_DASH_DOT);
cellStyle.setBottomBorderColor(HSSFColor.DARK_RED.index);
// 創建一個字體對象,因為字體也是單元格格式的一部分,所以從屬于HSSFCellStyle
// 下面幾個字體的相關設置望文生義,就不用一一說明了吧
HSSFFont font = wb.createFont();
font.setFontName("宋體");
font.setItalic(true);
font.setColor(HSSFColor.BLUE.index);
font.setFontHeightInPoints((short) 20);
font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
// 將字體對象賦值給單元格樣式對象
cellStyle.setFont(font);
// 將單元格樣式對應應用于單元格
cell.setCellStyle(cellStyle);
這樣就OK了,可以可以看到效果了。
補充,各個章節的例子最終都在同一個附件內,下載的時候下任何一個頁面內的都可以,都是一樣的。
Java-Excel報表開發POI系列講座
第三講:單元格的合并、數據行的分組以及Excel窗口的凍結
本來想把這三個東西分開來實現的,后來發現分開后內容都很少,于是就合在一起說吧。那總不能干巴巴的列幾個例子就完了吧,那就拿比較初級但又會經常遇到的表格類數據的統計的設計來做個小例子。 (源碼下載)
結果發現——還真夠辛苦的。
這次先看效果圖吧,其中的豎排并不是真正意義上Excel那種設置的豎排,而是稍微轉變了一下輸出的方式實現的,因為老外的英文單詞沒有這種豎排的可能(頂多是旋轉,但是那樣字體就變了)。除此之外想到的另外一種豎排文字的實現方式就是樣式旋轉+字體旋轉,沒測試,不知道是否可用,誰有功夫實現一下,然后記得告訴我結果啊。
老樣子,把核心的代碼和簡要的說明列出來大家看一下吧。
// 這里首先創建一個單元格樣式對象,設置了四周的邊框以及字體可以換行
// 其中的字體換行是用來豎向顯示其中的一個單元格的
// 更好的一點兒做法是再做一個單獨的單元格樣式對象
// 要不然在處理自動列寬的時候可能會有點兒小問題
HSSFCellStyle normalStyle = wb.createCellStyle();
normalStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);
normalStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);
normalStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);
normalStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);
normalStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
normalStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
normalStyle.setWrapText(true);
// 合并單元格A1-C1,填入內容的時候添到第一個格子里就可以
// 但是注意一點:單元格合并後設置邊框只在原第一個上有效,
// 如果想應用的合并後的整體,則需要一個個的Create出單元格并應用樣式
// 這個明顯是一個不太方便的操作,期待POI下一版的改進了
st.addMergedRegion(new Region(0, (short) 0, 0, (short) 2));
HSSFRow row = st.createRow(0);
HSSFCell cell = row.createCell((short) 0);
cell.setCellValue(new HSSFRichTextString("業務一覽表"));
cell.setCellStyle(normalStyle);
row.createCell((short) 1).setCellStyle(normalStyle);
row.createCell((short) 2).setCellStyle(normalStyle);
// 設置列頭,當然也可以一個一個格子的寫,用循環感覺有些取巧而已
// 同樣,需要單獨給每個單元格應用樣式對象
String[] seasonName = { "第一季度", "第二季度", "第三季度", "第四季度" };
for (short i = 3; i < 7; i++)
{
cell = row.createCell(i);
cell.setCellValue(new HSSFRichTextString(seasonName[i - 3]));
cell.setCellStyle(normalStyle);
}
// 這個是豎排文字的實現
// 目前POI沒找到(或許沒提供,或許我無知)讓文字豎排的方法,
// HSSFCellStyle.setRotation()方法是設置旋轉角度的,和豎排不太一樣,
// 后來想了一下,因為只有中文等全角字符才有豎排的可能,
// 一個英文單詞要是豎排看起來恐怕會非常怪異,不過不排除搞藝術的……
st.addMergedRegion(new Region(1, (short) 0, 6, (short) 0));
row = st.createRow(1);
cell = row.createCell((short) 0);
cell.setCellValue(new HSSFRichTextString("地\n區\n代\n理\nA"));
cell.setCellStyle(normalStyle);
for (int i = 2; i < 7; i++)
st.createRow(i).createCell((short) 0).setCellStyle(normalStyle);
// 屬于地區的二級分類,豎向合并相鄰的兩個單元格,其他同上
String[] shopName = { "連鎖店A", "連鎖店B", "連鎖店C" };
for (int i = 1; i < 6; i = i + 2)
{
row = st.createRow(i);
cell = row.createCell((short) 1);
cell.setCellValue(new HSSFRichTextString(shopName[(i - 1) / 2]));
cell.setCellStyle(normalStyle);
st.createRow(i + 1).createCell((short) 1).setCellStyle(normalStyle);
st.addMergedRegion(new Region(i, (short) 1, i + 1, (short) 1));
}
// 屬于連鎖店的下一級,基本也是創建出來然后賦值+應用樣式
for (int i = 1; i < 7; i = i + 2)
{
cell = st.getRow(i).createCell((short) 2);
cell.setCellValue(new HSSFRichTextString("收入"));
cell.setCellStyle(normalStyle);
cell = st.getRow(i + 1).createCell((short) 2);
cell.setCellValue(new HSSFRichTextString("支出"));
cell.setCellStyle(normalStyle);
}
// 數據部分,直接Create然后應用樣式,有數據的話這個地方就打數據好了
for (int i = 1; i < 7; i++)
for (short j = 3; j < 7; j++)
st.createRow(i).createCell(j).setCellStyle(normalStyle);
// 凍結Excel的窗口,邊界為數據部分的邊界
st.createFreezePane(3, 1);
// 按照連鎖店級別分組(當然實際情況這樣分組沒啥意義)
for (int i = 1; i < 7; i = i + 2)
st.groupRow(i, i);
// 按照地區分組
st.groupRow(1, 5);
其實這樣實現起來是不是很麻煩呢?答案是:是。
其實這只是舉個例子,熟悉一下POI的各種API而已,真正要實現這樣一個表格的時候,例如項目需要制作報表等等,通常的做法都是事先把格式一切的東西都手動制作好(這個做好了的文件在實際的項目里我們稱之為“數據模板”,簡稱“模板”),然后在Java應用中適當的時機把這個文件讀進來修改,最后再另存到指定的位置或者傳遞給下一個處理者(例如以流的方式送給Servlet等等),這樣其實POI具體做的事情就是向模板里寫業務的數據,還是很方便快捷的。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
