Jsp:内置对象和四种域对象的理解
由来:在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");
这时结果如图: