目錄javascript
多是JSP
知識總結的最全的博客之一了,你想要尋找的知識,這裏都有 ;php
做者:淮左白衣 來源:筆者當時學web的筆記 時間:-2018年5月4日21:25:09
jsp
JSP
全稱是 java servlet pages
,它和 servlet
技術同樣,都是Sun公司定義的一種用於開發動態web頁面的技術html
爲何jsp
也是一種動態web資源的開發技術呢?java
寫jsp
,雖然就像是在寫HTML
,可是jsp
容許在頁面中編寫java
代碼,而且容許開發人員在頁面中獲取request
、response
等web
開發經常使用對象,實現與瀏覽器的交互,因此jsp也是一種動態web資源的開發技術;web
例子:輸出當前時間apache
Date date = new Date();
//這個out對象是能夠直接使用的,它是JspWriter的實例
out.write(date.toLocaleString());
Jsp
調用和運行原理(簡略版)瀏覽器訪問 jsp
頁面時,Web
服務器是如何調用並執行一個jsp頁面的?
首先知道,咱們訪問服務器的資源時,不管訪問的是什麼?好比訪問的是HTML、jsp,其實咱們訪問的都是一個servlet,而不是真正的jsp、html ,所以,咱們訪問 jsp
其實就是去訪問 servlet
;編程
Jsp
在被訪問的時候,服務器會將它 翻譯爲 servlet
,轉換後的servlet
,被保存在服務器目錄下的work/項目名/apache/…
跨域
提問:瀏覽器
web 服務器在執行jsp頁面時,是如何把jsp頁面中的HTML排版標籤輸出給瀏覽器的?緩存
這裏實際上是 jsp
對應的 servlet
的功勞,咱們知道服務器會將jsp
轉爲一個servlet
對象,咱們去訪問jsp
的時候,實際訪問到的也是這個servlet
對象;
在這個servlet
對象對應的類中。它是經過out.writer()
語句將 jsp
中的 HTML
語句,原封不動的打給瀏覽器;遇到<%java代碼%>
,就直接執行;
jsp頁面中的java代碼,服務器是如何執行的?
是原封不動的,代碼最後都在在servlet
類中執行了;
Web服務器在調用jsp時,會給jsp提供一些什麼java對象?
會提供許多對象;request、response、out、application、session
等這些對象,在jsp
中是直接可使用的,由於在jsp對應的servlet類中已經提供好了;
若是想要得到jsp
對應的servlet
類的對象的自身,使用page
,也是它內置提供的;
上面的幾個問題,其實均可以翻看對應的 servlet 類的源碼,,找到答案;
Jsp模板元素
Jsp
頁面中的 HTML
內容稱之爲 jsp
模板元素。
Jsp的模板元素定義了網頁的基本骨架,即定義了頁面的結構和外觀;
下面的幾個概念,分清楚了,別混淆;
Jsp腳本表達式
語法:<%= xxxx %>
jsp腳本表達用於將程序數據輸出到客戶端,只能寫在一行;
Jsp
引擎在翻譯腳本表達式時,會將程序數據轉成字符串,而後在相應的位置用out.print(...)
,將數據輸出給客戶端。
Jsp腳本表達式的變量或者表達式後面不能有分號
,其實緣由很簡單,腳本表達式是要被放到 out.print(...)
裏面的,在結尾加上一個 ; 會被輸出,而咱們並不想輸出這個分號;
Jsp腳本片斷
jsp腳本片斷用於在jsp頁面中編寫 多行 java代碼;
語法:
<%
多行java代碼
%>
注意:jsp
腳本片斷中只能出現java
代碼,不能出現其餘模板元素
,由於,jsp引擎
在翻譯jsp
頁面時,會將jsp腳本片斷
中的 java
代碼原封不動的放到 servlet
的 _jspService
方法中。
jsp腳本片斷中的java代碼,必須嚴格遵照java語法!廢話,最後被轉到servlet中,java代碼原封不動的;
在一個jsp頁面中能夠有多個腳本片斷,在腳本片斷之間是能夠寫上模板元素的;而且多個腳本片斷之間的數據是共享的;(瞭解下底層原理,就知道爲啥共享了
)
單個腳本片斷中的java代碼能夠是不完整的,可是多個腳本片斷中,java代碼必須完整了 ;
Jsp聲明
在jsp中,腳本片斷中java代碼,都被翻譯到servlet的jspService方法中了;
那麼假如,咱們想要將java代碼,寫到jspService方法外面的話,就須要使用jsp聲明
了;
<%!
java代碼
%>
咱們就能夠爲servlet
類添加方法
、字段
等屬性了,可是通常沒啥人使用這個技術;
Jsp註釋
格式:
<%--
註釋信息
--%>
JSP引擎在將 jsp
頁面翻譯成 servlet
程序時,會 忽略jsp
頁面中被註釋的內容 ;注意是被jsp引擎翻譯時,就拋棄了,也就是在servlet類中將沒有這個註釋的內容;可是你要是使用HTML的註釋,就不行了;
Jsp指令
jsp指令
是爲 jsp引擎
而設計的。它們並不直接產生任何可見輸出,而只是告訴引擎如何處理jsp頁面中的其他部分。
在jsp2.0
規範中共定義3個指令:
今天2018年4月23日,jsp規範,早就不是2.0點了。須要注意下,可是不影響你學習JSP
page指令
Include指令
taglib指令
<%@ 指令 屬性名=「值」 %>
舉例:
<%@ page contentType="text/html; ISO-8859-1" %>
若是一個指令有多個屬性,這多個屬性能夠寫在一個指令中,用 空格
分隔多個屬性,也能夠分開寫 ;
下面講解3大指令;
page指令
用於定義jsp頁面的各類屬性,不管page指令出如今jsp頁面中的什麼地方,它做用的都是整個jsp頁面;
爲了保持程序的可讀性和遵循良好的編程習慣,page指令
最好是放在整個jsp頁面的初始位置。
Jsp2.0規範中定義的 page指令
的完整語法:
屬性名 = 「值 」 |
做 用 |
---|---|
pageEncoding = "xxx" |
指明翻譯 jsp 的時候,使用 xxx 碼錶 |
contentType = "text/html;charset=UTF-8" |
指明jsp 翻譯成的 servlet 文件,裏面的 response 使用的碼錶 |
language = "java" |
指明 jsp 頁面中的語言是 java |
extends = "xxx.class" |
表名生成jsp 翻譯的servlet 類繼承自xxx ,不過通常,繼承自默認類,便可。不須要改動 |
import = "xxx" |
表示,咱們的java 語句,須要導入的包,通常自動導包就行了,不用咱們手動去指定這個屬性 |
session = "false / true " |
false 表示,翻譯過去的servlet 中不要自動建立session 對象,目的是爲了,在不須要 session 的狀況下,避免生成 session ,減輕服務器的壓力。或者咱們須要session 對象,可是,咱們想手動讓服務器建立session 對象的 |
buffer = "8kb / none / xx kb" |
out.print() 的數據,不是直接寫到瀏覽器中(效率太慢),仍是先寫到緩衝區中,再寫到瀏覽器,buffer 指定緩衝區的大小,默認是8kb |
autoFlush = "false / true" |
是否自動刷新緩衝區,默認爲true |
isThreadSafe = "true" |
翻譯過去的servlet 是不是線程安全的,這個最TM奇怪了,默認爲true。可是表示默認線程不安全 |
isErrorPage = "true" |
表示該jsp 是頁面 錯誤處理 頁面,屬性值置爲true 時,jsp 翻譯爲 servlet 時,會傳進去一個異常對象,表示錯誤的異常;做用 當服務器出錯了,跳到錯誤頁面(404頁面),而後返回給瀏覽器,但這404是個正確的頁面,服務器就會返回200狀態碼,咱們 爲了告知瀏覽器咱們出錯了,就在頁面中加上這個屬性值,服務器將返回500 |
isELIgnored = "true" |
是否忽略 EL表達式 |
errorPage = "url" |
用來指定當前頁面出錯時,跳轉的界面。屬性值必須使用相對路徑,以 / 開頭則相對當前 web 應用;沒有 / 打頭,則相對於當前頁面;固然,咱們也能夠在服務器的 web.xml 文件 使用<error-page> 元素爲整個web 應用指定錯誤處理頁面,其中的兩個子標籤,一個用於指明異常的類型(寫全名),這個子標籤還能夠寫成狀態碼,一個用於指明出現該異常。跳準的界面地址;若是咱們在 jsp 中寫明瞭 errorPage 屬性,那麼web.xml 文件中的錯誤處理配置,對此jsp 不生效 |
include
指令用於引入 jsp
頁面,若是使用 include
引入其餘 jsp
頁面,那麼 jsp
引擎將把這兩個jsp
翻譯爲一個servlet
,因此,include
指令引入一般也稱爲 靜態導入;
屬性名 = 「值 」 |
做 用 |
---|---|
file = "url" |
其中的file 屬性用於指定被引入文件的路徑。路徑以「/」 開頭,來表示當前web 應用; |
細節:
jsp
語法HTML
擴展名,jsp引擎
仍是會按照處理jsp
頁面的方式處理頁面的內容;爲了,見名思意,jsp規範
建議使用 .jspf
做爲靜態導入文件的擴展名;.jspf
指令會涉及到兩個jsp頁面,並會把2個jsp翻譯爲一個servlet,全部這兩個jsp頁面的指令不能衝突;HTML
語句了,不然頁面將不是一個完成的頁面,會出現兩個 <head>
這樣的標籤;動態包含:
語法: request.getRequestDispatcher("url").include(request,response);
這是在運行時包含,會將 每個 jsp
都對應生成一個servlet
,也就是最終生成不止一個 servlet
;
咱們通常選擇靜態導入
,性能高 ;
在講標籤庫的時候,再講;
亂碼產生的根由:無外乎兩種
jsp文件
保存的編碼和服務器翻譯 servlet
的時候的編碼不一致servlet
的 response
的編碼編碼不一致;解決方法: <%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" %>
咱們發現只要這兩個地方使用相同的編碼,亂碼就不會產生;
pageEncoding=」xxx」
告訴服務器翻譯時使用什麼碼錶;
contentType="text/html;charset=UTF-8"
再告訴瀏覽器用什麼碼錶打開 ;
其實能夠不告訴瀏覽器用什麼碼錶,由於 只要告訴服務器翻譯的碼錶,服務器會自動將servlet的response的碼錶設爲一致的;可是,咱們仍是寫上吧
每一個jsp
頁面在 第一次 被訪問時,web容器
都會把請求交給 jsp引擎
(即一個java程序)去處理。Jsp引擎
先將 jsp
翻譯成一個_jspServlet
(實際上就是一個servlet),而後按照 servlet
的調用方式進行調用 ;
因爲JSP
第一次訪問時,會被翻譯成servlet,全部第一次訪問一般會比較慢,可是第二次訪問,JSP引擎
若是發現 JSP
沒有變化,就再也不翻譯,而是直接調用,因此程序的執行效率不會受到影響;
JSP引擎
在調用 JSP
對應的 _JspServlet
時,會 傳遞或建立 9個與WEB開發相關的對象供_JspServlet
使用。
JSP
技術的設計者爲了方便web
開發人員在編寫JSP
頁面時,得到這些對象的引用,特地定義了9個相應的變量,開發人員在JSP頁面中經過這9個變量就能夠快速的得到這9大對象的引用;
這九大隱式對象就是:response
、request
、session
、application(ServletContext)
、page
(jsp
對象自身)、config(servlertConfig)
、exception
、out(JspWriter)
、PageContext
前面7個,在學JSP以前,都已經學過了,這裏重點講最後兩個;
Out隱式對象
做用:Out隱式對象
用於向客戶端發送文本數據;
Out對象
是經過調用 PageContext
對象的 getOut()
方法返回的,其做用和用法與servletResponse.getWriter
方法返回的 PrintWriter
對象很是類似。
JSP
頁面中的out
隱式對象的類型爲JspWriter
,JspWriter
至關於一種帶緩存功能的PrintWriter
,設置JSP
頁面的page
指令的buffer
屬性能夠調整它的緩存大小,甚相當閉它的緩存(buffer
屬性的值爲none
);
只有向out
對象中寫入了內容,且 知足以下任何一個條件時(至關於刷新緩衝區),out
對象纔會去調用servletResponse.getWriter
方法,而且經過該方法返回PrinterWriter
對象將out
對象緩衝區中的內容 真正的寫入 到servlet
引擎提供的緩衝區中(response
緩衝區):
條件
:
√ 設置page
指令的buffer屬性關閉了out
對象的緩存功能
√ out
對象的緩衝區已滿 ;
√ 整個JSP
頁面結束;
備註
:
Out
對象輸出的數據 可能滯後於 response.getWriter
對象輸出的數據,緣由就在於out對象本身的緩衝區;out對象的緩存區滿了,纔將數據刷新到response的緩衝區;服務器發現response緩衝區有數據,纔會將數據發送到客戶端;
是jsp
技術中最重要
的一個對象,它表明jsp
頁面的運行環境
;
生命週期
是一個jsp
頁面;
這個對象自身就封裝可其餘8大隱式對象的引用;(這個最厲害了)
它自身仍是一個域對象,能夠用來保存數據;
這個對象中,還封裝了web開發中常常涉及到的一些經常使用操做,例如引入和跳轉其餘資源、檢索其餘域對象中的屬性;
PageContext
對象得到其餘對象經過 getXXX()
方法;
PageContext
對象中包含其餘8大隱式對象的引用;
首先知道一個事實:JSP
頁面中是不該該出現java
代碼,良好的jsp
中,是不該該出現一行java
代碼的;
可是有些時候,咱們爲了獲取servlet
傳過來的數據,不得已要使用java
代碼,這時候,咱們就須要一個技術:自定義標籤;(之後會講這個技術)
咱們把java
代碼替換成一個自定義標籤
,這個標籤對應着一個java
類,咱們須要把web中的這些對象傳給java
類,一個一個傳,很麻煩的,所以,咱們就直接傳一個pageContext
對象過去;
域 | 範圍(從小到大 ) |
---|---|
Page 域: |
pageContext,最小的域,只能在頁面中使用 |
Request 域: |
請求域 |
Session 域: |
會話級別的域 |
ServletContext 域: |
最大的域,在整個應用程序中可用 |
獲取數據
pageContext.getAttribute(String) ;
設置數據
pageContext.setAttribute(String,String);
移除數據
pageContext.removeAttribute(String);
獲取id對應的域的數據
pageContext.getAttribute(String,id) ;
設置id對應的域數據
pageContext.setAttribute(String,String,id);
移除id對應的域數據
pageContext.removeAttribute(String,id);
PageContext查找屬性的方法
pageContext.findAttribute(String)
用於查找某個屬性的屬性值,它會依次從page
、request
、session
、application
四個域,從小到大的查找,在某個域中查到數據,即刻返回這個數據,不會再繼續查下去。若是四個域都沒查到,則返回null;
這個方法,便利於咱們能夠在jsp
中直接使用這個方法來查找數據,而不要去關注數據在哪個域中;
PageContext
類中定義了一個forward
方法和兩個include
方法來分別簡化和替代RequestDispatcher(...).forward
方法和RequestDispatcher(...).include
方法。
原始的操做
:
// forward
request.getRequestDispatcher("/xxx").forward(request, response);
// include
request.getRequestDispatcher("/xxx").include(request, response);
使用pageContext
簡化:
// forward
pageContext.forward("/xxx");
// include
pageContext.include("/xxxx");
方法接受的資源若是以 /
開頭,/
表明當前web
應用;
JSP Action (JSP動做)
,它用於jsp
頁面中提供業務邏輯功能,避免在JSP
頁面中直接編寫java
代碼,形成jsp
頁面難以維護;
經常使用的三種標籤:
// 動態包含
<jsp:include page=""> </jsp:include>
//跳轉頁面
<jsp:forward page="">
// 負責帶數據到另外一個JSP頁面中,value的值,能夠是腳本表達式 // 通常和包含include便籤一塊兒使用
<jsp:param name="" value=""></jsp:param>
// 將數據帶到xxx.jsp 中
<jsp:include page="xxxx.jsp">
<jsp:param name="xxx" value="xxx"/>
</jsp:include>
其中 </jsp:forward>
Jsp跳轉
應用場景:
在配置歡迎首頁的時候,是不讓配置servlet的,只能配置成jsp。 所以,在jsp中進行跳轉頁面;
<servlet>
<servlet-name>myform</servlet-name>
<!--Jsp的路徑須要 / 來指認 -->
<jsp-file>/form.jsp</jsp-file>
</servlet>
<servlet-mapping>
<servlet-name>myform</servlet-name>
<url-pattern>/myform.html</url-pattern>
</servlet-mapping>
若是訪問JSP
的時候,出現服務器報錯,緊接着再次訪問,服務器又不報錯的狀況,像神經病同樣一時好一時壞;
出現這樣的問題的緣由在於:JSP
文件被咱們寫錯了;並其寫錯以前,這個JSP曾經被咱們正確寫對過,而且在服務器中有翻譯過的servlet,這樣,當咱們把JSP
修改出錯之後,再次訪問,服務器發現JSP
被修改過,就會從新翻譯一次,生成新的servlet,覆蓋以前的servlet。可是因爲,JSP
語法有錯,沒法被正確的翻譯爲servlet
,這樣舊的servlet
就不會被覆蓋掉。還存在在服務器中;
這樣,當咱們第一次訪問的時候,服務器翻譯JSP
失敗,就會爆錯,可是咱們緊接着,再次訪問,服務器發現,這人怎麼回事啊,我剛翻譯完這個servlet
啊,它就不會再次翻譯servlet,而是把以前舊的servlet當成上一次翻譯的servlet
(這個過程,跟JSP變沒變,沒有任何關係,應該是JSP設計者,爲了減輕服務器的壓力設計的),給咱們;這就是咱們第一次報錯,緊接着再次訪問,就正確的緣由;
當咱們,過一會再次訪問,服務器就會發現,我曹這個JSP,我並無翻譯啊,就會再次翻譯,而後,就會再次報錯,周而復始,給咱們的感受就是JSP在抽風,時好時壞;
彷彿一會兒回到了90年代的夏天,你光着上身,穿着大褲衩,一雙簡單的人字拖,搖着一把破舊的芭蕉扇,VCD裏轉動着盜版的碟片,滿滿都是廣東香港氾濫到內地的流行歌曲和港片,手裏的冰激凌在融化,碟片偶爾會卡,你拿起遙控摁了一下快進鍵,一會兒就這麼快進了十幾年。
寫的真好!
《over》