我先说说在JBUILDER中将程序外观变的更酷的办法!
JAVA程序默认的外观(LOOKANDFEEL)可以改变为JAVA外观、MOTIF外观、WINDOWS外观、MAC外观;
而JAVA外观又有五种风格分别是海蓝宝石风格、祖母绿风格、红宝石风格、木炭风格、
高对比风格。
外观改变具体方法如下:
1:可以直接在程序中调用下面三个中的一个:
import javax.swing.*;
UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel") ;
UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel") ;
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel") ;
2:或采用菜单来变换:
import javax.swing.*;
JMenuBar mb = new JMenuBar();
JMenu file = new JMenu("Look & Feel", true);
ButtonGroup buttonGroup = new ButtonGroup();
final UIManager.LookAndFeelInfo[] info = UIManager.getInstalledLookAndFeels();
for (int i = 0; i < info.length; i++) {
JRadioButtonMenuItem item = new
JRadioButtonMenuItem(info[i].getName(), i == 0);
final String className = info[i].getClassName();
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
try { UIManager.setLookAndFeel(className); }
catch (Exception e) { System.out.println(e); }
SwingUtilities.updateComponentTreeUI(TouchyFeely.this); }
});
buttonGroup.add(item);
file.add(item);
}
mb.add(file);
setJMenuBar(mb);
}
以前发表过内容的大富翁朋友请将内容改为JBUILDER相关内容。谢谢。
希望多多写入精华,不要灌水!
来自:humanc2d4, 时间:2003-5-16 14:45:00, ID:1867298
我再说一下JBUILDER中APPLET的数字签名(转载自:编程爱好者)
自从Java技术开始应用以来,人们对Java平台的安全性以及由于部署Java技术所引发的安全问题给予了极大的关注。特别是在1998年11月Java2发布后,Java的安全体系结构发生了根本的改进,对于终端用户而言,它可以保护文件和私人数据不被恶意的程序或病毒感染和破坏,鉴别代码提供者的身份。对于开发者而言,通过使用API方法,能够将安全性功能集成到应用程序中,因为API的体系结构能够定义和集成对特定的资源的使用权限、加密、安全性管理、策略管理,并提供了一些类来管理公钥/密钥对及信任用户群的公钥证书。同时系统管理员、开发者和用户可以使用它提供的工具管理钥匙库,在JAR文件中生成数字签名、签名的完整性检测、创建和修改策略文件。按照Java设计者的观点,Java安全包括2个方面的内容,首先将Java作为一种安全的平台提供给用户,在此平台上,可安全地运行Java程序;其次提供用Java编程语言实现的安全工具和服务,它使得诸如企业界这样一些对安全非常敏感的领域也可应用Java技术。本文将就这二个方面介绍Java2的安全性新特性以及该新特性下的Applet数字签名的具体实现方法。
Java2采用了如图1所示的新的安全体系结构,并基于这种安全体系结构提供了很多新特?
1.1 密纹访问控制
这种能力从一开始就在JDK中存在。但要使用它,应用程序的编写者不得不做大量的编程工作例如,创建SecurityManager和Classloader类的子类并使其用户化。HotJava1.0就是一个这样的应用程序,它允许浏览器用户在几个不同的安全等级上进行选择。然而,这种编程涉及非常敏感的安全问题,它要求程序员对计算机安全有精深的理解和纯熟的技巧。新的安全体系结构将使这些变得简单而安全。
1.2 易于配置的安全策略
与上述情况相似,这种能力在原来的JDK中也是存在的,但是不便于使用,而且编写安全代码也不是简单明了的事情。于是,人们期望能够允许应用程序的编写者和用户能够不通过编程来设置安全策略。
1.3 便于扩展的访问控制结构
一直到JDK1.1为止,为了创建1个新的访问许可,你必须在SecurityManager类中增加1个新的check方法。新的安全体系结构则允许设置各类访问许可(每个都表示对1个系统资源的访问),并能对所有正确访问许可(包括未定义的许可)进行自动处理。
1.4 安全检查扩展至所有Java程序
那种所有本地代码是可信的内置概念将不复存在,取而代之的将是本地代码(例如非系统代码,安装在本地的应用程序包等)服从于与Applet相同的安全控制,但是可以声明对本地代码的政策是最宽容的,从而使这些代码可被认为是完全可信而有效地运行。上述原则也可应用于已签字的Applet和任何Java应用程序。
2 Java2安全体系的概念及运行机制
2.1 保护域
Java2安全体系结构中的一个基本的概念是保护域(Protected Domain)。1个域可通过对象集来划分范围,这些对象当前可由1个主体直接访问。而主体是在计算机系统中被授予许可的实体。JDK1.0所利用的沙箱就是一个有着固定边界的保护域实例。保护域的概念是一种在保护单元间起着分组和隔离作用的便利机制。例如,我们可以将保护域分开以避免它们之间的直接交互作用,于是,任何允许的交互作用必须通过可信系统代码或被有关的域所明确允许。
保护域通常分为明确的2个类别,系统域和应用程序域。所有被保护的外部资源如:文件系统、网络设施以及屏幕和键盘等仅能通过系统域来访问。图2中显示了1个Java应用环境的域的组成。从概念上讲,1个域包括1组类,这些类的实例被授予相同的一组许可。保护域是由现行策略所确定的。Java应用程序环境保持了来自代码(类和实例)到它们的保护域然后再到它们的许可的映射,如图3所示。1个线程的执行可能完全发生在1个单一的保护域中,也可能涉及1个应用程序域或是系统域。例如:1个打印消息的应用程序将不得不与系统域发生交互作用,因为系统域是唯一对输出流的访问点。在此种情况下的任何时候,应用程序域都不能通过调用系统域获得除打印消息外的任何额外许可,否则将是一个严重的安全性隐患。在相反的情形下,1个系统域从1个应用程序域中调用1个方法,如当1个AWT系统域调用1个Applet的绘画方法来显示这个Applet时,有效访问权限与应用程序域所允许的当前权限在任何时候都相同,这一点也是同样至关重要的。换句话说,一个具有较低权限的域不能通过调用一个更高权限的域,或被一个更高权限的域所调用来获得额外的许可。上述有关1个线程涉及2个保护域的讨论自然地归纳为1个遍历多重保护域的线程,计算许可的一个简单而谨慎的经验做法是:
(1)一个执行线程的许可集可被认为是由该线程所遍历的所有保护域的许可的交集。
(2)当1条代码调用doPrivileged方法时,执行线程的许可集被认为是包括所有代码的保护域以及由它直接或间接调用的保护域的权限。即通过doPrivileged方法可使1条可信代码能临时访问更多的资源,这在某些情况下是必要的。例如,1个应用程序可能不被允许直接访问包含字体的文件,但是,显示文本的系统实用程序必须代表用户获得那些字体。
在执行期间,当请求访问1个关键系统资源(如文件I/O和网络I/O)或者API方法需要执行1个敏感的操作时,例如读1个文件,资源处理代码直接或间接地调用1个特殊的称为访问控制(AccessController)类的方法,访问控制类通过检查调用栈来作出决定是否准予该请求或操作发生。在调用栈中是执行该操作需要调用的一些类的成员方法,因为每个类都属于一些保护域,每个保护域都建立了一些策略,因此在调用栈的每个方法都被分配了1组权限。访问控制类由栈顶开始,自顶向下检查每个方法,看是否方法被所在的保护域所允许,如果发现一个方法权限没有得到允许,访问控制
就抛出安全性异常;反之,如果到达栈底仍未抛出异常,即说明调用栈中的所有方法均满足保护域的权限要求,访问控制允许操作发生。其中有一种特殊的情况,即当访问控制遍历调用栈时,将查找是否存在优先域(Privileged Domain),如果存在优
域,即使没有到达栈底,访问控制也将停止遍历调用栈并允许操作发生。虽然新的安
机制初看上去增加了许多调用API方法的消耗,但是Java2确实使用了一些技术去加速
查权限的过程,例如访问控制将过滤掉重复的域并在遇到第一个优先域时停止检查,
说明额外的操作将是一个本地的方法调用,SUN的基准测试显示了新的安全检查是相当快的。
最后,每个域包括系统或应用程序域可以对其域边界内的内部资源进行附加保。例如,一个银行系统的应用程序可能需要支持并保护其内部的一些概念,如查帐、存
和取款等。由于此种保护的语义不像那些可预测的语义可以被JDK预置,因而,在这个
次上的保护最好留给系统或应用程序开发员来做。
目前,1个域单独地由1个代码来源(CodeSource)鉴别,它封装了在该域中运行的代码的2个特性:代码基址和公共密钥证书集,公共密钥对应于在该域中为所有代码签字的私有密钥。因而,由相同的密钥签字和来自相同URL的类被放在同一个域中。1个域还包含在该域中授予代码的许可,它是由现行安全策略所决定的。
2.2 证书、钥匙库及其相关工具
在Java2的安全体系下,1个Applet开发和运行的过程如下:
在代码的分发端:
(1)开发Java源程序并对其进行编译。
(2)用JAR工具对类文件和资源文件进行封装。
(3)用keytool创建公钥和密钥,生成X。509V1签名证书,输出证书。
(4)通过jarsigner工具用生成的密钥对JAR文件进行数字签名。
在代码的接收端:
(1)用keytool输入证书视其为可信任。
(2)用policytool创建和修改安全性策略配置文件,授权请求的访问权限。
(3)从网络取得字节码,用公钥验证数字签名证书和文档代码的完整性。
(4)验证字节码的合法性,根据策略文件分配相应权限。
(5)执行代码,完成后被垃圾回收器回收内存。
在用公钥验证数字签名证书之前,接收方需要确认公钥自身的可靠性,因此通常情况是提供一个包含公钥的证书而不是公钥自身。1个证书包括:
(1)1个公钥。
(2)1个唯一的名字实体(个人或公司),它是证书的所有者,包含用户名字、公司、组织、城市、地址、国家代码、省份等信息。
(3)数字签名:1个证书被1个分发者的实体签名,保证证书确实包含另1个
实体(所有者)的公钥。
(4)分发者的标识名信息。
对于接收者可以用分发者的公钥来验证他的数字签名,检查证书的合法性。然而公钥可能包含在另一个证书中,而数字签名需要用另一个证书的分发者的公钥来验证,这样嵌套下去,直到一个公钥被接收者确认是可信任的。如果接收者不能建立信任链,例如:1个分发者的证书不合法,那么可以用keytool-import命令来计算指纹,每个指纹是一个相关的短数字,它唯一可靠地标识证书(指纹是一个用信息摘要算法计算的证书信息的哈希值),接收者可以呼叫证书的所有者,并比较发出的证书和接收证书的指纹,如果指纹相同,则证书不同。因此能够保证证书在传递的过程中未被修改。另一个潜在的问题是发送者身份的标识,有时一个证书是自签名的,即使用证书中的公钥相对应的密钥进行签名,如果接收者已经知道或信任发送者,那么就没有任何问题。否则发送者需要从一个可信任的第3方得到证书,这个第3方通常是一个证书的授权机构CA,那么首先发送一个自签名的证书签名请求CSR给CA,由CA验证CSR的签名及发送CSR的身份、许可证以及其它信息。然后CA通过一个用CA的密钥进行签名的证书,授权CSR的发送者作为公钥的所有者,任何人只要信任CA的公钥,都可以用之来验证证书的签名,很多情况下CA自身有一个来自更高一级的CA的证书,从而构成证书链。所有信任的证书实体都可以作为信任证书被引入钥匙库,每个证书中的公钥都可以用来验证用相应的密钥生成的签名。
发送者在发送签名的代码和文档时还相应提供包含与签名的密钥相应的公钥证书。用keytool-export命令或API函数可以从钥匙库中输出证书到文件中,然后将这个文件发送给需要的接收者,由接收者用keytool-import命令或API函数将其引入钥匙库中。如果用jarsigner工具为JAR文件生成签名,他会从钥匙库中取出证书及证书链,并和签名一起放入JAR文件。
密钥和相应的公钥证书存放在一个由口令保护的数据库中,称为钥匙库(keystore)。1个钥匙库包含2种类型的条目,可信任的证书条目,钥匙和证书条目,每个都包含1个密钥和与密钥相应的公钥证书,在钥匙库中的每个条目都有1个别名进行标识。1个钥匙库的所有者在钥匙库中可以有多个钥匙,可以通过不同的别名进行访问,每个别名通常是用钥匙库的所有者使用的钥匙的特定角色来命名,别名也可以标识钥匙的目的。例如:
SignPersonalEmail可以被用来标识1个钥匙库的条目,它的密钥用于签名个人邮件,SignJarFiles用于标识1个条目,它的密钥用于签名JAR文件。
3 Applet的数字签名认证实现的具体方法、步骤
3.1 结合我自己开发的基于JAVA2的Applet
我的项目是使用APPLET制作一个实时消息队列监控程序,由于涉及到了本地资源,对APPLET一定要进行数字签名和认证。我使用的环境是WINDOWS2000,应用服务器是WEBLOGIC6.0,开发环境是JBUILDER4.0。之前我提醒大家一定要注意服务器端和客户端的概念。那些文件应该在服务器端,那些文件应该在客户端。
首先在客户端使用JRE1.3.0_01(JAVA运行环境1.3.0.1版本)以取代IE的JVM(JAVA虚拟机),可以到WWW.JAVA.SUN.COM网站上去下载,下载好了先在客户端安装好,安装过程非常简单。
在服务器端的调用APPLET的HTML文件中也需要将它包含进来,以便没有事先安装JRE的客户端下载,具体的写法,请接着往下看;
具体步骤如下:
服务器端:
1.将程序需要用到的各种包文件全部解压(我这儿要用到WEBLOGIC的JMS包使用命令jar xf weblogicc.jar),然后使用JDK的打包命令将编译好的监控程序.class和刚才解压的包一起打包到一个包中。(前提我已经将监控程序和解开的包都放在同一个目录下了),都是dos状态下的命令,具体命令见jdk1.3(1.2)的bin目录下,命令如下:
jar cvf monitor.jar *.class
此命令生成一个名为monitor.jar的包
2.为刚才创建的包文件(monitor.jar)创建keystore和keys。其中keystore将用来存放密匙(private keys)和公共钥匙的认证,alias别名这儿取为monitor。
命令如下:
keytool -genkey -keystore monitor.keystore –alias monitor
此命令生成了一个名为monitor.keystore的keystore文件,接着这条命令,系统会问你好多问题,比如你的公司名称,你的地址,你要设定的密码等等,都由自己的随便写。
3.使用刚才生成的钥匙来对jar文件进行签名
命令如下:
jarsigner -keystore monitor.keystore monitor.jar monitor
这个命令将对monitor.jar文件进行签名,不会生成新文件。
4.将公共钥匙导入到一个cer文件中,这个cer文件就是要拷贝到客户端的唯一文件
。
命令如下:
keytool -export -keystore monitor.keystore -alias monitor -file
monitor.cer
此条命令将生成monitor.cer认证文件,当然这几步都有可能问你刚才设置的密码。
这样就完成了服务器端的设置。这时你就可以将jar文件和keystore文件以及cer文件(我这儿是monitor.jar,monitor.keystore,monitor.cer)拷贝到服务器的目录下了,我用的是weblogic6.0,所以就拷贝到C:eawlserver6.0configmydomainapplicationsDefaultWebApp_myserver下的自己建的一个目录下了。
客户端:
1. 首先应该安装jre1.3.0_01,然后将服务器端生成的monitor.cer文件拷贝到jre的特定目录下,我这儿是:
c:program filesjavasoftjre1.3.0_01libsecurity目录下。
2. 将公共钥匙倒入到jre的cacerts(这是jre的默认keystore)
命令如下:
keytool -import -alias monitor -file monitor.cer
-keystore cacerts
注意这儿要你输入的是cacerts的密码,应该是changeit,而不是你自己设定的keystore的密码。
3. 修改policy策略文件,在dos状态下使用命令 policytool系统会自动弹出一个policytool的对话框,如图4所示,在这里面首先选择file菜单的open项,
打开c:program
filesjavasoftjre1.3.0_01libsecurity目录下的java.poliy文件,然
后在edit菜单中选择Change keystore ,在对话框中new keystore url:中输入file:/c:/program files /javasoft/jre/1.3.0_01/lib/security/cacerts,这儿要注意反斜杠,在new keystore type中输入JKS,这是cacerts的固定格式,然后单击Add PolicyEntry,在出现的对话框中CodeBase中输入:
http://URL:7001/*
其中的URL是服务器的IP地址,7001是我的weblogic的端口,如果你是在别的应用服务器上比如说是apache,那端口号就可以省略掉。在SignedBy中输入(别名alias):这儿是Monitor然后单击add peimission按钮,在出现的对话框中permission中选择你想给这个applet的权限,这儿具体有许多权限,读者可以自己找资料看看。我这儿就选用allpeimission,右边的signedBy中输入别名:monitor最后保存,在file菜单的save项。当然你可以看见我已经对多个包实现了签名认证。
这样客户端的设置就完成了。在客户端用ie运行该applet程序时,会询问你是不是对该签名授权,选择授权后,包会自动从服务器下载到本地计算机,而且ie会自动启动jre,在右下栏中可以看见,相当于ie的java控制台。
4.调用applet的html文件
大家都知道由于java2的安全性,对applet的正常调用的html文件已经不能再使用了,而改为ActiveX类型的调用。具体的又分ie和nescape的不同写法,这一些在sun网上都能找到现成的教程。我就不多说了,只是将我的这个小程序为ie写的的html给大家看看。
<html>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html;CHARSET=gb2312">
<center>
<h3>消息中心实时监控平台</h3>
<hr>
<OBJECT classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"
width="900" height="520" align="baseline"
codebase="http://192.168.2.217:7001/j2re-1_3_0_01-win-i.exe#Version=1,3,0,0">
<PARAM NAME="java_code" VALUE="wise.monitor.applet.monitorApplet">
<PARAM NAME="java_codebase" VALUE="monitor/classes">
<PARAM NAME="java_type" VALUE="application/x-java-applet;version=1.3">
<PARAM NAME="ARCHIVE" VALUE="monitor.jar" >
<PARAM NAME="scriptable" VALUE="true">
</OBJECT>
</center>
</html>
其中我要强调一点,因为applet每一次的改动都需要重新打包签名,手续非常繁琐,所以在具体的实现中要将一些会变化参数放到html文件中来,传到applet中去,这一点网上文章好多,自己去看吧。
另外一个就是有朋友问我,那这样不是太麻烦了,每一个客户端都要进行复杂的dos命令操作,我只能说一目前我的水平只能将一个已经做好的客户端文件cer文件和java.policy以及cacerts文件直接拷贝到客户端,当然这也有缺陷,如果别人的计算机已经有了认证,就会丢失。就这些问题我们可以一起探讨。
另外还有一点优化,就是在打包的时候,我这儿只讲了把所有要用的涉及到安全性的包和源程序到要打到一个包中。这样如果包非常大的话,会非常影响下载的速度,如果可以使用本地计算机的包就好了,这一点jre也做到了,具体的要到控制面板的jre控制台上去设置。这个就留着读者自己去摸索吧。
来自:humanc2d4, 时间:2003-5-16 14:47:00, ID:1867304
我说一下JAVA控制EXCEL的方法之一。(BORLAND.COM)
使用Windows操作系统的朋友对Excel(电子表格)一定不会陌生,但是要使用Java语言来操纵Excel文件并不是一件容易的事。在Web应用日益盛行的今天,通过Web来操作Excel文件的需求越来越强烈,目前较为流行的操作是在JSP或Servlet 中创建一个CSV (comma separated values)文件,并将这个文件以MIME,text/csv类型返回给浏览器,接着浏览器调用Excel并且显示CSV文件。这样只是说可以访问到Excel文件,但是还不能真正的操纵Excel文件,本文将给大家一个惊喜,向大家介绍一个开放源码项目??Java Excel API,使用它大家就可以方便地操纵Excel文件了。
JAVA EXCEL API简介
Java Excel是一开放源码项目,通过它Java开发人员可以读取Excel文件的内容、创建新的Excel文件、更新已经存在的Excel文件。使用该API非Windows操作系统也可以通过纯Java应用来处理Excel数据表。因为是使用Java编写的,所以我们在Web应用中可以通过JSP、Servlet来调用API实现对Excel数据表的访问。 现在发布的稳定版本是V2.0,提供以下功能:
? 从Excel 95、97、2000等格式的文件中读取数据;
? 读取Excel公式(可以读取Excel 97以后的公式);
? 生成Excel数据表(格式为Excel 97);
? 支持字体、数字、日期的格式化;
? 支持单元格的阴影操作,以及颜色操作;
? 修改已经存在的数据表;
? 现在还不支持以下功能,但不久就会提供了:
? 不能够读取图表信息;
可以读,但是不能生成公式,任何类型公式最后的计算值都可以读出;
应用示例
从Excel文件读取数据表
Java Excel API既可以从本地文件系统的一个文件(.xls),也可以从输入流中读取Excel数据表。读取Excel数据表的第一步是创建Workbook(术语:工作薄),下面的代码片段举例说明了应该如何操作:(完整代码见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();
}
一旦创建了Workbook,我们就可以通过它来访问Excel Sheet(术语:工作表)。参考下面的代码片段:
//获取第一张Sheet表
Sheet rs = rwb.getSheet(0);
我们既可能通过Sheet的名称来访问它,也可以通过下标来访问它。如果通过下标来访问的话,要注意的一点是下标从0开始,就像数组一样。
一旦得到了Sheet,我们就可以通过它来访问Excel Cell(术语:单元格)。参考下面的代码片段:
//获取第一行,第一列的值
Cell c00 = rs.getCell(0, 0);
String strc00 = c00.getContents();
//获取第一行,第二列的值
Cell c10 = rs.getCell(1, 0);
String strc10 = c10.getContents();
//获取第二行,第二列的值
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()方法,它可以将任何类型的Cell值都作为一个字符串返回。示例代码中Cell(0, 0)是文本型,Cell(1, 0)是数字型,Cell(1,1)是日期型,通过getContents(),三种类型的返回值都是字符型。
如果有需要知道Cell内容的确切类型,API也提供了一系列的方法。参考下面的代码片段:
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()方法可以获得该单元格的类型,然后与API提供的基本类型相匹配,强制转换成相应的类型,最后调用相应的取值方法getXXX(),就可以得到确定类型的值。API提供了以下基本类型,与Excel的数据格式相对应。
每种类型的具体意义,请参见Java Excel API Document。
当你完成对Excel电子表格数据的处理后,一定要使用close()方法来关闭先前创建的对象,以释放读取数据表的过程中所占用的内存空间,在读取大量数据时显得尤为重要。参考如下代码片段:
//操作完成时,关闭对象,释放占用的内存空间
rwb.close();
Java Excel API提供了许多访问Excel数据表的方法,在这里我只简要地介绍几个常用的方法,其它的方法请参考附录中的Java Excel API Document。
? Workbook类提供的方法
1. int getNumberOfSheets()
获得工作薄(Workbook)中工作表(Sheet)的个数,示例:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
int sheets = rwb.getNumberOfSheets();
2. Sheet[] getSheets()
返回工作薄(Workbook)中工作表(Sheet)对象数组,示例:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
Sheet[] sheets = rwb.getSheets();
3. String getVersion()
返回正在使用的API的版本号,好像是没什么太大的作用。
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
String apiVersion = rwb.getVersion();
? Sheet接口提供的方法
1. String getName()
获取Sheet的名称,示例:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
jxl.Sheet rs = rwb.getSheet(0);
String sheetName = rs.getName();
2. int getColumns()
获取Sheet表中所包含的总列数,示例:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
jxl.Sheet rs = rwb.getSheet(0);
int rsColumns = rs.getColumns();
3. Cell[] getColumn(int column)
获取某一列的所有单元格,返回的是单元格对象数组,示例:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
jxl.Sheet rs = rwb.getSheet(0);
Cell[] cell = rs.getColumn(0);
4. int getRows()
获取Sheet表中所包含的总行数,示例:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
jxl.Sheet rs = rwb.getSheet(0);
int rsRows = rs.getRows();
5. Cell[] getRow(int row)
获取某一行的所有单元格,返回的是单元格对象数组,示例子:
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)
获取指定单元格的对象引用,需要注意的是它的两个参数,第一个是列数,第二个是行数,这与通常的行、列组合有些不同。
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
jxl.Sheet rs = rwb.getSheet(0);
Cell cell = rs.getCell(0, 0);
生成新的Excel工作薄
下面的代码主要是向大家介绍如何生成简单的Excel工作表,在这里单元格的内容是不带任何修饰的(如:字体,颜色等等),所有的内容都作为字符串写入。(完整代码见ExcelWriting.java)
与读取Excel工作表相似,首先要使用Workbook类的工厂方法创建一个可写入的工作薄(Workbook)对象,这里要注意的是,只能通过API提供的工厂方法来创建Workbook,而不能使用WritableWorkbook的构造函数,因为类WritableWorkbook的构造函数为protected类型。示例代码片段如下:
import java.io.*;
import jxl.*;
import jxl.write.*;
… … … …
try
{
//构建Workbook对象, 只读Workbook对象
//Method 1:创建可写入的Excel工作薄
jxl.write.WritableWorkbook wwb = Workbook.createWorkbook(new File(targetfile));
//Method 2:将WritableWorkbook直接写入到输出流
/*
OutputStream os = new FileOutputStream(targetfile);
jxl.write.WritableWorkbook wwb = Workbook.createWorkbook(os);
*/
}
catch (Exception e)
{
e.printStackTrace();
}
API提供了两种方式来处理可写入的输出流,一种是直接生成本地文件,如果文件名不带全路径的话,缺省的文件会定位在当前目录,如果文件名带有全路径的话,则生成的Excel文件则会定位在相应的目录;另外一种是将Excel对象直接写入到输出流,例如:用户通过浏览器来访问Web服务器,如果HTTP头设置正确的话,浏览器自动调用客户端的Excel应用程序,来显示动态生成的Excel电子表格。
接下来就是要创建工作表,创建工作表的方法与创建工作薄的方法几乎一样,同样是通过工厂模式方法获得相应的对象,该方法需要两个参数,一个是工作表的名称,另一个是工作表在工作薄中的位置,参考下面的代码片段:
file://创建Excel工作表
jxl.write.WritableSheet ws = wwb.createSheet("Test Sheet 1", 0);
"这锅也支好了,材料也准备齐全了,可以开始下锅了!",现在要做的只是实例化API所提供的Excel基本数据类型,并将它们添加到工作表中就可以了,参考下面的代码片段:
file://1/.添加Label对象
jxl.write.Label labelC = new jxl.write.Label(0, 0, "This is a Label cell");
ws.addCell(labelC);
//添加带有字型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);
//添加带有字体颜色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.添加Number对象
jxl.write.Number labelN = new jxl.write.Number(0, 1, 3.1415926);
ws.addCell(labelN);
//添加带有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.添加Boolean对象
jxl.write.Boolean labelB = new jxl.write.Boolean(0, 2, false);
ws.addCell(labelB);
//4.添加DateTime对象
jxl.write.DateTime labelDT = new jxl.write.DateTime(0, 3, new java.util.Date());
ws.addCell(labelDT);
//添加带有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);
这里有两点大家要引起大家的注意。第一点,在构造单元格时,单元格在工作表中的位置就已经确定了。一旦创建后,单元格的位置是不能够变更的,尽管单元格的内容是可以改变的。第二点,单元格的定位是按照下面这样的规律(column, row),而且下标都是从0开始,例如,A1被存储在(0, 0),B1被存储在(1, 0)。
最后,不要忘记关闭打开的Excel工作薄对象,以释放占用的内存,参见下面的代码片段:
file://写入Exel工作表
wwb.write();
//关闭Excel工作薄对象
wwb.close();
这可能与读取Excel文件的操作有少少不同,在关闭Excel对象之前,你必须要先调用write()方法,因为先前的操作都是存储在缓存中的,所以要通过该方法将操作的内容保存在文件中。如果你先关闭了Excel对象,那么只能得到一张空的工作薄了。
拷贝、更新Excel工作薄
接下来简要介绍一下如何更新一个已经存在的工作薄,主要是下面二步操作,第一步是构造只读的Excel工作薄,第二步是利用已经创建的Excel工作薄创建新的可写入的Excel工作薄,参考下面的代码片段:(完整代码见ExcelModifying.java)
file://创建只读的Excel工作薄的对象
jxl.Workbook rw = jxl.Workbook.getWorkbook(new File(sourcefile));
//创建可写入的Excel工作薄对象
jxl.write.WritableWorkbook wwb = Workbook.createWorkbook(new File(targetfile), rw);
//读取第一张工作表
jxl.write.WritableSheet ws = wwb.getSheet(0);
//获得第一个单元格对象
jxl.write.WritableCell wc = ws.getWritableCell(0, 0);
//判断单元格的类型, 做出相应的转化
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();
之所以使用这种方式构建Excel对象,完全是因为效率的原因,因为上面的示例才是API的主要应用。为了提高性能,在读取工作表时,与数据相关的一些输出信息,所有的格式信息,如:字体、颜色等等,是不被处理的,因为我们的目的是获得行数据的值,既使没有了修饰,也不会对行数据的值产生什么影响。唯一的不利之处就是,在内存中会同时保存两个同样的工作表,这样当工作表体积比较大时,会占用相当大的内存,但现在好像内存的大小并不是什么关键因素了。
一旦获得了可写入的工作表对象,我们就可以对单元格对象进行更新的操作了,在这里我们不必调用API提供的add()方法,因为单元格已经于工作表当中,所以我们只需要调用相应的setXXX()方法,就可以完成更新的操作了。
尽单元格原有的格式化修饰是不能去掉的,我们还是可以将新的单元格修饰加上去,以使单元格的内容以不同的形式表现。
新生成的工作表对象是可写入的,我们除了更新原有的单元格外,还可以添加新的单元格到工作表中,这与示例2的操作是完全一样的。
最后,不要忘记调用write()方法,将更新的内容写入到文件中,然后关闭工作薄对象,这里有两个工作薄对象要关闭,一个是只读的,另外一个是可写入的。
下面是在一个Excel表格中创建一个矩阵的简单例子:
import org.apache.poi.hssf.usermodel.*;
import java.io.FileOutputStream;
// code run against the jakarta-poi-1.5.0-FINAL-20020506.jar.
public class PoiTest {
static public void main(String[] args) throws Exception {
FileOutputStream fos = new FileOutputStream("foo.xls");
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s = wb.createSheet();
wb.setSheetName(0, "Matrix");
for(short i=0; i<50; i++) {
HSSFRow row = s.createRow(i);
for(short j=0; j<50; j++) {
HSSFCell cell = row.createCell(j);
cell.setCellValue(""+i+","+j);
}
}
wb.write(fos);
fos.close();
}
}
这段代码首先创建一个Workbook,从该Workbook中得到一个表格、命名,然后继续写入一个50x50的矩阵。最后输出到一个名为foo.xls的Excel文件,甚至在Apple Mac机上也可以打开。
POI项目是Java应用的令人兴奋的一步,为用户提供了Windows文档集成的新功能,允许Java开发人员方便地扩展其产品的功能。
来自:humanc2d4, 时间:2003-5-16 14:49:00, ID:1867310
我说一下JAVA中收发EMAIL的方法(转载自:Java爱好者)
本文将讨论如何用Java来编写可根据SMTP和POP3协议来收发E-mail的Java Applet。
一.Java网络编程初步
1.建立TCP/IP连接
Socket类中的构造函数Socket(String host,int port)用于创建一个Socket,并与指定的主机(host)及端口(port)连接。由于受到Java Applet安全机制的限制,主机名不可以任意指定,而应和被调用的Applet所在主机的名字相同。因此,可先由GetCodeBase方法取得浏览器当前读取的CLASS文件所在的URL,再通过GetHost方法从该URL返回用字符串表示的该主机的名称。例如从 http://person.zj.cninfo.net/~caveman/ 这个URL中可以返回用字符串表示的主机名"person.zj.cninfo.net"。
关于标准端口地址的值一般是:SMTP为25、POP3为110、FTP为21等,当然也有的主机用的是非标准的端口,在使用之前最好先确定一下。
2.数据的发送与接收
使用Socket类中的GetOutputStream方法可以取得与当前Socket对应的输出数据流,用DataOutputStream类中的WriteBytes方法可以逐个字符地将数据写入到输出数据流中。
使用Socket类中的GetInputStream方法可以取得与当前Socket对应的输入数据流,用DataInputStream类中的ReadLine方法可以逐行地读取输入数据流中的数据。
3.关闭TCP/IP连接
可以用Socket类中的close方法来关闭TCP/IP连接。
二.基于SMTP协议发送E-mail的Java Applet
1.SMTP协议和服务器
SMTP(Simple Mail Transfer Protocol)协议是目前网上流行的发送E-mail的协议,SMTP协议共有14条命令。不过,发一封E-mail只需用如下5条命令就足够了(见表1)。
表1
命 令 功 能
HELO <SP> <domain> <CRLF> 与SMTP服务器握手,传送本机域名
MAIL <SP> FROM:<reverse-path> <CRLF>传送发信者的信箱名称
RCPT <SP> TO:<forward-path> <CRLF> 传送接收者的信箱名称
DATA <CRLF> 发送信件数据(包括信头和信体)
QUIT <CRLF> 退出与SMTP服务器的连接
除了ISP提供的SMTP服务器以外,国内一些存放免费个人主页的服务器的SMTP端口也是打开的,如果该服务器对外来的E-mail没有增加RELAY限制(例如网易nease.net就有此限制),那么也可以把它当作SMTP服务器来用。如Person.zj.cninfo.net等,在这些服务器上放一个下面要编的Java Applet和调用它的htm文件,用户就可以实现在线发送E-mail了。
2.SMTPtester.java中的主要程序
该Java Applet用了三个文本条(TextField)部件tf1、tf2和tf3,它们分别用来供用户输入发信者的信箱名称、接收者的信箱名称和信件的标题;还用了两个文本区(TextArea)部件ta1和ta2,ta1供用户输入信体内容,ta2用来显示Smtp服务器的应答信息和出错信息等;当然还用了一个按钮(Button)部件bu1,用户输入正确的信息后,用鼠标点击一下它,信件就可以被发出去了。
事件捕获处理程序见程序1:
public boolean handleEvent(Event event1){
if ((event1.target != bu1) || (event1.id != 1001))
/*如果不是按钮bu1被鼠标按下*/
{
return false;
}
if ((tf1.getText().length()!= 0) && (tf2.getText().length() != 0))
/*如果发信者和收信人的信箱名称都填好了,执行发信程序Bu1run*/
{ bu1.disable();
bu1run();
return true;
}
else{
ta2.appendText("Please give me enough information to send your email!\n");
return true;
}
(程序1)
发送E-mail程序bu1run见程序2:
public void bu1run(){
try{
Socket socket1= new Socket(getCodeBase().getHost(),25);
/*建立与smtp服务器的连接*/
DataOutputStream dataout2= new DataOutputStream(socket1.getOutputStream());
DataInputStream dataIn3= new DataInputStream(socket1.getInputStream());
GetReply(dataIn3);
dataout2.writeBytes("HELO person.zj.cninfo.net\r\n");
/*开始按SMTP协议发信*/
GetReply(dataIn3);
dataout2.writeBytes("MAIL FROM: " + tf1.getText() + "\r\n");
GetReply(dataIn3);
dataout2.writeBytes("RCPT TO: " + tf2.getText() + "\r\n");
GetReply(dataIn3);
dataout2.writeBytes("DATA\r\n");
GetReply(dataIn3);
dataout2.writeBytes("From: " + tf1.getText() + "\r\n");
dataout2.writeBytes("To: " + tf2.getText() + "\r\n");
dataout2.writeBytes("Subject:"+tf3.getText()+"\n\n"+ta1.getText()+"\r\n.\r\n");
GetReply(dataIn3);
dataout2.writeBytes("QUIT\r\n");
GetReply(dataIn3);
socket1.close();
/*退出连接*/
bu1.enable();
return;
}
catch (java.io.IOException IOException0) /*捕获IO错误*/
{
ta2.appendText("Error!\n");
bu1.enable();
return;
}
}
(程序2)
接收服务器应答程序GetReply见程序3:
void GetReply(DataInputStream dataIn1)
{
String string2;
string2= "";
try
{
string2= dataIn1.readLine();
ta2.appendText(string2 + "\n");
}
catch (java.io.IOException IOException0)
{
ta2.appendText("Error!\n");
bu1.enable();
return;
}
}
(程序3)
3.实例运行
在 http://person.zj.cninfo.net/~caveman 上已经放了编译好的SMTPtester.class和调用它的smtp.htm,图1是该Applet在运行时的画面,这时这封信已被发往
[email protected] 了!
三.基于POP3协议读取E_mail的Java Applet
1.POP3协议和服务器
POP3(Post Office Protocol version 3)是一种常用的网络协议,用于从远程服务器的信箱里收取E_mail,它的常用命令根据连接时的不同状态有:
(1)授权状态(AUTHORIZATION state)
User<SP><name><CRLF> 用户名
Pass<SP><string><CRLF> 用户密码
Quit<CRLF> 退出
(2)执行状态(TRANSACTION state)
STAT<CRLF> 信箱状态,即信箱内共有几封信,总共大小(8进制表示)等。
LIST<SP><msg><CRLF> 不用msg参数时显示每封信的大小列表,用msg参数时显示编号为msg的信件的长度(8进制表示)。
TOP<SP><msg><SP><n><CRLF> 取编号为msg的信件的信头(head)和部分信体(body),n=0时只取信头,n≠0时取信头和信体的前n行。该命令为可选命令,有些POP3服务器软件不支持它。
RETR<SP><msg><CRLF> 读取编号为msg的信件。
DELE<SP><msg><CRLF> 删编号为msg的信件,其实只是作个标记,真正删除要到更新状态。
(3)更新状态(UPDATE state)
QUIT<CRLF> 退出并把做过DELE标记的邮件删掉。
另外还有NOOP、LAST、RSET、RPOP等命令用得较少。
与SMTP服务器的情况相似,除了ISP提供的POP3服务器外,国内的一些存放免费个人主页的服务器也提供POP3服务(例如网易nease.net)。用户在获得免费主页的同时也可以得到一个POP3信箱,例如我的信箱为
[email protected] ,在服务器上放一个下面要编写的Applet和调用它的htm文件,在线运行它,输入正确的用户名和密码后就可以读取E-mail了。
2.POP3tester.java中的主要程序
该Java Applet共用了三个文本条(TextField)部件tf1、tf2和tf3,它们分别用来供用户输入用户名、密码和要读取的E-mail的编号(为0时,只取信箱状态不读信);还用了一个文本区(TextArea)部件ta2,用来显示POP3服务器的应答信息、信件内容和出错信息等;当然还用了一个按钮(Button)部件bu1,用户输入正确的信息后,用鼠标点击一下它,就可以读取指定的信件了。
事件捕获处理程序与SMTPtester中的一样,读取E-mail程序bu1run见程序4:
public void bu1run()
{
try
{
Socket socket1= new Socket(getCodeBase().getHost(), 110);
/*连接POP3服务器*/
DataOutputStream dataout2= new DataOutputStream(socket1.getOutputStream());
DataInputStream dataIn3= new DataInputStream(socket1.getInputStream());
GetReply(dataIn3);
dataout2.writeBytes("USER" + tf1.getText() + "\r\n");
GetReply(dataIn3);
dataout2.writeBytes("PASS" + tf2.getText() + "\r\n");
GetReply(dataIn3);
dataout2.writeBytes("STAT\r\n");
/*信箱状态*/
GetReply(dataIn3);
dataout2.writeBytes("LIST\r\n");
/*信件长度列表*/
GetReply2(dataIn3);
ta2.appendText("\n");
if (tf3.getText().equals("0") == false)
{
dataout2.writeBytes("RETR" + tf3.getText() + "\r\n");
/*读取指定信件*/
GetReply2(dataIn3);
ta2.appendText("\n");
}
dataout2.writeBytes("QUIT\r\n");
GetReply(dataIn3);
socket1.close();
bu1.enable();
return;
}
catch (java.io.IOException IOException0)
{
ta2.appendText("Error!\n");
bu1.enable();
return;
}
}
(程序4)
接收服务器应答程序GetReply和GetReply2见程序5:
void GetReply2(DataInputStream dataIn1)
{
String string2;
string2= "";
try
{
for (string2=dataIn1.readLine();
(string2.equals(".")=false);
string2=dataIn1.readLine())
/*List和Retr命令的应答虽然有多行,但都用一句"."作为结束,可据此取应答信息*/
{
ta2.appendText(string2 + "\n");
}
}
catch (java.io.IOException IOException0)
{
ta2.appendText("Error!\n");
bu1.enable();
return;
}
}
(程序5)
读取单句应答的程序GetReply和SMTPtester中的相同,因为在与POP3服务器对话时,List和Retr的应答不只一句,因此又编了一个GetReply2程序来处理这个问题。
3.实例运行
在 http://www.netease.com/~caveman 上已经放了编译好的POP3tester.class和调用它的POP3.html,图2是该Applet运行时的画面,刚才在person.zj.cninfo.net上用SMTPtester发出的那封信已到了我网易的信箱里了。
四.程序的改进
以上两个Java Applet还很不完善,在加强错误捕获、对邮件附件的支持等方面需要改进的地方还很多。另外,根据上面提到的一些基本方法,只需稍加变化,还可以用Java来实现其他网络协议,如FTP、NEWS等。