jsp的實現和原理理解


JSP介紹

JSP全稱java server pagesservlets一樣都是sun公司定義的一種用於開發動態web資源的技術。

JSP這門技術的最大的特點在於,寫jsp就像在寫html,但它相比html而言,html只能為用戶提供靜態數據,而Jsp技術允許在頁面中嵌套java代碼,為用戶提供動態數據。

 

JSP運行原理

瀏覽器向服務器發請求,不管訪問的是什么資源,其實都是在訪問Servlet,所以當訪問一個jsp頁面時,其實也是在訪問一個Servlet,服務器在執行jsp的時候,首先把jsp翻譯成一個Servlet,所以我們訪問jsp時,其實不是在訪問jsp,而是在訪問jsp翻譯過后的那個Servlet

 

當我們通過瀏覽器訪問index.jsp時,服務器首先將index.jsp翻譯成一個index_jsp.class,在Tomcat服務器的work\Catalina\localhost\項目名\org\apache\jsp目錄下可以看到index_jsp.class的源代碼文件index_jsp.java。代碼如下:

 

從上面的代碼可以發現b_jsp是繼承org.apache.jasper.runtime.HttpJspBase的,但是這個類其實是繼承HttpServlet的,所以其本質上訪問b.jsp還是在訪問servlet

 

JSP的排版標簽是如何發送到瀏覽器的 

jsp中編寫的java代碼和html代碼都會被翻譯到_jspService方法中去,在jsp中編寫的java代碼會原封不動地翻譯成java代碼,如<%out.print("Hello Jsp");%>直接翻譯成out.print("Hello Jsp”);,而HTML代碼則會翻譯成使用out.write("<html標簽>\r\n");的形式輸出到瀏覽器。在jsp頁面中編寫的html排版標簽都是以out.write("<html標簽>\r\n");的形式輸出到瀏覽器,瀏覽器拿到html代碼后才能夠解析執行html代碼。

JSP頁面中的java代碼服務器是如何執行的

 

jsp中編寫的java代碼會被翻譯到_jspService方法中去,當執行_jspService方法處理請求時,就會執行在jsp編寫的java代碼了,所以Jsp頁面中的java代碼服務器是通過調用_jspService方法處理請求時執行的。

 

web服務器在調用jsp的時候會提供jsp8個對象使用

PageContext pageContextHttpSession sessionServletContext applicationServletConfig configJspWriter outObject page=nullHttpServletRequest requestHttpServletResponse response。這8個對象是可以直接在jsp頁面中使用的。

 

其中的requestresponsepage是已經完成了初始化,而其它的5個通過下面的代碼完成初始化。

 

jsp的整個運行流程。

 

1.瀏覽器對服務器發送請求,請求是動態的。連接器將請求交給Servlet容器處理,

2.servlet容器查找要執行的.jsp文件

3.jsp轉為.java,

4.在編譯為.class

5.最終服務器要加載這個class文件,最后調用這個servlet實例。

 

注意:第二次執行的時候,如果內容沒有發生變化,則直接執行原來的class文件。

JSP模版元素

 

jsp頁面中的HTML內容稱之為jsp模版元素。

jsp模版元素定義了網頁的基本骨架,即定義了頁面的結構和外觀。

 

JSP表達式

 

JSP腳本表達式(expression)用於將程序數據輸出到客戶端。

語法:<%= 變量或表達式 %>

例如:<%= 5 %> 將會將5輸出到客戶端。

 

JSP腳本片段

JSP腳本片斷(scriptlet)用於在JSP頁面中編寫多行Java代碼。

語法:<%

             多行java代碼

     %>

<% %>中可以定義變量、編寫語句,不能定義方法。

注意:

1.jsp腳本片段中只能出現java代碼不可以出現其他jsp模版元素。

2.jsp腳本片段中的所有代碼必須遵循java語法規范。

3.一個jsp中可以有多個jsp腳本片段,之間可以加其它的元素。

4.多個腳本片段中的代碼可以互相訪問。

5.單個腳本片段中的代碼可以是不完整的,但是多個腳本片段組合后必須是完整的。

 

JSP聲明

 

JSP頁面中編寫的所有代碼,默認會翻譯到servlet_jspservice方法中, Jsp聲明中的java代碼被翻譯到_jspService方法的外面。

語法:<%

        java代碼

   %>

所以,JSP聲明可用於定義JSP頁面轉換成的Servlet程序的靜態代碼塊、成員變量和方法   

 

 

 

JSP指令

JSP指令(directive)是為JSP引擎而設計的,它們並不直接產生任何可見輸出,而只是告訴引擎如何處理JSP頁面中的其余部分。JSP中定義了三個指令,分別是pageincludetaglib

JSP指令的基本語法格式:<%@ 指令 屬性名="" %>

 

page指令

 

page指令用於定義JSP頁面的各種屬性,無論page指令出現在JSP頁面中的什么地方,它作用的都是整個JSP頁面,為了保持程序的可讀性和遵循良好的編程習慣,page指令最好是放在整個JSP頁面的起始位置。

—Language屬性:指定在頁面中的腳本語言。

—contentType:表示JSP輸出的MIME類型和編碼。

—pageEncoding:表示jsp的輸出編碼方式。

 

page指令的import屬性

可以在一條page指令的import屬性中引入多個類或包,其中的每個包或類之間使用逗號,分隔.

<% @ page import="java.util.*,java.net" %>

 

page指令的errorPage屬性

 

該屬性用於頁面出錯的時候,指明跳轉到哪一個頁面。

—errorPage屬性的設置值必須使用相對路徑,如果以“/”開頭,表示相對於當前Web應用程序的根目錄(注意不是站點根目錄),否則,表示相對於當前頁面。

可以在web.xml文件中使用<error-page>元素為整個Web應用程序設置錯誤處理頁面。

—<error-page>元素有3個子元素,<error-code><exception-type><location>

—<error-code>子元素指定錯誤的狀態碼,例如:<error-code>404</error-code>

—<exception-type>子元素指定異常的類的完全限定名

—<location>子元素指定以“/”開頭的錯誤處理頁面的路徑。即/ErrorPage/404Error.jsp類似。

如果設置了某個JSP頁面的errorPage屬性,那么在web.xml文件中設置的錯誤處理將不對該頁面起作用。

 

使用page指令的的isErrorPage屬性顯式聲明頁面為錯誤頁面

如果一個頁面為系統的錯誤頁面,應該用屬性isErrotPagetrue顯示的聲明。使用該屬性后,jsp引擎在將error.jsp轉為servlet的時候,會在jspservice方法中生成一個exception對象,通過調用exception.getErrorMessage()可以獲取到錯誤的具體信息。 

 include的指令

 @include可以包含任意的文件,當然,只是把文件的內容包含進來。

語法:<%@ include file=“relativeURL”%>  —靜態包含。

include指令用於引入其它JSP頁面,如果使用include指令引入了其它JSP頁面,那么JSP引擎將把這兩個JSP在翻譯階段合並成一個java文件。所以include指令引入通常也稱之為靜態引入。

 

 一、JSP運行原理

  每個JSP 頁面在第一次被訪問時,WEB容器都會把請求交給JSP引擎(即一個Java程序)去處理。JSP引擎先將JSP翻譯成一個_jspServlet(實質上也是一個servlet) ,然后按照servlet的調用方式進行調用。
  由於JSP第一次訪問時會翻譯成servlet,所以第一次訪問通常會比較慢,但第二次訪問,JSP引擎如果發現JSP沒有變化,就不再翻譯,而是直接調用,所以程序的執行效率不會受到影響。
  JSP引擎在調用JSP對應的_jspServlet時,會傳遞或創建9個與web開發相關的對象供_jspServlet使用。JSP技術的設計者為便於開發人員在編寫JSP頁面時獲得這些web對象的引用,特意定義了9個相應的變量,開發人員在JSP頁面中通過這些變量就可以快速獲得這9大對象的引用。

 

 

 


out
對象

該對象是通過pageContextgetout方法獲得,其類似於PrintWriter,但是它在PrintWriter基礎上增加了自己的一個out緩存區,意味着調用out.write並不會直接將數據寫入response的緩存區,而是將數據寫入out的緩存區,當出現下面3種情況時out對象才去調用ServletResponse.getWriter方法,並通過該方法返回的PrintWriter對象將out對象的緩沖區中的內容真正寫入到Servlet引擎提供的緩沖區中。

—page指令將buffer區關閉了。

—JSP頁面加載結束了。

—out對象的緩沖區滿了。 

pageContext對象

 

pageContext對象是JSP技術中最重要的一個對象,它代表JSP頁面的運行環境,這個對象不僅封裝了對其它8大隱式對象的引用,它自身還是一個域對象(容器),可以用來保存數據。並且,這個對象還封裝了web開發中經常涉及到的一些常用操作,例如引入和跳轉其它資源、檢索其它域對象中的屬性等。

 

通過pageContext獲得其他對象

—getException方法返回exception隱式對象

—getPage方法返回page隱式對象

—getRequest方法返回request隱式對象

—getResponse方法返回response隱式對象

—getServletConfig方法返回config隱式對象

—getServletContext方法返回application隱式對象

—getSession方法返回session隱式對象

—getOut方法返回out隱式對象

 

pageContext封裝其它8大內置對象的意義

如果在編程過程中,把pageContext對象傳遞給一個普通java對象,那么這個java對象將可以獲取8大隱式對象,此時這個java對象就可以和瀏覽器交互了,此時這個java對象就成為了一個動態web資源了,這就是pageContext封裝其它8大內置對象的意義,把pageContext傳遞給誰,誰就能成為一個動態web資源,那么什么情況下需要把pageContext傳遞給另外一個java類呢,什么情況下需要使用這種技術呢,在比較正規的開發中,jsp頁面是不允許出現java代碼的,如果jsp頁面出現了java代碼,那么就應該想辦法把java代碼移除掉,我們可以開發一個自定義標簽來移除jsp頁面上的java代碼,首先圍繞自定義標簽寫一個java類,jsp引擎在執行自定義標簽的時候就會調用圍繞自定義標簽寫的那個java類,在調用java類的時候就會把pageContext對象傳遞給這個java類,由於pageContext對象封裝了對其它8大隱式對象的引用,因此在這個java類中就可以使用jsp頁面中的8大隱式對象(requestresponseconfigapplicationexceptionSessionpageout)了,pageContext對象在jsp自定義標簽開發中特別重要。

 

pageContext作為域對象

  pageContext對象可以作為容器來使用,因此可以將一些數據存儲在pageContext對象中。

  pageContext對象的常用方法

public void setAttribute(java.lang.String name,java.lang.Object value)

public java.lang.Object getAttribute(java.lang.String name)

public void removeAttribute(java.lang.String name)

public java.lang.Object findAttribute(java.lang.String name)

當要查找某個屬性時,findAttribute方法按照查找順序"pagerequestsessionapplication"在這四個對象中去查找,只要找到了就返回屬性值,如果四個對象都沒有找到要查找的屬性,則返回一個null

pageContext對象中封裝了訪問其它域的方法

public java.lang.Object getAttribute(java.lang.String name,int scope)

public void setAttribute(java.lang.String name, java.lang.Object value,int scope)

public void removeAttribute(java.lang.String name,int scope)

代表各個域的常量

 

—PageContext.APPLICATION_SCOPE

—PageContext.SESSION_SCOPE

—PageContext.REQUEST_SCOPE

—PageContext.PAGE_SCOPE 

PageContext引入和跳轉到其他資源

PageContext類中定義了一個forward方法(用來跳轉頁面)和兩個include方法(用來引入頁面)來分別簡化和替代RequestDispatcher.forward方法和include方法。

pagecontext.forward(uri)  pagecontext.include(uri)一般不用這種方法。

 

 

JSP的屬性范圍

 

JSP中提供了四種屬性范圍,四種屬性范圍分別指以下四種:

—當前頁:一個屬性只能在一個頁面中取得,跳轉到其他頁面無法取得。

一次服務請求:一個頁面中設置的屬性,只要經過了服務器跳轉,則跳轉之后的頁面可以繼續取得。

一次會話:一個用戶設置的內容,只要是與此用戶相關的頁面都可以訪問(一個會話表示一個人,這個人設置的東西只要這個人不走,就依然有效)。

上下文中:在整個服務器上設置的屬性,所有人都可以訪問。

該四種屬性范圍都具有setAttributegetAttributeremoveAttribute方法。

 

page屬性范圍

 

當服務器發生了一次跳轉后,當前頁面的屬性在跳轉后的頁面是不能夠獲得的。

a.jsp 

b.jsp 

瀏覽器結果

 

 

request屬性范圍

request屬性范圍,在服務器發生跳轉的時候,該屬性會傳遞下去。簡單說就是你的瀏覽器的url沒有變,則這個屬性可以一直使用。

 

 <% request.setAttribute("name","yu"); %>

 <% pageContext.forward("b.jsp"); %>

 <% String name = (String)request.getAttribute("name"); %>

 <p>這是一個錯誤的界面</p>

    <%=name %>

 

session屬性范圍

 

session屬性范圍不管是服務端跳轉還是客戶端跳轉都可以繼續操作該屬性。

 

application屬性范圍

 

application是在服務器上設置的一個屬性,所以一旦設置了,任何用戶都可以瀏覽到此屬性。

 

 

JSP標簽

 

JSP標簽也稱之為Jsp Action(JSP動作)元素,它用於在Jsp頁面中提供業務邏輯功能,避免在JSP頁面中直接編寫java代碼,造成jsp頁面難以維護。

 

<jsp:include>

 <jsp:include>標簽用於把另外一個資源的輸出內容插入進當前JSP頁面的輸出內容之中,這種在JSP頁面執行時的引入方式稱之為動態引入。

語法:<jsp:include page="relativeURL | <%=expression%>" flush="true|false" />

page屬性用於指定被引入資源的相對路徑,它也可以通過執行一個表達式來獲得。

flush屬性指定在插入其他資源的輸出內容時,是否先將當前JSP頁面的已輸出的內容刷新到客戶端。 

 

 

<jsp:include>標簽與include指令的區別

<jsp:include>標簽是動態引入, <jsp:include>標簽涉及到的2JSP頁面會被翻譯成2servlet,這2servlet的內容在執行時進行合並。

  而include指令是靜態引入,涉及到的2JSP頁面會被翻譯成一個servlet,其內容是在源文件級別進行合並。

 

 

jspf擴展名文件在jsp:include和@include的區別。

 

 

注意:只有使用@include包含jspf文件的時候,文件內容才能被解析執行。而使用jspinclude動態包含的時候會在客戶端輸出文件的原內容。本身動態包含是將多個文件翻譯為多個servlet,然后將執行的結果進行合並輸出,但是jspf文件在使用動態包含的時候被當作純文本文件處理了,即該jspf文件並沒有被翻譯為servlet執行,僅僅是當作文本進行輸出了。

 

 

如何讓服務器解析jspf文件呢

 

方法一:修改web應用的web.xml文件,添加映射  

 

 

 

 

方法二:修改服務器上的web.xml文件,添加類似上面的映射。

 

 

<jsp:forward>標簽

該標簽用於將請求轉發給另一個資源。

語法:<jsp:forward page="relativeURL | <%=expression%>" />。服務器端跳轉。

 

 

 

 

 

 

<jsp:param>標簽

當使用<jsp:include><jsp:forward>標簽引入或將請求轉發給其它資源時,可以使用<jsp:param>標簽向這個資源傳遞參數。

語法一:

<jsp:include page="relativeURL | <%=expression%>">

        <jsp:param name="parameterName" value="parameterValue|<%= expression %>" />

</jsp:include>

語法二:

<jsp:forward page="relativeURL | <%=expression%>">

        <jsp:param name="parameterName" value="parameterValue|<%= expression %>" />

</jsp:include>

<jsp:param>標簽的name屬性用於指定參數名,value屬性用於指定參數值。在<jsp:include><jsp:forward>標簽中可以使用多個<jsp:param>標簽來傳遞多個參數。

 

 

 

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM