JSP的學習(1)——基本知識與底層原理


  通過之前的學習,我們已經對Servlet有所了解,現在我們先來學習JSP,當能使用JSP進行友好的頁面顯示之后,再回去學習Servlet的其他高級特性會將整個學習很好的融入進來。

  JSP,即Java Server Pages,和Servlet一樣,都是SUN公司定義的一種用於開發動態WEB資源的技術。

  為什么說JSP也是動態web開發的一項技術呢?這是因為寫JSP雖然像是在寫HTML,但是JSP允許在頁面中嵌套Java代碼,或者利用某個標簽表示Java代碼(EL與jstl)。這就使得我們在寫JSP時能夠獲取請求對象Request和響應對象Response等這樣的web開發常用對象,實現與瀏覽器的交互。其實JSP就是一種Servlet,為什么這么說,后面會談到。

  我們先來寫一個JSP,具體的原理我們先不用管,只先看效果:

  在MyEclipse中創建一個【JSPLearning】的web項目,在【WebRoot】下創建一個“1.jsp”

  

  可以看到頭部分內容是比較多的,這原因其實和Servlet一樣,都是由於MyEclipse創建JSP也是依靠模板來創建的(當然我們可以改模板代碼使我們的JSP更加簡潔):

  

我們在<body>標簽中輸入如下代碼:

1  <body>
2          <%
3              Date date = new Date();
4              out.write(date.toLocaleString());
5           %>
6   </body>

 

然后通過瀏覽器來瀏覽我們這個JSP,就可以看到當前時間:

  

  寫JSP的一大便捷之處在於如果該JSP不在【WEB-INF】文件下,那么每次修改代碼只需保存即可在瀏覽器上觀察,不需要像Servlet一樣要重新部署。

我們看到上面JSP例子,不僅包含了HTML標簽語言,同時融入了JAVA代碼。

 

  我們知道瀏覽器在訪問JSP時能將JSP解釋並將內容顯示在瀏覽器上,JSP中有HTML的部分不用說,這瀏覽器肯定知道,但是我們上面的例子中JSP內還有Java部分,那么瀏覽器又不是JVM,怎么能執行這部分代碼呢?

  這就要說明一點了,其實瀏覽器訪問JSP只是一個假象,真正的還是去訪問Servlet。只是Servlet將JSP文件進行了翻譯轉換,即將JSP又變成了Servlet,然后輸出給瀏覽器的就是這翻譯轉換后的Servlet。

  那翻譯轉換后的Servlet在哪里呢?我們並沒有看到在自己的web工程中有多出來的Servlet。其實這個Servlet就在Tomcat的【work】目錄下。【work】目錄是Tomcat的工作目錄,也是Tomcat將JSP轉換為class文件的工作目錄。轉換的工作原理是當瀏覽器訪問某個JSP頁面時,Tomcat會在【work】目錄下把這個JSP頁面轉換成 .java文件(例如index.jsp會被轉換成index_jsp.java,如果以數字開頭,最前面還會有一下划線,例如: _1_jsp.java),而后編譯為 .class文件,最后Tomcat容器通過ClassLoader類將這個轉換后的 .class類裝載進內存,響應客戶端的工作。

  當第一次有人來訪問時,Tomcat需要將JSP轉換成Servlet,訪問可能會比較慢,但是一旦編譯成Servlet后,除非JSP再次修改,否則之后再有用戶訪問就可以直接訪問該Servlet,所以之后訪問速度快。如果清空了【work】目錄中的內容,那么所有的過程都會重新來過。

  Tomcat會定時掃描容器內的JSP文件,當發現某個JSP進行了修改之后,Tomcat會重新編譯轉換這個JSP成Servlet。但是Tomcat對JSP的掃描是定時的,即不是實時的,所有並不是修改完后就立即生效(如上面所說的雖然修改JSP並不需要重新部署,但是有可能會發生訪問時還未修改)。所以有時候為了能立刻生效,很多老前輩會建議在修改JSP后立即清除【work】目錄里的內容。

  (另外,Tomcat容器中,對於轉換后的Java文件(例如index_jsp.java)的編譯最大只支持64K,所以在其他服務器容器中的JSP移植到Tomcat容器中時會發生大JSP文件無法編譯的情況。所以建議把JSP中的業務邏輯寫入單獨的類,在JSP中通過調用這個類的靜態方法來執行,並將JSP中的JS,CSS等放入單獨的JS文件或CSS文件依靠鏈接來加入樣式等。)

 

  上面說了這么多,我們來探究下Tomcat的【work】目錄,我們會發現在這個目錄下還有【Catalina】文件夾,還有【localhost】文件夾(如果我們有其他虛擬主機,那么也在【Catalina】下建立其他虛擬主機的目錄來存放JSP轉換后的class文件):

  

這時候我們也看到了剛才剛建的web工程,接着我們繼續點擊進去(你會發現目錄相當的多 T_T):

  

進到【JSP】目錄下,我們就可以看到剛才從1.JSP轉換過來的 _1_jsp.java文件和 _1_jsp.class文件了(數字開頭,所以前面有一個下划線)。

  我們點擊 _1_jsp.java文件,看一看里面的內容:

  

我們的 _1_jsp作為我們1.JSP所定義的類,繼承了一個名為HttpJspBase這個類,而HttpJspBase類是可以從Tomcat的源碼中(因為包中有apache)根據這個類的包名找到:

  

在這個類中繼承了HttpServlet!所以這必須是一個Servlet :

  

  所以我們訪問JSP,其實並不是真正在訪問JSP,而是訪問將JSP轉換后的Servlet。在這個Servlet中,我們使用請求對象,將所需要的數據通過流的形式寫回客戶端,這點跟之前Servlet的學習到的是一樣的。我們可以再看看那個瀏覽器訪問的JSP頁面,查看其碼源:

  

  我們看到其碼源已經像是正常的HTML頁面,因為只有這樣瀏覽器才能解釋和顯示,同時在原來JSP寫Java代碼的地方直接變成了我們Java運行后的結果,這是為什么呢?

  當知道JSP要轉成Servlet,然后又Servlet來處理瀏覽器的請求,那根據之前學習的Servlet可以知道,這個請求是在Servlet中的service()方法中執行的,我們來看一看 _1_jsp 中的service()方法:

  

  

  我們可以看到,在這個service方法中,確實有接收請求對象和響應對象為參數,同時在方法的內部,通過IO流對象將一些HTML代碼通過write()方法寫出到瀏覽器,並且也將在JSP中寫的Java代碼原封不動的搬移到這個Servlet中,這就是為什么可以在JSP中寫Java代碼,因為最后Java代碼都會交給Servlet,剩下的就跟之前Servlet的學習沒啥區別了,通過流寫給響應對象,再將響應對象交給瀏覽器顯示。

  這里你可能會注意到我們在JSP編寫是對Date對象是通過傳統Java創建對象的方式來實現實例對象,而后面我們直接通過“out”這個對象來調用方法,那么這個“out”指的是哪個對象?還有別的什么對象可以直接調用嗎?

  我們已經知道了JSP最終是要轉換為Servlet的,而Servlet就是一個Java代碼的類,那么在JSP中寫的Java代碼會原封不動的搬移到Servlet上,那么某些某名出現在JSP上的對象肯定就是在Servlet上已經被定義過的,我們再次看看上面剛才的截圖,可以看到“out”這個對象是JSPWriter的實例(截圖中out還未獲得引用,但是后面的代碼會使out對象獲得引用,具體請看JSP轉換后的JAVA源碼),通過JSP的API手冊:

  

  JspWriter是繼承Writer的一個類。如果還記得通過響應對象Response.getWriter()方法獲得的PrintWriter其實也是Writer下的一個類,所以JSP使用的字符流和Servlet能獲取到的字符流其實都一個意思。

  綜上,正是因為在轉換的Servlet中會自動幫我們定義了JspWriter類的一個實例對象:out,所以我們能在JSP中直接使用這個對象,當然通過上訴截圖我們還可以直接使用別的已經定義好的對象,比在JSP中使用“application”代表這個web的Context對象,用“page”代表了JSP對於的這個Servlet,用“session”代表這個web應用中的Session對象 等等,所以這些都是可以直接在JSP中使用,並代表某個類的對象的:

  

  簡單說來,只要是在JSP轉換后的Servlet中的_jspService()方法中定義過的變量,在JSP頁面編寫代碼時都可以直接使用。

 

  在本篇博客的最后,我們來最后說明一點,不管是JSP還是Servlet,雖然都可以用於開發動態web工程,但由於這兩個技術的各自特點:

  · 使用JSP即用Java代碼產生動態數據,又做瀏覽器界面顯示會導致頁面難以維護。

  · 使用Servlet即處理數據,又在里面嵌套HTML代碼用於界面顯示,同樣導致程序可讀性差,難以維護,就如同上面的轉換后的Servlet中各種out輸出HTML代碼。

  · 因此最好的方法就是根據這兩門技術的特點,讓它們各自負責各的,Servlet只負責響應請求並處理數據,並把數據通過轉發(forward()方法)帶給JSP,由JSP來顯示,其實就是丟給轉換后自動產生的Servlet來顯示,讓它來幫我們通過各種out來輸出HTML代碼。

  這篇文章主要介紹了JSP的一些知識和底層的一些技術,下一篇會具體講訴JSP中所需要學習的語法。

 


免責聲明!

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



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