Rising Sun

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  148 随笔 :: 0 文章 :: 22 评论 :: 0 Trackbacks

#

connection.setAutoCommit(false); 当设为True 时,它就当事务来处理,就有一个时间段.这个搞了出一些未明的问题.还是手动设为False ,hibarnate 以作了相应的处理.
posted @ 2006-07-19 14:29 brock 阅读(161) | 评论 (0)编辑 收藏

String cl=new String(req.getParameter("checkboxvalue").getBytes("iso8859-1"),"gb2312");

excel

 Connection connection = DbConnectionManager.getConnection();
        try{
          
         
            PreparedStatement prst = connection.prepareStatement(sql);
            ResultSet rs = prst.executeQuery();
            if(rs.next()){
             //if(rs == null){rs.close();
                Blob blob = rs.getBlob("bb");
             
                byte[] ab = blob.getBytes(1, (int)blob.length());
                //URLEncoder.encode(rname, "utf-8");
                //new String("文件名.xls".getBytes("GBK"),"ISO8859_1")
                //response.setHeader("Charset","gb2312");
                //application/msexcel-comma
                String fs = new String(rname.getBytes("GBK"),"ISO8859_1");
                
                response.reset();
                response.setLocale(java.util.Locale.CHINA);
                response.setContentType("application/vnd.ms-excel");
                request.setCharacterEncoding("GBK");
              
              
                String s = "attachment; filename="+fs;
                response.setHeader("Content-Disposition", s);
                ServletOutputStream op = response.getOutputStream();
                op.write(ab);
                op.flush();
                op.close();
            }
         }catch(SQLException e){
        log.info(e.toString()+"sql:"+sql);
     }
         catch(NullPointerException ex){
          System.out.print("数据为空");
         }
        
         finally{
         try{
         connection.close();
       }catch(Exception e){
        System.out.print("ddd");
       }
posted @ 2006-07-18 16:26 brock 阅读(194) | 评论 (0)编辑 收藏

1如何将字串 String 转换成整数 int?

A. 有两个方法:

1). int i = Integer.parseInt([String]); 或
i = Integer.parseInt([String],[int radix]);

2). int i = Integer.valueOf(my_str).intValue();

注: 字串转成 Double, Float, Long 的方法大同小异.


2 如何将整数 int 转换成字串 String ?


A. 有叁种方法:

1.) String s = String.valueOf(i);

2.) String s = Integer.toString(i);

3.) String s = "" + i;

注: Double, Float, Long 转成字串的方法大同小异.



JAVA数据类型转换 ynniebo [收藏]
关键字 类型转换
出处

这是一个例子,说的是JAVA中数据数型的转换.供大家学习引

package cn.com.lwkj.erts.register;
import java.sql.Date;
public class TypeChange {
public TypeChange() {
}
//change the string type to the int type
public static int stringToInt(String intstr)
{
Integer integer;
integer = Integer.valueOf(intstr);
return integer.intValue();
}
//change int type to the string type
public static String intToString(int value)
{
Integer integer = new Integer(value);
return integer.toString();
}
//change the string type to the float type
public static float stringToFloat(String floatstr)
{
Float floatee;
floatee = Float.valueOf(floatstr);
return floatee.floatValue();
}
//change the float type to the string type
public static String floatToString(float value)
{
Float floatee = new Float(value);
return floatee.toString();
}
//change the string type to the sqlDate type
public static java.sql.Date stringToDate(String dateStr)
{
return java.sql.Date.valueOf(dateStr);
}
//change the sqlDate type to the string type
public static String dateToString(java.sql.Date datee)
{
return datee.toString();
}

public static void main(String[] args)
{
java.sql.Date day ;
day = TypeChange.stringToDate("2003-11-3");
String strday = TypeChange.dateToString(day);
System.out.println(strday);
}


}

posted @ 2006-07-18 11:07 brock 阅读(256) | 评论 (1)编辑 收藏

作者:郎云鹏(dev2dev ID: hippiewolf)

摘要:虽然session机制在web应用程序中被采用已经很长时间了,但是仍然有很多人不清楚session机制的本质,以至不能正确的应用这一技术。本文将详细讨论session的工作机制并且对在Java web application中应用session机制时常见的问题作出解答。

目录:
一、术语session
二、HTTP协议与状态保持
三、理解cookie机制
四、理解session机制
五、理解javax.servlet.http.HttpSession
六、HttpSession常见问题
七、跨应用程序的session共享
八、总结
参考文档

一、术语session
在我的经验里,session这个词被滥用的程度大概仅次于transaction,更加有趣的是transaction与session在某些语境下的含义是相同的。

session,中文经常翻译为会话,其本来的含义是指有始有终的一系列动作/消息,比如打电话时从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个session。有时候我们可以看到这样的话“在一个浏览器会话期间,...”,这里的会话一词用的就是其本义,是指从一个浏览器窗口打开到关闭这个期间①。最混乱的是“用户(客户端)在一次会话期间”这样一句话,它可能指用户的一系列动作(一般情况下是同某个具体目的相关的一系列动作,比如从登录到选购商品到结账登出这样一个网上购物的过程,有时候也被称为一个transaction),然而有时候也可能仅仅是指一次连接,也有可能是指含义①,其中的差别只能靠上下文来推断②。

然而当session一词与网络协议相关联时,它又往往隐含了“面向连接”和/或“保持状态”这样两个含义,“面向连接”指的是在通信双方在通信之前要先建立一个通信的渠道,比如打电话,直到对方接了电话通信才能开始,与此相对的是写信,在你把信发出去的时候你并不能确认对方的地址是否正确,通信渠道不一定能建立,但对发信人来说,通信已经开始了。“保持状态”则是指通信的一方能够把一系列的消息关联起来,使得消息之间可以互相依赖,比如一个服务员能够认出再次光临的老顾客并且记得上次这个顾客还欠店里一块钱。这一类的例子有“一个TCP session”或者“一个POP3 session”③。

而到了web服务器蓬勃发展的时代,session在web开发语境下的语义又有了新的扩展,它的含义是指一类用来在客户端与服务器之间保持状态的解决方案④。有时候session也用来指这种解决方案的存储结构,如“把xxx保存在session里”⑤。由于各种用于web开发的语言在一定程度上都提供了对这种解决方案的支持,所以在某种特定语言的语境下,session也被用来指代该语言的解决方案,比如经常把Java里提供的javax.servlet.http.HttpSession简称为session⑥。

鉴于这种混乱已不可改变,本文中session一词的运用也会根据上下文有不同的含义,请大家注意分辨。
在本文中,使用中文“浏览器会话期间”来表达含义①,使用“session机制”来表达含义④,使用“session”表达含义⑤,使用具体的“HttpSession”来表达含义⑥

二、HTTP协议与状态保持
HTTP协议本身是无状态的,这与HTTP协议本来的目的是相符的,客户端只需要简单的向服务器请求下载某些文件,无论是客户端还是服务器都没有必要纪录彼此过去的行为,每一次请求之间都是独立的,好比一个顾客和一个自动售货机或者一个普通的(非会员制)大卖场之间的关系一样。

然而聪明(或者贪心?)的人们很快发现如果能够提供一些按需生成的动态信息会使web变得更加有用,就像给有线电视加上点播功能一样。这种需求一方面迫使HTML逐步添加了表单、脚本、DOM等客户端行为,另一方面在服务器端则出现了CGI规范以响应客户端的动态请求,作为传输载体的HTTP协议也添加了文件上载、cookie这些特性。其中cookie的作用就是为了解决HTTP协议无状态的缺陷所作出的努力。至于后来出现的session机制则是又一种在客户端与服务器之间保持状态的解决方案。

让我们用几个例子来描述一下cookie和session机制之间的区别与联系。笔者曾经常去的一家咖啡店有喝5杯咖啡免费赠一杯咖啡的优惠,然而一次性消费5杯咖啡的机会微乎其微,这时就需要某种方式来纪录某位顾客的消费数量。想象一下其实也无外乎下面的几种方案:
1、该店的店员很厉害,能记住每位顾客的消费数量,只要顾客一走进咖啡店,店员就知道该怎么对待了。这种做法就是协议本身支持状态。
2、发给顾客一张卡片,上面记录着消费的数量,一般还有个有效期限。每次消费时,如果顾客出示这张卡片,则此次消费就会与以前或以后的消费相联系起来。这种做法就是在客户端保持状态。
3、发给顾客一张会员卡,除了卡号之外什么信息也不纪录,每次消费时,如果顾客出示该卡片,则店员在店里的纪录本上找到这个卡号对应的纪录添加一些消费信息。这种做法就是在服务器端保持状态。

由于HTTP协议是无状态的,而出于种种考虑也不希望使之成为有状态的,因此,后面两种方案就成为现实的选择。具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案。同时我们也看到,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的,但实际上它还有其他选择。

三、理解cookie机制
cookie机制的基本原理就如上面的例子一样简单,但是还有几个问题需要解决:“会员卡”如何分发;“会员卡”的内容;以及客户如何使用“会员卡”。

正统的cookie分发是通过扩展HTTP协议来实现的,服务器通过在HTTP的响应头中加上一行特殊的指示以提示浏览器按照指示生成相应的cookie。然而纯粹的客户端脚本如JavaScript或者VBScript也可以生成cookie。

而cookie的使用是由浏览器按照一定的原则在后台自动发送给服务器的。浏览器检查所有存储的cookie,如果某个cookie所声明的作用范围大于等于将要请求的资源所在的位置,则把该cookie附在请求资源的HTTP请求头上发送给服务器。意思是麦当劳的会员卡只能在麦当劳的店里出示,如果某家分店还发行了自己的会员卡,那么进这家店的时候除了要出示麦当劳的会员卡,还要出示这家店的会员卡。

cookie的内容主要包括:名字,值,过期时间,路径和域。
其中域可以指定某一个域比如.google.com,相当于总店招牌,比如宝洁公司,也可以指定一个域下的具体某台机器比如www.google.com或者froogle.google.com,可以用飘柔来做比。
路径就是跟在域名后面的URL路径,比如/或者/foo等等,可以用某飘柔专柜做比。
路径与域合在一起就构成了cookie的作用范围。
如果不设置过期时间,则表示这个cookie的生命期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。这种生命期为浏览器会话期的cookie被称为会话cookie。会话cookie一般不存储在硬盘上而是保存在内存里,当然这种行为并不是规范规定的。如果设置了过期时间,浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie仍然有效直到超过设定的过期时间。

存储在硬盘上的cookie可以在不同的浏览器进程间共享,比如两个IE窗口。而对于保存在内存里的cookie,不同的浏览器有不同的处理方式。对于IE,在一个打开的窗口上按Ctrl-N(或者从文件菜单)打开的窗口可以与原窗口共享,而使用其他方式新开的IE进程则不能共享已经打开的窗口的内存cookie;对于Mozilla Firefox0.8,所有的进程和标签页都可以共享同样的cookie。一般来说是用javascript的window.open打开的窗口会与原窗口共享内存cookie。浏览器对于会话cookie的这种只认cookie不认人的处理方式经常给采用session机制的web应用程序开发者造成很大的困扰。

下面就是一个goolge设置cookie的响应头的例子
HTTP/1.1 302 Found
Location: http://www.google.com/intl/zh-CN/
Set-Cookie: PREF=ID=0565f77e132de138:NW=1:TM=1098082649:LM=1098082649:S=KaeaCFPo49RiA_d8; expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.google.com
Content-Type: text/html


这是使用HTTPLook这个HTTP Sniffer软件来俘获的HTTP通讯纪录的一部分


浏览器在再次访问goolge的资源时自动向外发送cookie


使用Firefox可以很容易的观察现有的cookie的值
使用HTTPLook配合Firefox可以很容易的理解cookie的工作原理。


IE也可以设置在接受cookie前询问


这是一个询问接受cookie的对话框。

四、理解session机制
session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。

当程序需要为某个客户端的请求创建一个session的时候,服务器首先检查这个客户端的请求里是否已包含了一个session标识 - 称为session id,如果已包含一个session id则说明以前已经为此客户端创建过session,服务器就按照session id把这个session检索出来使用(如果检索不到,可能会新建一个),如果客户端请求不包含session id,则为此客户端创建一个session并且生成一个与此session相关联的session id,session id的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个session id将被在本次响应中返回给客户端保存。

保存这个session id的方式可以采用cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发挥给服务器。一般这个cookie的名字都是类似于SEEESIONID,而。比如weblogic对于web应用程序生成的cookie,JSESSIONID=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764,它的名字就是JSESSIONID。

由于cookie可以被人为的禁止,必须有其他机制以便在cookie被禁止时仍然能够把session id传递回服务器。经常被使用的一种技术叫做URL重写,就是把session id直接附加在URL路径的后面,附加方式也有两种,一种是作为URL路径的附加信息,表现形式为http://...../xxx;jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
另一种是作为查询字符串附加在URL后面,表现形式为http://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
这两种方式对于用户来说是没有区别的,只是服务器在解析的时候处理的方式不同,采用第一种方式也有利于把session id的信息和正常程序参数区分开来。
为了在整个交互过程中始终保持状态,就必须在每个客户端可能请求的路径后面都包含这个session id。

另一种技术叫做表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。比如下面的表单
<form name="testform" action="/xxx">
<input type="text">
</form>
在被传递给客户端之前将被改写成
<form name="testform" action="/xxx">
<input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764">
<input type="text">
</form>
这种技术现在已较少应用,笔者接触过的很古老的iPlanet6(SunONE应用服务器的前身)就使用了这种技术。
实际上这种技术可以简单的用对action应用URL重写来代替。

在谈论session机制的时候,常常听到这样一种误解“只要关闭浏览器,session就消失了”。其实可以想象一下会员卡的例子,除非顾客主动对店家提出销卡,否则店家绝对不会轻易删除顾客的资料。对session来说也是一样的,除非程序通知服务器删除一个session,否则服务器会一直保留,程序一般都是在用户做log off的时候发个指令去删除session。然而浏览器从来不会主动在关闭之前通知服务器它将要关闭,因此服务器根本不会有机会知道浏览器已经关闭,之所以会有这种错觉,是大部分session机制都使用会话cookie来保存session id,而关闭浏览器后这个session id就消失了,再次连接服务器时也就无法找到原来的session。如果服务器设置的cookie被保存到硬盘上,或者使用某种手段改写浏览器发出的HTTP请求头,把原来的session id发送给服务器,则再次打开浏览器仍然能够找到原来的session。

恰恰是由于关闭浏览器不会导致session被删除,迫使服务器为seesion设置了一个失效时间,当距离客户端上一次使用session的时间超过这个失效时间时,服务器就可以认为客户端已经停止了活动,才会把session删除以节省存储空间。

五、理解javax.servlet.http.HttpSession
HttpSession是Java平台对session机制的实现规范,因为它仅仅是个接口,具体到每个web应用服务器的提供商,除了对规范支持之外,仍然会有一些规范里没有规定的细微差异。这里我们以BEA的Weblogic Server8.1作为例子来演示。

首先,Weblogic Server提供了一系列的参数来控制它的HttpSession的实现,包括使用cookie的开关选项,使用URL重写的开关选项,session持久化的设置,session失效时间的设置,以及针对cookie的各种设置,比如设置cookie的名字、路径、域,cookie的生存时间等。

一般情况下,session都是存储在内存里,当服务器进程被停止或者重启的时候,内存里的session也会被清空,如果设置了session的持久化特性,服务器就会把session保存到硬盘上,当服务器进程重新启动或这些信息将能够被再次使用,Weblogic Server支持的持久性方式包括文件、数据库、客户端cookie保存和复制。

复制严格说来不算持久化保存,因为session实际上还是保存在内存里,不过同样的信息被复制到各个cluster内的服务器进程中,这样即使某个服务器进程停止工作也仍然可以从其他进程中取得session。

cookie生存时间的设置则会影响浏览器生成的cookie是否是一个会话cookie。默认是使用会话cookie。有兴趣的可以用它来试验我们在第四节里提到的那个误解。

cookie的路径对于web应用程序来说是一个非常重要的选项,Weblogic Server对这个选项的默认处理方式使得它与其他服务器有明显的区别。后面我们会专题讨论。

关于session的设置参考[5] http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869

六、HttpSession常见问题
(在本小节中session的含义为⑤和⑥的混合)


1、session在何时被创建
一个常见的误解是以为session在有客户端访问时就被创建,然而事实是直到某server端程序调用HttpServletRequest.getSession(true)这样的语句时才被创建,注意如果JSP没有显示的使用 <%@page session="false"%> 关闭session,则JSP文件在编译成Servlet时将会自动加上这样一条语句HttpSession session = HttpServletRequest.getSession(true);这也是JSP中隐含的session对象的来历。

由于session会消耗内存资源,因此,如果不打算使用session,应该在所有的JSP中关闭它。

2、session何时被删除
综合前面的讨论,session在下列情况下被删除a.程序调用HttpSession.invalidate();或b.距离上一次收到客户端发送的session id时间间隔超过了session的超时设置;或c.服务器进程被停止(非持久session)

3、如何做到在浏览器关闭时删除session
严格的讲,做不到这一点。可以做一点努力的办法是在所有的客户端页面里使用javascript代码window.oncolose来监视浏览器的关闭动作,然后向服务器发送一个请求来删除session。但是对于浏览器崩溃或者强行杀死进程这些非常规手段仍然无能为力。

4、有个HttpSessionListener是怎么回事
你可以创建这样的listener去监控session的创建和销毁事件,使得在发生这样的事件时你可以做一些相应的工作。注意是session的创建和销毁动作触发listener,而不是相反。类似的与HttpSession有关的listener还有HttpSessionBindingListener,HttpSessionActivationListener和HttpSessionAttributeListener。

5、存放在session中的对象必须是可序列化的吗
不是必需的。要求对象可序列化只是为了session能够在集群中被复制或者能够持久保存或者在必要时server能够暂时把session交换出内存。在Weblogic Server的session中放置一个不可序列化的对象在控制台上会收到一个警告。我所用过的某个iPlanet版本如果session中有不可序列化的对象,在session销毁时会有一个Exception,很奇怪。

6、如何才能正确的应付客户端禁止cookie的可能性
对所有的URL使用URL重写,包括超链接,form的action,和重定向的URL,具体做法参见[6]
http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770

7、开两个浏览器窗口访问应用程序会使用同一个session还是不同的session
参见第三小节对cookie的讨论,对session来说是只认id不认人,因此不同的浏览器,不同的窗口打开方式以及不同的cookie存储方式都会对这个问题的答案有影响。

8、如何防止用户打开两个浏览器窗口操作导致的session混乱
这个问题与防止表单多次提交是类似的,可以通过设置客户端的令牌来解决。就是在服务器每次生成一个不同的id返回给客户端,同时保存在session里,客户端提交表单时必须把这个id也返回服务器,程序首先比较返回的id与保存在session里的值是否一致,如果不一致则说明本次操作已经被提交过了。可以参看《J2EE核心模式》关于表示层模式的部分。需要注意的是对于使用javascript window.open打开的窗口,一般不设置这个id,或者使用单独的id,以防主窗口无法操作,建议不要再window.open打开的窗口里做修改操作,这样就可以不用设置。

9、为什么在Weblogic Server中改变session的值后要重新调用一次session.setValue
做这个动作主要是为了在集群环境中提示Weblogic Server session中的值发生了改变,需要向其他服务器进程复制新的session值。

10、为什么session不见了
排除session正常失效的因素之外,服务器本身的可能性应该是微乎其微的,虽然笔者在iPlanet6SP1加若干补丁的Solaris版本上倒也遇到过;浏览器插件的可能性次之,笔者也遇到过3721插件造成的问题;理论上防火墙或者代理服务器在cookie处理上也有可能会出现问题。
出现这一问题的大部分原因都是程序的错误,最常见的就是在一个应用程序中去访问另外一个应用程序。我们在下一节讨论这个问题。

七、跨应用程序的session共享

常常有这样的情况,一个大项目被分割成若干小项目开发,为了能够互不干扰,要求每个小项目作为一个单独的web应用程序开发,可是到了最后突然发现某几个小项目之间需要共享一些信息,或者想使用session来实现SSO(single sign on),在session中保存login的用户信息,最自然的要求是应用程序间能够访问彼此的session。

然而按照Servlet规范,session的作用范围应该仅仅限于当前应用程序下,不同的应用程序之间是不能够互相访问对方的session的。各个应用服务器从实际效果上都遵守了这一规范,但是实现的细节却可能各有不同,因此解决跨应用程序session共享的方法也各不相同。

首先来看一下Tomcat是如何实现web应用程序之间session的隔离的,从Tomcat设置的cookie路径来看,它对不同的应用程序设置的cookie路径是不同的,这样不同的应用程序所用的session id是不同的,因此即使在同一个浏览器窗口里访问不同的应用程序,发送给服务器的session id也可以是不同的。

根据这个特性,我们可以推测Tomcat中session的内存结构大致如下。

笔者以前用过的iPlanet也采用的是同样的方式,估计SunONE与iPlanet之间不会有太大的差别。对于这种方式的服务器,解决的思路很简单,实际实行起来也不难。要么让所有的应用程序共享一个session id,要么让应用程序能够获得其他应用程序的session id。

iPlanet中有一种很简单的方法来实现共享一个session id,那就是把各个应用程序的cookie路径都设为/(实际上应该是/NASApp,对于应用程序来讲它的作用相当于根)。
<session-info>
<path>/NASApp</path>
</session-info>

需要注意的是,操作共享的session应该遵循一些编程约定,比如在session attribute名字的前面加上应用程序的前缀,使得setAttribute("name", "neo")变成setAttribute("app1.name", "neo"),以防止命名空间冲突,导致互相覆盖。


在Tomcat中则没有这么方便的选择。在Tomcat版本3上,我们还可以有一些手段来共享session。对于版本4以上的Tomcat,目前笔者尚未发现简单的办法。只能借助于第三方的力量,比如使用文件、数据库、JMS或者客户端cookie,URL参数或者隐藏字段等手段。

我们再看一下Weblogic Server是如何处理session的。

从截屏画面上可以看到Weblogic Server对所有的应用程序设置的cookie的路径都是/,这是不是意味着在Weblogic Server中默认的就可以共享session了呢?然而一个小实验即可证明即使不同的应用程序使用的是同一个session,各个应用程序仍然只能访问自己所设置的那些属性。这说明Weblogic Server中的session的内存结构可能如下

对于这样一种结构,在session机制本身上来解决session共享的问题应该是不可能的了。除了借助于第三方的力量,比如使用文件、数据库、JMS或者客户端cookie,URL参数或者隐藏字段等手段,还有一种较为方便的做法,就是把一个应用程序的session放到ServletContext中,这样另外一个应用程序就可以从ServletContext中取得前一个应用程序的引用。示例代码如下,

应用程序A
context.setAttribute("appA", session);

应用程序B
contextA = context.getContext("/appA");
HttpSession sessionA = (HttpSession)contextA.getAttribute("appA");

值得注意的是这种用法不可移植,因为根据ServletContext的JavaDoc,应用服务器可以处于安全的原因对于context.getContext("/appA");返回空值,以上做法在Weblogic Server 8.1中通过。

那么Weblogic Server为什么要把所有的应用程序的cookie路径都设为/呢?原来是为了SSO,凡是共享这个session的应用程序都可以共享认证的信息。一个简单的实验就可以证明这一点,修改首先登录的那个应用程序的描述符weblogic.xml,把cookie路径修改为/appA访问另外一个应用程序会重新要求登录,即使是反过来,先访问cookie路径为/的应用程序,再访问修改过路径的这个,虽然不再提示登录,但是登录的用户信息也会丢失。注意做这个实验时认证方式应该使用FORM,因为浏览器和web服务器对basic认证方式有其他的处理方式,第二次请求的认证不是通过session来实现的。具体请参看[7] secion 14.8 Authorization,你可以修改所附的示例程序来做这些试验。

八、总结
session机制本身并不复杂,然而其实现和配置上的灵活性却使得具体情况复杂多变。这也要求我们不能把仅仅某一次的经验或者某一个浏览器,服务器的经验当作普遍适用的经验,而是始终需要具体情况具体分析。

posted @ 2006-07-17 15:47 brock 阅读(125) | 评论 (0)编辑 收藏

<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>文件上载</title>
<script>
//可以上传的文件类形

function filetype(){
   var sTheFile = document.forms[0].pic.value;
 var  filename  = document.forms[0].filename;
  var sFileName = sTheFile.substring(sTheFile.lastIndexOf("\\") + 1);
 var Name=sFileName.substring(sFileName.indexOf(".")+1).toLowerCase();
 var ext = new Array('jpg','jpeg','png','gif','bmp','ico');
 for (var i=0 ;i<ext.length; i++){
  if( Name == ext[i]){
  filename.value = sFileName;
  //alert(filename.value)
  return true;
  }
 }
 alert("上传文件格式不正确!");
 document.getElementById("div1").innerHTML='<input type="file" name="pic" id="pic" value="" onChange="filetype()">'
 return false;
 
}
//验证表单
function checkValue(){
 var sJbr = document.forms[0].jbr.value;
 var sSelect = document.forms[0].select.options(document.forms[0].select.selectedIndex).value;
 var sContent = document.forms[0].content.value;
 var sTheFile = document.forms[0].pic.value;
 if (sJbr =="" ||sJbr == null){
 alert("请填写举报人!");
 return  false;
 }
 if (sSelect =="" ||sSelect == null){
 alert("请选择分局!");
 return  false;
 }
 if (sContent =="" ||sContent == null){
 alert("请填写缺陷!");
 return  false;
 }
 if (sTheFile =="" ||sTheFile == null){
 alert("缺陷截图不能为空!");
 return  false;
 }
 
 
 
}

</script>

 

</head>
<body>
<form action="/report/servlet/BugFeed" onSubmit="return checkValue()" enctype="MULTIPART/FORM-DATA" method=post>
  <p>举报人:
    <input type="text" name="jbr" onBlur="checkValue()">
</p>
  <p>分局:
    <select name="select">
        <option value="">请选择分局</option>
        <option value="城东局">城东局</option>
        <option value="城南局">城南局</option>
        <option value="城西局">城西局</option>
        <option value="城北局">城北局</option>
  <option value="其它">其它</option>
      </select>
  </p>
  <p>描述缺陷: 
    <textarea name="content"></textarea>
  </p>
  <p>选择要上载的图片:
    <div id="div1"><input type="file" name="pic" id="pic" value="" onChange="filetype()"></div>
  </p>
  <input type="hidden" value="" name="filename" id="filename">
  <p>
    <input type=submit value="Upload">
   
          </p>
</form>
</body>
</html>

posted @ 2006-07-14 15:09 brock 阅读(587) | 评论 (0)编辑 收藏

  1. <!--$Header: ProcessFileUpload.jsp 1.0.0 2004/10/22 15:10:19 pkm ship  $-->
  2. <%@ page contentType="text/html;charset=GB2312"%>
  3. <%@ page import="org.apache.commons.fileupload.DiskFileUpload"%>
  4. <%@ page import="org.apache.commons.fileupload.FileItem"%>
  5. <%@ page import="java.util.*"%>
  6. <%@ page import="java.io.File"%>
  7. <%@ page import="java.sql.*" %>
  8. <html>
  9. <head>
  10. <style>
  11. .NButton
  12. {
  13.     cursor:hand;
  14.     width: 87px;
  15.     height: 20px;
  16.     font-family: 宋体;
  17.     font-size: 12px;
  18.     text-align:center ;
  19.     background-image: url(btn_bkg.gif);
  20.     border:0px;
  21. }
  22. </style>
  23. <%!
  24. // Connect to Oracle database and Insert into cux_upload_files
  25. public  void dbInsert(String p_c_file_name,String p_c_path,String p_s_file_name,String p_s_path) {
  26.     Connection conn = null;
  27.     String connStr;
  28.   try {
  29.     connStr="jdbc:oracle:thin:@local:1521:orcl";
  30.     DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
  31.     conn = DriverManager.getConnection(connStr,"apps""apps");
  32.     // Insert into table
  33.     conn.setAutoCommit(false); 
  34.     PreparedStatement insertCUF = conn.prepareStatement("INSERT INTO cux.cux_upload_files(file_id,client_file_name,client_path,server_file_name,server_path,created_by,creation_date) "
  35.     + " VALUES (cux.cux_upload_files_s.nextval,?,?,?,?,?,SYSDATE) ");
  36.   
  37.     //insertCUF.setInt(1,2);
  38.     insertCUF.setString(1,p_c_file_name);
  39.     insertCUF.setString(2,p_c_path);
  40.     insertCUF.setString(3,p_s_file_name);
  41.     insertCUF.setString(4,p_s_path);
  42.     insertCUF.setString(5,"XXX");
  43.     insertCUF.executeUpdate();
  44.   
  45.     conn.commit();
  46.   
  47.     conn.setAutoCommit(true);
  48.   
  49.     conn.close();
  50.   }catch(SQLException ex) { // Handle SQL errors
  51.       System.out.println("Error in Connecting to the Database "+'\n'+ex.toString());
  52.   }
  53. }
  54. //
  55. String  getCurDate(){
  56.     GregorianCalendar gcDate = new GregorianCalendar(); 
  57.     int year  = gcDate.get(GregorianCalendar.YEAR);
  58.     int month = gcDate.get(GregorianCalendar.MONTH);
  59.     int day   = gcDate.get(GregorianCalendar.DAY_OF_MONTH);
  60.     return "" + year + "-" + month + "-" + day;
  61. }
  62. %>
  63. <meta http-equiv="Content-Type" content="text/html; charset=gb2312" >
  64. <title>Process File Upload</title>
  65. </head>
  66. <body>
  67. <table width="800" border bordercolor="#0000FF">
  68. <tr bgcolor="#66CCFF">
  69. <td colspan=1 rowspan=1 align=left valign=top>
  70.     <strong><font size=2 face="宋体" color=#000000>
  71.     <nobr>客户端文件</nobr>
  72.     </font>
  73.     </strong></td>
  74. <td colspan=1 rowspan=1 align=left valign=top>
  75.     <strong><font size=2 face="宋体" color=#000000>
  76.     <nobr>服务器文件</nobr>
  77.     </font>
  78.     </strong></td>
  79. <td colspan=1 rowspan=1 align=left valign=top>
  80.     <strong><font size=2 face="宋体" color=#000000>
  81.     <nobr>上传用户</nobr>
  82.     </font>
  83.     </strong></td>
  84. </tr>
  85. <%
  86.     //out.println("Content Type ="+request.getContentType());
  87.     
  88.     DiskFileUpload fu = new DiskFileUpload();
  89.     // If file size exceeds, a FileUploadException will be thrown
  90.     fu.setSizeMax(1000000);
  91.     // maximum size that will be stored in memory
  92.     fu.setSizeThreshold(4096);
  93.     // the location for saving data that is larger than getSizeThreshold()
  94.     //fu.setRepositoryPath("/tmp/");
  95.     
  96.     
  97.     List fileItems = fu.parseRequest(request);
  98.     Iterator itr = fileItems.iterator();
  99.     int i = 0;
  100.   
  101.     while(itr.hasNext()) {
  102.       FileItem fi = (FileItem)itr.next();
  103.       i++;
  104.       //Check if not form field so as to only handle the file inputs
  105.       //else condition handles the submit button input
  106.       if (!fi.isFormField()) {
  107.             String filename = fi.getName();
  108.             long filesize = fi.getSize();
  109.       String pUserName = "XIAOHUIPING";
  110.             if((filename==null||filename.equals("")) && filesize==0)
  111.             continue;
  112.             // 注意fi.getName()
  113.             // 会返回上载文件在客户端的完整路径名称,这似乎是一个BUG。
  114.             // 为解决这个问题,这里使用了fullFile.getName()。
  115.             filename=filename.replace('\\','/');
  116.             //new String(filename.getBytes("ISO-8859-1"),"UTF-8");
  117.             File fullFile = new File(filename);
  118.             // 指定fullFile.getName() = "Works.txt";
  119.             File savedFile= new File(application.getRealPath("/Download/"), fullFile.getName());
  120.             fi.write(savedFile);
  121.             // 上传文件成功后写入数据库表
  122.             dbInsert(fullFile.getName(),filename.replace('/','\\'),fullFile.getName(),savedFile.getAbsolutePath());
  123.       if ((i%2) == 0) {
  124.             // 文件上载成功提示,以表格形式打印
  125.       out.println("<tr bgcolor=\"#CCCCCC\"><td colspan=1 rowspan=1 align=left valign=top><font size=2 face=\"宋体\" color=#000000><nobr>" + fullFile.getName() + "</nobr></font></td><td colspan=1 rowspan=1 align=left valign=top><font size=2 face=\"宋体\" color=#000000><nobr>" + fullFile.getName() + "</nobr></font></td><td colspan=1 rowspan=1 align=left valign=top><font size=2 face=\"宋体\" color=#000000><nobr>" + pUserName + "</nobr></font></td></tr>");
  126.             //out.println("<br>" + "Local Filename = " + "\"" + filename.replace('/','\\') + "\"" + " Upload To \""  + savedFile.getAbsolutePath() + "\"" + " Successful!!");
  127.             }
  128.       else if ((i%2) == 1) {
  129.       out.println("<tr><td colspan=1 rowspan=1 bgcolor=#ffffff align=left valign=top><font size=2 face=\"宋体\" color=#000000><nobr>" + fullFile.getName() + "</nobr></font></td><td colspan=1 rowspan=1 bgcolor=#ffffff align=left valign=top><font size=2 face=\"宋体\" color=#000000><nobr>" + fullFile.getName() + "</nobr></font></td><td colspan=1 rowspan=1 bgcolor=#ffffff align=left valign=top><font size=2 face=\"宋体\" color=#000000><nobr>" + pUserName + "</nobr></font></td></tr>");
  130.       }
  131.       }
  132.     }
  133. %>
  134. </table>
  135. <table width="800" border bordercolor="#0000FF">
  136.   <tr>
  137.     <td height="20" align="center" nowrap="nowrap">
  138.       <DIV align="center">
  139.         <input class="NButton" type="button" value="Back" onClick="javascript:history.back()"/>
  140.         <input class="NButton" type="button" value="Close" onClick="javascript:window.close()"/>
  141.       </DIV>
  142.     </td>
  143.   </tr>
  144. </table>
  145. </body>
  146. </html>



  1. <!--$Header: index.jsp 1.0.0 2004/10/22 15:10:19 pkm ship  $-->
  2. <%@ page contentType = "text/html;charset=gb2312" %>
  3. <html>
  4. <head>
  5. <title>数据文件上传</title>
  6. <style>
  7. BODY
  8. {
  9.   FONT-FAMILY: 宋体;
  10.   FONT-SIZE: 10pt;
  11.     background-color: #F6F6F6;
  12.     margin-top: 10px;
  13.     margin-right: 50px;
  14.     margin-bottom: 50px;
  15.     margin-left: 10px;
  16.     margin-top: 0px
  17.     SCROLLBAR-FACE-COLOR: #D0E5FF;
  18.     SCROLLBAR-HIGHLIGHT-COLOR: #F5F9FF;
  19.     SCROLLBAR-SHADOW-COLOR: #828282;
  20.     SCROLLBAR-3DLIGHT-COLOR: #828282;
  21.     SCROLLBAR-ARROW-COLOR: #797979;
  22.     SCROLLBAR-TRACK-COLOR: #ECECEC;
  23.     SCROLLBAR-DARKSHADOW-COLOR: #ffffff
  24. }
  25. TABLE
  26. {
  27.   FONT-FAMILY: 宋体;
  28.   FONT-SIZE: 10pt
  29. }
  30. .HeaderTitle{
  31.     font-family: 黑体;
  32.     font-size: 30px;
  33.     font-weight: bolder;
  34.     color: #041986;
  35. }
  36. .TitleBar
  37. {
  38.   BACKGROUND-COLOR: #E5EAED;
  39.   Color:#565656;
  40.   FONT-FAMILY: 宋体;
  41.   font-weight:bold;
  42.   FONT-SIZE: 11pt;
  43. }
  44. .TextBox
  45. {
  46.     FONT-FAMILY: 宋体;
  47.     FONT-SIZE: 10pt;
  48.     height: 20px;
  49.     BORDER-BOTTOM: 1pt solid #C6C6C6;
  50.     BORDER-LEFT: 1pt solid #C6C6C6;
  51.     BORDER-RIGHT: 1pt solid #C6C6C6;
  52.     BORDER-TOP: 1pt solid #C6C6C6;
  53. }
  54. .InputGridTable{
  55.   FONT-FAMILY: 宋体;
  56.   FONT-SIZE: 10pt;
  57.     border-collapse: collapse;
  58.     border-color:#C6C6C6;
  59.     border-style: solid;
  60.     border-width: 1;
  61.     padding: 0;
  62. }
  63. .TitleColumn{
  64.     background-color: #E8ECF0;
  65.     nowrap="nowrap";
  66.   HEIGHT: 20px
  67. }
  68. .NButton
  69. {
  70.     cursor:hand;
  71.     width: 87px;
  72.     height: 20px;
  73.     font-family: 宋体;
  74.     font-size: 12px;
  75.     text-align:center ;
  76.     background-image: url(btn_bkg.gif);
  77.     border:0px;
  78. }
  79. </style>
  80. <script language="javascript">
  81. var count = 1;
  82. function delAttacheFile(){
  83.     var targetRow = event.srcElement.parentElement.parentElement;
  84.     InputTable.deleteRow(targetRow.rowIndex);
  85. }
  86. function addAttacheFile(){
  87.     count ++;
  88.     var row = InputTable.insertRow(InputTable.rows.length);
  89.     var firstCell = row.insertCell(0);
  90.     firstCell.className = "TitleColumn";
  91.     firstCell.width = "10%";
  92.     firstCell.height = "20";
  93.     firstCell.innerHTML = "<strong> 附件 " + count+ " :</strong>";
  94.     var lastCell = row.insertCell(1);
  95.     lastCell.height = "20";
  96.     lastCell.innerHTML = "<input type='file' name='attacheFile" + count + "' size='50' class='TextBox'> <input type='button' value='删除附件 " + count + "' onclick='delAttacheFile();' class='NButton'>";
  97. }
  98. </script>
  99. </head>
  100. <body>
  101.   <form name="filesForm" method="POST" action="ProcessFileUpload.jsp" enctype="multipart/form-data">
  102.     <table id="InputTable" border="1" cellpadding="0" cellspacing="0" class="InputGridTable" width="100%" height="40" >
  103.       <tr>
  104.         <td nowrap="nowrap" height="20" colspan="3" class="TitleColumn"><div align="center"><strong>附件列表:</strong></div></td>
  105.       </tr>
  106.       <tr>
  107.         <td nowrap="nowrap" width="10%" height="20" class="TitleColumn"><strong>附件 1 :</strong></td>
  108.         <td height="20" nowrap="nowrap"><input type="file" class="TextBox" name="attacheFile1" size="50"> <input name="adfile" type="button" class="NButton" onClick="addAttacheFile();" value="添加附件"></td>
  109.       </tr>
  110.     </table>
  111.     <table id="SubmitTable" border="1" cellpadding="0" cellspacing="0" class="InputGridTable" width="100%" height="20" >
  112.       <tr>
  113.         <td height="20" align="center" nowrap="nowrap">
  114.           <input type="submit" name="close" value="Close" onClick="self.close();" class="NButton"/>
  115.           <input type="reset" name="reset" value="Clear" class="NButton"/>
  116.           <input type="submit" name="Submit" value="Upload" class="NButton"/> 
  117.         </td>
  118.       </tr>
  119.     </table>
  120.   </form>
  121.     <p> </p>
  122. </body>
  123. </html>
posted @ 2006-07-13 16:32 brock 阅读(605) | 评论 (0)编辑 收藏

package MEDET.servlets;
import java.net.*;
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class SaveFileServlet extends HttpServlet
{
   FileWriter savefile;
   String filename = null;
   String value = null;
   /**
   * Handles a POST request
   */
   public void doPost(
         HttpServletRequest request,
         HttpServletResponse response)
      throws ServletException, IOException
   {
      PrintWriter out = response.getWriter();
      response.setContentType("text/html");
      //FileWriter savefile;
      try {

         // Verify the content type

         String ct = request.getContentType();
         if (!ct.startsWith("multipart/form-data"))
            throw new RuntimeException
            ("Invalid content type");

         // Get the boundary string

         int p = ct.indexOf("boundary=");
         if (p == -1)
            throw new RuntimeException
            ("No boundary string found");

         p += "boundary=".length();
         String boundary = "--" + ct.substring(p);
         String finalBoundary = boundary + "--";

         // We'll parse the multipart/form-data
         // with a finite state machine

         // Define names for the parser states

         final int INIT = 0;
         final int READING_HEADERS = 1;
         final int READING_DATA = 2;

         int state = INIT;

         // Read and extract the fields

         BufferedReader in = request.getReader();
         main: for (;;) {
            String line = in.readLine();
            if (line == null)
               break;

            switch (state) {

               // State 0: Ignoring everything before
               // the first boundary

               case INIT:
                  if (line.startsWith(finalBoundary))
                     break main;
                  if (line.startsWith(boundary)) {
                     state = READING_HEADERS;
                     filename = "";
                     value = "";
                  }
                  break;

               // State 1: Parsing the headers

               case READING_HEADERS:
                  if (line.length() == 0)
                     state = READING_DATA;
                  else {

                     // Get the field name

                     p = line.indexOf("filename=\"");
                     if (p == -1)
                        break;
                     p += "filename=\"".length();

                     // ... up to the closing quote.

                     int q = line.indexOf("\"", p);
                     if (q == -1)
                        break;
                     filename = line.substring(p, q);
                     filename="./config/medet/applications/DefaultWebApp/"+filename.substring(filename.lastIndexOf("\\")+1);
                     savefile=new FileWriter(filename);
                     value = "";
                  }
                  break;

               // State 2: Reading the data

               case READING_DATA:
                  if (line.startsWith(finalBoundary)) {
                     savefile.write(value);
                     savefile.close();
                     break main;
                  }
                  if (line.startsWith(boundary)) {
                     state = READING_HEADERS;
                  }
                  else {
                     if (value.length() > 0)
                        value += "\n";
                     value += line;
                  }
                  break;
            }

         }
         // Report the incident number back to the client
         String[] text = {
            "<HTML>",
            "<HEAD>",
            "<meta http-equiv='Content-Type' content='text/html; charset=gb2312'>",
            "<TITLE>文件上传成功</TITLE>",
            "</HEAD>",
            "<BODY>",
            "<CENTER>",
            "<H3>文件上传成功!</H3>",
            "</CENTER>"
         };
         for (int i = 0; i < text.length; i++)
            out.println(text[i]);
            out.println(filename);
            out.println("</BODY>");
            out.println("</HTML>");
      }

      catch (Exception e) {
         // Write the exception message
         out.println("<H3>Error:</H3>");
         out.println("<PRE>");
         out.println(e.getMessage());
         out.println("</PRE>");
      }
      finally {
         out.flush();
      }
   }
}
posted @ 2006-07-13 15:01 brock 阅读(910) | 评论 (0)编辑 收藏

Class文件如下:

import java.io.*;
import java.sql.*;
import java.util.Date ;
import oracle.sql.*;
import javax.servlet.http.*;
import org.apache.struts.action.*;
import org.apache.struts.upload.*;

public class UploadAction extends Action
{
  public ActionForward execute(ActionMapping mapping,
                               ActionForm form,
                               HttpServletRequest request,
                               HttpServletResponse response)
      throws Exception {
    if (form instanceof UploadForm) {
      Date date = new Date();
      System.out.println("-------------File Upload Begins-------------------") ;
      UploadForm theForm = (UploadForm) form;
      file://通/过struts的FormFile类来获得上传的文件,前台jsp页面对应的代码
      file://</html:file property="theFile" />
      FormFile file = theForm.getTheFile();
     
      Connection conn = null;
      PreparedStatement ps = null ;

      String union_Id = "" ;
      String union_Version = "" ;
      union_Id = theForm.getUnion_Id() ;
      union_Version = theForm.getUnion_Version() ;
      file://actionpart/是数据库表中的字段名,由于表中有多个blob字段,所以用变量来表示其名称
      String actionpart = theForm.getActionpart() ;
      System.out.println("actionpart is:"+actionpart) ;
      file://取/得数据库连接,dbPool的源代码附在后面
      dbPool dbp = new dbPool();
      conn = dbp.getConnection() ;

      ResultSet BlobDetails = null;
      Statement stmt = null;

      try {
        InputStream stream = null;
        FileInputStream fstream = null;
        stream = file.getInputStream();
        System.out.println("------------uploadFileSize is : "+stream.available() +"------------") ;

        conn.setAutoCommit(false);
        stmt = conn.createStatement();
        file://先/用empty_blob()来初始化该字段
        sql = " update regunion set " + actionpart + "  = empty_blob() where  union_id= " + union_Id +" and  union_Version = "+ union_Version;
        stmt.executeUpdate(sql) ;
        conn.commit() ;
        stmt.close() ;
        stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
        sql = "select " +actionpart + " from regunion where union_id= " + union_Id +" and  union_Version = "+ union_Version + " for  update ";
        BlobDetails = stmt.executeQuery(sql);

        if (BlobDetails.next()) {
          BLOB l_mapBlob = (BLOB)BlobDetails.getBlob(1);
          OutputStream l_blobOutputStream = ((BLOB) l_mapBlob).getBinaryOutputStream();

          byte[] l_buffer = new byte[10* 1024];

          int l_nread = 0;
          while ((l_nread=stream.read(l_buffer)) != -1) // Read from file
            {
            l_blobOutputStream.write(l_buffer,0,l_nread); // Write to Blob
            }

          stream.close();
          l_blobOutputStream.close ();
        }
        BlobDetails.close();
        conn.commit() ;
      }
      catch (FileNotFoundException fnfe) {
        fnfe.printStackTrace() ;
        return mapping.findForward("error");
      }
      catch (IOException ioe) {
        ioe.printStackTrace() ;
        return mapping.findForward("error");;
      }
      catch(SQLException ex){
        ex.printStackTrace() ;
        return mapping.findForward("error");;
      }finally{
        if(conn != null){
          try{
            stmt.close();
            conn.close() ;
          }catch(Exception sqle){
            sqle.printStackTrace() ;
          }
        }
      }


      request.setAttribute("union_Id",union_Id) ;
      request.setAttribute("union_Version",union_Version) ;
      System.out.println("-------------File Upload Ends-------------------") ;
      return mapping.findForward("success");
    }else{
      return null;
    }
  }
}

附:dbPool.java程序

package com.prient.nbsc.unifylaw;
import java.sql.*;
import com.prient.nbsc.common.DBPOOL;
public class dbPool {
  public Connection getConnection(){
    try {
      Connection conn = null;
      Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
      String bridge = "jdbc:oracle:thin:@10.6.89.2:1521:sjk";
      conn = DriverManager.getConnection(bridge,"user","user") ;
      return  conn;
    }
    catch (Exception e) {
      System.out.println(e);
      return null;
       }
  }
}

posted @ 2006-07-13 14:39 brock 阅读(353) | 评论 (0)编辑 收藏

    使用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);
支持字体、数字、日期的格式化;
支持单元格的阴影操作,以及颜色操作;
修改已经存在的数据表;
现在还不支持以下功能,但不久就会提供了:

不能够读取图表信息;
可以读,但是不能生成公式,任何类型公式最后的计算值都可以读出;
应用示例

1 从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);

2 生成新的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电子表格。

接下来就是要创建工作表,创建工作表的方法与创建工作薄的方法几乎一样,同样是通过工厂模式方法获得相应的对象,该方法需要两个参数,一个是工作表的名称,另一个是工作表在工作薄中的位置,参考下面的代码片段:


//创建Excel工作表
jxl.write.WritableSheet ws = wwb.createSheet("Test Sheet 1", 0);

"这锅也支好了,材料也准备齐全了,可以开始下锅了!",现在要做的只是实例化API所提供的Excel基本数据类型,并将它们添加到工作表中就可以了,参考下面的代码片段:


//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工作薄对象,以释放占用的内存,参见下面的代码片段:


//写入Exel工作表
wwb.write();

//关闭Excel工作薄对象
wwb.close();

这可能与读取Excel文件的操作有少少不同,在关闭Excel对象之前,你必须要先调用write()方法,因为先前的操作都是存储在缓存中的,所以要通过该方法将操作的内容保存在文件中。如果你先关闭了Excel对象,那么只能得到一张空的工作薄了。

3 拷贝、更新Excel工作薄

接下来简要介绍一下如何更新一个已经存在的工作薄,主要是下面二步操作,第一步是构造只读的Excel工作薄,第二步是利用已经创建的Excel工作薄创建新的可写入的Excel工作薄,参考下面的代码片段:(完整代码见ExcelModifying.java)


//创建只读的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()方法,将更新的内容写入到文件中,然后关闭工作薄对象,这里有两个工作薄对象要关闭,一个是只读的,另外一个是可写入的。

以上摘自IBM网站

posted @ 2006-07-13 13:50 brock 阅读(175) | 评论 (0)编辑 收藏

Poi即poor object interface之意,是poi项目组对微软封闭的office文件格式(接口)的称谓!
其中提供了对word和excel的java接口,用法非常简单,并且是完全免费的,对中文的支持也相当不错,下面是处理excel一个简单的实例:


package test;

import java.io.*;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;

public class Test {
public static void main(String[] args) {
try {
/**************创建一个xls文档*************/
HSSFWorkbook wb = new HSSFWorkbook();
FileOutputStream fileOut = new FileOutputStream("workbook.xls");
HSSFSheet sheet = wb.createSheet("new sheet");
HSSFRow row = sheet.createRow((short)0);
HSSFCell cell = row.createCell((short)0);
row.createCell((short)1);
row.createCell((short)2);
row.createCell((short)3);
row.createCell((short)4);
row.createCell((short)5);
cell.setCellValue("test_write!");
wb.write(fileOut);
fileOut.close();
/*************读取并修改xls文档***************/
POIFSFileSystem pfs=new POIFSFileSystem(new FileInputStream("workbook.xls"));
HSSFWorkbook hwb=new HSSFWorkbook(pfs);
HSSFSheet hs=hwb.getSheetAt(0);
HSSFRow hr=hs.getRow(0);
HSSFCellStyle style=hwb.createCellStyle();
style.setAlignment(style.ALIGN_CENTER);
HSSFFont hf=hwb.createFont();
hf.setFontName("楷体_GB2312");
style.setFont(hf);
HSSFCell cl=hr.getCell((short)2);
cl.setEncoding(cl.ENCODING_UTF_16);
cl.setCellStyle(style);
cl.setCellValue("test_modify! 测试\u2014\u2014编辑!");
FileOutputStream fos=new FileOutputStream("workbook.xls");
hwb.write(fos);
fos.flush();
fos.close();
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}

posted @ 2006-07-13 13:48 brock 阅读(244) | 评论 (0)编辑 收藏

仅列出标题
共15页: First 上一页 7 8 9 10 11 12 13 14 15 下一页