JSP页面out隐式对象和pageContext隐式对象

一.out隐式对象

out隐式对象是通过调用pageContext对象的getOut方法返回的,其作用与ServletResPonse.getWriter方法返回的PrintWriter对象非常相似,但两者为不同类型的对象。JSP页面的out对象类型为JspWriter,相当于一种带缓存的PrintWriter,可以在page指令里设置缓存的大小甚至关闭它的缓存。out对象会在满足某种条件时去调用ServletResponse.getWriter方法,并通过该方法返回的PrintWriter对象将out对象的缓冲区中的内容写入到Servlet引擎提供的缓冲区中。条件如下:

  • 设置page指令的buffer属性关闭了out对象的缓存功能
  • 写入到out对象中的内容充满了out对象的缓冲区
  • 整个JSP页面结束

如下测试:JSP页面

<%
    out.println("First Output");
    response.getWriter().println("Second Output<br>");
%>

输出

通过这个测试可以看出,尽管out对象的输出语句在前,但输出内同缺在后面,这是因为out对象只把内容写入到自身的缓冲区,在JSP页面结束时,才把内容写入到Servlet引擎的缓冲区,而PrintWriter类型的对象是直接把内容输出到Servlet引擎的缓冲区中。

对于Response对象,不能同时使用它的字符输出流和字节输出流!!!在JSP页面中,及其不推荐使用字节输出流。如下测试:

123456
<%
    ServletOutputStream sos = response.getOutputStream();
    sos.println("www.baidu.com");
%>

这个代码段在执行时会报错,那是因为在将这个JSP页面转换成一个Servlet时,123456会转换成out.print("123456"),这儿的out对象是JspWriter类型的对象,当在这个JSP页面结束时,out对象会调用Response对象的getWriter方法,因为前面使用过Response对象的字节输出流,此时在使用字符输出流就会导致异常,因此在JSP页面中及其不推荐使用字节输出流。除非这个页面不带"文本消息"且其余输出内容都用字节输出流处理,不过这样便丧失了使用JSP技术的意义。

如果在JSP页面使用转发语句,建议事先调用一次Response.getWriter,比如下例测试:

<body>
<%
    request.getRequestDispatcher("/test.html").forward(request,response);
%>
</body>

这个测试代码段会报错,那是因为<body>标签和</body>标签都会被当作文本消息输出,并且是由out对象来写入缓冲区,最后调用Response.getWriter对象来写入Servlet引擎缓冲区,而输出一个静态文件是通过缺省Servlet来访问的,缺省Servlet会根据转发前的Servlet使用的输出流来选择合适的输出流,如果转发Servlet没有使用过输出流,则缺省Servlet会使用字节流输出的,因此同时使用了Response对象的字节流和字符流导致异常。

二.pageContext对象

pageContext对象封装了当前JSP页面的运行信息,它提供了返回JSP页面的其他隐式对象的方法。pageContext对象是通过JspFactory.getPageContext方法返回的,getPageContext方法的完整语法如下:

public PageContext getPageContext(javax.servlet.Servlet servlet, javax.servlet.ServletRequest request,

                                                               javax.servlet.ServletResponse response, java.lang.String errorPageURL

                                                               boolean needsSession, int buffer, boolean autoflush)

参数的意义如下:

  1. servlet:当前JSP页面翻译成了Servlet对象
  2. request:当前请求对象
  3. response:当前响应对象
  4. errorPageURL:错误处理页
  5. needsSession:是否自动创建Session对象
  6. buffer:out对象的缓冲区大小
  7. autoflush:缓冲区满时是否自动刷新

pageContext对象封装了JSP页面所有其他的隐式对象,并且4-7号参数是通过page指令进行设置的,因此pageContext对象页封装了部分page指令的属性设置。

pushBody方法与popBody方法

pushBody方法和PopBody方法用于管理嵌套的JspWriter流,以便支持扩展标签的功能。一般不用调用pushBody和popBody方法,为了便于理解带标签的自定义标签的工作方式,这儿对pushBody与popBody的工作方式进行说明。pushBody与popBody的返回值类型都是BodyContent,BodyContent是JspWriter的一个子类,提过了一些扩展的功能,当调用pushBody时,会产生一个新的BodyContent,使out隐式对象指向这个新的BodyContent对象,而以前的JspWriter对象则被保存起来,当使用popBody方法时,将out隐式对象指向上次保存起来的JspWriter对象,并返回这个JspWriter对,没调用一个pushBody方法,最后都要调用一个popBody方法来恢复到之前的状态。如下测试:

<%@ page import="javax.servlet.jsp.tagext.BodyContent" %><%--
  Created by IntelliJ IDEA.
  User: Mloong
  Date: 2018/11/22
  Time: 10:48
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%
    JspWriter anotherOut=pageContext.getOut();
    if(anotherOut==out)
    {
        out.println("1.初始的pageContext.getOut方法的返回值"+"就是隐式out对象。<br>");
    }
    BodyContent out1=pageContext.pushBody();
    JspWriter out2=pageContext.getOut();
    if(out1==out2)
    {
        out.println("2.pageContext.pushBody方法与它后面调用的"+"pageContext.getOut方法的返回值相同。<br>");
    }
    if(out2!=out)
    {
        out.println("这个返回值不等于隐式out对象。");
        out2.println("此时写入到pageContext.getOut方法返回的"+
        "JspWriter对象中的内容不会发送给客户端,但是以后可以"+
        "将这些内容直接写入到另一个字符输出流对象中,或者"+
        "将这些内容以字符串返回后进行其他方式的处理!<br>");

        out1.writeOut(((BodyContent)out2).getEnclosingWriter());
        out.println("将上面内容以字符串返回后再输出一篇:"+out1.getString());
    }
    JspWriter out3=pageContext.popBody();
    JspWriter out4=pageContext.getOut();
    if(out3==out4)
    {
        out.println("3.pageContext.popBody方法与它后面调用的pageContext.getOut方法的返回值相同。<br>");
    }
    if(out4==out)
    {
        out.println("这个返回值又等于隐式out对象了。<br>");
    }
%>
</body>
</html>

输出如下:

 

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值