由來:在jsp開發中,會頻繁使用到一些對象 。例如HttpSession,ServletContext,ServletContext,HttpServletRequet。所以Sun公司設計Jsp時,在jsp頁面加載完畢之后就會自動幫開發者創建好這些對象,開發者只需要直接使用這些對象調用方法即可!這些創建好的對象就叫內置對象,一共有九個。
內置對象名 | 類型 |
request | HttpServletRequest |
response | HttpServletResponse |
config | ServletConfig |
application | ServletContext |
session | Httpsession |
exception | Thrwable(錯誤處理頁面) |
page | Object(this:當前jsp翻譯的類如我們上次寫到的hello.jsp翻譯變成了hello_jsp.java中的生命周期方法) |
out | JspWriter |
pageContext | pageContext |
我們可以隨便打開一個以jsp翻譯的java源文件
public void _jspService(HttpServletRequest request, HttpServletResponse response) throws java.io.IOException, ServletException { PageContext pageContext = null; HttpSession session = null; ServletContext application = null; ServletConfig config = null; JspWriter out = null; Object page = this; JspWriter _jspx_out = null; PageContext _jspx_page_context = null; try { response.setContentType("text/html;charset=UTF-8"); pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 8192, true); _jspx_page_context = pageContext; application = pageContext.getServletContext(); config = pageContext.getServletConfig(); session = pageContext.getSession(); out = pageContext.getOut(); _jspx_out = out; String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; }
從上面可以看到內置對象都是在service方法中創建的,而指令和聲明是成員變量和方法,故不能在指令和聲明中使用內置對象
1、out對象
是jspWriter類,相當於帶緩存的PrintWriter。有點與PrintWriter方法相似
如果我們在jsp頁面執行以下代碼會發現
<% out.write("abc"); response.getWriter().write("2222223"); %>
因為out中添加了緩沖區的設置,所以在瀏覽器中先打印出后面的語句,前面的要等其緩沖區(默認大小是8kb)沒有滿,要等jsp頁面執行完之后才打印,我們也可以去手動刷新頁面
我們可以在jsp的指令部分去設置緩沖區大小
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" buffer="8kb"%>
我們繼續做實驗,在jsp頁面運行如下的代碼
<% out.write("abc"); //查看緩沖區的大小 System.out.println("當前緩沖區的大小:"+out.getBufferSize()); System.out.println("當前緩沖區的剩余大小:"+out.getRemaining()); %>
看到的結果是這樣的:
我們在瀏覽端發送了只有“abc”這樣3個字節,卻是用了兩百多個字節的大小,多余的部分去哪了呢?這個時候我們可以全看看out_jsp.java文件,
out.write("\r\n"); out.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\r\n"); out.write("<html>\r\n"); out.write(" <head>\r\n"); out.write(" <base href=\""); out.print(basePath); out.write("\">\r\n"); out.write(" <title>My JSP 'out.jsp' starting page</title>\r\n"); out.write(" </head>\r\n"); out.write(" <body>\r\n"); out.write(" \t"); out.write("abc"); //查看緩沖區的大小 System.out.println("當前緩沖區的大小:"+out.getBufferSize()); System.out.println("當前緩沖區的剩余大小:"+out.getRemaining()); out.write("\r\n"); out.write(" </body>\r\n"); out.write("</html>\r\n");
其實我們會發現,我們向瀏覽發送字節遠不止abc,其實還有一些標簽等的內容,他們是要發送到瀏覽器端,也是占大小的。
我們再來做一個實驗,如下代碼,
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" buffer="1kb"%> <% System.out.println(out.getRemaining()); for(int i=1;i<=1024;i++) out.write("a"); //查看緩沖區的大小 response.getWriter().write("郭慶興"); %>
看到這個時候的效果:
不知道為什么我這里出現了一開始的緩沖區大小是1022(我設置了應該是1kb buffer="1kb"),但是這不是我的重點,重點是他這個圖說明了緩沖區的運行機制,如果緩沖區滿了,就立即將其打印出來,沒有滿,就等待頁面執行完才打印,就像第一次1022緩沖區滿了之后去打印,然后又重新往里放兩個a,此時緩沖區沒有滿,就必須等待jsp頁面加載完后執行,所以出現在“郭慶興”的后面出現。
(我發現不知道哪里用了兩個字節使得一開始的緩沖區大小只有1022B,我有試了buffer="2kb"和buffer="3kb",發現其剩余大小都正常)
2、exception 對象
該對象表示其他頁面所拋出的異常對象(Throwable對象)
我們打開jsp翻譯后的java源文件發現,在該文件的service方法中居然里面八大內置對象都存在,就唯獨沒有該對象,這是因為我們沒有指定其為錯誤處理頁面,只有指定當前頁面為錯誤錯里頁面后才可以去使用它。
3、pageContext對象
jsp的上下文對象,為了我們更方便的去使用其他八個內置對象。
(例如當我們要在service方法之外去調用session對象或者request對象等,)
public void _jspService(request,response){
創建內置對象
HttpSession session =....;
ervletConfig config = ....;
把8個經常使用的內置對象封裝到PageContext對象中
PageContext pageContext = 封裝;
調用method1方法(如果將這八個內置對象一個一個的作為參數傳遞給下面的方法,顯然過於麻煩,這個時候我們可以使用已經封裝好了的pageContext作為參數傳遞過去明顯就簡單多了)
method1(pageContext);
}
public void method1(PageContext pageContext){
希望使用內置對象
從PageContext對象中獲取其他8個內置對象
JspWriter out =pageContext.getOut();
HttpServletRequest rquest = pageContext.getRequest();
........
}
注意:pageContext也是一個域對象,已經有四個域對象了:request,servletContext,還有session,現在又有pageContext,(cookie不是域對象,而是將數據發送到瀏覽器端保存),那么現在servlet已經有三個域對象了,而jsp有四個域對象(jsp就是一個servlet)。
#保存數據
1)默認情況下,保存到page域
pageContext.setAttribute("name");
2)可以向四個域對象保存數據
pageContext.setAttribute("name",域范圍常量)
#獲取數據
1)、默認情況下,從page域獲取
pageContext.getAttribute("name")
2)、可以從四個域中獲取數據
pageContext.getAttribute("name",域范圍常量)
PageContext.PAGE_SCOPE (page域)
PageContext.REQUEST_SCOPE(request域)
PageContext..SESSION_SCOPE(session域)
PageContext.APPLICATION_SCOPE(aplication域:即servletContext)
3)、自動在四個域中搜索數據
pageContext.findAttribute("name");
如果有相同的名字,則按照順序:page域 -> request域 -> session域- > context域(application域)
我們可以來對pageContext來做實驗
<% //pageContext作為域對象去保存數據 pageContext.setAttribute("message", "i am coming"); pageContext.setAttribute("message", "我是pageContext中設置的request域中的值,i am coming", pageContext.REQUEST_SCOPE); //request.setAttribute("name", "gqxing"); //等價於上面的代碼 request.setAttribute("value", "request's value"); %> <hr> <%-- 原則:在那個域中保存數據,必須在哪個域中取數據。 --%> <% //獲取數據 String message=(String)pageContext.getAttribute("message"); out.print(message+"<hr>"); String name=(String)request.getAttribute("message"); out.print(name); %> <hr> <span>用pageContext中的request域去取request域中設置的值(request.setAttribute("value", "request's value");)</span> <% String value=(String)pageContext.getAttribute("message", pageContext.REQUEST_SCOPE); out.print(value); %> <hr><span>用findattribute去查找:</span> <%-- findAttribute:自動搜索功能 順序:page域(pageContext)——>request域——>session域——>application域。 --%> <% String name3=(String)pageContext.findAttribute(message); out.print(name); %>
結果如圖所示:
關於四種域對象的理解
可以來試着去辨別各自的區別(jsp的四個域對象的作用范圍)
page域(pageContext):只能作用於當前頁面,既不能用來做做轉發的數據分享,也不能做重定向的數據分享
request域:只能作用於同一個請求的數據共享,所以只能在請求的轉發中使用
session域:只能作用於一次對話中共享數據(一次對話:用戶打開瀏覽器,瀏覽多個web站點后,關閉該瀏覽器),轉發和重定向都可以使用
context域(application):只能在同一個web應用中使用。(全局的)
我們可以做如下的實驗:
先用請求的轉發做一個實驗,如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'demo4.jsp' starting page</title> </head> <body> <%--數據的保存面 --%> <%pageContext.setAttribute("messsage", "page'vale",pageContext.PAGE_SCOPE); pageContext.setAttribute("message", "request'value",pageContext.REQUEST_SCOPE); pageContext.setAttribute("message", "session'value",pageContext.SESSION_SCOPE); pageContext.setAttribute("message", "context'value", pageContext.APPLICATION_SCOPE); %> <% request.getRequestDispatcher("/demo5.jsp").forward(request, response); %> </body> </html>
然后在另一個頁面去接受數據
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> </head> <body> page:<%=pageContext.getAttribute("message") %> <hr> request:<%=pageContext.getAttribute("message",pageContext.REQUEST_SCOPE) %> <hr> session:<%=pageContext.getAttribute("message",pageContext.SESSION_SCOPE) %> <hr> application(context):<%=pageContext.getAttribute("message",pageContext.APPLICATION_SCOPE) %> </body> </html>
最后發現結果如圖所示:
當我們將轉發方式改為重定向的時候,如下:
response.sendRedirect(request.getContextPath()+"/demo5.jsp");
這時結果如圖: