• <label id="pxtpz"><meter id="pxtpz"></meter></label>
      1. <span id="pxtpz"><optgroup id="pxtpz"></optgroup></span>

        當(dāng)前位置:雨林木風(fēng)下載站 > 技術(shù)開發(fā)教程 > 詳細(xì)頁面

        servlet2.3

        servlet2.3

        更新時間:2022-05-02 文章作者:未知 信息來源:網(wǎng)絡(luò) 閱讀次數(shù):

        明天的Java開發(fā)什么樣?
        (仙人掌工作室 2001年06月19日 14:44)

        和當(dāng)前的Servlet 2.2規(guī)范相比,Servlet 2.3 建議最終草案(PFD)最大的不同之處在于把filter(過濾器)和event(事件)加入了Servlet模型。過濾器提供了一種讓應(yīng)用程序在任何Servlet運(yùn)行之前或運(yùn)行之后執(zhí)行標(biāo)準(zhǔn)動作的方法。很長時間以來,Servlet規(guī)范中都沒有事件。事件提供的是特定動作的通知,特別是應(yīng)用程序的啟動/結(jié)束與會話的啟動/結(jié)束,使得應(yīng)用程序能夠進(jìn)行某些一次性的初始化/清理操作。

        事件句柄
        在許多場合,應(yīng)用程序一啟動就必須進(jìn)行一些初始化操作。例如,創(chuàng)建和初始化JDBC連接時,或者創(chuàng)建JDBC連接池時,或者讀取在應(yīng)用程序的整個生命周期內(nèi)都要用到的資源時,或者進(jìn)行簡單的檢查以確保應(yīng)用程序要用到的某些資源確實(shí)存在時,這種情況都會發(fā)生。在遵從2.2規(guī)范的容器上,應(yīng)用程序沒有保證能夠執(zhí)行這類初始化操作的辦法。

        在2.2規(guī)范中,部署Servlet時可以在web.xml文件中設(shè)置<load-on-startup>項(xiàng)目。這個元素應(yīng)該包含一個正數(shù),它決定了Servlet啟動的次序,有關(guān)該標(biāo)記的更多說明,請參見Servlet規(guī)范中的web.xml DTD說明。采用這種方案有幾個問題。首先,Servlet規(guī)范說:“l(fā)oad-on-startup元素表示該Servlet應(yīng)該(should)在Web應(yīng)用程序啟動的時候裝入。”Servlet容器開發(fā)者可能把它理解成“應(yīng)該裝入,但不是必須裝入”(因此,當(dāng)應(yīng)用程序啟動時Servlet可能沒有被裝入)。另外一個問題在于,我們是在用一種與Servlet設(shè)計意圖不同的方式使用Servlet。

        Servlet有一個“請求”級的作用范圍。也就是說,按照設(shè)計,Servlet對于每個客戶端的請求執(zhí)行一次。但在這里,Servlet有了“應(yīng)用”級作用范圍,它執(zhí)行一次然后就掛起。

        在2.2規(guī)范中,Servlet還可以被卸載——容器檢查初始化Servlet,判斷出Servlet在一段時間內(nèi)已經(jīng)沒有使用,于是就卸載它。如果這個Servlet“占據(jù)”了一些啟動的時候它初始化的資源,那么它應(yīng)該釋放這些資源。但是,Servlet不會被告知應(yīng)用程序什么時候結(jié)束。Servlet的拆除方法會在應(yīng)用程序關(guān)閉的時候被調(diào)用,但它無法知道是否所有其他Servlet也被卸載。當(dāng)其他Servlet被卸載時,它們可能需要用到由初始化Servlet創(chuàng)建的資源。如果先卸載的是初始化Servlet,那么其他Servlet的處境就不妙了。

        使用會話的時候也會出現(xiàn)完全同樣的問題,因?yàn)閼?yīng)用程序完全有理由在建立/拆除每一個會話的時候,做一些初始化或者清理工作。

        為了解決這些問題,Servlet 2.3規(guī)范引入了事件句柄的概念。事件句柄是一些回應(yīng)和處理由容器初始化的特定事件的代碼。Servlet 2.3規(guī)范定義了兩種類型的事件:應(yīng)用程序事件,會話事件。對于所有這兩種事件類型,事件句柄能夠捕獲啟動和結(jié)束事件,能夠捕獲屬性改變事件。

        我們將把注意力主要集中到應(yīng)用程序的啟動和結(jié)束事件上,但對于其他事件類型來說,代碼也是相似的。

        我們來看看事件句柄的代碼。應(yīng)用程序的事件句柄必須擴(kuò)展javax.servlet.ServletContextListener接口。這個接口有兩個方法,即contextDestroyed()和contextInitialized()。兩個方法都有一個ServletContextEvent參數(shù)。正如你可以猜想到的,contextInitialized()方法在應(yīng)用程序啟動的時候被調(diào)用,contextDestroyed()方法在應(yīng)用程序結(jié)束的時候被調(diào)用。ServletContextEvent類有一個方法,它能夠返回正在被創(chuàng)建或拆除的ServletContext的引用。

          舉例來說,假設(shè)你正在設(shè)計一個基于Web的簡單白頁(White Page)應(yīng)用。在這個應(yīng)用中,用戶通過email查找姓名和地址,如Listing 1所示。這個例子在一個Hashtable(散列表)中保存白頁的內(nèi)容,散列表必須在應(yīng)用程序啟動的時候創(chuàng)建,而且它必須保存到應(yīng)用程序的ServletContext。


        【Listing 1】
        import javax.servlet.ServletContextListener;

        public class WhitePagesListener implements ServletContextListener {
         Hashtable whitePages;
         public WhitePagesServletListener() {
         whitePages = new Hashtable();
         }
        public void contextDestroyed(ServletContextEvent sce) { }
        public void contextInitialized(ServletContextEvent sce) {
        System.out.println("contextInitialized");
        WhitePageEntry wpe = new WhitePageEntry("Kevin Jones", "555-1234");
        whitePages.put("kev@dev.com", wpe);
        wpe = new WhitePageEntry( "Simon Horrell", "555-8765");
        whitePages.put("simon@dev.com", wpe);
        wpe = new WhitePageEntry( "Don Box", "555-2137");
        whitePages.put("don@dev.com", wpe);
        // 把散列表保存到ServletContext
        sce.getServletContext().setAttribute( "addrbook", whitePages);
        }
        }

        代碼非常簡單。WhitePagesListener類實(shí)現(xiàn)了ServletContextListener。散列表由類的構(gòu)造方法創(chuàng)建。contextDestroyed()方法什么事情也不錯,因?yàn)閼?yīng)用程序是被完全卸載,我們不需要清理過程。令人感興趣的部分是在contextInitialized()方法內(nèi)。這個方法把我們需要的數(shù)據(jù)保存到散列表,然后把散列表保存到ServletContext。當(dāng)contextInitialized()被調(diào)用時,它的參數(shù)中傳入了一個對ServletContextEvent對象的引用。ServletContextEvent類有一個getServletContext()方法,它返回的是對當(dāng)前應(yīng)用程序的ServletContext的引用。獲得ServletContext的引用之后,散列表就被保存到了ServletContext之中。

        應(yīng)用程序必須經(jīng)過配置才能使用這個事件句柄,具體通過修改應(yīng)用程序的部署描述器(即web.xml文件)完成:


        <web-app>
        <listener>
        <listener-class>
         WhitePagesListener
        </listener-class>
        </listener>...

        用這種方法可以配置任意數(shù)量的監(jiān)聽器(Listener)。調(diào)用監(jiān)聽器的次序就是它們在部署描述器中出現(xiàn)的次序。監(jiān)聽器屬于Singleton,開發(fā)者必須負(fù)責(zé)進(jìn)行同步。這一點(diǎn)對于本例來說不是特別重要,但對于所有其它類型的應(yīng)用來說,它可能很重要。

        過濾器
        過濾器是Servlet 2.3規(guī)范中最主要的新增功能。過濾器使得Servlet開發(fā)者能夠在請求到達(dá)Servlet之前截取請求,在Servlet處理請求之后修改應(yīng)答。正如我們即將看到的,過濾器的創(chuàng)建和安裝都很簡單。

        所有的過濾器實(shí)現(xiàn)javax.filter.Filter接口。這個接口有三個方法:setFilterConfig()方法,在最后的規(guī)范中,這個方法很可能被兩個方法取代,取代的方法可能是init(Filterconfig config)和destroy();getFilterConfig()方法,在規(guī)范的稍后版本中這個方法可能消失;doFilter()方法。setFilterConfig()方法在第一次創(chuàng)建過濾器實(shí)例以及從調(diào)用鏈刪除過濾器時被調(diào)用。創(chuàng)建實(shí)例時,傳入過濾器的參數(shù)是一個非null的FilterConfig對象。這個對象使得過濾器能夠訪問它的名字和當(dāng)前的ServletContext。初始化參數(shù)可以作為過濾器配置的一部分指定,這些參數(shù)也可以通過FilterConfig訪問。當(dāng)過濾器被刪除時,傳入setFilterConfig()的是一個值為null的FilterConfig。

        配置過濾器時,我們可以把過濾器關(guān)聯(lián)到一個或者多個Servlet上。只要請求傳遞到了與某個過濾器關(guān)聯(lián)的Servlet上,該過濾器就會執(zhí)行。過濾器以調(diào)用鏈中一部分的形式執(zhí)行,執(zhí)行次序由過濾器在部署描述器(即web.xml文件)中的次序決定。容器通過調(diào)用過濾器的doFilter()方法執(zhí)行過濾器。doFilter()方法的參數(shù)包括一個ServletRequest對象、一個ServletResponse對象、一個javax.servlet.FilterChain對象。

        FilterChain只有一個方法doFilter(),過濾器通過調(diào)用該方法把請求和應(yīng)答繼續(xù)向調(diào)用鏈的下一環(huán)傳遞。當(dāng)然這也意味著,過濾器可以不再向調(diào)用鏈傳遞它,從而阻塞調(diào)用。此時,當(dāng)前過濾器必須負(fù)責(zé)生成合適的應(yīng)答內(nèi)容。

        舉一個例子,我們來看一個在調(diào)試Servlet時很有用的Servlet,如Listing 2所示。這個過濾器將輸出“下游”Servlet和過濾器設(shè)置的HttpRequest頭和HttpResponse頭。如果讓這個過濾器成為調(diào)用鏈中的第一個過濾器,它可能能夠讓我們捕獲所有的應(yīng)答頭,不過容器可能決定以過濾器永遠(yuǎn)不能了解的方式設(shè)置應(yīng)答頭:


        【Listing 2】下面清單中的Servlet將輸出由“下游”Servlet和 過濾器設(shè)置的HttpRequest頭和HttpResponse頭

        public class DumpHeadersimplements
        javax.servlet.Filter {
        private FilterConfig fc;
        private ServletContext ctx;
        ... ...

        public FilterConfig getFilterConfig() {
        return fc;
        }
        publicvoid setFilterConfig( FilterConfig filterConfig) {
        fc = filterConfig;
        if(fc !=null) ctx = fc.getServletContext();
        }
        }

        這個過濾器實(shí)現(xiàn)了javax.servlet.Filter接口,所以它必須按照前面所顯示的實(shí)現(xiàn)setFilterConfig()和getFilterConfig()。setFilterContext()保存了一個對ServletContext的引用以便以后使用。

        doFilter()方法的實(shí)現(xiàn)需要一點(diǎn)技巧。doFilter()的第一部分很簡單:獲取request對象,分析HTTP方法和查詢字符串,然后枚舉請求頭。代碼如Listing 3所示。


        【Listing 3】下面顯示了doFilter()第一部分的實(shí)現(xiàn),它獲取request對象, 分析HTTP方法和查詢字符串。

        public void doFilter(
        ServletRequest request,
        ServletResponse response, chain)
        throws java.io.IOException,
        ServletException {

         // 獲得request對象
         HttpServletRequest req = (HttpServletRequest)request;

         // 重新構(gòu)造HTTP請求行
         String temp;
         temp = req.getMethod() + req.getRequestURI();
         if(req.getQueryString() != null)
         temp += "?"+req.getQueryString();
         temp += " " + req.getProtocol();

         // 用ServletContext記錄HTTP請求行
         ctx.log(temp); temp = "";

         // 枚舉請求頭
         Enumeration names = req.getHeaderNames();
         while(names.hasMoreElements()) {
        String name = (String)names.nextElement();
        temp += name + ": " ;
        Enumeration values = req.getHeaders(name);
        while (values.hasMoreElements()) {
         String value = (String)values.nextElement();
         temp += value + " ";
         } // 記錄 ctx.log(temp); temp = "";
        }

        但處理應(yīng)答比較復(fù)雜,而且它涉及到Servlet的一個新概念——封裝request和response對象。在Servlet規(guī)范以前的版本中,調(diào)用任何一個要求有[Http]ServletRequest或[Http]ServletResponse的方法時,你必須把傳遞給Servlet service方法的request和response對象傳遞給該方法。最明顯的例子就是分派請求的時候:


        RequestDispatch rd = getServletContext().getRequestDispatcher("foo"); rd.forward(request, response); // or rd.include(request, response);

        假設(shè)你想執(zhí)行一個包含操作,然后,在把應(yīng)答發(fā)送給客戶端之前又要對它進(jìn)行處理,或者在把應(yīng)答發(fā)送給客戶端之前從RequestDispatcher.forward()查看應(yīng)答。在以前的Servlet規(guī)范中,這是不可能的。但在Servlet 2.3規(guī)范中這一切都成為可能。

        新的規(guī)范定義了兩個新類,即javax.servlet.http.HttpServletRequestWrapper和javax.servlet.http.HttpServletResponseWrapper(這兩個類從它們各自的非HTTP版本繼承)。這兩個類的構(gòu)造方法如下:


        HttpServletRequestWrapper(HttpServletRequest request) HttpServletResponseWrapper(HttpServletResponse response)

        在這些類中,這兩個方法的默認(rèn)行為是把調(diào)用傳遞給它們所封裝的對象。使用這些類的時候,你一般要派生這些類并覆蓋那些感興趣的方法。對于本文的過濾器,我們必須創(chuàng)建一個應(yīng)答封裝器,記錄對addXXXHeader()方法和setXXXHeader()方法的調(diào)用。另外,我們還想要捕獲對setStatus()、setContentLength()、setContentType()和setLocale()方法的調(diào)用。代碼如Listing 4所示,它簡單地記錄了對各個方法的調(diào)用。


        【Listing 4】應(yīng)答封裝器。下面的代碼為過濾器構(gòu)造了一個應(yīng)答封裝器, 它將記錄對addXXXHeader()和setXXXHeader()方法的調(diào)用。另外, 它還要捕獲對setStatus()、setContentLength()、setContentType()和 setLocale()方法的調(diào)用。

        class HeaderResponseWrapper extends
        HttpServletResponseWrapper {
        ServletContext ctx;

        public HeaderResponseWrapper(
        HttpServletResponse response,
        ServletContext ctx) {
        super(response);
        this.ctx = ctx;
         }

        public void addCookie(Cookie cookie) {
        ctx.log("Set-Cookie: " + cookie.getName() + ":" + cookie.getValue());
        super.addCookie(cookie);
         }

        public void addHeader(String name, String value) {
        ctx.log(name + ": " + value); super.addHeader(name, value);
         }

        public void addIntHeader(String name, int value) {
        ctx.log(name + ": " + value); super.addIntHeader(name, value);
         }

        public void addDateHeader(String name, long value) {
        ctx.log(name + ": " + value); super.addDateHeader(name, value);
         }

        public void setHeader( String name, String value) {
        ctx.log(name + ": " + value); super.setHeader(name, value);
         }

        public void setIntHeader( String name, int value) {
        ctx.log(name + ": " + value); super.setIntHeader(name, value);
         }

        public void setDateHeader( String name, long value) {
        ctx.log(name + ": " + value); super.setDateHeader(name, value);
         }

        public void setStatus(int sc) {
        ctx.log("status: " + sc); super.setStatus(sc);
         }

        public void setStatus( int sc, java.lang.String sm) {
        ctx.log("status: " + sc); super.setStatus(sc, sm);
         }

        public void setContentLength(int len) {
        ctx.log("Content-Length: " + len); super.setContentLength(len);
         }

        public void setContentType(java.lang.String type) {
        ctx.log("Content-Type: " + type); super.setContentType(type);
         }

        public void setLocale(java.util.Locale loc) {
        ctx.log("locale: " + loc); super.setLocale(loc);
         }
        }

        在過濾器中,我們按照如下方式使用這個對象:


        HttpServletResponse resp = (HttpServletResponse)response;
        HeaderResponseWrapper hrespw = new HeaderResponseWrapper(resp, ctx);

        System.out.println("********");

        chain.doFilter(request, hrespw);

        注意創(chuàng)建好封裝器之后chain.doFilter()方法就被調(diào)用。

        定義好過濾器之后就應(yīng)該安裝它。為此,web.xml中應(yīng)該定義一個filter元素:


        <filter>
        <filter-name>
        Headers Filter
        </filter-name>
        <filter-class>
        DumpHeaders
        </filter-class>
        <!- optional <init-params> ->
        </filter>

        完成這一步之后,你還要把過濾器和你想要過濾的資源關(guān)聯(lián)起來。這時你有兩種選擇:在web.xml中,把過濾器關(guān)聯(lián)到單個命名的Servlet,或者把過濾器關(guān)聯(lián)到一個URL。如下所示:


        <filter-mapping>
        <filter-name>
        Headers Filter
        </filter-name>
        <servlet-name>
        AddressBookServlet
        </servlet-name>
        </filter-mapping>

        或者:


        <filter-mapping>
        <filter-name>
        Header Filter
        </filter-name>
        <url-pattern>/*</url-pattern>
        </filter-mapping>

        輸出的請求頭如下所示:


        GET/AddressBook/Browse.jsp HTTP/1.1
        accept: */*
        referer: http://localhost/ AddressBook/
        accept-language: en-gb
        accept-encoding: gzip, deflate
        user-agent: Mozilla/4.0 ( compatible; MSIE 5.5; Windows NT 5.0)
        host: localhost
        connection: Keep-Alive
        cookie: JSESSIONID= E0F9646772F4448004C16122020664F1

        輸出的應(yīng)答頭如下所示:


        Content-Type: text/html;charset=8859_1 Content-Type: text/plain

        如果進(jìn)行網(wǎng)絡(luò)跟蹤,你會發(fā)現(xiàn)這里少了一些東西。例如,狀態(tài)代碼沒有顯示,這是因?yàn)橛幸恍⿷?yīng)答頭由容器在過濾器鏈執(zhí)行之前或之后設(shè)置。

        過濾器有很多用途,比如驗(yàn)證、轉(zhuǎn)換、加密/解密。但有一點(diǎn)必須注意:你可以把過濾器關(guān)聯(lián)到任意資源,而不僅僅是Servlet。如果你使用的是一個插入到其他Web服務(wù)器的Servlet引擎,Web服務(wù)器很可能會不依賴于Servlet容器獨(dú)立地提供服務(wù)。在這種情況下,Servlet容器將接收不到所有的請求,所以過濾器也就不會總是被執(zhí)行。

        JSP 1.1中有一個問題涉及到請求分派。如果你有一個頁面執(zhí)行include操作,jsp:include有一個必須設(shè)置為true的強(qiáng)制性flush(刷新)屬性:


        <jsp:include page="somePage" flush="true" />

        這個屬性強(qiáng)制容器把當(dāng)前緩沖區(qū)內(nèi)容刷新到客戶端。這樣,JSP頁面不能再設(shè)置任意HTTP應(yīng)答頭。JSP 1.2規(guī)范已經(jīng)修正這個問題,jsp:include標(biāo)記中現(xiàn)在已經(jīng)可以指定flush="false"。

        溫馨提示:喜歡本站的話,請收藏一下本站!

        本類教程下載

        系統(tǒng)下載排行

        主站蜘蛛池模板: 亚洲成a人片在线观看久| 成年女人午夜毛片免费看| 亚洲中文字幕成人在线| 免费一级特黄特色大片| 亚洲JIZZJIZZ中国少妇中文| 国产精品亚洲精品爽爽| 国产国产人免费人成免费视频 | 亚洲成AV人片在线观看无| 久久精品免费网站网| 国产亚洲精品自在久久| 国产激情免费视频在线观看| 亚洲春色在线观看| 91精品免费在线观看| 亚洲日产乱码一二三区别| 国产精品酒店视频免费看| 国产亚洲精品欧洲在线观看| 国产亚洲精久久久久久无码77777| 波霸在线精品视频免费观看| 亚洲嫩模在线观看| 91在线品视觉盛宴免费| 激情小说亚洲色图| 亚洲人成网亚洲欧洲无码久久| 久久免费视频观看| 亚洲www在线观看| 免费在线观看亚洲| a级在线免费观看| 亚洲伊人久久大香线蕉啊| 国产女高清在线看免费观看 | 国产精品亚洲专区在线播放| 国产午夜亚洲不卡| 1000部夫妻午夜免费| 亚洲A∨精品一区二区三区下载| 亚洲精品视频在线看| 97精品免费视频| 亚洲妇女无套内射精| 亚洲深深色噜噜狠狠爱网站| 免费黄色网址网站| 一区二区免费电影| 亚洲欧洲日产v特级毛片| 亚洲精品无码av天堂| 久草视频免费在线观看|