詳談JSP執行原理、生命週期、語法、指令、動作標籤、九大內建物件(JSP 全家桶)

hcz666發表於2020-10-14

JSP 結構

以下是表明Web伺服器是如何使用JSP來建立網頁的:

  • 使用者在瀏覽器上傳送一個HTTP請求給伺服器,web伺服器會判斷是否是JSP網頁請求,如果是則啟動JSP引擎。
  • JSP引擎從磁碟中載入JSP檔案,然後將它們翻譯為servlet檔案並將servlet編譯成可執行類,再將原始請求傳遞給servlet引擎。這種轉化只是簡單地將所有模板文字改用println()語句,並且將所有的JSP元素轉化成Java程式碼。
  • web伺服器的某元件將會呼叫servlet引擎,然後載入並執行servlet類。在執行過程中,servlet產生HTML格式的輸出並將其內嵌於HTTP response中上交給Web伺服器。
  • web伺服器以靜態HTML網頁的形式將HTTP response返回到您的瀏覽器中。
  • 最後,web瀏覽器處理HTTP response中動態產生的HTML網頁,就好像在處理靜態網頁一樣。
    在這裡插入圖片描述

JSP執行原理及本質

  1. 使用者在瀏覽器位址列上輸入http://localhost:8080/hcz/index.jsp,web伺服器判斷使用者請求的資源是hcz應用中index.jsp頁面,web伺服器在hcz應用中找到index.jsp
  2. 啟動JSP引擎(是Tomcat伺服器內建的一個JSP翻譯引擎,專門負責翻譯JSP檔案,編譯java原始檔),將index.jsp翻譯成index_jsp.java檔案,並且將index_jsp.java檔案編譯生成index_jsp.class位元組碼檔案,將其儲存在Tomcat伺服器work目錄中。
  3. index_jsp.class類繼承了HttpJspBase,HttpJspBase繼承了HttpServlet,所以JSP本質上就是Servlet,和Servlet完全相同。
  4. 只有使用者第一次訪問這個JSP或者JSP頁面被修改了,才會重新翻譯。JSP有三個階段:翻譯(一次),編譯(一次),執行(多次)。JSP更改,不需要重啟伺服器,也不需要重新部署專案。
  5. Jsp和Servlet本質上沒有區別,但是JSP和Servlet它們的主要職責是有區別的:JSP主要是提取資料做頁面展示,而Servlet主要完成業務邏輯處理以及資源跳轉。Servlet是Controller(控制層),JSP是View(展示層)。
  6. 在JSP檔案中編寫的所有HTML、CSS、Javascript,對於JSP來說,只是普通的字串,被翻譯成:out.writer("…");
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    <meta charset="UTF-8">
    <title>jsp頁面</title>
  </head>
  <body>
    This is my JSP page. 666888<br>
           賬號:<input type="text" name="username"><br>
           密碼:<input type="text" name="password"><br>
        <input type="submit" value="提交">
        <%
         System.out.println("666888");
         %>
  </body>
</html>
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent,
                 org.apache.jasper.runtime.JspSourceImports { 
    public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
      throws java.io.IOException, javax.servlet.ServletException { 
      
      out.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\r\n");
      out.write("<html>\r\n");
      out.write("  <head>\r\n");
      out.write("    <base href=\"");
      out.print(basePath);
      out.write("\">\r\n");
      out.write("    <meta charset=\"UTF-8\">\r\n");
      out.write("    <title>jsp頁面</title>\r\n");
      out.write("  </head>\r\n");
      out.write("  <body>\r\n");
      out.write("    This is my JSP page. 666888<br>\r\n");
      out.write("           賬號:<input type=\"text\" name=\"username\"><br>\r\n");
      out.write("           密碼:<input type=\"text\" name=\"password\"><br>\r\n");
      out.write("        <input type=\"submit\" value=\"提交\">\r\n");
      out.write("        ");
      System.out.println("666888");
      out.write("\r\n");
      out.write("  </body>\r\n");
      out.write("</html>\r\n");
     }
}

JSP生命週期

JSP生命週期就是從建立到銷燬的整個過程,類似於servlet生命週期,區別在於JSP生命週期還包括將JSP檔案編譯成servlet。

  • 編譯階段
    當瀏覽器請求JSP頁面時,JSP引擎會首先去檢查是否需要編譯這個檔案。如果這個檔案沒有被編譯過,或者在上次編譯後被更改過,則編譯這個JSP檔案。

編譯的過程包括三個步驟

  • 解析JSP檔案
  • 將JSP檔案轉換為servlet
  • 編譯servlet
  • 初始化階段
    載入與JSP對應的servlet類,建立其例項,並呼叫它的初始化_jspInit()方法
public void _jspInit(){
  // 初始化程式碼
}

一般來講程式只初始化一次,servlet也是如此。通常情況下您可以在_jspInit()方法中初始化資料庫連線、開啟檔案和建立查詢表。

  • 執行階段
    這一階段描述了JSP生命週期中一切與請求相關的互動行為,直到被銷燬。
    當JSP網頁完成初始化後,JSP引擎將會呼叫_jspService()方法。
    _jspService()方法需要一個HttpServletRequest物件和一個HttpServletResponse物件作為它的引數,就像下面這樣:
public void _jspService(HttpServletRequest request,HttpServletResponse response)
{
   // 服務端處理程式碼
}
  • 銷燬階段
    呼叫與JSP對應的servlet例項的銷燬方法_jspDestroy(),然後銷燬servlet例項
public void jspDestroy()
{
   // 清理程式碼
}

以上通過描述JSP的生命週期,發現和servlet生命週期非常相似,下面給出圖示:
在這裡插入圖片描述

JSP語法

JSP檔案以.jsp/.jspx結尾,通常存放在和HTML資源同級目錄中,在JSP檔案中編寫的普通字串,以後翻譯成Servlet的service方法中的out.write()將該字串響應給瀏覽器。所以我們必須在JSP檔案中編寫一些特殊的符號,和jsp檔案中的普通文字加以區別,這樣jsp引擎就會根據不能的符號將其翻譯到Servlet類中的不同位置。

指令碼程式(scriptlet)

指令碼程式的語法格式:

<% 程式碼片段 %>
  • 在jsp檔案中使用 <% %>,出現在該符號內的java程式翻譯之後會被存放在Servlet的service方法中。
  • 所以在該符號內只能編寫java語句或者定義區域性內部類(通常很少使用區域性內部類),每一個java語句以“;”結尾,在這個符號中的程式大家就當做在service方法中程式設計一樣就行了。
  • 在該符號中宣告的變數屬於區域性變數,不能使用訪問控制許可權修飾符修飾,所以在service方法中不能編寫例項變數、不能編寫方法、不能編寫靜態語句塊。
<%-- 以下程式編譯無法通過 --%>
<%--
    public String username;
--%>

<%--
    public void m1(){
    
    }
--%>

<%--
    static{
    
    }
--%>
  • 小指令碼的數量隨意,可以多個,小指令碼中編寫java程式出現在service方法中,service方法的程式碼是有執行順序的,所以小指令碼中的程式也是有順序的。編寫以下JSP檔案:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%
    int i = 10;
 %>
<html>
    <%
        System.out.println(i);
    %>
  <head>
    <%
        double d = 3.0;
    %>
    <meta charset="UTF-8">
    <title>jsp頁面</title>
    <%
        System.out.println(d + i);
    %>
  </head>
  <body>
    This is my JSP page<br>
         <%
            System.out.println(d*i);
         %>
        <% 
            out.println("Your IP address is " + request.getRemoteAddr()); 
        %>
  </body>
</html>
<%
    String ename = "king";
    System.out.println("ename = " + ename);
%>

其經過JSP引擎翻譯後成Servlet的service方法變為:

public class index_jsp extends HttpJspBase{
   public void _jspInit(){
   }
   public void _jspService(HttpServletRequest request,HttpServletResponse response){
   	
out.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\r\n");

    int i = 10;
 
      out.write("\r\n");
      out.write("<html>\r\n");
      out.write("\t");

        System.out.println(i);
    
      out.write("\r\n");
      out.write("  <head>\r\n");
      out.write("  \t");

        double d = 3.0;
    
      out.write("\r\n");
      out.write("    <meta charset=\"UTF-8\">\r\n");
      out.write("    <title>jsp頁面</title>\r\n");
      out.write("    ");

        System.out.println(d + i);
    
      out.write("\r\n");
      out.write("  </head>\r\n");
      out.write("  <body>\r\n");
      out.write("    This is my JSP page<br>\r\n");
      out.write("    \t ");

            System.out.println(d*i);
         
      out.write("\r\n");
      out.write("        ");
 
            out.println("Your IP address is " + request.getRemoteAddr()); 
        
      out.write("\r\n");
      out.write("  </body>\r\n");
      out.write("</html>\r\n");

    String ename = "king";
    System.out.println("ename = " + ename);
   }
}
JSP宣告(declaration)

宣告的語法格式:

<%! declaration; [ declaration; ]+ ... %>
  • 在jsp檔案中使用==<%! %>==,出現在該符號內的java程式翻譯之後會被存放在和Servlet的service方法並列的位置上。
  • 在該符號內宣告靜態變數、靜態方法、靜態程式碼塊、例項程式碼塊、例項變數、例項方法,大家就當做在類體中直接編碼就可以了,所以宣告的變數、方法都是可以使用訪問控制許可權修飾符修飾的。
  • 宣告塊中不能直接編寫java語句,除非是變數的宣告。例如:

<%!
    //java語句不能直接出現在類體中
    //System.out.println("Hello World!");

    public void doSome(){
        System.out.println("do some!");
    }
%>

模擬JSP檔案執行後在Servlet的service方法中的執行順序是什麼樣的,示例如下:


<%@page contentType="text/html; charset=UTF-8"%>
<%
    doSome();
%>
<%!
    int i = 100;
%>
<%
    //java語句不能直接出現在類體中
    //System.out.println("Hello World!");

    public void doSome(){
        System.out.println("do some!");
    }
%>
<%
    System.out.println("servlet's service method execute!");
%>
<%!
    static{
        System.out.println("Class Loader!");
    }
%>
<%
    int j = 100;
%>
<%!
    public static void doOther(){
        System.out.println("do other!");
    }
%>
<%
    System.out.println("j = " + j);
    System.out.println("i = " + i);
%>

其經過JSP引擎翻譯後成Servlet的service方法變為:

public class index_jsp extends HttpJspBase{
   int i = 100;
   public void doSome(){
  	System.out.println("do some!");
  }
  static{
  	System.out.println("Class Loader!");
  }
  public static void doOther(){
  	System.out.println("do other!");
  }
   public void _jspService(HttpServletRequest request,HttpServletResponse response){
   	dosome();
   	System.out.println("servlet's service method execute!");
   	int j = 100;
   	System.out.println("j = " + j);
 	System.out.println("i = " + i);
   }
}
JSP表示式(expression)

表示式語法,具有輸出功能,輸出到瀏覽器上
表示式的語法格式:

<%= 表示式 %>
  • <%= %> 等同於 out.print();
  • <%=“Hello World!”%> 等同於 out.print(“Hello World!”);
  • <%=1+1%> 等同於 out.print(1+1);
  • <%=“1+1”%> 等同於 out.print(“1+1”);
  • <%= %>中的程式碼不能以“;”結尾,否則就 out.print(xxx;);顯然是沒有這種語法的。

JSP指令(directive)

  • JSP指令用來設定整個JSP頁面相關的屬性,如網頁的編碼方式和指令碼語言。
  • 為JSP引擎而設計的,它們並不直接產生任何可見輸出,而只是告訴引擎如何處理JSP頁面中的其餘部分
    語法格式:
<%@ 指令名 屬性名=屬性值 屬性名=屬性值.....  %>

JSP中的三種指令標籤:

指令描述
<%@ page … %>定義網頁依賴屬性,比如指令碼語言、error頁面、快取需求等等
<%@ include … %>包含其他檔案
<%@ taglib … %>引入標籤庫的定義
Page指令(頁面指令)

Page指令為容器提供當前頁面的使用說明。一個JSP頁面可以包含多個page指令。
Page指令的語法格式:

<%@ page attribute="value" %>
  • importl 屬性(翻譯生成java語言中的import語句)

<%@page import=”java.util.Date,java.util.ArrayList”%>

  • contentType屬性(指定JSP頁面響應內容型別)

<%@page contentType=”text/html”%>

  • pageEncoding屬性(指定JSP頁面響應的頁面字元編碼)

<%@page pageEncoding=”UTF-8”%>

  • session屬性(指定當前JSP頁面是否可以使用session這個內建物件)

<%@page session=”false”%> session內建物件不可用
<%@page session=”true”%> session內建物件可用(預設的

  • errorPage屬性(指定當前JSP頁面發生錯誤之後跳轉的資源路徑)

<%@page contentType=“text/html; charset=UTF-8” errorPage="/error.jsp"%>

  • isErrorPage屬性(指定當前JSP頁面是一個錯誤頁面,這樣才能使用內建物件exception)

<%@page contentType=“text/html; charset=UTF-8” isErrorPage=“true”%>

  • isErrorPage = “false” 表示內建物件exception無法使用【預設情況下是false】
  • isErrorPage = “true” 表示內建物件exception可以使用
  • isELIgnored屬性指定當前頁面中如果有EL表示式是否忽略,true表示忽略,false表示不忽略
Include指令(包含指令)

語法格式如下:

<%@include file="filePath"%>
  • JSP include 指令用於通知 JSP 引擎在翻譯當前 JSP 頁面時,將其他檔案中的內容合併進當前 JSP 頁面轉換成的 Servlet 原始檔中,這種在原始檔級別進行引入的方式,稱為靜態引入
  • 當前 JSP 頁面與靜態引入的檔案緊密結合為一個 Servlet。
  • 因此,在所包含的檔案中不能使用 html、body 標記,否則會因為與原有的 JSP 檔案有相同標記而產生錯誤。另外,因為原檔案和被包含檔案可以相互訪問彼此定義的變數和方法,所以要避免變數和方法在命名上產生衝突。
  • 這些檔案可以是 JSP 頁面、HTML 頁面、文字檔案或是一段 Java 程式碼。
    • file 屬性指定被包含的檔案,不支援任何表示式,例如下面是錯誤的用法:

    <% String f="top.html"; %>
    <%@ include file="<%=f %>" %>

    • 不可以在 file 所指定的檔案後接任何引數,如下用法也是錯誤的:

    <%@ include file="top.jsp?name=zyf" %>

    • 如果 file 屬性值以“/”開頭,將在當前應用程式的根目錄下查詢檔案;如果是以檔名或資料夾名開頭,將在當前頁面所在的目錄下查詢檔案。
  • include實現原理:
  1. 編譯期包含
  2. a.jsp包含b.jsp,底層共生成一個java原始檔,一個class位元組碼檔案,翻譯期包含/編譯期包含/靜態聯編
  3. 靜態聯編的時候,多個jsp中可以共享同一個區域性變數。因為最終翻譯之後service方法只有一個。
Taglib指令(標籤庫指令)

語法格式:

<%@taglib attribute="value"  %>
  • 為了讓JSP看起來更加的專業(只做頁面展示),減少jsp頁面中java程式碼的數量,我們引入了標籤庫,使用了標籤庫之後JSP程式中不再出現太多的java程式了,這樣JSP頁面看起來主要工作就是頁面展示。

相關文章