【菜鳥學Java】6:JSP的基本原理

連江偉發表於2015-12-17

        在上篇博文中介紹了JavaWeb開發中比較基礎也是比較經典的Servlet技術,同時也在文章的結尾點出了Servlet技術所帶來的問題,那就是由於包括大量的HTML標籤,大量的靜態文字及格式等,導致Servlet的開發效率極為低下。所有的表現邏輯,包括佈局、色彩及影像等,都必須耦合在Java程式碼中,這的確讓人覺得非常糟糕。

        JSP的出現彌補了這種不足,JSP通過在標準的HTML頁面中嵌入Java程式碼,其靜態的部分無須Java程式控制,只有那些需要從資料庫讀取或者需要動態生成的頁面內容,才使用Java指令碼控制。從本質上來說,JSP也是Servlet,當使用者向指定的Servlet傳送請求時,Servlet利用輸出流動態生成HTML頁面,包括每一個靜態的HTML標籤和所有在HTML頁面中出現的內容。

        JSP頁面的組成部分:

        #靜態部分:標準的HTML標籤、靜態的頁面內容,這些內容與靜態HTML頁面相同。

        #動態部分:受Java程式控制的內容,這些內容由Java指令碼動態生成。

        下面我們來看一個最簡單的JSP頁面程式碼。      

<%@ page language="java" contentType="text/html; charset=GBK"
	pageEncoding="GBK"%>
<html>
	<head>
		<title>歡迎</title>
	</head>
	<body>
		尊敬的使用者:您好!<br>
		當前時間是:<br>
		<% out.println(new java.util.Date());%>

	</body>
</html>

        上面的程式碼中,使用<%……%>符號包起來的內容,稱之為Java指令碼,這就是所謂的動態內容,通過這種方式可以把Java程式碼嵌入在HTML頁面中,這樣就成了動態的JSP頁面。我們在瀏覽器中訪問改頁面,可以看到如下頁面:

        

        從表面上看,JSP頁面似乎已經不再需要Java類,好像完全脫離了Java物件導向的核心思想。事實上,JSP的本質依然是Servlet,這個在上文中已經提到,這裡詳細闡述一下。

        其實每個JSP頁面就是一個Servlet例項——JSP頁面由系統編譯成Servlet,Servlet再負責響應使用者的請求。也就是說,JSP其實也是Servlet的一種簡化,使用JSP時,其實還是在使用Servlet,因為Web應用中的每個JSP頁面都會由Servlet容器生成對應的Servlet。對於Tomcat而言,JSP頁面生成的Servlet放在work路徑對應的Web應用下。

        我們開啟Tomcat的檔案路徑,來檢視一下上面的JSP頁面所對應的類檔案和Java程式碼檔案,如下圖所示:

        開啟welcome_jsp.java檔案,我們來看看它的程式碼是什麼樣的:     

/*
 * Generated by the Jasper component of Apache Tomcat
 * Version: Apache Tomcat/7.0.42
 * Generated at: 2015-12-17 08:33:01 UTC
 * Note: The last modified time of this file was set to
 *       the last modified time of the source file after
 *       generation to assist with modification tracking.
 */
package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;

public final class welcome_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent {

  private static final javax.servlet.jsp.JspFactory _jspxFactory =
          javax.servlet.jsp.JspFactory.getDefaultFactory();

  private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;

  private javax.el.ExpressionFactory _el_expressionfactory;
  private org.apache.tomcat.InstanceManager _jsp_instancemanager;

  public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
    return _jspx_dependants;
  }

  public void _jspInit() {
    _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
    _jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
  }

  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 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; charset=GBK");
      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("\r\n");
      out.write("<html>\r\n");
      out.write("\t<head>\r\n");
      out.write("\t\t<title>歡迎</title>\r\n");
      out.write("\t</head>\r\n");
      out.write("\t<body>\r\n");
      out.write("\t\t尊敬的使用者:您好!<br>\r\n");
      out.write("\t\t當前時間是:<br>\r\n");
      out.write("\t\t");
 out.println(new java.util.Date());
      out.write("\r\n");
      out.write("\r\n");
      out.write("\t</body>\r\n");
      out.write("</html>");
    } catch (java.lang.Throwable t) {
      if (!(t instanceof javax.servlet.jsp.SkipPageException)){
        out = _jspx_out;
        if (out != null && out.getBufferSize() != 0)
          try { 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);
    }
  }
}

        對於初學者來說,看到上面的Java類可能有點懵,這是什麼玩意啊?其實這就是一個Servlet類的原始碼,該Java類主要包含三個方法:

        #init():初始化JSP/Servlet的方法。

        #destroy():銷燬JSP/Servlet之前的方法。

        #service():對使用者請求生成響應的方法。

        即使不瞭解,也沒關係,這不影響我們開發自己JSP頁面,因為編譯的工作是由Web容器完成的。比如我們使用Tomcat就是一個Web容器。

        小結一下:

        關於JSP的工作原理,我們先來看一張圖,這是從網上找的,我覺得還不錯,可能對大家的理解有幫助。

        

        綜上所述,我們可以得到幾個結論:

        1JSP檔案必須在JSP伺服器內才可以執行

        2JSP檔案必須生成Servlet才可以被執行

        3每個JSP頁面的第一個訪問者的響應速度會很慢,因為這個使用者需要等待JSP被編譯成Servlet。

        4JSP頁面的訪問者無需安裝任何客戶端,甚至不需要可以執行Java的執行環境,因為JSP頁面輸送到客戶端的是標準的HTML頁面,你有個瀏覽器就夠了。

        JSP技術的出現,大大的提高了Java動態網站的開發效率,所以得到了廣大動態網站開發人士的青睞。

相關文章