JSP內置對象的範圍和屬性

●●●範圍( Scope )
      有些 JSP 程序員會將 requestsessionapplication pageContext 歸爲一類,原因在於:它們皆能借助 setAttribute( ) getAttribute( )來設定和取得其屬性(Attribute),通過這兩種方法來做到數據分享
      我們先來看下面這段小程序:
Page1.jsp
<%@ page contentType="text/html;charset=GB2312" %>
<html>
<head>
 <title>Page1.jsp</title>
</head>
<body>
</br>
<%   
     application.setAttribute("Name","mike");      
     application.setAttribute("Password","browser");
%>
<jsp:forward page="Page2.jsp"/>
</body>
</html>
      在這個程序中,我們設定兩個屬性:NamePassword,其值爲:mikebrowser。然後再轉交(forward)Page2.jsp。我只要在Page2.jsp當中加入 application.getAttribute( ),就能取得在Page1.jsp設定的數據。
Page2.jsp
<%@ page contentType="text/html;charset=GB2312" %>
<html>
<head>
 <title>Page2.jsp</title>
</head>
<body>
<%
     String Name = (String) application.getAttribute("Name");
     String Password = (String) application.getAttribute("Password");
     out.println("Name = "+Name);
     out.println("Password = "+ Password);
%>
</body>
</html>
      執行結果爲:
      Name=mike Password=browser
      由這個例子可以看出,JSP提供給開發人員一項傳遞數據的機制,那就是利用setAttribute( )getAttribute( )方法,如同Page1.jspPage2.jsp的做法。
      在上面Page1.jspPage2.jsp的程序當中,是將數據存入到 application 對象之中。除了application之外,還有requestpageContext session,也都可以設定和取得屬性值,那它們之間有什麼分別嗎?
      它們之間最大的差別在於範圍(Scope)不一樣,這個概念有點像 CC++中的全局變量和局部變量的概念。接下來就介紹JSP的範圍。
      JSP有四種範圍,分別爲PageRequestSessionApplication
     1JSP Scope—Page
      所謂的 Page,指的是單單一頁JSP Page的範圍。若要將數據存入 Page 範圍時,可以用pageContext對象的 setAttribute()方法;若要取得Page範圍的數據時,可以使用 pageContext對象的getAttribute( )方法。我們將之前的範例做小幅度的修改,將application改爲 pageContext
PageScope1.jsp
<%@ page contentType="text/html;charset=GB2312" %>
<html>
<head>
 <title>PageScope1.jsp</title>
</head>
<body>
<h2>Page 範圍 - pageContext</h2>
<%   
     pageContext.setAttribute("Name","mike");      
     pageContext.setAttribute("Password","browser");
%>
<jsp:forward page="PageScope2.jsp"/>
</body>
</html>
PageScope2.jsp
<%@ page contentType="text/html;charset=GB2312" %>
<html>
<head>
 <title>CH5 - PageScope2.jsp</title>
</head>
<body>
<h2>Page 範圍 - pageContext</h2>
</br>
<%   
     String Name = (String)pageContext.getAttribute("Name");
     String Password = (String)pageContext.getAttribute("Password");
     out.println("Name = "+Name);
     out.println("Password = "+ Password);
%>
</body>
</html>
      執行結果爲:
      Name=null Password=null
      這個範例程序和之前有點類似,只是之前的程序是 application,現在改爲 pageContext,但是結果卻大不相同,PageScope2.jsp 根本無法取得 PageScope1.jsp 設定的 Name Password 值,因爲在PageScope1.jsp當中,是把NamePassword 的屬性範圍設爲Page,所以Name Password 值只能PageScope1.jsp當中取得。若修改PageScope1.jsp的程序,重新命名爲PageScope3.jsp,如下:
PageScope3.jsp
<%@ page contentType="text/html;charset=GB2312" %>
<html>
<head>
 <title>CH5 - PageScope3.jsp</title>
</head>
<body>
<h2>Page 範圍 - pageContext</h2>
</br>
<%   
     pageContext.setAttribute("Name","mike");      
     pageContext.setAttribute("Password","browser");
     
     String Name = (String)pageContext.getAttribute("Name");    
     String Password = (String)pageContext.getAttribute("Password"); 
     
     out.println("Name = "+Name);    
     out.println("Password = "+ Password);
%>
</body>
</html>
      PageScope3.jsp的執行結果爲:
      Name=mike Password=browser
      經過修改後的程序,Name Password 的值就能順利顯示出來。這個範例主要用來說明一個概念:若數據設爲Page範圍時,數據只能在同一個 JSP網頁上取得,其他 JSP網頁卻無法取得該數據。
     2JSP Scope—Request
      Request 的範圍是指在JSP網頁發出請求到另一個JSP網頁之間,隨後這個屬性就失效。設定 Request 的範圍時可利用 request 對象中的setAttribute()getAttribute()。我們再來看下列這個範例:
RequestScope1.jsp
<%@ page contentType="text/html;charset=GB2312" %>
<html>
<head>
 <title>CH5 - RequestScope1.jsp</title>
</head>
<body>
<h2>Request 範圍 - request</h2>
<%   
     request.setAttribute("Name","mike");     
     request.setAttribute("Password","browser");
%>
<jsp:forward page="RequestScope2.jsp"/>
</body>
</html>
RequestScope2.jsp
<%@ page contentType="text/html;charset=GB2312" %>
<html>
<head>
 <title>RequestScope2.jsp</title>
</head>
<body>
<h2>Request 範圍 - request</h2>
<%   
     String Name = (String) request.getAttribute("Name"); 
     String Password = (String) request.getAttribute("Password");    
     out.println("Name = "+Name);    
     out.println("Password = "+ Password);    
%>
</body>
</html>
      執行結果爲:
      Name=mike Password=browser
      RequestScope1.jsp轉向到RequestScope2.jsp時, RequestScope2.jsp也能取得RequestScope1.jsp設定的NamePassword值。不過其他的JSP網頁無法得到NamePassword值,除非它們也和RequestScope1.jsp有請求的關係。
      除了利用轉向(forward)的方法可以存取 request 對象的數據之外,還能使用包含(include)的方法。
      假若我將RequestScope1.jsp
      <jsp:forward page="RequestScope2.jsp"/>
      改爲
      <jsp:include page="RequestScope2.jsp" flush="true"/>
      執行結果還是一樣的。表示使用<jsp:include>標籤所包含進來的網頁,同樣也可以取得Request範圍的數據。
      3JSP ScopeSessionApplication
      下表介紹了最後兩種範圍:SessionApplication
●●●屬性(Attribute)
      下表列出了一般儲存和取得屬性的方法,以下 pageContextrequestsession application皆可使用(注意:pageContext並無getAttributeNames( )方法)。
      使 Object getAttribute(String name)取得 name ,它 java.lang.Object,因此,我們還必須根據name屬性值的類型做轉換類型(Casting)的工作。
      例如,若要取得String類型的Name屬性時:
      String Name = (String)Sessio.getAttribute("Name");
      若要取得Integer類型的Year屬性時:
      Integer Year = (Integer)session.getAttribute("Year");
      假若我們的數據要設爲Page範圍時,則只需要:
      pageContext.setAttribute("Year", new Integer(2001));
      若要爲 RequestSession Application 時,就分別存入 requestsession application對象之中,如下:
      request.setAttribute("Month", new Integer(12) );
      session.setAttribute("Day", new Integer(27) );
      application.setAttribute("Times", new Integer(10));
 (3)Response對象
       Response對象主要將 JSP 處理數據後的結果傳回到客戶端。Response對象實現的是javax.servlet.http.HttpServletResponse 接口。
       Response對象的方法:
       ①設定表頭的方法
       void addCookie(Cookie cookie):添加一個Cookie對象(保存到硬盤),用來保存客戶端的用戶信息,用request的getCookies()方法可以獲得這個Cookie。
       void addHeader(String name,String value):添加String類型的值(value)到指定名字(name)的HTTP文件頭。該header將會傳到客戶端去,如果有同名的header存在,那麼原來的header將會被覆蓋掉。
       void addIntHeader(String name, int value):添加int類型的值(value)到指定名字(name)的HTTP文件頭。該header將會傳到客戶端去,如果有同名的header存在,那麼原來的header將會被覆蓋掉。
       Void addDateHeader(String name, long date):添加long類型的值(value)到指定名字(name)的HTTP文件頭。該header將會傳到客戶端去,如果有同名的header存在,那麼原來的header將會被覆蓋掉。
       void setHeader(String name,String value):指定String類型的值(value)到指定名字(name)的HTTP文件頭。該header將會傳到客戶端去,如果有同名的header存在,那麼原來的header將會被覆蓋掉。
       void setIntHeader(String name, int value):指定int類型的值(value)到指定名字(name)的HTTP文件頭。該header將會傳到客戶端去,如果有同名的header存在,那麼原來的header將會被覆蓋掉。
       Void setDateHeader(String name, long date):指定long類型的值(value)到指定名字(name)的HTTP文件頭。該header將會傳到客戶端去,如果有同名的header存在,那麼原來的header將會被覆蓋掉。
       ②設定響應狀態碼的方法
       void sendError(int sc):向客戶端發送狀態碼。例如,505指示服務器內部錯誤;404指示網頁找不到的錯誤。
       void sendError(int sc, String msg):向客戶端發送狀態碼和錯誤信息。
       void setStatus(int sc):設定狀態碼。
       ③與URL有關的方法
       sendRedirect(URL):可以將用戶重定向到一個不同的頁面(URL)。sendRedirect(URL)方法通過返回特定的狀態代碼而起作用,當它被調用時,返回一個狀態代碼,然後在響應中定位,給新頁面一個新地址。狀態代碼和定位頭會自動把瀏覽器重定位到新頁面。不過,用戶通常不能被順利重定位到新的頁而,特別是老一些的瀏覽器,而且一些新版本的瀏覽器在自動響應定向作用狀態代碼時會有些問題,當瀏覽器無法自動響應狀態代碼時,會收到一些字段信息。
       String encodeRedirectURL(String url):對使用sendRedirect( )方法的URL予以編碼。
       ④其他方法
       Boolean containsHeader(String name):判斷指定名字的HTTP文件頭是否存在,並返回布爾值。
       void setContenType(String type):響應設置內容類型頭。
       例子:
       有時候,當我們修改程序後,產生的結果卻是之前的數據,執行瀏覽器上的刷新,才能看到更改數據後的結果,針對這個問題,有時是因爲瀏覽器會將之前瀏覽過的數據存放在瀏覽器的 Cache中,所以當我們再次執行時,瀏覽器會直接從 Cache 中取出,因此,會顯示之前舊的數據。現寫一個Non-cache.jsp 程序來解決這個問題。
       Non-cache.jsp
<%@ page contentType="text/html;charset=GB2312" %>
<html>
<head>
 <title> Non-cache.jsp</title>
</head>
<body>
<h2>解決瀏覽器 cache 的問題 - response</h2>
<%   
     if (request.getProtocol().compareTo("HTTP/1.0") == 0)       
          response.setHeader("Pragma", "no-cache");    
     else if (request.getProtocol().compareTo("HTTP/1.1") == 0)      
         response.setHeader("Cache-Control", "no-cache"); 
     response.setDateHeader("Expires", 0); 
%>
</body>
</html>
       先用 request 對象取得協議,如果爲 HTTP/1.0,就設定標頭,內容爲 setHeader ("Pragma", "no-cache");若爲HTTP/1.1,就設定標頭爲 response.setHeader ("Cache-Control", "no-cache"),最後再設定response.setDateHeader("Expires", 0)。這樣 Non-cache.jsp網頁在瀏覽過後,就不會再存放到瀏覽器或是 proxy服務器的 Cache 中。
       HTTP/1.1 Cache-Control 標頭的設定參數詳見http://esoft.bokee.com/5202557.html
       有時候,我們想要讓網頁自己能自動更新,因此,須使用到 Refresh 這個標頭。舉個例子,我們告訴瀏覽器,每隔三分鐘,就重新加載此網頁:response.setIntHeader("Refresh" , 180)
       如果想要過十秒後,調用瀏覽器轉到 http://esoft.bokee.com的網頁時,可用如下代碼:
response.setHeader("Refresh","10; URL=http://esoft.bokee.com" )
       HTML 語法中也有類似的功能:
<META HTTP-EQUIV="Refresh" CONTENT=" 10; URL=http://Server/Path" >
       上述兩種方法皆可以做到自動重新加載。
 (4)Session對象
       Session 對象表示目前個別用戶的會話(session)狀況,用此項機制可以輕易識別每一個用戶,然後針對每一個別用戶的要求,給予正確的響應。例如:購物車最常使用 session 的概念,當用戶把物品放入購物車時,他不須重複做身份確認的動作(如:Login),就能把物品放入用戶的購物車。但服務器利用 session 對象,就能確認用戶是誰,把它的物品放在屬於用戶的購物車,而不會將物品放錯到別人的購物車。session對象實現的是javax.servlet.http.HttpSession 接口。
       Session對象的方法:
       setAttribute(String name,java.lang.Object value):設定指定名字的屬性值,並且把它存儲在Session對象中。
       getAttribute(String name):獲得指定名字的屬性,如果該屬性不存在,將會返回null。
       Enumeration getAttributeNames():返回Session對象中存儲的每個屬性對象,結果集是一個Enumeration類的實例。
       Boolean isNew():判斷目前Session是否爲新的Session,若是則返回ture,否則返回false(所謂"新"的Session,表示session已由服務器產生,但是client尚未使用)。
       String getId():返回Session對象在服務器端的編號。每生成一個Session對象,服務器都會給它一個編號,並且該編號不會重複,這樣服務器才能根據編號來識別Session,並且正確的處理某一特定的Session及其提供的服務。
       long getCreationTime():返回Session對象被創建的時間,單位爲毫秒,由1970年1月1日零時算起。
       long getLastAccessedTime():返回用戶最後通過這個session送出請求的時間,單位是毫秒,由1970年1月1日零時算起。
       long getMaxInactiveInterval():取得最大session不活動的時間,若超過這時間,session 將會失效,時間單位爲秒。
       void setMaxInactiveInterval(int interval):設置最大session不活動的時間,若超過這時間,session 將會失效,時間單位爲秒。
       void removeAttribute(String name)“刪除指定的屬性(包含屬性名、屬性值)。如果在有效時間內,用戶做出了新的請求,那麼服務器就會將其看作一個新的用戶,此時,服務器將創建一個新的Session,舊的Session信息將會丟失
       void invalidate():取消 session對象,並將對象存放的內容完全拋棄。
       例子:
       session 對象也可以儲存或取得用戶相關的數據,例如:用戶名、用戶所訂購的物品、用戶的權限等等,這些要看我們的程序如何去設計。例如:我要設定某些網頁必須要求用戶先做登錄(Login)的動作,確定是合法的用戶時,才允許讀取網頁內容,否則把網頁重新轉向到登錄的網頁上。
       Login.jsp
<%@ page contentType="text/html;charset=GB2312" %>
<html>
<head>
 <title> Login.jsp</title>
</head>
<body>
<h2>javax.servlet.http.HttpSession - session 對象</h2> 
<form action=Login.jsp method="POST" >
Login Name: <input type="text" name="Name"><br>
Login Password: <input type="text" name="Password" ><br>
<input type="submit" value="Send"><br>
<form>
<% if (request.getParameter("Name") != null &&
request.getParameter("Password") != null) {       
         String Name = request.getParameter("Name");
         String Password = request.getParameter("Password");
         if (Name.equals("mike") && Password.equals("1234")) {      
              session.setAttribute("Login", "OK");
              response.sendRedirect("Member.jsp");
         }
         else {            
              out.println("登錄錯誤,請輸入正確名稱");         
         }    
     }
%>
</body>
</html>
       Login.jsp 的程序中,我要求用戶分別輸入名稱和密碼,如果輸入的名稱和密碼分別爲 mike和1234時,就把名稱爲Login、其值爲OK 的屬性,加入到 session對象當中,然後進入 Member.jsp網頁;若輸入錯誤時,就顯示出“登錄錯誤,請輸入正確名稱”。不允許登錄至 Member.jsp
       這時大家一定會想,如果我不通過Login.jsp 網頁,直接執行 Member.jsp,那不就能夠進去了。沒錯,因此我們還要在Member.jsp中加入一段程序代碼,來確認用戶是否有先通過 Login.jsp的身份確認,然後再到Member.jsp中。Member.jsp程序如下:
       Member.jsp
<%@ page contentType="text/html;charset=GB2312" %>
<html>
<head>
 <title> Member.jsp</title>
</head>
<body>
<h2>javax.servlet.http.HttpSession - session 對象</h2> 
<%   
     String Login = (String)session.getAttribute("Login");
     if (Login != null && Login.equals("OK")) {        
         out.println("歡迎進入");
         session.invalidate();  
     }    
     else {        
         out.println("請先登錄,謝謝")    ;
         out.println("<br>經過五秒之後,網頁會自動返回 Login.jsp");
         response.setHeader("Refresh","5;URL=Login.jsp"); 
     }
%>
</body>
</html>
       Member.jsp中我利用session.getAttribute("Login"),如果用戶是通過Login.jsp網頁進入,並且順利通過身份確認取得 Login=OK,到 Member.jsp 再做確認時,也能順利通過;否則,如果直接連接到Member.jsp時,Login的值會等於NULL,則程序經過五秒後,重新加載Login.jsp,要求用戶先行登錄。
       最後要提醒一點,session對象不像其他的隱含對象,可以在任何的 JSP網頁中使用,如果在JSP網頁中,page 指令的屬性session 設爲 false 時,使用 session 對象就會產生編譯錯誤 (javax.servlet.ServletException: Compilation error occurred )
 (5)Application對象
       Application對象用於取得或更改Servlet的設定,他的生存期是由服務器產生開始至服務器關機爲止。application 對象實現的是javax.servlet.ServletContext接口。
       Application對象的方法:
       ①與容器相關的方法
       int getMajorVersion( ):取得Container 主要的 Servlet API 版本,如:2。
       int getMinorVersion( ):取得Container 次要的 Servlet API 版本,如:4。
       String getServerInfo( ):取得Container 的名稱和版本。
       例子:
       <%=application.getMajorVersion() %><br>
       <%=application.getMinorVersion() %><br>
       <%=application.getServerInfo() %><br>
       上述的 getMajorVersion( )getMinorVersion( )是取得 Servlet Engine 的版本信息,假如想要取得JSP容器的版本信息,則可能就要使用到下面這段程序代碼:
       GetJspVersion.jsp
<%@ page import="javax.servlet.jsp.JspFactory" contentType="text/html;charset=GB2312" %>
<html>
<head>
 <title> GetJspVersion.jsp</title>
</head>
<body>
<h2>取得 JSP Container 版本 - JspFactory 對象</h2>     
<%
       JspFactory factory = JspFactory.getDefaultFactory();
        out.println("JSP v 2.0"+ 
                        factory.getEngineInfo().getSpecificationVersion());
%>
</body>
</html>
       ②有關服務端的路徑和文件的方法
       String getMimeType(String file):取得指定文件的 MIME 類型。
       ServletContext getContext(String uripath):取得指定 Local URL 的 Application context。
       String getRealPath(String path):取得本地端 path 的絕對路徑。
       例子:
       <%= application.getMimeType("MyFile")
       <%= application.getContext("/") %>
       <%= application.getRealPath("/") %>
       ③有關信息記錄的方法
       void log(String message):將信息寫入 log 文件中。
       void log(String message, Throwable throwable):將 stack trace 所產生的異常信息寫入log文件中。
       application對象最常被使用在存取環境的信息,因爲環境的信息通常都儲存在ServletContext中,所以常利用application對象來存取ServletContext中的信息。
*******************************************************************************
●●●JSP內置對象與Servlet子類映射
JSP內置對象       Servlet子類                          作用域
request             javax.servlet.http.HttpServletRequest       Request
response           javax.servlet.http.HttpServletResponse     Page
session             javax.servlet.http.HttpSession                 Session
application        javax.servlet.ServletContext                    Application
out                  javax.servlet.jsp.JSPWrite                       Page
pageContext     javax.servlet.jsp.PageContext                  Page
config              javax.servlet.ServletConfig                     Page
page                java.lang.Object                                     Page
exception         java.lang.Throwable                               Page
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章