其餘更多java基礎文章:
java基礎學習(目錄)html
本章內容較多,所有認真看完可能須要一小時以上,建議邊看邊作筆記,不然容易混亂java
網絡服務器須要一個JSP引擎,也就是一個容器來處理JSP頁面。容器負責截獲對JSP頁面的請求。內嵌JSP容器的Apache支持JSP開發。
JSP容器與Web服務器協同合做,爲JSP的正常運行提供必要的運行環境和其餘服務,而且可以正確識別專屬於JSP網頁的特殊元素。
下圖顯示了JSP容器和JSP文件在Web應用中所處的位置。web
如下步驟代表了Web服務器是如何使用JSP來建立網頁的:編程
以上說起到的步驟能夠用下圖來表示: api
通常狀況下,JSP引擎會檢查JSP文件對應的servlet是否已經存在,而且檢查JSP文件的修改日期是否早於servlet。若是JSP文件的修改日期早於對應的servlet,那麼容器就能夠肯定JSP文件沒有被修改過而且servlet有效。這使得整個流程與其餘腳本語言(好比PHP)相比要高效快捷一些。瀏覽器
Jsp 生成java源碼,默認第一次生成,以後直接執行,除非內容修改,具體點說,因爲JSP只會在客戶端第一次請求的時候被編譯,所以第一次請求JSP時會感受比較慢,而以後的請求由於不會編譯JSP,因此速度就快多了。
若是將Tomcat保存的JSP編譯後的class文件刪除,Tomcat也會從新編譯JSP。在開發Web程序的時候常常須要修改JSP, Tomcat可以自動檢測到JSP程序的改動,若是檢測到JSP源代碼發生了改動,Tomcat會在下次客戶端請求JSP時從新編譯JSP,而不須要重啓Tomcat,這種自動檢測功能默認是開啓的,檢測改動會消耗少許的時間,在部署web應用程序的時候能夠在web.xml中將它關掉。
這也就是爲何咱們可以在jsp頁面直接修改內容,而不用從新啓動服務器的緣由。緩存
總的來講,JSP網頁就是用另外一種方式來編寫servlet而不用成爲Java編程高手。除了解釋階段外,JSP網頁幾乎能夠被當成一個普通的servlet來對待。安全
理解JSP底層功能的關鍵就是去理解它們所遵照的生命週期。JSP生命週期就是從建立到銷燬的整個過程,相似於servlet生命週期,區別在於JSP生命週期還包括將JSP文件編譯成servlet。
如下是JSP生命週期中所走過的幾個階段:
編譯階段:
servlet容器編譯servlet源文件,生成servlet類
初始化階段:
加載與JSP對應的servlet類,建立其實例,並調用它的初始化方法
執行階段:
調用與JSP對應的servlet實例的服務方法
銷燬階段:
調用與JSP對應的servlet實例的銷燬方法,而後銷燬servlet實例
很明顯,JSP生命週期的四個主要階段和servlet生命週期很是類似,下面給出圖示:bash
使用<%=result %>來輸出結果,servlet中就會將其轉換爲out.print(result)進行輸出。輸出各類類型數據:int、double、boolean、String、Object等。服務器
<%-- --%>:jsp註釋 <!-- -->:這個註釋,會發送到瀏覽器端的源碼中顯示 註釋分別在servlet中如何顯示:
在servlet中
總結:JSP註釋不會在servlet文件中顯示,而java註釋則會,但其全部的註釋到了瀏覽器端,都不會出如今源碼中,只有這個註釋會到瀏覽器的網頁源碼中去。
JSP指令(directive)是爲JSP引擎而設計的,它們並不直接產生任何可見輸出,而只是告訴引擎如何處理JSP頁面中的其他部分。指令用來申明JSP頁面的一些屬性,好比編碼方式,文檔類型。咱們在servlet中也會申明咱們使用的編碼方式和響應的文檔類型的,而JSP就是用指令來申明。
JSP指令格式:<%@ directive {attribute=value}* %>(<%@ 指令名稱 屬性1=「屬性值1」 屬性2=「屬性值2」。。。%>)
分析:
directive:指令名稱,例如page指令
attribute=value:緊跟指令名稱後面的就是各類屬性,以鍵值對的形式書寫
*:表明後面能跟0個或多個屬性。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> page指令,後面跟着三個屬性,分別是language、contentType、pageEncoding。
這只是其中的幾個屬性,並無寫全,page指令容許的屬性以下表所示:
屬性名稱 | 取值範圍 | 描述 |
---|---|---|
language | java | 解釋該JSP文件時採用的語言,通常爲java語言,默認爲java |
extends | 任何類的全名 | 編譯該JSP文件時繼承哪一個類,JSP爲Servlet,所以當指明繼承普通類時須要實現Servlet的init、destroy等方法 |
import | 任何包名、類名 | 引入該JSP中用到的類、包等,import是惟一能夠聲明屢次的page指令屬性,一個import能夠引用uogelei,中間用英文逗號隔開,如<%@ page import="java.util.List,java.util.ArrayList"%> |
session | true、false | 該JSP內是否內置Session對象,若是爲true,則內置Session對象,可直接使用,不然反之,默認爲true |
autoFlush | true,false | 是否運行緩存,若是爲true,則使用out.println()等方法輸出的字符串並非馬上到達客戶端服務器的,而是暫時存到緩存裏,緩存滿了或者程序執行完畢或者執行out.flush()操做時纔到客戶端,默認爲true。 |
buffer | none或者數字KB | 指定緩存大小,當autoFlush設爲true時有效,例如<%@ page buffer=10kb%> |
isThreadSafe | true,false | 是否線程安全,若是爲true,則運行多個線程同時運行該jsp程序,不然只運行一個線程,其他線程等待,默認爲false |
isErrorPage | true,false | 指定該頁面是否爲錯誤顯示頁面,若是爲true,則該JSP內置有一個Exception對象exception,可直接使用,不然沒有,默認爲false |
errorPage | 某個JSP頁面的相對路徑 | 指明一個錯誤頁面,若是該JSP程序拋出一個未捕捉的異常,則轉到errorPage指定的頁面,errorPage指定的頁面一般isErrorPage屬性爲true,且內置的exception對象爲未捕捉的異常 |
contentType | 有效的文檔類型 | 客戶端瀏覽器根據該屬性判斷文檔類型,例如 HTML格式爲text/html、純文本格式爲text/plain、JPG圖像爲image/jpeg、GIF圖像爲image/gif、WORD文檔爲application/msword,該屬性常跟着charset設置編碼一塊兒,做用是通知服務器和瀏覽器都使用同一個碼錶 |
info | 任意字符串 | 指明JSP的信息,該信息能夠經過Servlet.getServletInfo()方法獲取到 |
trimDirective Whitespaces | true、false | 是否去掉指令先後的空白字符,默認爲false |
pageEncoding | UTF-8,ISO-8859-1等 | 指定一張碼錶來對該JSP頁面進行編碼 |
比較簡單,只有一種形式 <%@ include file="relativeURL"%> relativeURL:本應用程序內另外一個JSP文件或者HTML文件的路徑,例如,網址內全部頁面均有一個統一風格的導航欄和頁腳版權,那麼就可使用該指令將其包含進來。
特色:
include指令會將包含頁面的源代碼添加到使用include指令的頁面中來,而後編譯成class文件,而等下會講到的一個JSP行爲,<jsp:include page="relativeURL">做用跟include指令同樣,可是不一樣的是,include行爲是運行時單獨執行包含頁面,而後把執行的結果包含到本頁面來,屬於先運行後包含。
注意:
靜態包含:把其它資源包含到當前頁面中 。
<%@ include file="/include/header.jsp" %>
動態包含:
<jsp:include page="/include/header.jsp"></jsp:include>
二者的區別:翻譯的時間段不一樣
前者:在翻譯時就把兩個文件合併
後者:不會合並文件,當代碼執行到include時,才包含另外一個文件的內容。
原則:能用靜的就不用動的。
JSP支持標籤技術,後面會講到標籤的用法,jstl標籤庫的使用等 做用:用來指明JSP頁面內使用的JSP標籤庫,taglib指令有兩個屬性,uri爲類庫的地址,prefix爲標籤的前綴 <%@ taglib uri="java.sun.com/jsp/jstl/co…" prefix="c"%>
前面講了JSP語法,介紹了JSP頁面中的內容有哪些,分別有什麼做用,就兩個東西,模塊數據和元素。其中元素有包括腳本,指令,標籤,腳本就是JSP中嵌入java代碼,指令做用就是申明頁面的屬性,那標籤是幹嗎的,標籤分爲JSP自帶內置的標籤,和經過taglib指令來使用JSP標籤庫,或者自定義標籤。如今咱們先來說一些JSP內置的標籤。 JSP內置的標籤就被稱爲JSP行爲(JSP Actions)。只要書寫不多的標記代碼就能使用JSP提供的豐富功能,JSP行爲實際上是對經常使用的JSP功能的抽象與封裝,能夠取代jsp腳本,讓JSP中就少一些嵌入java代碼的地方。
簡單的說就是使用標籤的形式來表示一段java代碼,格式:
<jsp:elements {attribute="value"}* />
分析:
jsp:標籤的前綴,說明是jsp內置的標籤 ,
elements:行爲的名稱,
attribute=value:使用鍵值對來編寫屬性
*:能指定0個或多個屬性對
<jsp:include page="/include/header.jsp"></jsp:include>
複製代碼
include行爲用於運行時包含某個文件,若是被包含的文件爲JSP程序,則先會執行JSP程序,而後在把執行的結果包含進來。
做用是跟include指令同樣的,惟一的區別就在於,include指令是將被包含的文件的源碼加入到了本JSP程序中,而後在進行編譯,屬於靜態包含,而include行爲只是將被包含的文件的運行結果包含進本身。屬於動態包含。
是一組與Java Bean 相關的行爲,包括useBean行爲、setProperty行爲、getProperty行爲等。Java Bean就是普通的Java類,也被稱爲POJO,只有私有的屬性與對應的getter方法和setter方法,注意其中當私有的屬性爲boolean類型時,習慣上通常把getter方法寫成isXxx();而不是getXxx();
1)userBean行爲
<jsp:useBean id="beanObject" class="className" scope="Value">  做用:在jsp中定義一個java bean對象。
複製代碼
分析:
id:指明Java Bean對象的名稱,JSP中可使用該名稱引用該Java Bean對象,至關於給new出來的對象取一個變量名
class:Java Bean類的全名
scope:該java bean對象的做用範圍,能夠寫的就四個,也就是JSP的四大做用域,page、request、session、application
---page:只能在當前JSP頁面使用,若是不在JSP頁面,那麼就會失效
---request:這個前面學過,A頁面請求轉發到B頁面,那麼使用的是同一個request,那麼A,B頁面都算是request的做用域,也就是經過請求轉發的頁面都是其做用域
----session:該做用域在一個web項目下任何位置應該讀訪問的到,只要cookie不關閉,而且cookie設置的訪問路徑爲"/",
---application:其實就是Servlet中的servletContext,服務器下的全部項目都能訪問到。
2)setProperty行爲 <jsp:setProperty name="beanName" property="propertyName" value="">
分析:
對Java Bean對象進行屬性的設置
name:java bean對象的名稱,也就是在useBean行爲中的id
property:對象中的屬性名,
value:要對其屬性進行賦值的值
3)getProperty行爲 <jsp:getProperty name="beanName" property="propertyName" />
分析:
獲取JavaBean對象的某個屬性值
name:java bean 對象的名稱,也就是在useBean行爲中的id
property:對象的屬性名
實現請求轉發功能,Servlet中經過request.getRequestDispatcher("someServlet").forward(request,response);而在JSP中也可以實現相同的功能,只不過用的是<jsp:forward />行爲,實際上forward行爲就是對其進行了封裝。
格式:
<jsp:forward page="someServlet">
  <jsp:param name="param1" value="value1"/>
  <jsp:param name="param2" value="value2"/>
</jsp:forward>
複製代碼
分析:page:須要跳轉到的頁面或者servlet、jsp:param/參數行爲,帶一些參數過去,name、value是以鍵值對的形式帶過去的
咱們知道JSP中的內容就只有兩種,模版數據和元素,元素就包括了指令,腳本,標籤(行爲),腳本會慢慢被標籤所有代替,也就是說JSP中基本上不會嵌入Java代碼,可是咱們也知道JSP會轉換爲servlet,在Servlet中,輸出數據時,都須要經過response.getWrite();可是在JSP中,直接使用out對象進行輸出,爲何呢?這就是由於out爲JSP的一個隱藏對象,JSP中內置了9個隱藏對象,使得JSP比Servlet使用起來更簡單,更方便。
分析:
request:請求對象,類型:httpServletRequest
response:響應對象,類型:httpServletResponse
session:表示一次會話,在服務器端記錄用戶狀信息的技術
application:標識web應用上下文,類型:ServletContext,詳情就看Servlet中的ServletContext的使用
exception:表示發生異常對象,類型 Throwable,在上面咱們介紹page指令中的一個errorPage屬性時就有說到他
page:page對象表明當前JSP頁面,是當前JSP編譯後的Servlet類的對象。至關於this。
config:標識Servlet配置,類型:ServletConfig,api跟Servlet中的ServletConfig對象是同樣的,能獲取該servlet的一些配置信息,可以獲取ServletContext
out:輸出響應體 類型:JspWriter
pageContext:表示 jsp頁面上下文(jsp管理者) 類型:PageContext
注意:標記了紅色的對象就是JSP獨有的,其餘的都是Servlet中的老東西。
在這個由jsp轉換爲servlet的文件中,只能看到8個內置對象,少了exception對象,由於咱們在將page指令時,說過一個isErrorPage屬性,默認是false,被關閉了,因此其中並無exception對象。
這個功能就比較強大了,基本上什麼他都有,由於是它是JSP頁面的管理者(上下文),因此JSP中的內置對象呀,它通通可以得到,下面介紹它的api:
1)得到其它八大內置對象 getXxx()
在普通類中能夠經過PageContext獲取其餘JSP隱式對象。自定義標籤時就使用。
pageContext.getOut(); //得到out對象
pageContext.getApplication(); //得到application對象
等等....
2)對做用域的屬性進行操做(四大做用域)
對默認做用域的屬性進行操做。page
Object getAttribute(String name); //得到page做用域數據
void setAttribute(String name,Object o); //給page做用域設置內容
void removeAttribute(String name); //給page做用域移除內容
3)對指定做用域的屬性進行操做
Object getAttribute(String name,int Scope); //得到 指定做用域中的數據
void setAttribute(String name,Object o,int Scope); //給指定做用域設置內容
void removeAttribute(String name,int Scope); // 移除指定做用域的內容(page/request/session/application)
4)提供做用域常量
PageContext.PAGE_SCOPE page
PageContext.REQUEST_SCOPE request
PageContext.SESSION_SCOPE response
PageContext.APPLICATION_SCOPE application
5)一次得到指定名稱內容
pageContext中最厲害的方法是:
findAttribute(String name); //自動從page request session application依次查找,找到了就取值,結束查找。
6)提供了的簡易方法
pageContext.forward("2.jsp");
pageContext.include("2.jsp");
類型:JspWriter
jsp 輸出底層使用 response.getWriter();什麼意思呢?這裏就要講解一下JSP緩存和Servlet緩存了,輸出的過程是這樣的
JSP頁面轉換爲Servlet後,使用的out對象是JspWriter類型的,因此是會先將要發送的數據存入JSP輸出緩存中,而後,等JSP輸出緩存滿了在自動刷新到servlet輸出緩存等serlvet輸出緩存滿了,或者程序結束了,就會將其輸出到瀏覽器上。除非手動out.flush()。
驗證servlet輸出緩存和JSP輸出緩存和咱們上面所說的是正確:
分析: 若是按沒有jsp緩存和servlet緩存的話,輸出的結果應該是aaaabbbbcccc,可是輸出的倒是bbbbaaaacccc,爲何呢?按照咱們上面所說的原理進行分析,out對象是先將其輸出到JSP緩存中,因此aaaa加入了jsp緩存,而response.getWriter().print("bbbb")是直接將bbbb輸出到servlet緩存中,而後又使用out對象將cccc輸出到jsp緩存,到程序結束,servlet緩存中有bbbb,而後jsp會將緩存中的內容就刷新到servlet緩存中,serlvet就是bbbbaaaacccc了,而後到瀏覽器也就獲得咱們的輸出結果了。若是在12行將註釋去掉,那麼輸出的結果又會是什麼呢?答案就是aaaabbbbcccc,過程自行分析。
類型:ServletConfig
可以獲取servlet的初始化參數,獲取servletContext對象,獲取servletName。
包含了異常的信息
使用它,必須結合page指令中的isErrorPage屬性和errorPage屬性。
以下例子,exception.jsp拋異常的一個NullPointException,而且跳轉到error.jsp錯誤顯示頁面,其中errorPage屬性的意思是若是發生未捕捉到的異常,將會跳轉到error.jsp頁面
error.jsp isErrorPage屬性說明該頁面是一個錯誤顯示頁面,則可使用exception對象
訪問:訪問http://localhost:8080/Web_Jsp/exception.jsp
page就是jsp轉換爲servlet對象自己,也就是this
config -- Servlet中的servletConfig
application -- Servlet中的ServletContext
request -- Servlet中的request
response -- Servlet中的response
session -- Servlet中的session out -- JspWriter
exception -- 異常對象
pageContext -- 表示 jsp頁面上下文(jsp管理者) 類型:PageContext
其中pageContext是最厲害的,由於它能夠獲得其餘8個內置對象
這四大做用域,其實就是其九大內置對象中的四個,爲何說他們也是JSP的四大做用域呢? 由於這四個對象都能存儲數據,好比request.setAttribute()注意和request.setParameter()區分開來,一個是存儲在域中的、一個是請求參數,session.setAttribute()、application其實就是SerlvetContext,天然也有setAttribute()方法。
而page做用域的操做就須要依靠pageContext對象來進行了。在上面咱們也有提到JSP的四大做用域。
1)page做用域 表明變量只能在當前頁面上生效
2)request做用域 表明變量能在一次請求中生效,一次請求可能包含一個頁面,也可能包含多個頁面,好比頁面A請求轉發到頁面B。
3)session做用域 表明變量能在一次會話中生效,基本上就是能在web項目下都有效,session的使用也跟cookie有很大的關係。通常來講,只要瀏覽器不關閉,cookie就會一直生效,cookie生效,session的使用就不會受到影響。
4)application做用域 表明變量能一個應用下(多個會話),在服務器下的多個項目之間都可以使用。好比baidu、wenku等共享賬號。