Java Excel是一开放源码项目,通过它Java开发h员可以读取Excel文g的内宏V创建新的Excel文g、更新已l存在的Excel文g。用该API非Windows操作pȝ也可以通过UJava应用来处理Excel数据表。因为是使用Java~写的,所以我们在Web应用中可以通过JSP、Servlet来调用API实现对Excel数据表的讉K?/p>
现在发布的稳定版本是V2.0Q提供以下功能:(x)
现在q不支持以下功能Q但不久׃(x)提供了:(x)
![]() ![]() |
![]()
|
Java Excel API既可以从本地文gpȝ的一个文?.xls)Q也可以从输入流中读取Excel数据表。读取Excel数据表的W一步是创徏Workbook(术语Q工作薄)Q下面的代码片段举例说明了应该如何操作:(x)(完整代码见ExcelReading.java)
import java.io.*; import jxl.*; … … … … try { //构徏Workbook对象, 只读Workbook对象 //直接从本地文件创建Workbook //从输入流创徏Workbook InputStream is = new FileInputStream(sourcefile); jxl.Workbook rwb = Workbook.getWorkbook(is); } catch (Exception e) { e.printStackTrace(); } |
一旦创ZWorkbookQ我们就可以通过它来讉KExcel Sheet(术语Q工作表)。参考下面的代码片段Q?/p>
//获取W一张Sheet? Sheet rs = rwb.getSheet(0); |
我们既可能通过Sheet的名U来讉K它,也可以通过下标来访问它。如果通过下标来访问的话,要注意的一Ҏ(gu)下标?开始,像数组一栗?/p>
一旦得CSheetQ我们就可以通过它来讉KExcel Cell(术语Q单元格)。参考下面的代码片段Q?/p>
//获取W一行,W一列的? Cell c00 = rs.getCell(0, 0); String strc00 = c00.getContents(); //获取W一行,W二列的? Cell c10 = rs.getCell(1, 0); String strc10 = c10.getContents(); //获取W二行,W二列的? Cell c11 = rs.getCell(1, 1); String strc11 = c11.getContents(); System.out.println("Cell(0, 0)" + " value : " + strc00 + "; type : " + c00.getType()); System.out.println("Cell(1, 0)" + " value : " + strc10 + "; type : " + c10.getType()); System.out.println("Cell(1, 1)" + " value : " + strc11 + "; type : " + c11.getType()); |
如果仅仅是取得Cell的|我们可以方便地通过getContents()Ҏ(gu)Q它可以Q何类型的Cell值都作ؓ(f)一个字W串q回。示例代码中Cell(0, 0)是文本型QCell(1, 0)是数字型QCell(1,1)是日期型Q通过getContents()Q三U类型的q回值都是字W型?/p>
如果有需要知道Cell内容的确切类型,API也提供了一pd的方法。参考下面的代码片段Q?/p>
String strc00 = null; double strc10 = 0.00; Date strc11 = null; Cell c00 = rs.getCell(0, 0); Cell c10 = rs.getCell(1, 0); Cell c11 = rs.getCell(1, 1); if(c00.getType() == CellType.LABEL) { LabelCell labelc00 = (LabelCell)c00; strc00 = labelc00.getString(); } if(c10.getType() == CellType.NUMBER) { NmberCell numc10 = (NumberCell)c10; strc10 = numc10.getValue(); } if(c11.getType() == CellType.DATE) { DateCell datec11 = (DateCell)c11; strc11 = datec11.getDate(); } System.out.println("Cell(0, 0)" + " value : " + strc00 + "; type : " + c00.getType()); System.out.println("Cell(1, 0)" + " value : " + strc10 + "; type : " + c10.getType()); System.out.println("Cell(1, 1)" + " value : " + strc11 + "; type : " + c11.getType()); |
在得到Cell对象后,通过getType()Ҏ(gu)可以获得该单元格的类型,然后与API提供的基本类型相匚wQ强制{换成相应的类型,最后调用相应的取值方法getXXX()Q就可以得到定cd的倹{API提供了以下基本类型,与Excel的数据格式相对应Q如下图所C:(x)
每种cd的具体意义,请参见Java Excel API Document?/p>
当你完成对Excel?sh)子表格数据的处理后Q一定要使用close()Ҏ(gu)来关闭先前创建的对象Q以释放d数据表的q程中所占用的内存空_(d)在读取大量数据时昑־ؓ(f)重要。参考如下代码片D:(x)
//操作完成Ӟ关闭对象Q释攑֍用的内存I间 rwb.close(); |
Java Excel API提供了许多访问Excel数据表的Ҏ(gu)Q在q里我只要地介绍几个常用的方法,其它的方法请参考附录中的Java Excel API Document?/p>
WorkbookcL供的Ҏ(gu)
1. int getNumberOfSheets()
获得工作薄(WorkbookQ中工作表(SheetQ的个数Q示例:(x)
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); int sheets = rwb.getNumberOfSheets(); |
2. Sheet[] getSheets()
q回工作薄(WorkbookQ中工作表(SheetQ对象数l,CZQ?
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); Sheet[] sheets = rwb.getSheets(); |
3. String getVersion()
q回正在使用的API的版本号Q好像是没什么太大的作用?
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); String apiVersion = rwb.getVersion(); |
Sheet接口提供的方?/strong>
1) String getName()
获取Sheet的名UͼCZQ?
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); jxl.Sheet rs = rwb.getSheet(0); String sheetName = rs.getName(); |
2) int getColumns()
获取Sheet表中所包含的d敎ͼCZQ?
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); jxl.Sheet rs = rwb.getSheet(0); int rsColumns = rs.getColumns(); |
3) Cell[] getColumn(int column)
获取某一列的所有单元格Q返回的是单元格对象数组Q示例:(x)
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); jxl.Sheet rs = rwb.getSheet(0); Cell[] cell = rs.getColumn(0); |
4) int getRows()
获取Sheet表中所包含的总行敎ͼCZQ?
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); jxl.Sheet rs = rwb.getSheet(0); int rsRows = rs.getRows(); |
5) Cell[] getRow(int row)
获取某一行的所有单元格Q返回的是单元格对象数组Q示例子Q?
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); jxl.Sheet rs = rwb.getSheet(0); Cell[] cell = rs.getRow(0); |
6) Cell getCell(int column, int row)
获取指定单元格的对象引用Q需要注意的是它的两个参敎ͼW一个是列数Q第二个是行敎ͼq与通常的行、列l合有些不同?
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); jxl.Sheet rs = rwb.getSheet(0); Cell cell = rs.getCell(0, 0); |
下面的代码主要是向大家介l如何生成简单的Excel工作表,在这里单元格的内Ҏ(gu)不带M修饰?如:(x)字体Q颜色等{?Q所有的内容都作为字W串写入?完整代码见ExcelWriting.java)
与读取Excel工作表相|首先要用Workbookcȝ工厂Ҏ(gu)创徏一个可写入的工作薄(Workbook)对象Q这里要注意的是Q只能通过API提供的工厂方法来创徏WorkbookQ而不能用WritableWorkbook的构造函敎ͼ因ؓ(f)cWritableWorkbook的构造函Cؓ(f)protectedcd。示例代码片D如下:(x)
import java.io.*; import jxl.*; import jxl.write.*; … … … … try { //构徏Workbook对象, 只读Workbook对象 //Method 1Q创建可写入的Excel工作? jxl.write.WritableWorkbook wwb = Workbook.createWorkbook(new File(targetfile)); //Method 2Q将WritableWorkbook直接写入到输出流 /* OutputStream os = new FileOutputStream(targetfile); jxl.write.WritableWorkbook wwb = Workbook.createWorkbook(os); */ } catch (Exception e) { e.printStackTrace(); } |
API提供了两U方式来处理可写入的输出,一U是直接生成本地文gQ如果文件名不带全\径的话,~省的文件会(x)定位在当前目录,如果文g名带有全路径的话Q则生成的Excel文g则会(x)定位在相应的目录Q另外一U是Excel对象直接写入到输出流Q例如:(x)用户通过览器来讉KWeb服务器,如果HTTP头设|正的话,览器自动调用客L(fng)的Excel应用E序Q来昄动态生成的Excel?sh)子表格?/p>
接下来就是要创徏工作表,创徏工作表的Ҏ(gu)与创建工作薄的方法几乎一P同样是通过工厂模式Ҏ(gu)获得相应的对象,该方法需要两个参敎ͼ一个是工作表的名称Q另一个是工作表在工作薄中的位|,参考下面的代码片段Q?/p>
//创徏Excel工作? jxl.write.WritableSheet ws = wwb.createSheet("Test Sheet 1", 0); |
"q锅也支好了Q材料也准备齐全了,可以开始下锅了Q?Q现在要做的只是实例化API所提供的Excel基本数据cdQƈ它们添加到工作表中可以了Q参考下面的代码片段Q?/p>
//1.dLabel对象 jxl.write.Label labelC = new jxl.write.Label(0, 0, "This is a Label cell"); ws.addCell(labelC); //d带有字型Formatting的对? jxl.write.WritableFont wf = new jxl.write.WritableFont(WritableFont.TIMES, 18, WritableFont.BOLD, true); jxl.write.WritableCellFormat wcfF = new jxl.write.WritableCellFormat(wf); jxl.write.Label labelCF = new jxl.write.Label(1, 0, "This is a Label Cell", wcfF); ws.addCell(labelCF); //d带有字体颜色Formatting的对? jxl.write.WritableFont wfc = new jxl.write.WritableFont(WritableFont.ARIAL, 10, WritableFont.NO_BOLD, false, UnderlineStyle.NO_UNDERLINE, jxl.format.Colour.RED); jxl.write.WritableCellFormat wcfFC = new jxl.write.WritableCellFormat(wfc); jxl.write.Label labelCFC = new jxl.write.Label(1, 0, "This is a Label Cell", wcfFC); ws.addCell(labelCF); //2.dNumber对象 jxl.write.Number labelN = new jxl.write.Number(0, 1, 3.1415926); ws.addCell(labelN); //d带有formatting的Number对象 jxl.write.NumberFormat nf = new jxl.write.NumberFormat("#.##"); jxl.write.WritableCellFormat wcfN = new jxl.write.WritableCellFormat(nf); jxl.write.Number labelNF = new jxl.write.Number(1, 1, 3.1415926, wcfN); ws.addCell(labelNF); //3.dBoolean对象 jxl.write.Boolean labelB = new jxl.write.Boolean(0, 2, false); ws.addCell(labelB); //4.dDateTime对象 jxl.write.DateTime labelDT = new jxl.write.DateTime(0, 3, new java.util.Date()); ws.addCell(labelDT); //d带有formatting的DateFormat对象 jxl.write.DateFormat df = new jxl.write.DateFormat("dd MM yyyy hh:mm:ss"); jxl.write.WritableCellFormat wcfDF = new jxl.write.WritableCellFormat(df); jxl.write.DateTime labelDTF = new jxl.write.DateTime(1, 3, new java.util.Date(), wcfDF); ws.addCell(labelDTF); |
q里有两点大家要引v大家的注意。第一点,在构造单元格Ӟ单元格在工作表中的位|就已经定了。一旦创建后Q单元格的位|是不能够变更的Q尽单元格的内Ҏ(gu)可以改变的。第二点Q单元格的定位是按照下面q样的规?column, row)Q而且下标都是?开始,例如QA1被存储在(0, 0)QB1被存储在(1, 0)?/p>
最后,不要忘记关闭打开的Excel工作薄对象,以释攑֍用的内存Q参见下面的代码片段Q?/p>
//写入Exel工作? wwb.write(); //关闭Excel工作薄对? wwb.close(); |
q可能与dExcel文g的操作有少不同Q在关闭Excel对象之前Q你必须要先调用write()Ҏ(gu)Q因为先前的操作都是存储在缓存中的,所以要通过该方法将操作的内容保存在文g中。如果你先关闭了Excel对象Q那么只能得C张空的工作薄了?/p>
接下来简要介l一下如何更C个已l存在的工作薄,主要是下面二步操作,W一步是构造只ȝExcel工作薄,W二步是利用已经创徏的Excel工作薄创建新的可写入的Excel工作薄,参考下面的代码片段Q?完整代码见ExcelModifying.java)
//创徏只读的Excel工作薄的对象 jxl.Workbook rw = jxl.Workbook.getWorkbook(new File(sourcefile)); //创徏可写入的Excel工作薄对? jxl.write.WritableWorkbook wwb = Workbook.createWorkbook(new File(targetfile), rw); //dW一张工作表 jxl.write.WritableSheet ws = wwb.getSheet(0); //获得W一个单元格对象 jxl.write.WritableCell wc = ws.getWritableCell(0, 0); //判断单元格的cd, 做出相应的{? if(wc.getType() == CellType.LABEL) { Label l = (Label)wc; l.setString("The value has been modified."); } //写入Excel对象 wwb.write(); //关闭可写入的Excel对象 wwb.close(); //关闭只读的Excel对象 rw.close(); |
之所以用这U方式构建Excel对象Q完全是因ؓ(f)效率的原因,因ؓ(f)上面的示例才是API的主要应用。ؓ(f)了提高性能Q在d工作表时Q与数据相关的一些输Z息,所有的格式信息Q如Q字体、颜色等{,是不被处理的Q因为我们的目的是获得行数据的|既没有了修饎ͼ也不?x)对行数据的g生什么媄响。唯一的不利之处就是,在内存中?x)同时保存两个同L(fng)工作表,q样当工作表体积比较大时Q会(x)占用相当大的内存Q但现在好像内存的大ƈ不是什么关键因素了?/p>
一旦获得了可写入的工作表对象,我们可以对单元格对象进行更新的操作了,在这里我们不必调用API提供的add()Ҏ(gu)Q因为单元格已经于工作表当中Q所以我们只需要调用相应的setXXX()Ҏ(gu)Q就可以完成更新的操作了?/p>
单元格原有的格式化修饰是不能去掉的Q我们还是可以将新的单元g饰加上去Q以使单元格的内容以不同的Ş式表现?/p>
新生成的工作表对象是可写入的Q我们除了更新原有的单元格外Q还可以d新的单元格到工作表中Q这与示?的操作是完全一L(fng)?/p>
最后,不要忘记调用write()Ҏ(gu)Q将更新的内容写入到文g中,然后关闭工作薄对象,q里有两个工作薄对象要关闭,一个是只读的,另外一个是可写入的?/p>
![]() ![]() |
![]()
|
本文只是对Java Excel API中常用的Ҏ(gu)作了介绍Q要x详尽C解APIQ请大家参考API文档Q或源代码。Java Excel API是一个开放源码项目,请大家关注它的最新进展,有兴的朋友也可以申请加入这个项目,或者是提出宝贵的意见?/p>
![]() |
||
|
![]() |
叫我Rubber吧,我是一个JavaqP希望我们能成为朋友,我的EamilQ?tim@trend.com.cnQ我的联pȝ(sh)?755-83501377 |
![]() |
U别: 初 宗锋 (zong_feng@263.net)西北大学计算机系士 2001 q?12 ?16 ?/p> 本文对 《一个简单的 JDBC 包装器?/font>中的JDBC包装器进行一些扩展,然后介绍一下其在jsp+javabean开发模式中的应用? 最q看?《一个简单的 JDBC 包装器?/font>Q觉得这文章很有应用h(hun)|我便在自q开发中使用了它Q不q这个包装器也存在一些不I于是我对它进行了一些扩展。首先原文中的Tablecȝ删除功能,我便增加了删除功能。代码如下:(x)
q两个函数分别用于删除一个Row和满一定条件的记录。对于具有主关键字的表,我们可以用下面代码中的方法二来进行删除,如果没有d键字Q我们可以用Ҏ(gu)一删除?/p> CZ如下Q?
另外q个包装器没有对查询l果为NULL的情况作处理Q我通过修改Tablecȝexecute函数和RowSetcȝget函数对这U情况作了处理。具体代码见附g?/p> 下面谈谈利用q个JDBC包装器实现对数据库的装Q假定我们有一个表:studentQ创的Sql语句如下Q?
我们对这个表q行装Q下面是Studentcȝ主要代码Q?
下面q个cL相应的一个查询类的主要代码:(x)
我用javabean来实现很多功能,q样可以减少在jsp中的java代码量,方便我们对界面的改进。我们要实现的功能ؓ(f)对学生的~辑Q添加,删除和列表。这些功能定义在两个javabean中:(x)下面是两个jsp文g的主要代码:(x)
我的x是在student.jsp中显C学生列表,从这个页面可以{到增加和~辑面Q也可以在这个页面中删除学生Q这三个功能都是由editstudent.jsp完成的。在editstudent.jsp中非常关键的一行代码就?lt;%table.processRequest(pageContext);%>Q这?x)调用EditStudentBeancȝprocessRequestҎ(gu)Q下面是EditStudentBeancprocessRequestҎ(gu)和addStudentҎ(gu)的代?
processRequestҎ(gu)的功能主要ؓ(f)获取提交leditstudent.jsp的event的|Ҏ(gu)不同的event调用不同的函数。例如event=addQ则调用addStudent函数?/p> 注意Q在讄Student对象的各个属性值时Q一定要按照?见上面的SQL语句)中顺序来讄Q例如在表中,id字段在name字段的前面,所以setIdҎ(gu)在setNameҎ(gu)前面Q这主要是由于TablecM的putRow函数中执行插入操作的SQL语句有缺陗在那个SQL语句中,它是按各属性在Row中的序来执行插入操作的。如q你不愿意按表中字段的顺序来讄Student的属性,可以对putRow函数更改如下Q?
限于幅Q我省略了student.jsp文g中的一些内容,对这个jsp文gq行处理的bean为ListStudentBeanQ这个类主要实现一个函数getStudentQ这个函C要通过StudentFactory查寻到所有的学生Q由于我在此函数中进行了分页处理Q因此此函数只返回当前页需要的Student数组。具体的代码参看 附g? MQ我改进之后的这个JDBC装器还是比较有效的Q它能满一般地需要,当然你也可以Ҏ(gu)你的情况对其q行扩充Q以更好地适应你的开发?/p> 代码在Tomcat4.01+mysql3.23.43下测试通过?/p>
|
一U简单程序的快速数据访问解x?/p>
![]() |
U别: 初 Greg Travis (mito@panix.com), 自由E序?br> 2001 q?8 ?04 ?/p> JDBC 提供了一U强大、全面的接口用来?Java E序讉K数据库。对于较?yu)的目来说Q?JDBC g是理所当然的,它一些程序员避免了一起用数据库。本文描qC一U简单的包装器库Q它让用简单的数据库易如反掌。?zhn)会(x)发现(zhn)已经开始想在编写的每一个程序中都?JDBC?/blockquote> |
GetPageCode gpc = new GetPageCode(); gpc.Url="http://ppcode.com"; gpc.ProxyState=1;//使用代理服务器,0Z使用Q设|ؓ(f)1后下面的代理讄才v作用 gpc.ProxyAddress="http://proxyName.com";//代理服务器地址 gpc.ProxyPort="80";//代理服务器的端口 gpc.ProxyAccount="proxy";//代理服务器̎?br> gpc.ProxyPassword="password";//代理服务器密?br> gpc.ProxyDomain="bqc";//代理服务器域 gpc.OutFilePath=filePath;//讄输出文g路径的地方,如果不设|,则返回字W串 gpc.GetSource();//处理 string tempErr=gpc.NoteMessage;//如果出错Q这里会(x)提示 string tempCode=gpc.OutString;//q回的字W串 #endregion cM码:(x) using System; using System.Collections; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Net; using System.Text; using System.Web; namespace Test.Com { /// <summary> /// 功能Q取得Internet上的URL늚源码 /// 创徏Q?004-03-22 /// 作者:(x)Rexsp MSN:yubo@x263.net /// </summary> public class GetPageCode { #region U有变量 /// <summary> /// |页URL地址 /// </summary> private string url=null; /// <summary> /// 是否使用代码服务器:(x)0 不?nbsp; 1 使用代理服务?br> /// </summary> private int proxyState=0; /// <summary> /// 代理服务器地址 /// </summary> private string proxyAddress=null; /// <summary> /// 代理服务器端?br> /// </summary> private string proxyPort=null; /// <summary> /// 代理服务器用户名 /// </summary> private string proxyAccount=null; /// <summary> /// 代理服务器密?br> /// </summary> private string proxyPassword=null; /// <summary> /// 代理服务器域 /// </summary> private string proxyDomain=null; /// <summary> /// 输出文g路径 /// </summary> private string outFilePath=null; /// <summary> /// 输出的字W串 /// </summary> private string outString=null; /// <summary> /// 提示信息 /// </summary> private string noteMessage; #endregion #region 公共属?br> /// <summary> /// Ʋ读取的URL地址 /// </summary> public string Url { get{return url;} set{url=value;} } /// <summary> /// 是否使用代理服务器标?br> /// </summary> public int ProxyState { get{return proxyState;} set{proxyState=value;} } /// <summary> /// 代理服务器地址 /// </summary> public string ProxyAddress { get{return proxyAddress;} set{proxyAddress=value;} } /// <summary> /// 代理服务器端?br> /// </summary> public string ProxyPort { get{return proxyPort;} set{proxyPort=value;} } /// <summary> /// 代理服务器̎?br> /// </summary> public string ProxyAccount { get{return proxyAccount;} set{proxyAccount=value;} } /// <summary> /// 代理服务器密?br> /// </summary> public string ProxyPassword { get{return proxyPassword;} set{proxyPassword=value;} } /// <summary> /// 代理服务器域 /// </summary> public string ProxyDomain { get{return proxyDomain;} set{proxyDomain=value;} } /// <summary> /// 输出文g路径 /// </summary> public string OutFilePath { get{return outFilePath;} set{outFilePath=value;} } /// <summary> /// q回的字W串 /// </summary> public string OutString { get{return outString;} } /// <summary> /// q回提示信息 /// </summary> public string NoteMessage { get{return noteMessage;} } #endregion #region 构造函?br> public GetPageCode() { } #endregion #region 公共Ҏ(gu) /// <summary> /// d指定URL地址Q存到指定文件中 /// </summary> public void GetSource() { WebRequest request = WebRequest.Create(this.url); //使用代理服务器的处理 if(this.proxyState==1) { //默认d80端口的数?br> if(this.proxyPort==null) this.ProxyPort="80"; WebProxy myProxy=new WebProxy(); myProxy = (WebProxy)request.Proxy; myProxy.Address = new Uri(this.ProxyAddress+":"+this.ProxyPort); myProxy.Credentials = new NetworkCredential(this.proxyAccount, this.proxyPassword, this.ProxyDomain); request.Proxy = myProxy; } try { //h服务 WebResponse response = request.GetResponse(); //q回信息 Stream resStream = response.GetResponseStream(); StreamReader sr = new StreamReader(resStream, System.Text.Encoding.Default); string tempCode= sr.ReadToEnd(); resStream.Close(); sr.Close(); //如果输出文g路径为空Q便得到的内容赋给OutString属?br> if(this.outFilePath==null) { this.outString=tempCode; } else { FileInfo fi = new FileInfo(this.outFilePath); //如果存在文g则先q掉 if(fi.Exists) fi.Delete(); StreamWriter sw = new StreamWriter(this.outFilePath,true,Encoding.Default); sw.Write(tempCode); sw.Flush(); sw.Close(); } } catch { this.noteMessage="出错了,h查网l是否连?"; } } #endregion } } |