詳談JSP執行原理、生命週期、語法、指令、動作標籤、九大內建物件(JSP 全家桶)
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執行原理及本質
- 使用者在瀏覽器位址列上輸入http://localhost:8080/hcz/index.jsp,web伺服器判斷使用者請求的資源是hcz應用中index.jsp頁面,web伺服器在hcz應用中找到index.jsp
- 啟動JSP引擎(是Tomcat伺服器內建的一個JSP翻譯引擎,專門負責翻譯JSP檔案,編譯java原始檔),將index.jsp翻譯成index_jsp.java檔案,並且將index_jsp.java檔案編譯生成index_jsp.class位元組碼檔案,將其儲存在Tomcat伺服器work目錄中。
- index_jsp.class類繼承了HttpJspBase,HttpJspBase繼承了HttpServlet,所以JSP本質上就是Servlet,和Servlet完全相同。
- 只有使用者第一次訪問這個JSP或者JSP頁面被修改了,才會重新翻譯。JSP有三個階段:翻譯(一次),編譯(一次),執行(多次)。JSP更改,不需要重啟伺服器,也不需要重新部署專案。
- Jsp和Servlet本質上沒有區別,但是JSP和Servlet它們的主要職責是有區別的:JSP主要是提取資料做頁面展示,而Servlet主要完成業務邏輯處理以及資源跳轉。Servlet是Controller(控制層),JSP是View(展示層)。
- 在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實現原理:
- 編譯期包含
- a.jsp包含b.jsp,底層共生成一個java原始檔,一個class位元組碼檔案,翻譯期包含/編譯期包含/靜態聯編
- 靜態聯編的時候,多個jsp中可以共享同一個區域性變數。因為最終翻譯之後service方法只有一個。
Taglib指令(標籤庫指令)
語法格式:
<%@taglib attribute="value" %>
- 為了讓JSP看起來更加的專業(只做頁面展示),減少jsp頁面中java程式碼的數量,我們引入了標籤庫,使用了標籤庫之後JSP程式中不再出現太多的java程式了,這樣JSP頁面看起來主要工作就是頁面展示。
相關文章
- JSP(JSTL EL表示式 三個指令 六個動作標籤 九個JSP內建物件)JS物件
- JSP筆記-生命週期JS筆記
- jsp標籤jsp:useBean用法JSBean
- JSP九大內建物件、四大作用域以及session的生命週期JS物件Session
- JSP九大內建物件解析、JSP指令(page、include)、靜態聯編概述JS物件
- JSP 內建物件(一)JS物件
- JSP基本語法JS
- JSP 自定義標籤介紹JS
- jsp第七週作業JS
- JSP九大內建物件JS物件
- JSP中無法使用內建物件解決方法JS物件
- JSP C 標籤的常見用法JS
- JSP九大內建物件 sessionJS物件Session
- JSP原理JS
- jsp forward 指令JSForward
- JSP自定義標籤就是如此簡單JS
- Web應用開發: JSP語法程式設計實踐(一) JSP中的標識WebJS程式設計
- 實驗三 JSP內建物件使用JS物件
- 【JSP進階】JSP九大內建物件,這你也不知道?JS物件
- jsp的執行過程JS
- JSP 九大物件、四大作用域、七大行為動作、三大指令JS物件
- 為ElementUI的標籤頁新增生命週期UI
- 實戰練習之Jsp自定義標籤JS
- Java—執行緒的生命週期及執行緒控制方法詳解Java執行緒
- JSP九大內建物件 out request responseJS物件
- Java執行緒的生命週期Java執行緒
- Unity指令碼生命週期Unity指令碼
- jsp隱式物件-Servlet物件JS物件Servlet
- DP全家桶(長期)
- Salesforce 生命週期管理(一)應用生命週期淺談Salesforce
- Java 物件的生命週期Java物件
- EL 表示式對照 JSP 內建物件表JS物件
- 淺談vue —— 生命週期Vue
- 【Java】【多執行緒】執行緒的生命週期Java執行緒
- Java之執行緒的生命週期Java執行緒
- JSP詳解-1JS
- Maven 構建生命週期Maven
- JSP簡介以及各種內建物件的用法JS物件