一、JSP运行原理
Web容器(Servlet引擎)接收到.jsp为扩展名的URL访问请求时,它将把该访问请求交给JSP引擎去处理,JSP引擎负责解释和执行JSP页面。
当Web容器接收到客户端的访问请求时,它将根据请求的URL在web.xml配置文件中查找匹配<servlet-mapping>元素,然后将请求交给元素中指定的servlet程序去处理,打开Tomcat下conf\web.xml文件可以发现以.jsp为扩展名的访问请求实际由JspServlet负责处理。
每个JSP页面在第一次被访问时,JSP引擎将它翻译成一个Servlet源程序,接着再把这个Servlet源程序编译成Servlet的class文件,然后再由Servlet引擎像调用普通Servlet程序一样的方式来装载和解释执行这个由JSP页面翻译成的servlet程序。
将JSP页面翻译成Servlet程序后再运行的机制有一个明显的好处,那就是JSP引擎仅需要将JSP页面翻译为Servlet程序,而与客户端的交互过程仍然由Servlet引擎来处理,重复利用了已有的Servlet引擎技术。
二、在JSP程序使用out.print与out.write的区别
print系列方法可将各种类型的数据转换成字符串的形式输出;write系列方法只能输出字符、字符数组和字符串等与字符相关的数据。
在<%= %>的表达式相当于在<% %>使用out.printl()方法。
三、JSP隐式对象(9个)
1、9个隐式对象介绍
JSP提供了9个预先定义的变量,这些变量也被称为隐式对象,某些书籍则称为JSP内部对象。这9个隐式对象分别是:
config,ServletConfig类型的实例对象
application,ServletContext类型的实例对象
request,作为_jspService(可以认为就相当于HttpServlet中的service方法)方法的参数(HttpServletRequest request)传递进来的
response,作为_jspService方法的参数(HttpServletResponse response)传递进来的
session,HttpSession的实例对象
page,对象的类型为Object,它被赋值为this,即代表JSP页面所编译成的Servlet对象自身,当前用处不大
exception,该对象只能在处理错误的JSP页面中使用,后面讲解
以及——
out对象
pageContext对象
2、out对象
out对象是通过调用pageContext对象的getOut方法返回的,其作用及用法与ServletResponse.getWriter方法返回的PrintWriter对象非常相似,但out隐式对象类型为JspWriter,JspWriter相当于一种带缓存功能的PrintWriter,设置page指令的buffer属性可以调整它的缓存大小,甚至关闭它的缓存。
只有向out对象中写入了内容,且满足以下任何一个条件,out对象才会去调用ServletResponse.getWriter方法,并通过该方法返回的PrintWriter对象将out对象的缓冲区中的内容真正写入到Servlet引擎提供的缓冲区中:
设置page指令的buffer属性关闭了out对象的缓存功能
写入到out对象中的内容充满了out对象的缓冲区
JSP页面结束
(1)
<%
out.println("first line<br>");
response.getWriter().println("second line<br>");
%>
用浏览器访问,发现显示结果为:
second line
first line
这是因为out.println语句只是把内容写入到了out对象的缓冲区中,直到整个JSP页面结束时,out对象才把它的缓冲区里面的内容真正写入到Servlet引擎提供的缓冲区中,而response.getWriter.println语句则是真正把内容写入到Servlet引擎提供的缓冲区中。
(2)
<%
ServletOutputStream sos = response.getOutputStream();
sos.println("www.baidu.com");
%>
如果在<%前面或最后的%>后面输入了任意字符,访问该JSP页面会报异常。因为位于JSP脚本元素之外的任何字符文本,在JSP页面所翻译成的Servlet程序中以out.write方法输出到客户端。由于只要向out对象写入了内容,它就会在JSP页面结束时调用getWriter方法,这就与getOutputStream方法发生了冲突。
3、pageContext对象
(这里就知道jsp-api包是干什么的?如果没有这个包,jsp页面根本不认识pageContext这个预定义对象)
pageContext对象封装了当前JSP页面的运行信息,它提供了返回JSP页面的其他隐式对象的方法。PageContext类中定义了一个setAttribute方法来将对象存储进pageContext对象内部的一个HashMap对象中,同时定义了一个getAttribute方法来获取存储在HashMap对象中的对象,以便在JSP页面与调用的普通Java类之间传递对象信息。PageContext除了可以存储和检索自身的属性对象外,还定义了可以检索其他域范围内的属性对象的方法。
(1)、获得其他隐式对象:
getException
getPage
getRequest
getResponse
getServletConfig
getServletContext
getSession
getOut
(2)、引入和跳转到其他资源
PageContext类中定义了一个forward和两个include方法来简化和替代RequestDispatcher.forward方法和RequestDispatcher.include方法的调用,完整定义为:
public void forward(String relativeUrlPath) throws ...Exception
public void include(String relativeUrlPath) throws ...Exception
public void include(String relativeUrlPath, boolean flush) throws ...Exception
传递给这些方法的资源路径都只能是相对路径,如果路径以“/”开头,表示相对于当前Web应用程序的根目录,否则表示相对于当前JSP所映射的访问路径。
第一个include方法在引入资源前先将out对象中的内容刷新到Servlet引擎提供的缓冲区中;第二个include方法则通过一个参数来决定在引入资源前是否刷新out对象中的内容。
forward方法在将请求转发给其他资源之前,先清空out对象中已写入的内容,然后调用RequestDispatcher.forward方法执行请求转发。
(3)访问各个域范围的属性
在application、session、request、pageContext对象中都可以调用setAttribut方法和getAttribute方法来设置和检索属于各自域范围内的属性。存储在application对象中的属性可以被同一个Web应用程序中的所有Servlet和JSP页面访问;存储在session对象中的属性可以被属于同一个会话的所有Servlet和JSP页面访问;存储在request对象中的属性可以被属于同一个请求的所有Servlet和JSP页面访问。存储在pageContext对象中的属性仅可以被当前JSP页面的当前响应过程(下次响应则不同)的各个组件访问。
此外,PageContext类中还提供了对各个域范围的属性进行统一管理的方法。
setAttribute方法
两种重载形式:
setAttribute(String name, Object o) // 默认把对象存储在page域范围(就是存储到pageContext对象)中
setAttribute(String name, Object o, int scope) //scope表示把对象存储进指定的域范围,PageContext定义了4个整数常量,分别是APPLICATION_SCOPE,SESSION_SCOPE,REQUEST_SCOPE,PAGE_SCOPE
getAttribute方法(两种)
removeAttribute方法(两种)
findAttribute方法
用于依次从page、request、session、application域范围查找某个指定名称的属性,找到则返回指定对象,否则返回null。