Java Web开发入行真功夫
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.5 JSP页面结构和技术原理

在介绍完HTML和各种动态技术后,本节将让大家对JSP页面结构及其技术原理有个大概的了解。

1.5.1 一个简单的JSP页面

首先我们来看看一个简单的JSP页面,大家知道在学任何语言的第一个程序估计都是“Hello World!”程序,本小节将给大家展示JSP中的“Hello World!”程序是什么样的。其源代码如程序1-22所示。

【程序1-22】 HelloWorld.jsp

            01   <%@ page language="java" import="java.util.*"
            02     pageEncoding="ISO-8859-1"%>
            03   <html>
            04    <head>
            05      <title>
            06       HelloWorld!
            07      </title>
            08    </head>
            09    <body>
            10      <%
            11          out.println("<h1>Hello World!</h1>");
            12       %>
            13    </body>
            14   </html>

程序1-22的结构和HTML文件很相似,只是其中多了一些特有的符号。其中第1和第2行是JSP的页面指令,该指令指出了JSP使用的脚本语言,还导入了相应的工具包。第3行到9行与HTML中的意义相同。

与 HTML 所不同的是第 10 行到 12 行,这是 JSP 中的脚本小程序,其功能是在浏览器上输出“<h1>Hello World!</h1>”的字样。不过这跟在浏览器上直接写“<h1>Hello World!</h1>”是不一样的,直接写是固定好了的,属于静态页面,而这里是动态的,也就是在此可以根据不同的请求,打印不同的语句。这在后面的章节中给出解释。将该文件放到 Web 服务器的相应位置,并进行相应的配置(具体环境的搭建和配置细节见第2章)。在浏览器中输入该文件的地址,出现如图1-13所示的结果。

图1-13 HelloWorld.jsp运行结果

我们还可以查看HTML的源代码,在网页上单击鼠标右键,在弹出的快捷菜单中选择“查看源文件”命令,得到如图1-14所示的源代码。

图1-14 HelloWorld.jsp运行后在浏览器中的源代码

从图1-14中我们可以看出,程序1-22中的“out.println("<h1>Hello World!</h1>");”,这条语句运行后,在浏览器上变成了“<h1>Hello World!</h1>”来显示结果。

1.5.2 一个典型的JSP页面文件

在上一节,我们给出了一个最简单的JSP页面,了解了它和HTML静态页面的区别,本小节我们将给出一个典型的JSP页面文件,通过该文件我们能对JSP有个大概的了解。在此我们可能看不懂代码是什么意思,不要紧,在学完了后面的章节后,我们将都会明白。程序 1-23 仅列出主要代码片段,完整程序请参照本书所附光盘。此代码为第8章中将要讲解的一个例子,为其中登录成功后的页面。

【程序1-23】loginSuccess.jsp

            01   <%@ page language="java" \注:Page指令
            02     import="java.util.*,com.bsw.book.*,com.bsw.user.*"pageEncoding="UTF-8"
            03   %>
            04
            05   <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
            06   <html>
            07     <head>
            08          <title>My JSP 'bookList.jsp' starting page</title>
            09     …
            10     </head>
            11     <body>
            12          <jsp:useBean id="user" class="com.bsw.user.User"></jsp:useBean>
            13
            14          <%!String userName;%>
            15     \注:声明
            16          <%-- 设置响应页面的编码和文档类型--%>    \注:注释
            17          <%
            18                request.setcharacterEncoding("UTF-8");
            19                response.setcharacterEncoding("UTF-8");
            20                response.setcontentType("text/html;charset=UTF-8");
            21                user = (User) session.getAttribute("user"); \注:脚本小程序
            22
            23                userName = user.getName();
            24          %>
            25          <jsp:useBean id="book" class="com.bsw.book.Book"
            26         scope="page"></jsp:useBean>
            27          <table align="center" width="742" border="0">
            28                …
            29                <tr>
            30                      <td>
            31                           <span class="style1"> 尊敬的<%=userName%>
            32                 ,欢迎您的到来!!</span>
            33                      </td>
            34              …
            35                </tr>
            36          </table>
            37          <form name="addShoppingCart" action="" method="post">
            38                …
            39                <table border="0" width="740" align="center">
            40                      <tr>
            41                           <td>
            42                                 <div align="center" class="style1">
            43                                      图书名称
            44                                 </div>
            45                           </td>
            46                           …
            47                      </tr>
            48                      …
            49                      <tr align="center" class="style1">
            50                           <td>
            51                                 <%=book.getName()%>
            52                           </td>
            53                   …
            54                      </tr>
            55                      <%
            56                      }
            57                      %>
            58                </table>
            59          </form>
            60     </body>
            61   </html>

我们可以看出,这个程序比简单的JSP页面复杂得多,在这个页面中包含了JSP的大部分成分,粗体的部分都是JSP的相关用法,具体细节在后面的章节进行详细介绍。其他的是HTML语法中元素的用法。

下面我们来看看它的运行结果,既然它比简单的JSP页面复杂那么多,那么它能实现的功能也是很丰富的。运行结果如图1-15所示。

图1-15 登录成功界面

1.5.3 JSP页面构成分析

从上一节的典型JSP页面可以看出,JSP包含了很多元素,如指令元素、注释、脚本元素、动作元素等。为了清晰地了解JSP页面的基本结构,图1-16按类别给出了JSP页面的组织结构图。

图1-16 JSP页面组织结构图

我们结合上一节的典型JSP页面的例子,来给出JSP页面的各部分组成。在程序1-23中,1、2行为page指令的用法。12行为动作指令的用法,动作指令有多种,如jsp:useBean,jsp:setProterty等。14行为声明的用法。16行为注释,该注释类型在客户端不显示。17~24行为脚本小程序的用法。31、51行等都为JSP表达式的用法。

1.5.4 JSP页面的执行过程

我们看到了典型的JSP页面的运行结果,那么到底JSP页面是怎样执行的呢?换句话说,JSP页面的生命周期是怎样的呢?

当我们通过Web浏览器向JSP服务器发出请求时,JSP服务器会检查是否存在该JSP页面对应的Servlet,如果存在,则会进一步检查该JSP页面有没有被更新,如果被更新过了,则将JSP翻译成Servlet源代码(即Java代码),然后对Java代码进行编译,使之变为class文件。然后将class文件加载到内存,并调用jspInit()函数对JSP进行初始化,紧接着调用_jspService()方法服务,然后将结果返回给客户端。如果第二次访问同一个JSP页面时,在服务器容器中已经存在了该JSP页面的Servlet,并没有被更新,则不用再重新转化为 Servlet,也不用重新编译,会直接调用_jspService()方法进行服务。其流程图如图1-17所示。

图1-17 JSP执行过程图

从图中可以看出,JSP文件在第一个用户访问该JSP页面时对JSP页面进行翻译,然后进行编译,翻译和编译比较花费时间。而第一个用户通常是该JSP页面的开发人员,这样用户访问该JSP页面时通常已经被转化成Servlet并已经被编译好了,访问的效率非常高。

1.5.5 翻译后的Java文件

在上一节中讲到,JSP页面要被翻译成Servlet文件,也就是Java文件。这个文件是经过JSP引擎翻译的。翻译好后通常放在服务器安装目录的work的相应目录下。如上面简单的JSP页面经翻译后的Java文件放在:安装目录\work\ Catalina\localhost\ch01\org\apache\jsp下。名字为HelloWorld_jsp.java。代码片段如程序1-24所示,完整程序请参照本书所附光盘。

【程序1-24】HelloWorld_jsp.java

            01   package org.apache.jsp;
            02
            03   import javax.servlet.*;
            04   import javax.servlet.http.*;
            05   import javax.servlet.jsp.*;
            06   import java.util.*;
            07
            08   public final class HelloWorld_jsp extends org.apache.jasper.runtime.HttpJspBase
            09      implements org.apache.jasper.runtime.JspSourceDependent {
            10    private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory();
            11
            12    private static java.util.List _jspx_dependants;
得到工厂
            13
            14    private javax.el.ExpressionFactory _el_expressionfactory;
            15    private org.apache.AnnotationProcessor _jsp_annotationprocessor;
            16
            17    public Object getDependants() {
            18      return _jspx_dependants;
            19    }
            20
            21    public void _jspInit() {
            22     …
            23    }
            24
            25    public void _jspDestroy() {}
            26
            27    public void _jspService(HttpServletRequest request, HttpServletResponse response)
            28         throws java.io.IOException, ServletException {
            29      PageContext pageContext = null;
            30      HttpSession session = null;
            31      ServletContext application = null;
            32      ServletConfig config = null;
            33      JspWriter out = null;
            34      Object page = this;
            35      JspWriter _jspx_out = null;
            36      PageContext _jspx_page_context = null;
            37
            38      try {
            39       response.setContentType("text/html;charset=ISO-8859-1");
            40       pageContext = _jspxFactory.getPageContext(this, request, response,
            41                      null, true, 8192, true);
            42       _jspx_page_context = pageContext;
            43       application = pageContext.getServletContext();
            44       config = pageContext.getServletConfig();
            45       session = pageContext.getSession();
            46       out = pageContext.getOut();
            47       _jspx_out = out;
            48
            49       out.write("\r\n");
            50       out.write("
            51       <!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01
            52         Transitional//EN\">\r\n");
            53       out.write("<html>\r\n");
            54       out.write(" <head>\r\n");
            55       out.write("   <title>HelloWorld!</title>\r\n");
            56       out.write(" </head>\r\n");
            57       out.write(" \r\n");
            58       out.write(" <body>\r\n");     \注:向浏览器写内容
            59       out.write("    ");
            60
            61      out.println("<h1>Hello World!</h1>");
            62       out.write("\r\n");
            63       out.write(" </body>\r\n");
            64       out.write("</html>");
            65      }
            66      catch (Throwable t) {
            67       if (!(t instanceof SkipPageException))
            68       {
            69         out = _jspx_out;
            70
            71         if (out != null && out.getBufferSize() != 0)
            72          try { out.clearBuffer(); } catch (java.io.IOException e) {}
            73
            74         if (_jspx_page_context != null)
            75          _jspx_page_context.handlePageException(t);
            76       }
            77      }
            78
            79      finally {
            80       _jspxFactory.releasePageContext(_jspx_page_context);
            81      }
            82    }
            83   }

从该程序中我们可以看出,HelloWorld.jsp在运行时首先被解析成一个Java类:HelloWorld_jsp.java。该类继承于org.apache.jasper.runtime.HttpJspBase,实现了org.apache. jasper.runtime.JspSourceDependent。在_jspInit()中对变量_el_expressionfactory 和_jsp_annotationprocessor 进行了初始化。而_jspService 函数有两个参数HttpServletRequest类的对象request和HttpServletResponse类的对象response。它们分别代表了请求和响应。通过request可以得到请求的一些信息;通过response可以给浏览器响应。

在_jspService里,服务器对JSP文件进行解析之前首先对几个内置对象进行初始化。然后设置响应的格式和编码。接着通过 pageContext 得到各内置对象。而 pageContext 是通过_jspxFactory 的getPageContext()方法得到的。_jspxFactory是类JspFactory的对象。JspFactory是javax.servlet.jsp包中定义的一个抽象类,其中定义了两个静态方法 set/getDefaultFactory()。set 方法由 JSP 容器实例化该页面Servlet(即HelloWorld_jsp类)的时候置入,所以可以直接调用JspFactory.getDefaultFactory()方法得到这个JSP工厂的实现类。接着通过out对象向浏览器写入JSP页面中的各HTML标签和内容。当服务器容器不需要HelloWorld_jsp类的对象(可能是服务器关闭)时,就会调用_jspDestroy()进行清理工作。

通过这一节的讲解,我们掌握了 JSP 页面的构成,了解了 JSP 的实现原理和运行机制,这对 JSP编程是非常重要的。