下面是我整理下來的JSP知識點:
圖上的知識點都可以在我其他的文章內找到相應內容。
JSP常見面試題
jsp靜態包含和動態包含的區別
jsp靜態包含和動態包含的區別
-
在講解request物件的時候,我們曾經使用過request.getRequestDispatcher(String url).include(request,response)來對頁頭和頁尾面進行包含
-
inclue指令也是做這樣的事情,我們來試驗一下吧!
-
這是頁頭
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>頁頭</title>
</head>
<body>
我是頁頭
<br>
<br>
<br>
</body>
</html>
複製程式碼
- 這是頁尾
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>頁尾</title>
</head>
<body>
我是頁尾
</body>
</html>
複製程式碼
- 在1.jsp中把頁頭和頁尾包含進來
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>包含頁頭和頁尾進來</title>
</head>
<body>
<%@include file="head.jsp" %>
<%@include file="foot.jsp" %>
</body>
</html>
複製程式碼
- 訪問1.jsp
- include指令是靜態包含。靜態包含的意思就是:把檔案的程式碼內容都包含進來,再編譯!,看一下jsp的原始碼就知道了!
- 上面已經提及到了,include指令是靜態包含,include行為是動態包含。其實include行為就是封裝了request.getRequestDispatcher(String url).include(request,response)
- include行為語法是這個樣子的
<jsp:include page=""/>
複製程式碼
- 我們先來使用一下把,在1.jsp頁面中也將頁頭和頁尾包含進來。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>包含頁頭和頁尾進來</title>
</head>
<body>
<jsp:include page="head.jsp"/>
<jsp:include page="foot.jsp"/>
</body>
</html>
複製程式碼
- 訪問1.jsp頁面看一下效果:
- 使用jsp行為來包含檔案,jsp原始檔是這樣子的:
-
jsp行為包含檔案就是先編譯被包含的頁面,再將頁面的結果寫入到包含的頁面中(1.jsp)
-
當然了,現在有靜態包含和動態包含,使用哪一個更好呢?答案是:動態包含。
-
動態包含可以向被包含的頁面傳遞引數(用處不大),並且是分別處理包含頁面的(將被包含頁面編譯後得出的結果再寫進包含頁面)【如果有相同名稱的引數,使用靜態包含就會報錯!】!
-
模擬一下場景吧,現在我的頭頁面有個名為s的字串變數
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>頁頭</title>
</head>
<body>
<%
String s = "zhongfucheng";
%>
我是頁頭呀
<br>
<br>
<br>
</body>
</html>
複製程式碼
- 我的頁尾也有個名為s的字串變數
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>頁尾</title>
</head>
<body>
<%
String s = "zhongfucheng";
%>
我是頁尾呀
</body>
</html>
複製程式碼
- 現在我使用靜態包含看看會發生什麼,出現異常了。
- 出現異常的原因很簡單,就是同一個檔案中有兩個相同的變數s
- 使用動態包含就可以避免這種情況
總結
-
<%@include file="xxx.jsp"%>
為jsp中的編譯指令,其檔案的包含是發生在jsp向servlet轉換的時期,而<jsp:include page="xxx.jsp">
是jsp中的動作指令,其檔案的包含是發生在編譯時期,也就是將java檔案編譯為class檔案的時期 -
使用靜態包含只會**產生一個class檔案,而使用動態包含會產生多個class檔案 **
-
使用靜態包含,包含頁面和被包含頁面的request物件為同一物件,因為靜態包含只是將被包含的頁面的內容複製到包含的頁面中去;而動態包含包含頁面和被包含頁面不是同一個頁面,被包含的頁面的request物件可以取到的引數範圍要相對大些,不僅可以取到傳遞到包含頁面的引數,同樣也能取得在包含頁面向下傳遞的引數
jsp有哪些內建物件?作用分別是什麼?
jsp有哪些內建物件?作用分別是什麼?
九個內建物件:
- pageContext
- page
- config
- request
- response
- session
- application
- exception
- out
其中,request、response、session、application、config這五個物件和Servlet的API是一樣的。這5個物件我就不解釋了。
在JSP中,尤其重要的是pageContext物件。
pageContext是內建物件中最重要的一個物件,它代表著JSP頁面編譯後的內容(也就是JSP頁面的執行環境)!
pageContext物件
- 既然它代表了JSP頁面編譯後的內容,理所當然的:它封裝了對其他8大內建物件的引用!,也就是說,通過pageContext可以獲取到其他的8個內建物件!
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>獲取八大內建物件</title>
</head>
<body>
<%
System.out.println(pageContext.getSession());
System.out.println(pageContext.getRequest());
System.out.println(pageContext.getResponse());
System.out.println(pageContext.getException());
System.out.println(pageContext.getPage());
System.out.println(pageContext.getServletConfig());
System.out.println(pageContext.getServletContext());
System.out.println(pageContext.getOut());
%>
</body>
</html>
複製程式碼
- 看下效果:
pageContext作為域物件
-
類似於request,session,ServletContext作為域物件而言都有以下三個方法:
- setAttribute(String name,Objcet o)
- getAttribute(String name)
- removeAttribute(String name)
-
當然了,pageContext也不例外,pageContext也有這三個方法!
-
pageContext本質上代表的是當前JSP頁面編譯後的內容,作為域物件而言,它就代表著當前JSP頁面(也就是page)!也就是說:pageContext域物件只在page範圍內有效,超出了page範圍就無效了!
-
首先來看看在page範圍內能不能使用
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>使用page域物件</title>
</head>
<body>
<%
pageContext.setAttribute("name", "zhongfucheng");
%>
<%
String value = (String) pageContext.getAttribute("name");
System.out.println(value);
%>
</body>
</html>
複製程式碼
- 效果如下:
-
我們現在來試驗一下是不是超出了page範圍就無效了!
-
在2.jsp中request域物件設定屬性
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>request域物件設定屬性</title>
</head>
<body>
<%
//這是request域物件儲存的內容
request.setAttribute("name","zhongfucheng");
%>
<%--跳轉到1.jsp中--%>
<jsp:forward page="1.jsp"/>
</body>
</html>
複製程式碼
- 企圖在1.jsp中pageContext取出request存進去的屬性
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>在page域物件獲取屬性</title>
</head>
<body>
<%
//企圖獲取request域物件存進的屬性
String value = (String) pageContext.getAttribute("name");
System.out.println(value);
%>
</body>
</html>
複製程式碼
- 效果如下:
-
pageContext本質上代表著編譯後JSP的內容,pageContext還可以封裝了訪問其他域的方法!
-
上面的pageContext預設是page範圍的,但pageContext物件過載了set、get、removeAttribute這三個方法
- getAttribute(String name,int scope)
- setAttribute(String name,Object value,int scope)
- removeAttribute(String name,int scope)
-
多了一個設定域範圍的一個引數,如果不指定預設就是page。當然了,pageContext把request、session、application、page這幾個域物件封裝著了靜態變數供我們使用。
- PageContext.APPLICATION_SCOPE
- PageContext.SESSION_SCOPE
- PageContext.REQUEST_SCOPE
- PageContext.PAGE_SCOPE
-
剛才我們沒有使用過載方法的時候,使用pageContext是無法獲取到request域物件設定的屬性的。現在我們使用過載後的方法看一下能不能獲取得到!
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>在page域物件獲取request域物件的屬性</title>
</head>
<body>
<%
//使用過載的方法獲取request域物件的屬性
String value = (String) pageContext.getAttribute("name",pageContext.REQUEST_SCOPE);
System.out.println(value);
%>
</body>
</html>
複製程式碼
- 效果:
-
pageContexst還有這麼一個方法:
- findAttribute(String name)
-
該方法會查詢各個域的屬性,從小到大開始尋找!也就是page—>request->session->application。
-
我們用此方法看能不能查詢出request域物件的屬性吧!
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>使用findAttribute</title>
</head>
<body>
<%
//使用findAttribute查詢2.jsp中request域物件的屬性
String value = (String) pageContext.findAttribute("name");
System.out.println(value);
%>
</body>
</html>
複製程式碼
- 效果如下:
out物件:
- out物件用於向瀏覽器輸出資料,與之對應的是Servlet的PrintWriter物件。然而這個out物件的型別並不是PrintWriter,是JspWriter
-
我們可以簡單理解為:JspWriter就是帶快取的PrintWrieter。
-
out物件的原理如下:
-
只有向out物件中寫入了內容,且滿足如下任何一個條件時,out物件才去呼叫ServletResponse.getWriter方法,並通過該方法返回的PrintWriter物件將out物件的緩衝區中的內容真正寫入到Servlet引擎提供的緩衝區中:
- 設定page指令的buffer屬性關閉了out物件的快取功能
- out物件的緩衝區已滿
- 整個JSP頁面結束
-
一般我們在JSP頁面輸出都是用表示式(<%=%>),所以out物件用得並不是很多!
page物件
內建物件page是HttpJasPage物件,其實page物件代表的就是當前JSP頁面,是當前JSP編譯後的Servlet類的物件。也就是說:page物件相當於普通java類的this
exception物件
-
**內建物件exception是java.lang.Exception類的物件,exception封裝了JSP頁面丟擲的異常資訊。**exception經常被用來處理錯誤頁面
-
前面我們已經講過了怎麼設定錯誤頁面了,下面我們就來簡單使用一下exception物件吧
-
1.jsp頁面
<%@ page contentType="text/html;charset=UTF-8" language="java" errorPage="error.jsp" %>
<html>
<head>
<title></title>
</head>
<body>
<%--模擬空指標異常的錯誤--%>
<%
String sss = null;
sss.length();
%>
</body>
</html>
複製程式碼
- error.jsp頁面
<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>
<html>
<head>
<title>錯誤頁面</title>
</head>
<body>
<%
out.println("程式丟擲了異常:" + exception);
%>
</body>
</html>
複製程式碼
- 效果:
總結
- request 使用者端請求,此請求會包含來自GET/POST請求的引數
- response 網頁傳回使用者端的回應
- pageContext 網頁的屬性是在這裡管理,代表的編譯後JSP內容
- session 與請求有關的會話期
- application servlet 正在執行的內容
- out 用來傳送回應的輸出
- config servlet的構架部件
- page JSP網頁本身
- exception 針對錯誤網頁,未捕捉的例外
jsp和servlet的區別、共同點、各自應用的範圍?
jsp和servlet的區別、共同點、各自應用的範圍?
- JSP是Servlet技術的擴充套件,本質上就是Servlet的簡易方式。JSP編譯後是“類servlet”。
- Servlet和JSP最主要的不同點在於:Servlet的應用邏輯是在Java檔案中,並且完全從表示層中的HTML裡分離開來。而JSP的情況是Java和HTML可以組合成一個副檔名為.jsp的檔案。
- JSP側重於檢視,Servlet主要用於控制邏輯。
屬性作用域範圍
屬性作用域範圍
- page【只在一個頁面中儲存屬性,跳轉頁面無效】
- requet【只在一次請求中儲存屬性,伺服器跳轉有效,瀏覽器跳轉無效】
- session【在一個會話範圍中儲存屬性,無論何種跳轉均有效,關閉瀏覽器後無效】
- application【在整個伺服器中儲存,所有使用者都可以使用】
應用場景:
- request:如果客戶向伺服器發請求,產生的資料,**使用者看完就沒用了,**像這樣的資料就存在request域,像新聞資料,屬於使用者看完就沒用的
- session:如果客戶向伺服器發請求,產生的資料,使用者用完了等一會兒還有用,像這樣的資料就存在session域中,像購物資料,使用者需要看到自己購物資訊,並且等一會兒,還要用這個購物資料結帳
- servletContext:如果客戶向伺服器發請求,產生的資料,使用者用完了,還要給其它使用者用,像這樣的資料就存在servletContext域中,像聊天資料
寫出5種JSTL常用標籤
寫出5種JSTL常用標籤
<c:if>,<c:item>,<c:foreach>,<c:out>,<c:set>
複製程式碼
寫一個自定義標籤要繼承什麼類
寫一個自定義標籤要繼承什麼類
我們可以有兩種方式來實現自定義標籤:
- 傳統方式,實現Tag介面(老方法)
- 簡單方式,繼承SimpleTagSupport類
SimpleTagSupport類的執行順序(原理):
- ①WEB容器呼叫標籤處理器物件的setJspContext方法,將代表JSP頁面的pageContext物件傳遞給標籤處理器物件
- ②WEB容器呼叫標籤處理器物件的setParent方法,將父標籤處理器物件傳遞給這個標籤處理器物件。【注意,只有在標籤存在父標籤的情況下,WEB容器才會呼叫這個方法】
- ③如果呼叫標籤時設定了屬性,容器將呼叫每個屬性對應的setter方法把屬性值傳遞給標籤處理器物件。如果標籤的屬性值是EL表示式或指令碼表示式,則WEB容器首先計算表示式的值,然後把值傳遞給標籤處理器物件。
- ④如果簡單標籤有標籤體,容器將呼叫setJspBody方法把代表標籤體的JspFragment物件傳遞進來
- ⑤執行標籤時:容器呼叫標籤處理器的doTag()方法,開發人員在方法體內通過操作JspFragment物件,就可以實現是否執行、迭代、修改標籤體的目的。
總結
SimpleTagSupport,一般呼叫doTag方法或者實現SimpleTag介面
JSP是如何被執行的?執行效率比SERVLET低嗎?
JSP是如何被執行的?執行效率比SERVLET低嗎?
- 當客戶端向一個jsp頁面傳送請求時,Web Container將jsp轉化成servlet的原始碼(只在第一次請求時),然後編譯轉化後的servlet並載入到記憶體中執行,執行的結果response到客戶端
- jsp只在第一次執行的時候會轉化成servlet,以後每次執行,web容器都是直接執行編譯後的servlet,所以jsp和servlet只是在第一次執行的時候不一樣,jsp慢一點,以後的執行都是相同的
如何避免jsp頁面自動生成session物件?為什麼要這麼做?
如何避免jsp頁面自動生成session物件?為什麼要這麼做?
可以使用頁面指令顯式關掉,程式碼如下:
<%@ page session="false" %>
jsp的缺點?
jsp的缺點?
- 1)不好除錯
- 2)與其他指令碼語言的互動(可讀性差)
說出Servlet和CGI的區別?
說出Servlet和CGI的區別?
- Servlet處於伺服器程式中,只會有一個servlet例項,每個請求都會產生一個新的執行緒,而且servlet例項一般不會銷燬
- CGI:來一個請求就建立一個程式,用完就銷燬,效率低於servlet
簡述JSP的設計模式。
簡述JSP的設計模式。
在Web開發模式中,有兩個主要的開發結構,稱為模式一(Mode I)和模式二(Mode II)
首先我們來理清一些概念吧:
- DAO(Data Access Object):主要對資料的操作,增加、修改、刪除等原子性操作。
- Web層:介面+控制器,也就是說JSP【介面】+Servlet【控制器】
- Service業務層:將多個原子性的DAO操作進行組合,組合成一個完整的業務邏輯
- 控制層:主要使用Servlet進行控制
- 資料訪問層:使用DAO、Hibernate、JDBC技術實現對資料的增刪改查
- JavaBean用於封裝資料,處理部分核心邏輯,每一層中都用到!
模式一指的就是在開發中將顯示層、控制層、資料層的操作統一交給JSP或者JavaBean來進行處理!
模式一有兩種情況:
完全使用JSP做開發:
-
優點:
- 開發速度賊快,只要寫JSP就行了,JavaBean和Servlet都不用設計!
- 小幅度修改程式碼方便,直接修改JSP頁面交給WEB容器就行了,不像Servlet還要編譯成.class檔案再交給伺服器!【當然了,在ide下開發這個也不算是事】
-
缺點:
- 程式的可讀性差、複用性低、程式碼複雜!什麼jsp程式碼、html程式碼都往上面寫,這肯定很難閱讀,很難重用!
使用JSP+JavaBean做開發:
-
優點:
- 程式的可讀性較高,大部分的程式碼都寫在JavaBean上,不會和HTML程式碼混合在一起,可讀性還行的。
- 可重複利用高,核心的程式碼都由JavaBean開發了,JavaBean的設計就是用來重用、封裝,大大減少編寫重複程式碼的工作!
-
缺點:
- 沒有流程控制,程式中的JSP頁面都需要檢查請求的引數是否正確,異常發生時的處理。顯示操作和業務邏輯程式碼工作會緊密耦合在一起的!日後維護會困難
Mode II 中所有的開發都是以Servlet為主體展開的,由Servlet接收所有的客戶端請求,然後根據請求呼叫相對應的JavaBean,並所有的顯示結果交給JSP完成!,也就是俗稱的MVC設計模式!
MVC設計模式:
- 顯示層(View):主要負責接受Servlet傳遞的內容,呼叫JavaBean,將內容顯示給使用者
- 控制層(Controller):主要負責所有使用者的請求引數,判斷請求引數是否合法,根據請求的型別呼叫JavaBean,將最終的處理結果交給顯示層顯示!
- 模型層(Mode):模型層包括了業務層,DAO層。
總結
- (1)ModelI,JSP+JavaBean設計模式。
- (2)ModelII,MVC設計模式。
如果文章有錯的地方歡迎指正,大家互相交流。習慣在微信看技術文章的同學,可以關注微信公眾號:Java3y