一、JSP運行原理
每個JSP 頁面在第一次被訪問時,WEB容器都會把請求交給JSP引擎(即一個Java程序)去處理。JSP引擎先將JSP翻譯成一個_jspServlet(實質上也是一個servlet) ,然后按照servlet的調用方式進行調用。
由于JSP第一次訪問時會翻譯成servlet,所以第一次訪問通常會比較慢,但第二次訪問,JSP引擎如果發現JSP沒有變化,就不再翻譯,而是直接調用,所以程序的執行效率不會受到影響。
JSP引擎在調用JSP對應的_jspServlet時,會傳遞或創建9個與web開發相關的對象供_jspServlet使用。JSP技術的設計者為便于開發人員在編寫JSP頁面時獲得這些web對象的引用,特意定義了9個相應的變量,開發人員在JSP頁面中通過這些變量就可以快速獲得這9大對象的引用。
二、認識九個內置對象
NO. | 內置對象 | 類型 |
1 | pageContext | javax.servlet.jsp.PageContext |
2 | request | javax.servlet.http.HttpServletRequest |
3 | response | javax.servlet.http.HttpServletResponse |
4 | session | javax.servlet.http.HttpSession |
5 | application | javax.servlet.ServletContext |
6 | config | javax.servlet.ServletConfig |
7 | out | javax.servlet.jsp.JspWriter |
8 | page | java.lang.Object |
9 | exception | java.lang.Throwable |
request,response,session,application,config這些對象在前面都已經作了詳細的介紹,這里重點介紹一下剩下的pageContext對象,out對象,page對象。
三、內置對象使用說明
3.1、page對象
page對象表示當前一個JSP頁面,可以理解為一個對象本身,即:把一個JSP當作一個對象來看待。page對象在開發中幾乎不用,了解一下即可
3.2、out對象
out對象用于向客戶端發送文本數據。
out對象是通過調用pageContext對象的getOut方法返回的,其作用和用法與ServletResponse.getWriter方法返回的PrintWriter對象非常相似。
JSP頁面中的out對象的類型為JspWriter,JspWriter相當于一種帶緩存功能的PrintWriter,設置JSP頁面的page指令的buffer屬性可以調整它的緩存大小,甚至關閉它的緩存。
只有向out對象中寫入了內容,且滿足如下任何一個條件時,out對象才去調用ServletResponse.getWriter方法,并通過該方法返回的PrintWriter對象將out對象的緩沖區中的內容真正寫入到Servlet引擎提供的緩沖區中:
- 設置page指令的buffer屬性關閉了out對象的緩存功能
- out對象的緩沖區已滿
- 整個JSP頁面結束
out對象的工作原理圖
3.3、pageContext對象
pageContext對象是JSP技術中最重要的一個對象,它代表JSP頁面的運行環境,這個對象不僅封裝了對其它8大隱式對象的引用,它自身還是一個域對象(容器),可以用來保存數據。并且,這個對象還封裝了web開發中經常涉及到的一些常用操作,例如引入和跳轉其它資源、檢索其它域對象中的屬性等。
3.4、通過pageContext獲得其他對象
- getException方法返回exception隱式對象
- getPage方法返回page隱式對象
- getRequest方法返回request隱式對象
- getResponse方法返回response隱式對象
- getServletConfig方法返回config隱式對象
- getServletContext方法返回application隱式對象
- getSession方法返回session隱式對象
- getOut方法返回out隱式對象
3.5、pageContext封裝其它8大內置對象的意義
如果在編程過程中,把pageContext對象傳遞給一個普通java對象,那么這個java對象將可以獲取8大隱式對象,此時這個java對象就可以和瀏覽器交互了,此時這個java對象就成為了一個動態web資源了,這就是pageContext封裝其它8大內置對象的意義,把pageContext傳遞給誰,誰就能成為一個動態web資源,那么什么情況下需要把pageContext傳遞給另外一個java類呢,什么情況下需要使用這種技術呢,在比較正規的開發中,jsp頁面是不允許出現java代碼的,如果jsp頁面出現了java代碼,那么就應該想辦法把java代碼移除掉,我們可以開發一個自定義標簽來移除jsp頁面上的java代碼,首先圍繞自定義標簽寫一個java類,jsp引擎在執行自定義標簽的時候就會調用圍繞自定義標簽寫的那個java類,在調用java類的時候就會把pageContext對象傳遞給這個java類,由于pageContext對象封裝了對其它8大隱式對象的引用,因此在這個java類中就可以使用jsp頁面中的8大隱式對象(request,response,config,application,exception,Session,page,out)了,pageContext對象在jsp自定義標簽開發中特別重要。
3.6、pageContext作為域對象
pageContext對象可以作為容器來使用,因此可以將一些數據存儲在pageContext對象中。
pageContext對象的常用方法
1 public void setAttribute(java.lang.String name,java.lang.Object value) 2 public java.lang.Object getAttribute(java.lang.String name) 3 public void removeAttribute(java.lang.String name) 4 public java.lang.Object findAttribute(java.lang.String name)
重點介紹一下findAttribute方法,這個方法是用來查找各個域中的屬性的,查看這個方法的API可以看到關于這個方法的描述:
Searches for the named attribute in page, request, session (if valid), and application scope(s) in order and returns the value associated or null.
當要查找某個屬性時,findAttribute方法按照查找順序"page→request→session→application"在這四個對象中去查找,只要找到了就返回屬性值,如果四個對象都沒有找到要查找的屬性,則返回一個null。
范例:使用pageContext的findAttribute方法查找屬性值
1 <%@page contentType="text/html;charset=UTF-8"%> 2 <%@page import="java.util.*"%> 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <head> 5 <title>pageContext的findAttribute方法查找屬性值</title> 6 </head> 7 <% 8 pageContext.setAttribute("name1", "孤傲蒼狼"); 9 request.setAttribute("name2", "白虎神皇"); 10 session.setAttribute("name3", "玄天邪帝"); 11 application.setAttribute("name4", "滅世魔尊"); 12 %> 13 <% 14 //使用pageContext的findAttribute方法查找屬性,由于取得的值為Object類型,因此必須使用String強制向下轉型,轉換成String類型 15 //查找name1屬性,按照順序"page→request→session→application"在這四個對象中去查找 16 String refName1 = (String)pageContext.findAttribute("name1"); 17 String refName2 = (String)pageContext.findAttribute("name2"); 18 String refName3 = (String)pageContext.findAttribute("name3"); 19 String refName4 = (String)pageContext.findAttribute("name4"); 20 String refName5 = (String)pageContext.findAttribute("name5");//查找一個不存在的屬性 21 %> 22 <h1>pageContext.findAttribute方法查找到的屬性值:</h1> 23 <h3>pageContext對象的name1屬性:<%=refName1%></h3> 24 <h3>request對象的name2屬性:<%=refName2%></h3> 25 <h3>session對象的name3屬性:<%=refName3%></h3> 26 <h3>application對象的name4屬性:<%=refName4%></h3> 27 <h3>查找不存在的name5屬性:<%=refName5%></h3> 28 <hr/> 29 <h1>使用EL表達式進行輸出:</h1> 30 <h3>pageContext對象的name1屬性:${name1}</h3> 31 <h3>request對象的name2屬性:${name2}</h3> 32 <h3>session對象的name3屬性:${name3}</h3> 33 <h3>application對象的name4屬性:${name4}</h3> 34 <h3>不存在的name5屬性:${name5}</h3>
運行結果:
EL表達式語句在執行時,會調用pageContext.findAttribute方法,用標識符為關鍵字,分別從page、request、 session、application四個域中查找相應的對象,找到則返回相應對象,找不到則返回”” (注意,不是null,而是空字符串)。
pageContext對象中封裝了訪問其它域的方法
1 public java.lang.Object getAttribute(java.lang.String name,int scope) 2 public void setAttribute(java.lang.String name, java.lang.Object value,int scope) 3 public void removeAttribute(java.lang.String name,int scope)
代表各個域的常量
1 PageContext.APPLICATION_SCOPE 2 PageContext.SESSION_SCOPE 3 PageContext.REQUEST_SCOPE 4 PageContext.PAGE_SCOPE
范例:pageContext訪問其它域
1 <%@page contentType="text/html;charset=UTF-8"%> 2 <%@page import="java.util.*"%> 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <head> 5 <title>pageContext訪問其它域</title> 6 </head> 7 <% 8 //此時相當于往session對象中存放了一個name屬性,等價于 session.setAttribute("name","孤傲蒼狼"); 9 pageContext.setAttribute("name","孤傲蒼狼",PageContext.SESSION_SCOPE); 10 %> 11 <% 12 //取得session對象的屬性,使用pageContext對象獲取 13 String refName1 = (String)pageContext.getAttribute("name",PageContext.SESSION_SCOPE); 14 //由于取得的值為Object類型,因此必須使用String強制向下轉型,轉換成String類型 15 String refName2 = (String)session.getAttribute("name"); 16 %> 17 <h1>取出存放在session對象中的屬性值:</h1> 18 <p>第一種做法:使用pageContext.getAttribute("attributeName",PageContext.SESSION_SCOPE);去取出session對象中值</p> 19 <h3>姓名:<%=refName1%></h3> 20 <p>第二種做法:使用session.getAttribute("attributeName");去取出session對象中值</p> 21 <h3>姓名:<%=refName2%></h3>
3.7、PageContext引入和跳轉到其他資源
PageContext類中定義了一個forward方法(用來跳轉頁面)和兩個include方法(用來引入頁面)來分別簡化和替代RequestDispatcher.forward方法和include方法。
方法接收的資源如果以“/”開頭, “/”代表當前web應用。
范例:使用pageContext的forward方法跳轉到其他頁面
1 <%@page contentType="text/html;charset=UTF-8"%> 2 <%@page import="java.util.*"%> 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <head> 5 <title>使用pageContext的forward方法跳轉頁面</title> 6 </head> 7 <% 8 //使用pageContext的forward方法跳轉到pageContextDemo05.jsp頁面,/代表了當前的web應用 9 pageContext.forward("/pageContextDemo05.jsp"); 10 //使用pageContext.forward(relativeUrlPath)替代RequestDispatcher.forward(relativeUrlPath) 11 //使用RequestDispatcher的forward方法實現的跳轉方式 12 //pageContext.getRequest().getRequestDispatcher("/pageContextDemo05.jsp").forward(request, response); 13 %>
運行結果如下:
1 pageContext.forward("/pageContextDemo05.jsp");
這種寫法是用來簡化和替代pageContext.getRequest().getRequestDispatcher("/pageContextDemo05.jsp").forward(request, response);這種寫法的。在實際開發中,使用pageContext.forward(relativeUrlPath)方法跳轉頁面用得不多,主要是因為要在Jsp頁面中嵌套java代碼,所以這種做法簡單了解一下即可,在開發中,要想從一個Jsp頁面采用服務器端跳轉的方式跳轉到另一個Jsp頁面,那么一般會使用<jsp:forward>標簽,<jsp:forward>標簽用于把請求轉發給另外一個資源。
范例:使用pageContext的include方法引入資源
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 3 <head> 4 <title>使用pageContext的include方法引入資源</title> 5 </head> 6 <% 7 pageContext.include("/jspfragments/head.jsp"); 8 %> 9 使用pageContext的include方法引入資源 10 <% 11 pageContext.include("/jspfragments/foot.jsp"); 12 %> 13 <hr/> 14 <%-- 15 <jsp:include page="/jspfragments/head.jsp"/> 16 使用jsp:include標簽引入資源 17 <jsp:include page="/jspfragments/foot.jsp"/> 18 --%>
運行結果:
在實際開發中,使用pageContext的include方法引入頁面這種做法也很少用,一般都使用jsp:include標簽引入資源,因此這種做法了解一下即可。
文章列表