java基礎學習:JavaWeb之JSP

Hiway發表於2018-12-16

其他更多java基礎文章:
java基礎學習(目錄)

本章內容較多,全部認真看完可能需要一小時以上,建議邊看邊做筆記,否則容易混亂


一、JSP概述

1.1、JSP結構

網路伺服器需要一個JSP引擎,也就是一個容器來處理JSP頁面。容器負責截獲對JSP頁面的請求。內嵌JSP容器的Apache支援JSP開發。
JSP容器與Web伺服器協同合作,為JSP的正常執行提供必要的執行環境和其他服務,並且能夠正確識別專屬於JSP網頁的特殊元素。
下圖顯示了JSP容器和JSP檔案在Web應用中所處的位置。

java基礎學習:JavaWeb之JSP

1.2、JSP執行流程

以下步驟表明了Web伺服器是如何使用JSP來建立網頁的:

  1. 就像其他普通的網頁一樣,您的瀏覽器傳送一個HTTP請求給伺服器。Web伺服器識別出這是一個對JSP網頁的請求,並且將該請求傳遞給JSP引擎。通過使用URL或者.jsp檔案來完成。
  2. JSP引擎從磁碟中載入JSP檔案,然後將它們轉化為servlet。這種轉化只是簡單地將所有模板文字改用println()語句,並且將所有的JSP元素轉化成Java程式碼。
  3. JSP引擎將servlet編譯成可執行類,並且將原始請求傳遞給servlet引擎。
  4. Web伺服器的某元件將會呼叫servlet引擎,然後載入並執行servlet類。在執行過程中,servlet產生HTML格式的輸出並將其內嵌於HTTP response中上交給Web伺服器。Web伺服器以靜態HTML網頁的形式將HTTP response返回到您的瀏覽器中。 最終,Web瀏覽器處理HTTP response中動態產生的HTML網頁,就好像在處理靜態網頁一樣。

以上提及到的步驟可以用下圖來表示:

java基礎學習:JavaWeb之JSP

一般情況下,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來對待。

1.3、JSP生命週期

理解JSP底層功能的關鍵就是去理解它們所遵守的生命週期。JSP生命週期就是從建立到銷燬的整個過程,類似於servlet生命週期,區別在於JSP生命週期還包括將JSP檔案編譯成servlet。
以下是JSP生命週期中所走過的幾個階段:
編譯階段:
servlet容器編譯servlet原始檔,生成servlet類
初始化階段:
載入與JSP對應的servlet類,建立其例項,並呼叫它的初始化方法
執行階段:
呼叫與JSP對應的servlet例項的服務方法
銷燬階段:
呼叫與JSP對應的servlet例項的銷燬方法,然後銷燬servlet例項
很明顯,JSP生命週期的四個主要階段和servlet生命週期非常相似,下面給出圖示:

java基礎學習:JavaWeb之JSP

二、JSP語法

2.1、jsp指令碼

  1. 使用<% 編寫java程式碼 %>,中間java程式碼必須遵循Java語法
          
    java基礎學習:JavaWeb之JSP
    來看看,jsp變為servlet時的程式碼是如何編寫的

      

java基礎學習:JavaWeb之JSP
2. 使用<%=xxx %>來輸出結果

      

java基礎學習:JavaWeb之JSP

使用<%=result %>來輸出結果,servlet中就會將其轉換為out.print(result)進行輸出。輸出各種型別資料:int、double、boolean、String、Object等。

      

java基礎學習:JavaWeb之JSP

  1. 註釋   

<%-- --%>:jsp註釋 <!-- -->:這個註釋,會傳送到瀏覽器端的原始碼中顯示 註釋分別在servlet中如何顯示:

        

java基礎學習:JavaWeb之JSP

在servlet中

        

java基礎學習:JavaWeb之JSP

總結:JSP註釋不會在servlet檔案中顯示,而java註釋則會,但其所有的註釋到了瀏覽器端,都不會出現在原始碼中,只有這個註釋會到瀏覽器的網頁原始碼中去。

  1. JSP中申明方法與屬性(全域性變數)  使用<%! 方法、屬性%>

2.2、3個指令

JSP指令(directive)是為JSP引擎而設計的,它們並不直接產生任何可見輸出,而只是告訴引擎如何處理JSP頁面中的其餘部分。指令用來申明JSP頁面的一些屬性,比如編碼方式,文件型別。我們在servlet中也會申明我們使用的編碼方式和響應的文件型別的,而JSP就是用指令來申明。

JSP指令格式:<%@ directive {attribute=value}* %>(<%@ 指令名稱 屬性1=“屬性值1” 屬性2=“屬性值2”。。。%>)
分析:
directive:指令名稱,例如page指令
attribute=value:緊跟指令名稱後面的就是各種屬性,以鍵值對的形式書寫
*:代表後面能跟0個或多個屬性。

2.2.1、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頁面進行編碼
2.2.2、include指令

比較簡單,只有一種形式 <%@ 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時,才包含另一個檔案的內容。
原則:能用靜的就不用動的。

2.2.3、taglib指令

JSP支援標籤技術,後面會講到標籤的用法,jstl標籤庫的使用等 作用:用來指明JSP頁面內使用的JSP標籤庫,taglib指令有兩個屬性,uri為類庫的地址,prefix為標籤的字首 <%@ taglib uri="java.sun.com/jsp/jstl/co…" prefix="c"%>

2.3、6個動作

前面講了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個或多個屬性對

2.3.1、<jsp:include />行為(動態包含)
<jsp:include page="/include/header.jsp"></jsp:include>
複製程式碼

include行為用於執行時包含某個檔案,如果被包含的檔案為JSP程式,則先會執行JSP程式,然後在把執行的結果包含進來。 

作用是跟include指令一樣的,唯一的區別就在於,include指令是將被包含的檔案的原始碼加入到了本JSP程式中,然後在進行編譯,屬於靜態包含,而include行為只是將被包含的檔案的執行結果包含進自己。屬於動態包含。

java基礎學習:JavaWeb之JSP

2.3.2、Java bean行為

是一組與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">&emsp;&emsp;作用:在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:物件的屬性名

2.3、<jsp:forward />行為

實現請求轉發功能,Servlet中通過request.getRequestDispatcher("someServlet").forward(request,response);而在JSP中也能夠實現相同的功能,只不過用的是<jsp:forward />行為,實際上forward行為就是對其進行了封裝。  

格式:

<jsp:forward page="someServlet">
&emsp;&emsp;<jsp:param name="param1" value="value1"/>
&emsp;&emsp;<jsp:param name="param2" value="value2"/>
</jsp:forward>
複製程式碼

分析:page:需要跳轉到的頁面或者servlet、jsp:param/引數行為,帶一些引數過去,name、value是以鍵值對的形式帶過去的

2.4、9個內建物件

我們知道JSP中的內容就只有兩種,模版資料和元素,元素就包括了指令,指令碼,標籤(行為),指令碼會慢慢被標籤全部代替,也就是說JSP中基本上不會嵌入Java程式碼,但是我們也知道JSP會轉換為servlet,在Servlet中,輸出資料時,都需要通過response.getWrite();但是在JSP中,直接使用out物件進行輸出,為什麼呢?這就是因為out為JSP的一個隱藏物件,JSP中內建了9個隱藏物件,使得JSP比Servlet使用起來更簡單,更方便。

2.4.1、九大內建物件概述

java基礎學習:JavaWeb之JSP

分析:
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中的老東西。

java基礎學習:JavaWeb之JSP

在這個由jsp轉換為servlet的檔案中,只能看到8個內建物件,少了exception物件,因為我們在將page指令時,說過一個isErrorPage屬性,預設是false,被關閉了,所以其中並沒有exception物件。

2.4.2、pageContext(重要)

這個功能就比較強大了,基本上什麼他都有,因為是它是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");

2.4.3、out物件

型別:JspWriter

jsp 輸出底層使用 response.getWriter();什麼意思呢?這裡就要講解一下JSP快取和Servlet快取了,輸出的過程是這樣的

  

java基礎學習:JavaWeb之JSP

JSP頁面轉換為Servlet後,使用的out物件是JspWriter型別的,所以是會先將要傳送的資料存入JSP輸出快取中,然後,等JSP輸出快取滿了在自動重新整理到servlet輸出快取等serlvet輸出快取滿了,或者程式結束了,就會將其輸出到瀏覽器上。除非手動out.flush()。

驗證servlet輸出快取和JSP輸出快取和我們上面所說的是正確:

java基礎學習:JavaWeb之JSP
結果:
java基礎學習:JavaWeb之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,過程自行分析。

java基礎學習:JavaWeb之JSP

2.4.4、config物件

型別:ServletConfig
能夠獲取servlet的初始化引數,獲取servletContext物件,獲取servletName。

2.4.5、exception異常物件

包含了異常的資訊
使用它,必須結合page指令中的isErrorPage屬性和errorPage屬性。
如下例子,exception.jsp拋異常的一個NullPointException,並且跳轉到error.jsp錯誤顯示頁面,其中errorPage屬性的意思是如果發生未捕捉到的異常,將會跳轉到error.jsp頁面

exception.jsp

error.jsp  isErrorPage屬性說明該頁面是一個錯誤顯示頁面,則可以使用exception物件

error.jsp

訪問:訪問http://localhost:8080/Web_Jsp/exception.jsp

    

java基礎學習:JavaWeb之JSP

2.4.6、總結:九大內建物件和servlet中物件的關係  

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個內建物件

2.5、4大作用域

這四大作用域,其實就是其九大內建物件中的四個,為什麼說他們也是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等共享帳號。

相關文章