前面講解了Servlet,了解了Servlet的繼承結構,生命周期等,并且在其中的ServletConfig和ServletContext對象有了一些比較詳細的了解,但是我們會發現在Servlet中編寫一些HTML代碼,是很不友善的一件事情,每次都需要out.println(HTML); 是以就出現了JSP,來解決這樣的問題,JSP中的内容就是html,但是能夠嵌套java語言,現在來詳細了解一下JSP。
--WZY
一、JSP
1、什麼是JSP?
JSP(Java Server Pages):是以Java語言為基礎的動态網頁開發技術,
特點:
Servlet特點:在Java源碼中嵌入html源碼
JSP特點:在html源碼中嵌入java代碼
JSP就是Servlet
1、tomcat獲得JSP檔案後,先将JSP轉成servlet,變成xxx.java(servlet源碼),
D:\java\tomcat7.0\apache-tomcat-7.0.53\apache-tomcat-7.0.53\work\Catalina\localhost\test01\org\apache\jsp
|------------------------------------------------------------------------| |---------|----------|-------|-----------------|
tomcat安裝目錄 引擎 主機 項目 固定包名 這個之下就是存放着jsp變成的servlet檔案.java和編譯檔案.class
2、tomcat将java檔案編譯成class檔案
3、tomcat運作class檔案,并将結果輸出到浏覽器,
執行個體:
建立一個jsp。檢視其轉換後的servlet代碼。
NewFile.jsp
View Code
NewFile_jsp.java
可以看到public final class NewFile_jsp extends org.apache.jasper.runtime.HttpJspBase implements org.apache.jasper.runtime.JspSourceDependent
NewFile_jsp.java繼承自HttpJspBase。來看看HttpJspBase的源碼
HttpJspBase.java
public abstract class HttpJspBase extends HttpServlet implements HttpJspPage
看到了一個熟悉的類,HttpServlet,我們編寫Servlet時就是繼承自該類,這裡也是繼承HttpServlet,并且HttpJspBase的源碼會發現,生命周期也是有init()方法,service()方法,destory()方法,相當于_jspService()方法就是servlet的service()方法的執行,是以說JSP也是一個servlet。
我們在JSP寫的所有html代碼,都會被轉換為servlet中的out.write(html)代碼來輸出。看圖
小總結:
對于jsp轉換成的servlet源碼,之後我們會在進行詳細分析,現在隻需要知道jsp中的内容在servlet中被轉換成什麼了,在哪裡被轉換了即可。其中_jspService()方法的詳細内容下面會講解
注意: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,那麼生命周期也就是跟serlvet一樣。
JSP和servlet有一點差別就在于:jsp是先部署後編譯,而servlet是先編譯後部署。
二、JSP文法
JSP模版資料:
就是JSP中的HTML代碼,它的内容給是固定的,無論程式如何運作模版資料輸出到用戶端浏覽器時都不會發生改變,當我們建立一個JSP時,模版就已經固定了。
元素:JSP中的java部分,包括腳本(JavaScript,或者java代碼)以及JSP指令(Directive)與JSP标簽(Tag)等,元素決定着程式的流程,元素是不會顯示到浏覽器的。這幾個都會在接下來講解到
JSP腳本:
1、使用<% 編寫java代碼 %>,中間java代碼必須遵循Java文法,
為什麼能夠使用out輸出?這裡就涉及到了JSP的九大内置對象了,後面會講解到,到時候回過頭來在看看這裡,就會知道為什麼可以使用。
來看看,jsp變為servlet時的代碼是如何編寫的。
在JSP中JSP指令(後面會講):
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
這句代碼在servlet就變為了
response.setContentType("text/html; charset=UTF-8");//這句代碼的意思就是通知tomcat和浏覽器都使用UTF-8碼表,并且發送回浏覽器的資料類型是text/html。這是有JSP指令中畫紅色部分代碼轉變的,而指令中的pageEncoding="UTF-8"的意思是JSP轉換為Servlet時采用UTF-8碼表編碼,因為可能JSP中包含中文。
對于JSP模版資料來說,就原封不動的使用out.write()來輸出到浏覽器
而對于JSP元素來說,就會變成普通的java代碼,因為在servlet中,就可以直接編寫java代碼。
2、使用<%=xxx %>來輸出結果
使用<%=result %>來輸出結果,servlet中就會将其轉換為out.print(result)進行輸出。輸出各種類型資料:int、double、boolean、String、Object等
3、JSP注釋
<%-- --%> :jsp注釋,
// :java單行注釋
/ / :Java多行注釋
:這個注釋,會發送到浏覽器端的源碼中顯示
注釋分别在servlet中如何顯示的?
JSP注釋不會在servlet檔案中顯示,而java注釋則會,但其所有的注釋到了浏覽器端,都不會出現在源碼中,隻有這個注釋會到浏覽器的網頁源碼中去
4、JSP中申明方法與屬性(全局變量) 使用<%! 方法、屬性%>
這個就不示範了,就是在JSP中編寫方法或者屬性時,使用<%! %>括起來。
5、在JSP中使用if語句,或者使用for循環,whilt循環等都可以實作,也就是編寫腳本而已。
三、JSP指令
指令用來申明JSP頁面的一些屬性,比如編碼方式,文檔類型。我們在servlet中也會申明我們使用的編碼方式和響應的文檔類型的,而JSP就是用指令來申明。上面我們也說到了一條指令,也就是page指令,
JSP指令格式:<%@ directive {attribute=value}* %>
解釋:
directive:指令名稱,例如page指令
attribute=value:緊跟指令名稱後面的就是各種屬性,以鍵值對的形式書寫
*:代表後面能跟0個或多個屬性。
例如: page指令:用來聲明JSP頁面的屬性等。
<%@ 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指令
比較簡單,隻有一種形式 <%@ include file="relativeURL"%> relativeURL:本應用程式内另一個JSP檔案或者HTML檔案的路徑,例如,網址内所有頁面均有一個統一風格的導航欄和頁腳版權,那麼就可以使用該指令将其包含進來,
特點:include指令會将包含頁面的源代碼添加到使用include指令的頁面中來,然後編譯成class檔案,而等下會講到的一個JSP行為,<jsp:include page="relativeURL">作用跟include指令一樣,但是不同的是,include行為是運作時單獨執行包含頁面,然後把執行的結果包含到本頁面來,屬于先運作後包含。
taglib指令
JSP支援标簽技術,後面會講到标簽的用法,jstl标簽庫的使用等,
作用:用來指明JSP頁面内使用的JSP标簽庫,taglib指令有兩個屬性,uri為類庫的位址,prefix為标簽的字首
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
四、JSP行為
前面講了JSP文法,介紹了JSP頁面中的内容有哪些,分别有什麼作用,就兩個東西,子產品資料和元素。其中元素有包括腳本,指令,标簽,腳本就是JSP中嵌入java代碼,指令作用就是申明頁面的屬性,那标簽是幹嘛的,标簽分為JSP自帶内置的标簽,和通過taglib指令來使用JSP标簽庫,或者自定義标簽。現在我們先來講一些JSP内置的标簽。
JSP内置的标簽就被稱為JSP行為(JSP Actions)。隻要書寫很少的标記代碼就能使用JSP提供的豐富功能,JSP行為其實是對常用的JSP功能的抽象與封裝,可以取代jsp腳本,讓JSP中就少一些嵌入java代碼的地方。
格式:<jsp:elements {attribute="value"}* />
jsp:标簽的字首,說明是jsp内置的标簽,
elements:行為的名稱,
attribute=value:使用鍵值對來編寫屬性
*:能指定0個或多個屬性對
<jsp:include />行為
include行為用于運作時包含某個檔案,如果被包含的檔案為JSP程式,則先會執行JSP程式,然後在把執行的結果包含進來。 作用是跟include指令一樣的,唯一的差別就在于,include指令是将被包含的檔案的源碼加入到了本JSP程式中,然後在進行編譯,屬于靜态包含,而include行為隻是将被包含的檔案的運作結果包含進自己。屬于動态包含
Java bean行為
是一組與Java Bean 相關的行為,包括useBean行為、setProperty行為、getProperty行為等
Java Bean就是普通的Java類,也被稱為POJO,隻有私有的屬性與對應的getter方法和setter方法,注意其中當私有的屬性為boolean類型時,習慣上一般把getter方法寫成isXxx();而不是getXxx();
useBean行為
<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,伺服器下的所有項目都能通路到。
setProperty行為
<jsp:setProperty name="beanName" property="propertyName" value="">
對Java Bean對象進行屬性的設定
name:java bean對象的名稱,也就是在useBean行為中的id
property:對象中的屬性名,
value:要對其屬性進行指派的值
getProperty行為
<jsp:getProperty name="beanName" property="propertyName" />
擷取JavaBean對象的某個屬性值
name:java bean 對象的名稱,也就是在useBean行為中的id
property:對象的屬性名
例子: javabean:User.java NewFile.jsp
User.java
NewFile.jsp
可以檢視NewFile.jsp變為servlet後的源代碼,看看我們寫的javabean行為會被轉換為何種語句
這裡出現了一個JSP九大内置對象中的一個,pageContext。現在簡單提一句,pageContext就是JSP頁面的管理者(上下文),其中的getAttribute(name,scope)方法是擷取指定作用域中的資料的,如果getAttribute(name)方法的話,預設是對page作用域進行操作,findAttribute(name)依次從page、request、session、application獲得内容。
在第一個紅框中,就代表中我們的useBean行為,其中進行了一次判斷,就是如果在page作用域中找不到user這個對象,那麼就建立一個新的,否則就使用找到的這個user對象,
第二個紅框中,代表着我們的setProperty行為,先找到user對象,然後在對其屬性進行指派
第三個紅框中,代表着我們的getProperty行為,也是先找到user對象,然後在擷取其屬性的值。
注意:對于javabean行為來說,有一個特點的地方,就是當請求過來的參數對應javabean的屬性時,可以為其一次性設定所有的值
<jsp:setProperty name="user" property="" /> //設定user的所有屬性,屬性值從request中自動取得,代表所有屬性。
<jsp:forward />行為
實作請求轉發功能,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是以鍵值對的形式帶過去的
例如:
NewFile.jsp
MyServlet.java
通路:
http://localhost:8080/test01/NewFile.jsp
浏覽器位址欄沒有改變,說明是請求轉發
NewFile_jsp.java
使用return的好處是執行完上面的轉發,就直接return,沒有必要在執行下面的代碼了,對參數使用了URLEncode進行編碼,說明該<jsp:param/>可以直接傳遞中文,但是前提是要設定request.setCharacterEncoding("UTF-8");為什麼這樣做,看上面框起來中的代碼。
<jsp:directive/>行為
directive行為,就相當于JSP指令,比如<jsp:directive.page/>相當于<%@ page %>指令,等等其它指令是一樣的書寫格式。
五、JSP隐藏的九大内置對象和四大作用域
之前那麼一大段内容,就是為了講解什麼是JSP,JSP中的内容是怎麼樣的,到這裡應該知道的差不多了, 但我們還要深入了解一些東西,我們知道JSP中的内容就隻有兩種,模版資料,和元素,元素就包括了指令呀,腳本呀,标簽(行為)呀,腳本會慢慢被标簽全部代替,也就是說JSP中基本上不會嵌入Java代碼,但是我們也知道JSP會轉換為servlet,在Servlet中,輸出資料時,都需要通過response.getWrite();但是在JSP中,直接使用out對象進行輸出,為什麼呢?這就是因為out為JSP的一個隐藏對象,JSP中内置了9個隐藏對象,使得JSP比Servlet使用起來更簡單,更友善,
page、config、application、request、response、session、out、exception、pageContext
page:page對象代表目前JSP頁面,是目前JSP編譯後的Servlet類的對象。相當于this。
config:辨別Servlet配置,類型:ServletConfig,api跟Servlet中的ServletConfig對象是一樣的,能擷取該servlet的一些配置資訊,能夠擷取ServletContext
application:辨別web應用上下文,類型:ServletContext,詳情就看Servlet中的ServletContext的使用
request:請求對象, 類型:httpServletRequest
response:響應對象 類型:httpServletResponse
session:表示一次會話,在伺服器端記錄使用者狀資訊的技術
out:輸出響應體 類型:JspWriter
exception 表示發生異常對象,類型 Throwable,在上面我們介紹page指令中的一個errorPage屬性時就有說到他
pageContext:表示 jsp頁面上下文(jsp管理者) 類型:PageContext
标記了紅色的對象就是JSP獨有的,其他的都是Servlet中的老東西。
在這個由jsp轉換為servlet的檔案中,隻能看到8個内置對象,少了exception對象,因為我們在将page指令時,說過一個isErrorPage屬性,預設是false,被關閉了,是以其中并沒有exception對象。
JSP的四大作用域:page、request、session、application
這四大作用域,其實就是其九大内置對象中的四個,為什麼說他們也是JSP的四大作用域呢?因為這四個對象都能存儲資料,比如request.setAttribute()注意和request.setParameter()區分開來,一個是存儲在域中的、一個是請求參數,session.setAttribute()、application其實就是SerlvetContext,自然也有setAttribute()方法。而page作用域的操作就需要依靠pageContext對象來進行了。在上面我們也有提到JSP的四大作用域,
page作用域:代表變量隻能在目前頁面上生效
request:代表變量能在一次請求中生效,一次請求可能包含一個頁面,也可能包含多個頁面,比如頁面A請求轉發到頁面B
session:代表變量能在一次會話中生效,基本上就是能在web項目下都有效,session的使用也跟cookie有很大的關系。一般來說,隻要浏覽器不關閉,cookie就會一直生效,cookie生效,session的使用就不會受到影響。
application:代表變量能一個應用下(多個會話),在伺服器下的多個項目之間都能夠使用。比如baidu、wenku等共享帳号。
out對象:
類型: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,過程自行分析。
pageContext對象:重點
這個功能就比較強大了,比較牛逼,基本上什麼他都有,因為是它是JSP頁面的管理者(上下文),是以JSP中的内置對象呀,它統統能夠獲得,下面介紹它的api。
1、獲得其它八大内置對象 getXxx()
pageContext.getOut(); //獲得out對象
pageContext.getApplication(); //獲得application對象
等等....
2、對作用域的屬性進行操作(四大作用域)
對預設作用域的屬性進行操作。page
pageContext.getAttribute(name); //獲得page作用域資料
pageContext.setAttribute(name,value); //給page作用域設定内容
pageContext.removeAttribute(name); //給page作用域移除内容
3、對指定作用域的屬性進行操作
getAttribute(name,scope); //獲得 指定作用域中的資料
setAttribute(name,value); //給指定作用域設定内容
removeAttribute(name ,scope) 移除指定作用域的内容(page/request/session/application)
4、提供作用域常量
PageContext.PAGE_SCOPE page
PageContext.REQUEST_SCOPE request
PageContext.SESSION_SCOPE response
PageContext.APPLICATION_SCOPE application
5、一次獲得指定名稱内容
findAttribute(name); //依次從page、request、session、application 獲得内容
response對象:
就是響應對象,、如果不了解就看看講解request和response的這一章節的内容
config對象:
類型:ServletConfig
能夠擷取servlet的初始化參數,擷取servletContext對象,擷取servletName
api詳情請看講解servlet這一章節
exception異常對象:
包含了異常的資訊
使用它,必須結合page指令中的isErrorPage屬性和errorPage屬性。
exception.jsp 抛異常的一個NullPointException,并且跳轉到error.jsp錯誤顯示頁面 errorPage屬性的意思是如果發生未捕捉到的異常,将會跳轉到error.jsp頁面
error.jsp isErrorPage屬性說明該頁面是一個錯誤顯示頁面,則可以使用exception對象
通路
:8080/test01/exception.jsp
六、總結
通過上面一大堆一大堆的學習,我們應該知道這些東西
JSP本質上就是一個servlet,因為servlet輸出html太麻煩了,是以就有了JSP,JSP就是專門用來書寫html的,當然其中也能寫java代碼。
2、JSP的内容包括什麼?
模版資料和元素。其中元素有包括腳本(java代碼)、指令(頁面屬性)、和行為(标簽,為了JSP中不嵌入那麼多java代碼衍生的)
3、JSP中九大内置對象是哪九個?
九大内置對象,page、config、appliction、request、response、session、out、exception、pageContext
4、九大内置對象和servlet中對象的關系
page就是jsp轉換為servletservlet對象本身,也就是this
config -- Servlet中的servletConfig
application -- Servlet中的ServletContext
request -- Servlet中的request
response -- Servlet中的response
session -- Servlet中的session
out -- JspWriter
exception -- 異常對象
pageContext -- 表示 jsp頁面上下文(jsp管理者) 類型:PageContext,
其中pageContext對象最牛逼,有了他就擁有了天下,哈哈~
5、JSP中的四大作用域。
page、request、session、application
其中操作page域中屬性需要借助pageContext對象。
6、JSP中還有其他兩大塊内容
一個是EL表達式,很重要,
另一個是jstl标簽庫的使用,也很重要,在接下來的兩節中,就會講解到。敬請期待。