本篇将介绍JSP中的九大隐式对象,并重点介绍其中的out对象。

  我们在之前的博客《JSP的学习(1)——基础知识与底层原理》一文中已经知道,JSP最终要被翻译和转换成Servlet,在转换后的Servlet中,由_jspService(…)方法代替我们以前直接使用Servlet中的service()方法,其实两个功能都是一样的,都是作为浏览器来访问,然后由服务器调用的方法。

  但JSP在转换成Servlet后,在这个Servlet中的_jspService(…)方法会自动根据我们在JSP中的一些指令,相应的生成一些对象,可供我们在JSP上直接使用这些对象,而不需要再重新使用类来创建,总共在JSP中共有直接可调用的九大隐式对象:

  1. request
  2. response
  3. page
  4. application
  5. session
  6. config
  7. exception
  8. out
  9. pageContext

  在《JSP的学习(1)——基础知识与底层原理》一文中也已经提到,这几个对象我们可以从Tomcat的【work】目录下由JSP转换后对应的.java文件可以看到在_jspService(…)方法对其中一些对象的定义:

  

我们对其中几个对象进行快速说明:

  request和response 分别代表了浏览器发来的请求对象和服务器回送浏览器的响应对象,这两个对象在之前学习Servlet时都开专门的几篇博客讲过,这里的也是一样的用法,因此不多再做叙述。

从截图来看:

  page对象代表了JSP转换后的该Servlet(因为可以看截图中定义”this”)。

  application是ServletContext的对象,因此ServletContext能怎么使用那么application在JSP中也就能怎么使用,具体请看《Servlet的学习之ServletContext(1)》。

  session对象由JSP转换后的Servlet在_jspService(…)方法中定义和创建,注意如果在JSP页面中使用page指令将”session”指令置为”false”,那么Servlet将不会对其进行创建。当然如果创建了session,那么功能还是同之前学习Servlet时的Session对象一样,具体请看《Servlet的学习之Session(1)》系列。

  config对象也由JSP转换后的Servlet在_jspService(…)方法中定义和创建,也可以按之前学习ServletConfig对象的方法作用于config对象,具体请看《Servlet的学习之ServletContext(1)》 。

  以上三个对象(application、session、config)不仅仅声明,而是都会自动创建:

  

  exception对象我们说过,这个对象如果要想能被Servlet自动定义和创建,那么这个页面就必须有“isErrorPage”属性置为”true”的这个page指令(<%@  page  isErrorPage="true" %>),通常来说我们对于这个JSP都是用作错误处理页面的用处。下图为设置了“isErrorPage”属性后Servlet自动创建exception对象:

  

  切记,一般平常没设置isErrorPage属性的JSP是不能直接使用exception对象的,而这对象的不容易出现,也造成很多人会忘记JSP还有这个隐式对象。

  接下来还有out对象和pageContext对象,这两个对象因为和之前Servlet的学习中有很大的不一样或者以前没有这个定义,所以是我们学习JSP隐式对象中的重点。本篇先来学习JSP中的out对象,而pageContext对象将在下一篇中进行学习。

===============================重点对象分割线==============================

  out对象用于JSP向客户端浏览器发送文本数据,我们之前在查看由JSP转换后的.java文件中可以看到,Servlet正是通过out对象,将JSP中所有的模板元素(HTML标签之类)和内容显示都以out对象的方法将其写入response对象中,并响应回浏览器:

  

  out对象是用过pageContext对象(后一篇会介绍到)的getOut()方法返回的,同时记住out对象是字符流对象,其作用和用法与ServletResponse.getWriter()方法返回的PrintWriter对象十分类似:

  

  out对象是JspWriter类的一个实例,至于JspWriter类,其实在幕后还是PrintWriter类,只是JspWriter具有缓存,只有JspWriter中的缓存进行了刷新后才创建PrintWriter类(是JspWriter幕后创建PrintWriter),并将JspWriter对象中的内容写入到PrintWriter类对象中。

  out对象(JspWriter的实例)是具有缓存的,这个缓存是由page指令中的“buffer”属性设置,我们在《JSP的学习(3)——语法知识二之page指令》已经学习了,“buffer”属性默认具有8kb字节的缓存,可以设置为“none”关闭JspWriter的缓存,也可以设置“XXXkb”来重新设置JspWriter的缓存。

  使用out对象写入了内容,只有满足以下任一条件时,out对象才去调用ServletResponse.getWriter()方法,通过PrintWriter对象将out对象缓冲区中的内容写到Response响应对象中:

  ① 设置page指令将“buffer”属性为“none”

  ② out对象的buffer已满

  ③ 整个JSP页面执行完毕

关于out对象两个示例的结论需要知道:

  1,如果在JSP页面上同时使用out对象和response.getWriter()对象进行输出,不管哪个对象在前面调用write()方法,都是response.getWriter()对象会先输出数据。说到这里不妨回顾下上一篇博客《JSP的学习(5)—语法知识三之include指令》中最后一个动态包含的例子,看看访问JSP页面后中的源码里面的内容。

  我们这里继续再做一个小例子:创建一个web工程【JSPLearning】, 在index.jsp中的<body>模板元素中将内容修改如下:

     <body>
<%
out.write("这是JspWriter对象输出的内容");
response.getWriter().write("这是PrintWriter对象输出的内容");
%>
</body>

那么在访问JSP页面时会发生什么情况呢?我们开启服务器,部署该web工程,对index.jsp页面进行访问:

  

从访问结果来看,并不是我们所期望的显示顺序,我们再来看看源码:

  

  从源码可以看到,结果正如我们开始结论所说的,使用ServletResponse.getWriter()方法获得的PrintWriter对象输出都会比out对象获得的JspWriter对象输出要早,无论两者顺序如何。

  这是由于通过PrintWriter对象输出的数据直接到Response响应对象的缓冲区中,而JspWriter通过out对象输出由于不满足某些条件(例如未使buffer满或者未到JSP页面结束),都无法幕后创建一个PrintWriter对象再将out对象缓冲区中的数据送到Response响应对象的缓冲区中。只有当JSP页面执行结束或者使out对象的buffer满时,才将数据再通过调用response.getWriter()获得的PrintWriter对象将数据送到Response响应对象的缓冲区中,但此时,Response响应对象中早已经有了通过直接调用Response.getWriter().write()方法所写入的内容

  请看如下动图,展示了这个例子的流程:

  因此我们在JSP的编写代码中,应该尽量采用out对象这个隐式对象来输出数据。

  2,如果我们要使用JSP来作为文件下载的方式,那么在JSP页面中我们不能使用out对象,因为out对象是字符流,而是应该使用response.getOutputStream()方法来获得字符流对象,并且在JSP页面中不能出现任何由out对象输出的数据(例如一些HTML标签和空格之类,这些可以在转换后的Servlet中查看是否还有)。

  我们来做一个使用JSP下载的示例,在MyEclipse中创建一个web工程【JSPLearning】,并且在【WebRoot】目录下新建一个【download】目录,添加进一张“1.jpg”图片:

  

然后直接在“index.jsp”中操作好了,我们在<body>标签中的代码如下:

     <body>
<%
String filePath = application.getRealPath("/download/1.jpg");
String fileName = filePath.substring(filePath.lastIndexOf("\\")+1); response.setHeader("content-disposition", "attachment;filename="+fileName); FileInputStream fis = new FileInputStream(filePath);
byte[] buffer = new byte[1024];
int len = 0;
while((len = fis.read(buffer))>0) {
response.getOutputStream().write(buffer, 0, len);
}
%>
</body>

如下图所示:

  

  这样就能下载了吗,当然不行,因为这些里面的<html>、<head>、<title>等等都是由out这个字符流对象输出的,如果这么操作,那么服务器肯定会有getOutputStream() has already been called for this response这个异常(《Servlet的学习之Response响应对象(3)》)。

  那么既然我们不能在JSP页面中同时用到字符流和字节流的话,那么应该怎么做呢?

因为图片不是字符,所以只能用字节流输出,那么我们只能将JSP中所有会被out对象用write()方法写出的数据全部删除,比如<html>、<head>、<title>等等这些,因此我们的JSP页面应该是成为这样:

  

  貌似就已经把该JSP页面中会通过out对象输出的内容都清理完,这样就完了吗?嗯……还差一点,我们先来访问下这个JSP,虽然可以下载文件,但发现还是会有getOutputStream() has already been called for this response这个异常:

  

我们不妨来看看这个“index.jsp”对应的Servlet文件:

  

  是的,还有换行,这个比较难发现,所以一般在JSP中使用字节流一定要看看对应的Servlet中到底还有没有通过out对象输出的数据,尤其是这些换行和空格之类的,我们再来看看修改后的样子:

  

  不留任何换行,这一次重新来访问该JSP,浏览器弹出下载窗口,服务器也没有抛出异常,因此这样就解决了getOutputStream() has already been called for this response这个异常。

  最后我们再来看看该“index.jsp”对应的Servlet文件源码,我们可以看到这时候已经没有任何通过out对象输出的数据,包括换行。但是out对象是依然有的,通过pageContext对象的getOut方法建立。也就是说,在JSP中,虽然该Servlet通过getOut方法获得了JspWriter这个字符流对象,但是只要没有使用,依然可以由JSP通过响应对象再获得字节流:

  

  于是,这篇介绍JSP中几个隐式对象和重点学习了下out对象,那么本篇博客就该结束了,等等,最后那个下载的图片到底是什么啊??哈哈,当然是我们可爱的银魂一家子:

  

JSP的学习(6)——九大隐式对象及其out对象的更多相关文章

  1. JSP页面以及JSP九大隐式对象

    €JSP全称是Java Server Pages,它和servle技术一样,都是SUN公司定义的一种用于开发动态web资源的技术. €JSP这门技术的最大的特点在于,写jsp就像在写html,但它相比 ...

  2. jsp学习--JSP运行原理,九大隐式对象和JSP常用标签

    一.JSP运行原理 每个JSP 页面在第一次被访问时,WEB容器都会把请求交给JSP引擎(即一个Java程序)去处理.JSP引擎先将JSP翻译成一个_jspServlet(实质上也是一个servlet ...

  3. JSP中的九大隐式对象及四个作用域

    在这篇博文中,我们将讨论和学习JSP中的隐式对象及四个作用域. 一.九大隐式对象 这些对象是JSP容器为每个页面中的开发人员提供的Java对象,开发人员可以直接调用它们而不用显式地声明它们再调用. J ...

  4. JSP九大隐式对象和四大域对象-----面试

    因为jsp实质是一个Servlet对象:jsp在第一次访问时会被Web容器翻译成Servlet,在执行过程:第一次访问---->inex.jsp---->index_jsp.java--- ...

  5. JSP JSP工作原理 JSP语法 JSP声明 JSP注释 JSP指令 jsp九大隐式/内置对象

    1 什么是JSP   1)为什么说,Servlet是一个动态Web开发技术呢?     Servlet是基于服务端的一种动态交互技术,     HttpServletRequest表示客户端到服务端的 ...

  6. JSP九大隐式对象

    JSP九大隐式对象 request HttpServletRequest response HttpServletResponse session HttpSession application Se ...

  7. 四大域对象,和jsp的九大隐式对象,已经el表达式的11个隐式对象

    四大域对象 1.PageContext :页面范围的数据 2.ServletRequest:请求范围的数据 3.HttpSession:回话范围的数据 4.ServletContext:应用范围的数据 ...

  8. JSP--JSP语法--指令---九大隐式对象--四大域对象--JSP内置标签--JavaBean的动作元素--MVC三层架构

    一.JSP 原理:JSP其实就是一个servlet. Servlet负责业务逻辑处理,JSP只负责显示.开发中,JSP中不能有一行JAVA代码 二.JSP语法 1. JSP模板元素:JSP中HTML标 ...

  9. JSP--JSP语法--指令--include(动态包含/静态包含)--九大隐式对象--四大域对象--JSP内置标签--JavaBean的动作元素--MVC三层架构

    一.JSP 原理:JSP其实就是一个servlet. Servlet负责业务逻辑处理,JSP只负责显示.开发中,JSP中不能有一行JAVA代码 二.JSP语法 1.    JSP模板元素:JSP中HT ...

随机推荐

  1. c/c++字符数组和字符串大揭秘

    第一:写这篇文章源于我对'\0'和“\0”的探讨 当我对char a []="\0"; int size_a=sizeof(a); //结果为2 当时我很纳闷字符串不是以'\0'结 ...

  2. [Swust OJ 552]--拼音教学(找规律)

    题目链接:http://acm.swust.edu.cn/problem/0552/ Time limit(ms): 1000 Memory limit(kb): 65535   Descriptio ...

  3. Linux 开放服务端口

    CentOS 6.5上安装Tomcat 服务器,需要开放服务端口,供其他计算机访问部署在Tomcat中的Web应用.下面是开放端口的方法. 我知道的方法有两种.下面以开放8080端口为例. 方法一:命 ...

  4. python——登陆接口设计(循环方法)

    近日重新整理了登陆接口设计程序,感觉以前的代码没有注释,让园子的其他童鞋读起来比较费劲.也没有流程图和程序运行说明. 1.流程图 2.user_file.txt&lock_file.txt文件 ...

  5. Ubuntu14.04 Y460闪屏问题解决方案

    我的笔记本是联想Y460,安装了Ubuntu之后发现屏幕闪烁移位,而且在使用IDE的时候出现无法输入中文等问题,其实是显卡驱动的问题,N卡官网给的驱动不好用,尝试使用大黄蜂 参考:https://wi ...

  6. Google Code Jam Round 1A 2015 Problem B. Haircut 二分

    Problem You are waiting in a long line to get a haircut at a trendy barber shop. The shop has B barb ...

  7. 基于FPGA的DW8051移植(二)

    基于上一篇博文继续,本来想换到oc8051,但是还是不甘心,弄了这么久还是没有弄出来,真是打击屎了. 上一篇说3f进入了operation code所以判断是代码错误,后来发现不可以这么判断. 因为地 ...

  8. 17.1.1 How to Set Up Replication

    17.1.1 How to Set Up Replication 17.1.1.1 Setting the Replication Master Configuration 17.1.1.2 Sett ...

  9. 【Flume NG用户指南】(1)设置

    作者:周邦涛(Timen) Email:zhoubangtao@gmail.com 转载请注明出处:  http://blog.csdn.net/zhoubangtao/article/details ...

  10. OCP-1Z0-051-题目解析-第25题

    25. You need to create a table with the following column specifications:  1. Employee ID (numeric da ...