<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Rising Sun

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      148 隨筆 :: 0 文章 :: 22 評論 :: 0 Trackbacks

    #

    connection.setAutoCommit(false); 當設為True 時,它就當事務來處理,就有一個時間段.這個搞了出一些未明的問題.還是手動設為False ,hibarnate 以作了相應的處理.
    posted @ 2006-07-19 14:29 brock 閱讀(163) | 評論 (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 閱讀(195) | 評論 (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 閱讀(130) | 評論 (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 閱讀(593) | 評論 (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 閱讀(608) | 評論 (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 閱讀(914) | 評論 (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 閱讀(356) | 評論 (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 閱讀(177) | 評論 (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 閱讀(251) | 評論 (0)編輯 收藏

    僅列出標題
    共15頁: First 上一頁 7 8 9 10 11 12 13 14 15 下一頁 
    主站蜘蛛池模板: 亚洲女初尝黑人巨高清| 亚洲福利电影一区二区?| 免费a级毛片无码a∨免费软件| 中文字幕亚洲精品资源网| 成年女人看片免费视频播放器| 免费一级做a爰片久久毛片潮| 国产亚洲综合久久系列| 成人黄软件网18免费下载成人黄18免费视频 | 亚洲精品无码久久久久久| 亚洲熟妇少妇任你躁在线观看无码| 99免费在线观看视频| 亚洲成av人片在线天堂无| 亚洲国产一二三精品无码| 成人免费AA片在线观看| 中文字幕在线观看免费| 国产精品亚洲综合五月天| 亚洲制服丝袜精品久久| 亚洲精品和日本精品| 免费福利视频导航| 一区二区三区在线免费| 日本亚洲精品色婷婷在线影院| 亚洲熟妇av一区二区三区漫画| 成年性生交大片免费看| 毛片无码免费无码播放| 永久免费无码网站在线观看个| 亚洲校园春色另类激情| 国产精品亚洲A∨天堂不卡| 日本特黄特色免费大片| 蜜桃AV无码免费看永久| 黄桃AV无码免费一区二区三区| 亚洲国产av玩弄放荡人妇| 亚洲美免无码中文字幕在线| 亚洲国产免费综合| 最近免费中文字幕4| 99热这里有免费国产精品| 精品国产免费人成网站| 国产精品久久久久久亚洲小说| 亚洲av无码不卡久久| 精品亚洲麻豆1区2区3区| 亚洲精品无码久久一线| 亚洲国产成人久久精品99|