Jsp技術總結
這節我們總結一下Jsp的相關技術。
1. 什麼是JSP
JSP即Java Server Pages,它和servlet技術一樣,都是sun公司定義的一種用於開發動態web資源的技術。該技術的最大特點在於:寫JSP就像寫html,但它相比html而言,html只能為使用者提供靜態資料,而JSP技術允許在頁面中巢狀java程式碼,為使用者提供動態資料。
2. JSP原理
1) web伺服器是如何呼叫並執行一個JSP頁面的?
伺服器首先將JSP翻譯為一個Servlet,翻譯過後的Servlet可以在\tomcat主目錄\work\Catalina\localhost\工程名\org\apache\jsp目錄下檢視,這是伺服器的工作目錄。開啟相應的Servlet可以看到,翻譯過後的servlet繼承了org.apache.jasper.runtime.HttpJspBase,而HttpJspBase繼承了HttpSerrvlet。說到這裡,我們就明白了,其實JSP就是一個Servlet,訪問jsp即訪問一個Servlet。
2) JSP頁面中的html排版標籤是如何被髮送到客戶端的以及java程式碼伺服器是如何執行的?
繼續瀏覽JSP翻譯過後的Servlet,裡面有個service方法_jspService(request, response),在該方法中可以看到,JSP中的所有內容都會翻譯到service方法中,html程式碼會通過out輸出,就像學習JSP之前,在Servlet中用out輸出html語句一樣,java部分程式碼會原封不動的搬到service方法中。
3) web伺服器在呼叫JSP時,會給JSP提供一些什麼java物件?
web伺服器在將JSP翻譯成Servlet時,會在service方法中提供web開發所有的物件,這樣在JSP頁面中,我們就可以直接使用這些物件了,而不用再去獲得。web伺服器所提供的物件(這些物件我們下面戶詳細分析)有:
final javax.servlet.jsp.PageContext pageContext; //pageContext物件 javax.servlet.http.HttpSession session = null; //session物件 final javax.servlet.ServletContext application; //application物件 final javax.servlet.ServletConfig config; //config物件 javax.servlet.jsp.JspWriter out = null; //out物件 final java.lang.Object page = this; //page物件 javax.servlet.jsp.JspWriter _jspx_out = null; javax.servlet.jsp.PageContext _jspx_page_context = null;
還有service方法的引數request和response。所以Servlet可以做的事,JSP都可以做。但是兩者各有特點,我們繼續往下看。
3. JSP的最佳實踐
不管是JSP還是Servlet,雖然都可以用於開發動態web資源,但是由於這2門技術各自的特點,在長期的軟體實踐中,人們逐漸把servlet作為web應用中的控制器元件來使用,而把JSP技術作為資料顯示模板來使用。原因在於,程式的資料通常要美化後再輸出。讓JSP既用java程式碼產生動態資料,又做美化會導致頁面難以維護;讓Servlet既產生資料,又在裡面巢狀html程式碼美化資料,同樣也會導致程式可讀性差,難以維護;因此最好的辦法就是讓Servlet負責相應請求產生的資料,並把資料通過轉發技術帶給JSP,JSP用來做資料的顯示。
4. JSP語法
1) JSP模板元素
JSP模板元素即JSP頁面中的HTML內容。JSP模板元素定義了網頁的基本骨架,即定義了頁面的結構和外觀。
2) JSP指令碼表示式
JSP指令碼表示式用於將程式資料輸出到客戶端。
語法:<%= 變數或表示式 %> 如:當前時間:<%= new java.util.Date() %>
JSP引擎在翻譯指令碼表示式時,會將程式資料轉成字串,然後在相應位置用out.print(...)將資料輸給客戶端。
注意:JSP指令碼表示式中的變數或表示式後面不能有分號(;)
3) JSP指令碼片段
JSP指令碼片段用於在JSP頁面中編寫多行java程式碼。
語法:<% 多行java程式碼 %>
注意:JSP指令碼片段只能出現java程式碼,不能出現其他模板元素,JSP引擎在翻譯JSP頁面中,會將JSP指令碼片段中的Java程式碼原封不動的放到Servlet的_jspService方法中。JSP指令碼片段中的java程式碼必須嚴格遵循java語法。
在一個JSP頁面中可以有多個指令碼片段,在兩個或多個指令碼片段之間可以嵌入文字、HTML標記和其他JSP元素。不同指令碼片段中的程式碼可以相互訪問,猶如將所有的程式碼放到一個<% %>中一樣。但是所有的指令碼片段組合在一起必須是一個完整的java程式碼。
4) JSP宣告
JSP宣告中的java程式碼會被翻譯到_jspService方法的外面。(面試題)
語法:<%! java程式碼 %>
所以,JSP宣告可用於定義JSP頁面轉換成Servlet程式的靜態程式碼塊、成員變數和方法。多個靜態程式碼塊、變數和方法可以定義在一個JSP宣告中,也可以分別單獨定義在多個JSP宣告中。
JSP隱式物件的作用範圍僅限於Servlet的_jspService方法中,而JSP宣告的程式碼會被翻譯到該方法的外面,所以在JSP宣告中不能使用這些隱式物件。
5) JSP註釋
語法:<%- 註釋資訊 -%>
JSP引擎在將JSP頁面翻譯成Servlet時,忽略JSP頁面中被註釋的內容。
如果在JSP中使用<!-- 註釋內容-->時,註釋內容會打給瀏覽器,瀏覽器認識這個註釋,所以不會顯示給使用者。而JSP註釋將註釋內容不打給瀏覽器。
6) JSP指令
JSP指令是為JSP引擎而設計的,它們並不直接產生任何可見輸出,而只是告訴引擎如何處理JSP頁面中其餘的部分。
語法:<%@ 指令 屬性名="值" %>
如:<%@ page contentType="text/html;charset=UTF-8" %> <%@ page import="java.util.Date" %>
如果一個指令有多個屬性,這多個屬性可以寫在一個指令中,中間用空格隔開。即上面兩條指令等價表示如下:
<%@ page contentType="text/html;charset=UTF-8" import="java.util.Date" %>
在JSP2.0規範中共定義了三個指令:
1)page指令:
page指令用於定義JSP頁面的各種屬性,無論page指令出現在JSP頁面中的什麼地方,它的作用都是整個JSP頁面。為了保持程式的可讀性,page指令最好放在整個JSP頁面的起始位置。
語法:
<%@ page [import="{package.class | package.*},..."] [session="true | false"] [errorPage=""relative_url] [isErrorPage="true | false"] [contentType="mimeType[;charset=characterSet]" | "text/html;charset=ISO-8859-1] [pageEncoding="characterSet | ISO-8859-1"] [isELIgnored="true | false"] %>
JSP引擎會自動匯入如下包:java.lang.* / java.servlet.* / javax.servlet.jsp.* / javax.servlet.http.*
JSP匯入多個包的時候,可以分開寫,也可以放在一起寫,放在一起的時候,使用逗號分隔:
<%@ paga import="java.util.Date,java.sql.*,java.io.*"%>
session屬性設定為true時,翻譯後的servlet中會自動建立session物件,false則不建立。
errorPage屬性用來設定錯誤相應頁面。它的值必須使用相對路徑,如果以"/"開頭,表示相對於當前web應用程式的根目錄(注意不是站點根目錄),否則,表示相對於當前頁面。也可以在web.xml檔案中使用<error-page>元素為整個web應用程式設定錯誤處理頁面,其中<exception-type>子元素指定異常類的完全限定名,<location>元素指定以"/"開頭的錯誤處理頁面路徑。如果設定了某個JSP頁面的errorPage屬性,那麼在web.xml檔案中設定的錯誤處理將不對該頁面起作用。
isErrorPage為true時,表示該頁面是處理錯誤頁面,JSP引擎在翻譯成servlet時,會定義一個exception物件,從而就可以用exception隱式物件獲得出錯資訊。
JSP引擎會根據page指令的contentType屬性生成相應的呼叫ServletResponse.setContentType方法的語句。
2) include指令:
include指令用於引入其他JSP頁面,如果使用include指令引入了其他JSP頁面,那麼JSP引擎將把這兩個JSP翻譯成一個servlet,所以include指令引入通常稱為靜態引入。由於JSP引擎會把多個JSP頁面翻譯成一個Servlet,所以,在被引入的JSP中,全域性架構的程式碼可以去掉(<html><head><body>等)(當然這不是必須的),這樣避免與當前JSP頁面中的重複。
語法:
<% include file="relativeURL"%>
其中file屬性用於指定被引入檔案的路徑。以"/"開頭,表示代表當前web應用。
幾個細節需要注意:
· 被引入的檔案必須遵循JSP語法;
· 被引入的檔案可以使用任意的副檔名,即使副檔名為html,JSP引擎也會按照處理JSP頁面的方式去處理,為了見名知意,JSP規範建議使用.jspf(JSP fragments)作為靜態引入檔案的副檔名;
· 由於使用include指令將會涉及到2個JSP頁面,並會把2個JSP翻譯成一個Servlet,所以這兩個JSP頁面的指令不能衝突(除了pageEncoding和導包除外)。比如現在要引入兩個JSP頁面,一個JSP中session="true",另一個JSP中session="false",這樣在引入這兩個JSP頁面時就會產生衝突,伺服器會報錯。
在JSP中也可以使用java程式碼實現動態包含:
<% request.getRequestDispather("relativeURL").include(request,response);%>
這樣JSP引擎會將不同的JSP頁面翻譯成不同的Servlet,動態包含只是引入其他JSP頁面的結果。動態包含的時候,伺服器會呼叫多個web資源,而靜態包含時,被翻譯成一個Servlet,伺服器只需要呼叫一個web資源,所以靜態包含效能好一點,開發時用靜態包含。
3)taglib指令:用來匯入自定義標籤庫,見後面自定義標籤部分的內容
5. JSP執行原理和9大隱式物件
由上文可知:每個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大物件的引用,9大隱式物件是哪些以及各自的作用是什麼?
request://就是Servlet裡的request response: //就是Servlet裡的response session: //就是Servlet裡的session application: //就是servlet裡的servletContext config: //就是Servlet裡的servletConfig page: //就是Servlet自己 exception: //異常,只有errorPage才有 out://JSP頁面輸出 pageContext:<span style="font-family:Microsoft YaHei;">//</span>pageContext物件是JSP技術中最重要的一個物件,它代表JSP頁面的執行環境
pageContext物件是JSP技術中最重要的一個物件,它代表JSP頁面的執行環境,這個物件不僅封裝了對其它8大隱式物件的引用,它自身還是一個域物件,可以用來儲存資料。並且,這個物件還封裝了web開發中經常涉及到的一些常用操作,例如引入和跳轉其它資源、檢索其它域物件中的屬性等。
getException<span style="font-family:Microsoft YaHei;">() //</span>方法返回exception隱式物件 getPage<span style="font-family:Microsoft YaHei;">() //</span>方法返回page隱式物件 getRequest() //方法返回request隱式物件 getResponse() //方法返回response隱式物件 getgetServletContext() //方法返回application隱式物件 getServletConfig() //方法返回config隱式物件 getSession() //方法返回session隱式物件 getOut() //方法返回out隱式物件
pageContext作為一個域物件,還封裝了下面的方法:
//pageContext域物件的方法: public void setAttribute(String name, Object value) public Object getAttribute(String name) public void removeAttribute(String name) //pageContext物件中還封裝了訪問其它域的方法(重要) public void setAttribute(String name, Object value, int scope) public Object getAttribute(String name, int scope) public void removeAttribute(String name, int scope) //代表各個域的常量 pageContext.APPLICATION_SCOPE pageContext.SESSION_SCOPE pageContext.REQUEST.SCOPE pageContext.PAGE_SCOPE
到現在為止,應該可以看出pageContext物件的強大之處了!另外還有個findAttribute方法(*重要,查詢各個域中的屬性,EL表示式就依賴於這個方法),可以直接呼叫pageContext.findAttribute(String name),首先會從pageContext裡找該屬性,如果沒有,會依次按照下面順序在相應的域中查詢:request, session, servletContext,如果沒找著,返回null,否則返回屬性值。
pageContext類中定義了一個forward方法和兩個include方法分別簡化和替代RequestDispatcher.forward方法和include方法,方法接收的資源如果以"/"開頭,"/"代表當前web應用。不過這裡的include是動態包含,不建議使用include。
6. JSP標籤
JSP標籤也稱為JSP動作元素,它用於在JSP頁面中提供業務邏輯功能,避免在JSP頁面中直接編寫java程式碼造成JSP頁面難以維護。JSP有三種標籤
1) <jsp:include>標籤
<jsp:include>標籤用於把另外一個資源的輸出內容插入進當前JSP頁面的輸出內容之中,這種在JSP頁面執行時的引入方式稱為動態引入。
語法:
<jsp:include page="relativeURL | <%= expression%>" flush="true | false" />
相當於呼叫pageContext.include("relativeURL")
page屬性用於指定被引入資源的相對路徑,它也可以通過執行一個表示式來獲得。flush屬性指定在插入其他資源的輸出內容時,是否先將當前JSP頁面都已輸出的內容重新整理到客戶端。
2) <jsp:forward>標籤
<jsp:forward>標籤用於把請求轉發給另一個資源
語法:
<jsp:forward page="relativeURL | <%= expression%>" />
page屬性用於指定請求轉發到的資源的相對路徑,它可以通過執行一個表示式來獲得。
3) <jsp:param>標籤
當使用<jsp:include>和<jsp:forward>標籤引入或將請求轉發給其它資源時,可以使用<jsp:param>標籤向這個資源傳遞引數。
語法1:
<jsp:include page="relativeURL | <%=expression%>"> <jsp:param name="parameterName" value="parameterValue | <%=expression%>" /> </jsp:include>
相當於relativeURL?name=...&value=....
語法2:
<jsp:forward page="relativeURL | <%=exception%>"> <jsp:param name="parameterName" value="parameterValue | <%=expression%>" /> </jsp:forward>
相當於relativeURL?name=...&value=....
<jsp:param>標籤的name屬性用於指定引數名,value屬性用於指定引數值。在<jsp:include>和<jsp:forward>標籤中可以使用多個<jsp:param>標籤來傳遞多個引數。
7. JSP對映
JSP也可以像Servlet那樣對映,因為JSP本來就是Servlet。
<servlet> <servlet-name>SimpleJspServlet</servlet-name> <jsp-file>/jsp/simple.jsp</jsp-file> </servlet> <servlet-mapping> <servlet-name>SimpleJspServlet</servlet-name> <url-pattern>/xxx/yyy.html</url-pattern> </servlet-mapping>
/jsp/simple.jsp表示在webRoot/jsp目錄下的simple.jsp檔案
8. 四個域物件
到目前為止,web開發共接觸到了4個域物件,這4個域物件是學習web的重點,也是筆試經常考察的知識點:
pageContext(稱為page域): //pageContext中存的資料在頁面範圍都可以取出 request(稱為request域): //request中存的資料在請求範圍內都可以取出 session(稱為session域): //session中存的資料在會話範圍內都可以取出 servletContext(稱為application域)://servletContext中存的資料在整個應用程式範圍內都可以取出
明確如下兩個問題:這四個物件的生命週期?哪種情況下用哪種物件?
request:如果客戶機向伺服器發請求產生的資料,使用者看完就沒用了,向這樣的資料就存在request域中。如使用者看的新聞。
session:如果客戶機向伺服器發請求產生的資料,使用者用完了等一會兒還有用,向這樣的資料就存在session域中。如使用者購買的東西,因為結賬還要用到。
servletContext:如果客戶機向伺服器發請求產生的資料,使用者用完了還要給其他使用者用,向這樣的資料就存在servletContext域中。如聊天室中說出的話,因為話要在自己頁面中看到,別人也要看到。
實際中,能用小的容器就不要用大的,即request能滿足就不要用session,session能滿足就不要用servletContext
9. 總結
由於JSP一般都是通過servlet轉發過來,servlet會通過容器將資料帶過來,所以會使用JSP從容器中取出資料然後顯示出來即可。取資料用指令碼片段<%%>來取,顯示用指令碼表示式<%= %>處理。在學習了EL表示式和自定義標籤後,指令碼片段就可以用自定義標籤替代,指令碼表示式就可以用EL表示式替代了。
相關文章
- CMake技術總結
- WPF技術總結
- BypassUAC技術總結
- easyui技術總結UI
- 最近技術總結
- docker技術總結Docker
- 個人技術棧總結
- 池化技術總結
- Oracle Flashback 技術 總結Oracle
- Oracle Flashback技術總結Oracle
- 智慧控制技術總結
- docker技術總結(二)Docker
- 總想著,有一種技術替代JSP.JS
- JSP初步總結JS
- 特徵選擇技術總結特徵
- #web前端技術使用總結Web前端
- MySQL分頁技術總結MySql
- 漏洞挖掘分析技術總結
- oracke閃回技術總結
- web長連結技術個人總結Web
- JSP總結(經典)JS
- iOS底層GCD (技術總結)iOSGC
- UI技術總結--效能優化UI優化
- Java Web 會話技術總結JavaWeb會話
- IO多路複用技術總結
- JavaCPP技術使用經驗總結Java
- 技術轉型與考研總結
- MySQL的分頁技術總結MySql
- VB作品展技術總結
- mongodb 階段性技術總結MongoDB
- 大學總結,技術與技術之外的事 | 掘金年度徵文
- 個人技術棧大體思路總結
- Ajax技術的一些總結
- WEB 實時推送技術的總結Web
- 〔總結系列〕前端技術精華清單前端
- 老J的技術分享之總結
- Android開發技術面總結Android
- H5製作技術總結H5