由來:在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");
這時結果如圖:

