美文网首页
Servlet与JSP学习笔记(四) JSP核心(上)

Servlet与JSP学习笔记(四) JSP核心(上)

作者: Toconscience | 来源:发表于2017-04-11 23:40 被阅读37次

    前面的文章已经覆盖了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生命周期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); %>
    ```

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

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

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

      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()方法的最前面预先定义好的局部变量。

    相关文章

      网友评论

          本文标题:Servlet与JSP学习笔记(四) JSP核心(上)

          本文链接:https://www.haomeiwen.com/subject/zgdpattx.html