本篇将介绍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. BZOJ 1637: [Usaco2007 Mar]Balanced Lineup( sort + 前缀和 )

    将 0 变为 -1 , 则只需找区间和为 0 , 即前缀和相同的最长区间 , 记录一下每个前缀和出现的最早和最晚的位置 , 比较一下就 OK 了 --------------------------- ...

  2. Krita 3.0 发布,KOffice 的图像处理器(刺激一下自己的神经)

    Krita 3.0 发布了,经历了一年多的开发,动画功能被集成到Krita核心,改善了绘画功能,可及时预览绘画结果,该版本也是最新移植到QT的版本. 查看完整发布说明,可以点击这里. 下载地址: Wi ...

  3. Cognos 图表用图片取代”没有数据显示”

    在Cognos中做出来报表展示的时候因为没有数据感觉显示“没有可用数据”感觉很不美观.所以想用一张图片代替. 在图表的属性里面有一个“无数据内容”,点击打开之后有三个选项: 默认就是显示“没有可用数据 ...

  4. myeclipse自动生成注释

    myeclipse自动生成注释 在使用Eclipse编写Java代码时,自动生成的注释信息都是按照预先设置好的格式生成的,例如其中author的属性值. 我们可以在Eclipse中进行设置自己希望显示 ...

  5. NGUI字体贴图压缩以及相关Shader解读

    一般游戏中,字体贴图是游戏贴图压缩的一个重点,特别是对于中文的游戏.考虑的字体贴图的特殊性,一般我们输出的字体贴图是不含颜色信息的,所以正常情况下,我们输出的字体贴图RGBA每一个通道都是一样的.这样 ...

  6. 使用Jquery+EasyUI 进行框架项目开发案例解说之二---用户管理源代码分享

    使用Jquery+EasyUI 进行框架项目开发案例解说之二 用户管理源代码分享  在上一篇文章<使用Jquery+EasyUI进行框架项目开发案例解说之中的一个---员工管理源代码分享> ...

  7. 【Unity 3D】学习笔记四十:射线

    射线 射线,类比的理解就是游戏中的子弹.是在3D世界里中一个点向一个方向发射的一条无终点的线.在发射的过程中,一旦与其它对象发生碰撞,就停止发射. 射线的原理 创建一个射线时,首先须要知道射线的起点和 ...

  8. 华为s5700 添加与删除vlan

    新建vlan 删除vlan ① 检查该VLAN下是否存在成员接口,使用如下命令:display vlan all② 如存在成员接口,则进入该接口视图,删除该成员,否则可略过此步骤,例如:interfa ...

  9. 富文本编辑器 - wangEditor 插入代码

    效果: 项目结构: 注意事项: highlightJS 代码高亮插件,wangEditor 本身就是集成的highlightJS代码高亮插件. 在wangEditor-1.3.12.js里找到var ...

  10. typedef 总结

    其实在正儿八经学C语言的时候typedef用的不是很多,记得书上对它的介绍只是一笔带过.的确它的用法是很简单,但这不代表在使用的过程中不会出错,今天来个彻底的总结. 作用:用来建立新的数据类型名.(注 ...