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页面: