3.1 JSP概述
JSP页面其实是一个Servlet。但是,使用JSP页面则比Servlet要容易得多,这有两个原因:第一,不需要编译JSP页面;第二,JSP页面一般是扩展名为jsp的文本文件,可以利用任何文本编辑器来编写。
JSP页面是在JSP容器中运行的。Servlet容器一般也是JSP容器。例如,Tomcat就是一个Servlet/JSP容器。
第一次请求一个JSP页面时,Servlet/JSP容器要做两件事情:
- 将JSP页面转换成一个JSP页面实现类,这是一个实现javax.servlet.jsp.JspPage接口或其子接口javax.servlet.jsp.HttpjspPage的Java类。JspPage是javax.servlet.Servlet的子接口,这样会使每个JSP页面都成为一个Servlet。所生成Servlet的类名取决于Servlet/JSP容器。这一点不必操心,因为不需要你直接处理。如果有转换错误,错误消息将会发送到客户端。
- 如果转换成功,Servlet/JSP容器将会编译Servlet类。之后,容器加载和实例化Java字节码,并执行它通常对Servlet所做的生命周期操作。
对于同一个JSP页面的后续请求,Servlet/JSP容器会查看这个JSP页面自从最后一次转换以来是否修改过。如果修改过,就会重新转换、重新编译,并执行。如果没有,则执行内存中已经存在的JSP Servlet。这样,第一次调用JSP页面的时间总是会比后续请求的更长,因为它需要转换和编译。为了解决这个问题,可以采取以下任意一种措施:
配置应用程序,以便在应用程序启动之时,调用所有的JSP页面(实际上是指转换和编译),而不是在初始请求时才调用。
预先编译JSP页面,并将它们以Servlet的方式进行部署。
JSP中有一个API,其中包含4个包:
javax.servlet.jsp。包含核心类和接口,Servlet/JSP容器用它们将JSP页面转换成Servlet。JspPage和HttpJspPage接口是这个包中的重要成员。所有JSP页面实现类都必须实现JspPage或HttpJspPage。在HTTP环境下,显然是选择HttpJspPage。
javax.servlet.jsp.tagext。包含用于开发定制标签的类型(详情查看第6章的内容)。
javax.el。为Unified Expression Language提供API。详情查看第4章的内容。
javax.servlet.jsp.el。提供Servlet/JSP容器必须支持的类,以便支持JSP中的Expression Language。
除了javax.servlet.jsp.tagext之外,很少需要直接用到JSP API。事实上,在编写JSP页面时,相对于JSP API本身,你会更关注Servlet API。当然,你还需要掌握JSP语法,这个在本章中会讲到。在开发JSP容器或者JSP编译器的时候,就要大量使用JSP API。
在下列网站可以查看到JSP API:
JSP页面可以包含模板数据和句法元素。对于JSP转换器而言,元素具有特别的含义。例如,<%是一个元素,因为它在JSP页面中表示一个Java代码块的开始。%>也是一个元素,因为它表示一个Java代码块的结束。不属于元素的其他内容都是模板数据。模板数据也发送到浏览器。例如,JSP页面中的HTML标签和文本都是模板数据。
代码清单3-1给出了一个名为welcome.jsp的JSP页面。这是一个简单的页面,它只是给客户端发送了一条问候消息。你注意到了吗?与具有相同功能的Servlet相比,JSP页面是多么简单啊!
在Tomcat中,第一次调用完welcome.jsp页面之后,它被转换成一个welcome_jsp Servlet。你可以在Tomcat的work目录的子目录下看到所生成的Servlet文件。这个Servlet继承了org.apache.jasper.runtime.HttpJspBase,这是一个继承javax.servlet.http.HttpServlet并实现javax.servlet.jsp.HttpJspPage的抽象类。
下面是为welcome.jsp生成的Servlet文件。如果你现在觉得它很神秘,不必担心。就算你目前不理解,也可以继续往下学。不过如果你能理解,当然就更好了。
从上述代码可以看出,JSP页面的主体被转换成一个_jspService方法。这个方法在HttpJspPage中定义,并且通过HttpJspBase的service方法实现调用。下面是来自HttpJspBase类的内容:
为了覆盖init和destroy方法,可以根据本章稍后的3.5节的内容来声明方法。
JSP页面与Servlet不同的另一个方面是,前者不需要在部署描述符中进行标注,或映射成一个URL。应用程序目录下的每一个JSP页面都可以通过在浏览器中输入页面的路径来实现直接的调用。图3-1展示了app03a的目录结构,这是本章配套提供的一个JSP应用程序范例。
因为只有一个JSP页面,因此app03a应用程序的结构非常简单,只包含一个空的WEB-INF目录和一个welcome.jsp页面。
利用下面这个URL可以调用welcome.jsp页面:
提示 添加完一个新的JSP页面之后,不需要重启Tomcat。
代码清单3-2展示了如何在JSP中利用Java代码来生成动态的页面。代码清单3-2中的todaysDate.jsp页面展示了当天的日期。
todaysDate.jsp页面会将几个HTML标签和字符串“Today is”加当天的日期发送到浏览器。
有两件事情需要注意。第一,Java代码要用<%和%>包起来,并且可以放在JSP页面中的任何位置;第二,为了导入一个JSP页面中要用到的Java类型,可以利用page指令的import属性。如果没有导入类型,那么在代码中必须编写Java类型的全类名。
<%...%>块称作scriplet,在本章稍后的3.5节还会进一步讨论它。page指令将在本章稍后的3.4节中做详细的探讨。
利用下面这个URL可以调用todaysDate.jsp页面: