4

前面的文章已经覆盖了Servlet核心知识,由于JSP与Servlet在很大程度上是相通的,因此关于JSP只需要介绍语法以及一些独特的性质。
同样可以参考菜鸟笔记

介绍JSP

首先,为什么要有JSP?

要回答这个问题,实际上只需要比较HTML、Servlet、JSP的优劣:

  • HTML文件是静态的,无法返回动态结果。

  • Servlet可以动态生成HTML页面,但是在代码里写HTML标记实在是不爽。

  • 于是反过来,在传统的HTML文件中加入Java程序片段和JSP标记,就构成了JSP文件。

JSP是怎么工作的?

当容器接收到客户端对JSP文件的请求时,会解析对应的JSP文件,把它翻译成Servlet源文件,接着把Servlet源文件编译成Servlet类,然后再初始化并运行Servlet。

当然,一旦JSP文件已经被编译过,下次运行时只需要找对应的Servlet类就行了。

可见JSP和Servlet其实是一回事,JSP只是一层外衣。其内容中不论是HTML标记还是Java代码,都大部分被编译到了Servlet类的service()方法中。于是接下来就顺便解释了JSP的生命周期:

JSP的生命周期

  • 编译阶段:Servlet容器编译servlet源文件,生成servlet类

  • 初始化阶段:加载与JSP对应的servlet类,创建其实例,并调用它的初始化方法

  • 执行阶段:调用与JSP对应的servlet实例的服务方法

  • 销毁阶段:调用与JSP对应的servlet实例的销毁方法,然后销毁servlet实例

下图给出了后面三个阶段的示意:
JSP生命周期

其中:编译出来的Servlet类继承自javax.servlet.jsp.HttpJspPage接口,该接口继承了javax.servlet.Servlet接口。jspInit()就对应Servlet的init(), jspDestroy()就对应Servlet的destroy(), _jspService()自不必说。

下面给出一个JSP文件和编译出来的代码,就一目了然了。

<!-- Hello.jsp -->
<html>
<head>
  <title>helloapp</title>
</head>
<body>
  <b>Hello,<%= request.getParameter("username") %></b>
</body>
</html>

编译出的Servlet文件:

public final class hello_jsp extends org.apache.jasper.runtime.HttpJspBase {
  
  ...
  public void _jspInit() {
  }

  public void _jspDestroy() {
  }

  public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
      throws java.io.IOException, javax.servlet.ServletException {

    final java.lang.String _jspx_method = request.getMethod();
    if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
      response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET POST or HEAD");
      return;
    }

    // 可以看出JSP的隐含对象是这么来的。
    final javax.servlet.jsp.PageContext pageContext;
    javax.servlet.http.HttpSession session = null;
    final javax.servlet.ServletContext application;
    final javax.servlet.ServletConfig config;
    javax.servlet.jsp.JspWriter out = null;
    final java.lang.Object page = this;
    javax.servlet.jsp.JspWriter _jspx_out = null;
    javax.servlet.jsp.PageContext _jspx_page_context = null;


    try {
      response.setContentType("text/html");
      pageContext = _jspxFactory.getPageContext(this, request, response,
                  null, true, 8192, true);
      _jspx_page_context = pageContext;
      application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      session = pageContext.getSession();
      out = pageContext.getOut();
      _jspx_out = out;

      out.write("<html>\r\n");
      out.write("<head>\r\n");
      out.write("  <title>helloapp</title>\r\n");
      out.write("</head>\r\n");
      out.write("<body>\r\n");
      out.write("  <b>Hello,");
      out.print( request.getParameter("username") );
      out.write("</b>\r\n");
      out.write("</body>\r\n");
      out.write("</html>\r\n");
    } catch (java.lang.Throwable t) {
      if (!(t instanceof javax.servlet.jsp.SkipPageException)){
        out = _jspx_out;
        if (out != null && out.getBufferSize() != 0)
          try {
            if (response.isCommitted()) {
              out.flush();
            } else {
              out.clearBuffer();
            }
          } catch (java.io.IOException e) {}
        if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
        else throw new ServletException(t);
      }
    } finally {
      _jspxFactory.releasePageContext(_jspx_page_context);
    }
  }
}

JSP的语法

概括地说,JSP文件中除了可以直接包含HTML文本,还可以包含以下内容:

  1. JSP指令(Directive)
    用来设置和整个JSP页面相关的属性。语法形式为<%@ 指令 属性1="值1" 属性2="值2" %>。包括三种指令:

    • Page: 可以指定language、content_type、errorPage、session等,还可以用import属性引入包。

    • Include: 包含其他文件。

    • Taglib: 指定自定义标签。

  2. JSP声明

    声明一个或多个变量、方法,供后面的Java代码使用。声明中的变量会被编译成Servlet的(私有)成员变量。示例:

    <%! int i = 0; %> 
    <%! int a, b, c; %> 
    <%! Circle a = new Circle(2.0); %> 
  3. Java程序片段
    任何在"<%"和"%>"标记之间的Java代码。默认会被编译到Servlet类的service()方法中(如果用Page指定了method属性,则会编到你指定的方法中)。如果你想复写jspInit()jspDestroy()方法,应该在前面的JSP声明中写。

  4. Java表达式
    语法形式为<%= JAVA表达式 %>。相当于被编译成out.print(JAVA表达式)

  5. JSP隐含对象
    JSP隐含对象是JSP容器为每个页面提供的Java对象,开发者可以直接使用它们而不用显式声明。JSP隐含对象也被称为预定义变量。
    JSP所支持的九大隐含对象:

    对象 描述
    request HttpServletRequest类的实例
    response HttpServletResponse类的实例
    out PrintWriter类的实例,用于把结果输出至网页上
    session HttpSession类的实例
    application ServletContext类的实例,与应用上下文有关
    config ServletConfig类的实例
    pageContext PageContext类的实例,提供对JSP页面所有对象以及命名空间的访问
    page 类似于Java类中的this关键字
    Exception Exception类的对象,代表发生错误的JSP页面中对应的异常对象

    看起来很犀利,但实际上从前面真实的Servlet代码可以看到,它们不过是在service()方法的最前面预先定义好的局部变量。


Toconscience
153 声望39 粉丝

引用和评论

0 条评论