首页 > 代码库 > Jsp(3):内置对象和四种域对象的理解

Jsp(3):内置对象和四种域对象的理解

由来:在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=http://www.mamicode.com/"");
      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=http://www.mamicode.com/(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");

这时结果如图:

技术分享

 

Jsp(3):内置对象和四种域对象的理解