一滴水

          java 2006年1月新開(kāi)始:)
          隨筆 - 10, 文章 - 2, 評(píng)論 - 6, 引用 - 0
          數(shù)據(jù)加載中……

          Jakata Poi HSSF:純Java的Excel解決方案 [zz]

                 微軟在桌面系統(tǒng)上的成功,令我們不得不大量使用它的辦公產(chǎn)品,如:Word,Excel。時(shí)至今日,它的源代碼仍然不公開(kāi)已封鎖了我們的進(jìn)一步應(yīng)用和開(kāi)發(fā)。然而在要求更高的服務(wù)器領(lǐng)域,微軟本身的產(chǎn)品移植性不好,性能不佳。

                 在我們實(shí)際的開(kāi)發(fā)中,表現(xiàn)層的解決方案雖然有多樣,但是IE瀏覽器已成為最多人使用的瀏覽器,因?yàn)榇蠹叶加肳indows。在企業(yè)辦公系統(tǒng)中,常常有客戶(hù)這樣子要求:你要把我們的報(bào)表直接用Excel打開(kāi)。

          或者是:我們已經(jīng)習(xí)慣用Excel打印。這樣子如果用.net開(kāi)發(fā)是沒(méi)有問(wèn)題的,但是有J2EE這個(gè)比.net更有前途的開(kāi)放式的開(kāi)發(fā)環(huán)境,難道我為了解決打印的要求去另寫(xiě)客戶(hù)端的控件?或者在服務(wù)器端使用本地代碼?第一種方案的問(wèn)題是關(guān)鍵數(shù)據(jù)的處理有時(shí)候不能在客戶(hù)端做,第2種方案的問(wèn)題是犧牲了代碼的可移植性和穩(wěn)定性。如果讓客戶(hù)端只負(fù)責(zé)處理生成好的報(bào)表,那將是一種誘人的選擇。

          Apache的Jakata項(xiàng)目的POI子項(xiàng)目,目標(biāo)是處理ole2對(duì)象。目前比較成熟的是HSSF接口,處理MS Excel(97-2002)對(duì)象。它不象我們僅僅是用csv生成的沒(méi)有格式的可以由Excel轉(zhuǎn)換的東西,而是真正的Excel對(duì)象,你可以控制一些屬性如sheet,cell等等。

          這是一個(gè)年輕的項(xiàng)目,所以象HDF這樣直接支持Word對(duì)象的好東西仍然在設(shè)計(jì)中。其它支持word格式的純Java方案還有itext,不過(guò)也是仍在奮斗中。但是HSSF已經(jīng)成熟到能夠和足夠我們使用了。

          其實(shí),從開(kāi)發(fā)歷史的角度講,在80年代中期starOffice的原作者在德國(guó)成立了StarOffice suite公司,然后到1999年夏天starOffice被sun收購(gòu),再到2000年6月starOffice5.2的發(fā)布;并且從starOffice6.0開(kāi)始,starOffice建立在OpenOffice的api的基礎(chǔ)上,這個(gè)公開(kāi)代碼的office項(xiàng)目已經(jīng)進(jìn)行了很長(zhǎng)的時(shí)間。雖然那是由C++寫(xiě)的,但是POI的代碼部分也是由openOffice改過(guò)來(lái)的。所以,應(yīng)該對(duì)POI充滿(mǎn)足夠的信心。國(guó)內(nèi)已經(jīng)有部分公司在他們的辦公自動(dòng)化等Web項(xiàng)目中使用poi了,如日恒的ioffice,海泰的HTOffice等。

          Java當(dāng)初把核心處理設(shè)成Unicode,帶來(lái)的好處是另代碼適應(yīng)了多語(yǔ)言環(huán)境。然而由于老外的英語(yǔ)只有26個(gè)字母,有些情況下,一些程序員用8位的byte處理,一不小心就去掉了CJK的高位。或者是由于習(xí)慣在程序中采用硬編碼,還有多種原因,使得許多Java應(yīng)用在CJK的處理上很煩惱。還好在POI HSSF中考慮到這個(gè)問(wèn)題,可以設(shè)置encoding為雙字節(jié)。

          POI可以到www.apache.org下載到。編譯好的jar主要有這樣4個(gè):poi包,poi Browser包,poi hdf包,poi hssf例程包。實(shí)際運(yùn)行時(shí),需要有poi包就可以了。

          如果用Jakarta ant編譯和運(yùn)行,下載apache Jakarta POI的release中的src包,它里面已經(jīng)為你生成好了build文件了。只要運(yùn)行ant就可以了(ant 的安裝和使用在此不說(shuō)了)。如果是用Jbuilder 運(yùn)行,請(qǐng)?jiān)谛陆ǖ捻?xiàng)目中加入poi包。

          以Jbuilder6為例,選擇Tools菜單項(xiàng)的config libraries...選項(xiàng),新建一個(gè)lib。在彈出的菜單中選擇poi包,如這個(gè)jakarta-poi-1.5.1-final-20020820.jar,把poi添加到j(luò)builder中。然后,右鍵點(diǎn)擊你的項(xiàng)目,在project的properties菜單中path的required Libraries中,點(diǎn)add,添加剛才加入到j(luò)builder中的poi到你現(xiàn)在的項(xiàng)目中。

          如果你僅僅是為了熟悉POI hssf的使用,可以直接看POI的samples包中的源代碼,并且運(yùn)行它。hssf的各種對(duì)象都有例程的介紹。hssf提供的例程在org.apache.poi.hssf.usermodel.examples包中,共有14個(gè),生成的目標(biāo)xls都是workbook.xls。如果你想看更多的例程,可以參考hssf的Junit test cases,在poi的包的源代碼中有。hssf都有測(cè)試代碼。
          這里只對(duì)部分例程的實(shí)現(xiàn)做介紹。

          HSSF提供給用戶(hù)使用的對(duì)象在org.apache.poi.hssf.usermodel包中,主要部分包括Excell對(duì)象,樣式和格式,還有輔助操作。有以下幾種對(duì)象:

          HSSFWorkbook excell的文檔對(duì)象

          HSSFSheet excell的表單

          HSSFRow excell的行

          HSSFCell excell的格子單元

          HSSFFont excell字體

          HSSFName 名稱(chēng)

          HSSFDataFormat 日期格式

          在poi1.7中才有以下2項(xiàng):

          HSSFHeader sheet頭

          HSSFFooter sheet尾

          和這個(gè)樣式

          HSSFCellStyle cell樣式

          輔助操作包括

          HSSFDateUtil 日期

          HSSFPrintSetup 打印

          HSSFErrorConstants 錯(cuò)誤信息表

          仔細(xì)看org.apache.poi.hssf包的結(jié)構(gòu),不難發(fā)現(xiàn)HSSF的內(nèi)部實(shí)現(xiàn)遵循的是MVC模型。

          這里我用Rose把org.apache.poi.hssf.usermodel包中的對(duì)象反向?qū)氩⒏鶕?jù)相互關(guān)系作了整理,詳見(jiàn)下面兩圖:







          圖1 基本對(duì)象



          從中不難可以發(fā)現(xiàn)每一個(gè)基本對(duì)象都關(guān)聯(lián)了一個(gè)Record對(duì)象。Record對(duì)象是一個(gè)參考Office格式的相關(guān)記錄。 





          圖2 HSSFWorkbook



          HSSFWorkbook即是一個(gè)Excell對(duì)象。這幅類(lèi)圖體現(xiàn)的是HSSFWorkbook和基本對(duì)象的相互關(guān)系。可見(jiàn),許多對(duì)象中也建立了Workbook的引用。還需要注意的是在HSSFWorkbook和HSSFSheet中建立了log機(jī)制POILogger,而且POILogger也是使用apache Log4J實(shí)現(xiàn)的。

          先看poi的examples包中提供的最簡(jiǎn)單的例子,建立一個(gè)空xls文件。


          import org.apache.poi.hssf.usermodel.HSSFWorkbook;
          import java.io.FileOutputStream;
          import java.io.IOException;
          public class NewWorkbook
          {
          public static void main(String[] args)throws IOException
          {
          HSSFWorkbook wb 
          = new HSSFWorkbook();
          //建立新HSSFWorkbook對(duì)象
          FileOutputStream fileOut =
          new FileOutputStream("workbook.xls");
          wb.write(fileOut);
          //把Workbook對(duì)象輸出到文件workbook.xls中
          fileOut.close();
          }

          }





          通過(guò)這個(gè)例子,我們建立的是一個(gè)空白的xls文件(不是空文件)。在此基礎(chǔ)上,我們可以進(jìn)一步看其它的例子。 


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

          import java.io.FileOutputStream;

          import java.io.IOException;

          public class CreateCells

          {

          public static void main(String[] args)

          throws IOException

          {

          HSSFWorkbook wb 
          = new HSSFWorkbook();
          //建立新HSSFWorkbook對(duì)象

          HSSFSheet sheet 
          = wb.createSheet("new sheet");
          //建立新的sheet對(duì)象


          // Create a row and put some cells in it.
          Rows are 0 based.

          HSSFRow row 
          = sheet.createRow((short)0);
          //建立新行

          // Create a cell and put a value in it.

          HSSFCell cell 
          = row.createCell((short)0);
          //建立新cell

          cell.setCellvalue(
          1);//設(shè)置cell的整數(shù)類(lèi)型的值


          // Or do it on one line.

          row.createCell((
          short)1).setCellvalue(1.2);
          //設(shè)置cell浮點(diǎn)類(lèi)型的值

          row.createCell((
          short)2).setCellvalue("test");
          //設(shè)置cell字符類(lèi)型的值

          row.createCell((
          short)3).setCellvalue(true);
          //設(shè)置cell布爾類(lèi)型的值 

          HSSFCellStyle cellStyle 
          = wb.createCellStyle();
          //建立新的cell樣式

          cellStyle.setDataFormat
          (HSSFDataFormat.getFormat(
          "m/d/yy h:mm"));
          //設(shè)置cell樣式為定制的日期格式

          HSSFCell dCell 
          =row.createCell((short)4);

          dCell.setCellvalue(
          new Date());
          //設(shè)置cell為日期類(lèi)型的值

          dCell.setCellStyle(cellStyle); 
          //設(shè)置該cell日期的顯示格式

          HSSFCell csCell 
          =row.createCell((short)5);

          csCell.setEncoding(HSSFCell.ENCODING_UTF_16);
          //設(shè)置cell編碼解決中文高位字節(jié)截?cái)?/SPAN>

          csCell.setCellvalue(
          "中文測(cè)試_Chinese Words Test");
          //設(shè)置中西文結(jié)合字符串

          row.createCell((
          short)6).setCellType
          (HSSFCell.CELL_TYPE_ERROR);
          //建立錯(cuò)誤cell


          // Write the output to a file

          FileOutputStream fileOut 
          = 
          new FileOutputStream("workbook.xls");

          wb.write(fileOut);

          fileOut.close();

          }


          }





          我稍微修改了原來(lái)的examples包中的CreateCells類(lèi)寫(xiě)了上面的功能測(cè)試類(lèi)。通過(guò)這個(gè)例子,我們可以清楚的看到xls文件從大到小包括了HSSFWorkbook HSSFSheet HSSFRow HSSFCell這樣幾個(gè)對(duì)象。我們可以在cell中設(shè)置各種類(lèi)型的值。 

          尤其要注意的是如果你想正確的顯示非歐美的字符時(shí),尤其象中日韓這樣的語(yǔ)言,必須設(shè)置編碼為16位的即是HSSFCell.ENCODING_UTF_16,才能保證字符的高8位不被截?cái)喽鹁幋a失真形成亂碼。 

          其他測(cè)試可以通過(guò)參考examples包中的測(cè)試?yán)诱莆誴oi的詳細(xì)用法,包括字體的設(shè)置,cell大小和低紋的設(shè)置等。需要注意的是POI是一個(gè)仍然在完善中的公開(kāi)代碼的項(xiàng)目,所以有些功能正在不斷的擴(kuò)充。 

          如HSSFSheet的getFooter() getHeader()和setFooter(HSSFFooter hsf) setHeader(HSSFHeader hsh)是在POI1.7中才有的,而POI1.5中就沒(méi)有。運(yùn)行測(cè)試熟悉代碼或者使用它做項(xiàng)目時(shí)請(qǐng)注意POI的版本。 

          另外需要注意的是HSSF也有它的對(duì)xls基于事件的解析。可以參考例程中的EventExample.java。它通過(guò)實(shí)現(xiàn)HSSFListener完成從普通流認(rèn)知Xls中包含的內(nèi)容,在apache Cocoon中的org.apache.cocoon.serialization.HSSFSerializer中用到了這個(gè)解析。因?yàn)镃ocoon2是基于事件的,所以POI為了提供快速的解析也提供了相應(yīng)的事件。當(dāng)然我們自己也可以實(shí)現(xiàn)這個(gè)事件接口。 

          因?yàn)镻OI還不是一個(gè)足夠成熟的項(xiàng)目,所以有必要做進(jìn)一步的開(kāi)發(fā)和測(cè)試。但是它已經(jīng)為我們用純Java操作ole2對(duì)象提供了可能,而且克服了ole對(duì)象調(diào)用的缺陷,提供了服務(wù)器端的Excel解決方案。

          posted on 2006-01-20 13:52 一滴水 閱讀(1028) 評(píng)論(0)  編輯  收藏


          只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 新丰县| 昌宁县| 梨树县| 宁蒗| 大荔县| 河间市| 江达县| 吴江市| 南华县| 曲水县| 永靖县| 呈贡县| 秦安县| 潼关县| 华阴市| 麻江县| 乐平市| 准格尔旗| 明水县| 伊宁市| 宜章县| 建湖县| 巴里| 临沂市| 三明市| 岢岚县| 贵州省| 襄垣县| 武城县| 炉霍县| 综艺| 松原市| 南乐县| 西安市| 敦煌市| 固原市| 志丹县| 师宗县| 廉江市| 宜章县| 湖口县|