礎(chǔ)知識,servlet是什么?
官方解釋:Servlet 是運(yùn)行在 Web 服務(wù)器或應(yīng)用服務(wù)器上的程序,它是作為來自 Web 瀏覽器或其他 HTTP 客戶端的請求和 HTTP 服務(wù)器上的數(shù)據(jù)庫或應(yīng)用程序之間的中間層
簡單來說,servlet是運(yùn)行在web服務(wù)器如tomcat,jetty這樣應(yīng)用服務(wù)器上的一段程序,他可以響應(yīng)http協(xié)議的請求,并且實(shí)現(xiàn)用戶自己的邏輯,最終將結(jié)果返回到用戶的客戶端(瀏覽器)
Java Servlet 通常情況下與使用 CGI(Common Gateway Interface,公共網(wǎng)關(guān)接口)實(shí)現(xiàn)的程序可以達(dá)到異曲同工的效果。但是相比于 CGI,Servlet 有以下幾點(diǎn)優(yōu)勢:
1、性能明顯更好。
2、Servlet 在 Web 服務(wù)器的地址空間內(nèi)執(zhí)行。這樣它就沒有必要再創(chuàng)建一個單獨(dú)的進(jìn)程來處理每個客戶端請求。
3、Servlet 是獨(dú)立于平臺的,因?yàn)樗鼈兪怯?Java 編寫的。
4、服務(wù)器上的 Java 安全管理器執(zhí)行了一系列限制,以保護(hù)服務(wù)器計(jì)算機(jī)上的資源。因此,Servlet 是可信的。
5、Java 類庫的全部功能對 Servlet 來說都是可用的。它可以通過 sockets 和 RMI 機(jī)制與 applets、數(shù)據(jù)庫或其他軟件進(jìn)行交互。
Servlet的生命周期
Servlet 生命周期可被定義為從創(chuàng)建直到毀滅的整個過程。以下是 Servlet 遵循的過程:
1、Servlet 通過調(diào)用 init () 方法進(jìn)行初始化。
2、Servlet 調(diào)用 service() 方法來處理客戶端的請求。
3、Servlet 通過調(diào)用 destroy() 方法終止(結(jié)束)。
4、最后,Servlet 是由 JVM 的垃圾回收器進(jìn)行垃圾回收的
init() 方法
init 方法被設(shè)計(jì)成只調(diào)用一次。它在第一次創(chuàng)建 Servlet 時(shí)被調(diào)用,在后續(xù)每次用戶請求時(shí)不再調(diào)用。因此,它是用于一次性初始化,就像 Applet 的 init 方法一樣。
Servlet 創(chuàng)建于用戶第一次調(diào)用對應(yīng)于該 Servlet 的 URL 時(shí),但是您也可以指定 Servlet 在服務(wù)器第一次啟動時(shí)被加載。
service() 方法
service() 方法是執(zhí)行實(shí)際任務(wù)的主要方法。Servlet 容器(即 Web 服務(wù)器)調(diào)用 service() 方法來處理來自客戶端(瀏覽器)的請求,并把格式化的響應(yīng)寫回給客戶端。
每次服務(wù)器接收到一個 Servlet 請求時(shí),服務(wù)器會產(chǎn)生一個新的線程并調(diào)用服務(wù)。service() 方法檢查 HTTP 請求類型(GET、POST、PUT、DELETE 等),并在適當(dāng)?shù)臅r(shí)候調(diào)用 doGet、doPost、doPut,doDelete 等方法。
destroy() 方法
destroy() 方法只會被調(diào)用一次,在 Servlet 生命周期結(jié)束時(shí)被調(diào)用。destroy() 方法可以讓您的 Servlet 關(guān)閉數(shù)據(jù)庫連接、停止后臺線程、把 Cookie 列表或點(diǎn)擊計(jì)數(shù)器寫入到磁盤,并執(zhí)行其他類似的清理活動。
在調(diào)用 destroy() 方法之后,servlet 對象被標(biāo)記為垃圾回收。
JSP是什么?
JSP全稱Java Server Pages,是一種動態(tài)網(wǎng)頁開發(fā)技術(shù)。它使用JSP標(biāo)簽在HTML網(wǎng)頁中插入Java代碼。標(biāo)簽通常以<%開頭以%>結(jié)束。
JSP是一種Java servlet,主要用于實(shí)現(xiàn)Java web應(yīng)用程序的用戶界面部分。網(wǎng)頁開發(fā)者們通過結(jié)合HTML代碼、XHTML代碼、XML元素以及嵌入JSP操作和命令來編寫JSP。
JSP通過網(wǎng)頁表單獲取用戶輸入數(shù)據(jù)、訪問數(shù)據(jù)庫及其他數(shù)據(jù)源,然后動態(tài)地創(chuàng)建網(wǎng)頁。
JSP標(biāo)簽有多種功能,比如訪問數(shù)據(jù)庫、記錄用戶選擇信息、訪問JavaBeans組件等,還可以在不同的網(wǎng)頁中傳遞控制信息和共享信息。
servlet和jsp的區(qū)別
1、Servlet在Java代碼中可以通過HttpServletResponse對象動態(tài)輸出HTML內(nèi)容。
2、JSP是在靜態(tài)HTML內(nèi)容中嵌入Java代碼,然后Java代碼在被動態(tài)執(zhí)行后生成HTML內(nèi)容。
servlet和jsp各自的特點(diǎn)
1、Servlet雖然能夠很好地組織業(yè)務(wù)邏輯代碼,但是在Java源文件中,因?yàn)槭峭ㄟ^字符串拼接的方式生成動態(tài)HTML內(nèi)容,這樣就容易導(dǎo)致代碼維護(hù)困難、可讀性差。
2、JSP雖然規(guī)避了Servlet在生成HTML內(nèi)容方面的劣勢,但是在HTML中混入大量、復(fù)雜的業(yè)務(wù)邏輯。
MVC的誕生
JSP和Servlet都有自身的適用環(huán)境,那么有沒有什么辦法能夠讓它們發(fā)揮各自的優(yōu)勢呢?答案是肯有的,MVC模式就能夠完美解決這一問題。
MVC模式,是Model-View-Controller的簡稱,是軟件工程中的一種軟件架構(gòu)模式,分為三個基本部分,分別是:模型(Model)、視圖(View)和控制器(Controller):
Controller——負(fù)責(zé)轉(zhuǎn)發(fā)請求,對請求進(jìn)行處理
View——負(fù)責(zé)界面顯示
Model——業(yè)務(wù)功能編寫(例如算法實(shí)現(xiàn))、數(shù)據(jù)庫設(shè)計(jì)以及數(shù)據(jù)存取操作實(shí)現(xiàn)
在JSP/Servlet開發(fā)的軟件系統(tǒng)中,這三個部分的描述如下所示:
MVC模型
1、Web瀏覽器發(fā)送HTTP請求到服務(wù)端,然后被Controller(Servlet)獲取并進(jìn)行處理(例如參數(shù)解析、請求轉(zhuǎn)發(fā))
2、Controller(Servlet)調(diào)用核心業(yè)務(wù)邏輯——Model部分,獲得結(jié)果
3、Controller(Servlet)將邏輯處理結(jié)果交給View(JSP),動態(tài)輸出HTML內(nèi)容
4、動態(tài)生成的HTML內(nèi)容返回到瀏覽器顯示
MVC模式在Web開發(fā)中有很大的優(yōu)勢,它完美規(guī)避了JSP與Servlet各自的缺點(diǎn),讓Servlet只負(fù)責(zé)業(yè)務(wù)邏輯部分,而不會生成HTML代碼;同時(shí)JSP中也不會充斥著大量的業(yè)務(wù)代碼,這樣大大提高了代碼的可讀性和可維護(hù)性。
相關(guān)面試題
如何讀取Servlet的初始化參數(shù)?
ServletConfig中定義了如下的方法用來讀取初始化參數(shù)的信息:
public String getInitParameter(String name)
參數(shù):初始化參數(shù)的名稱。
返回:初始化參數(shù)的值,如果沒有配置,返回null。
init(ServletConfig)方法執(zhí)行次數(shù)
在Servlet的生命周期中,該方法執(zhí)行一次。
service()方法的職責(zé)
service()方法為Servlet的核心方法,客戶端的業(yè)務(wù)邏輯應(yīng)該在該方法內(nèi)執(zhí)行,典型的服務(wù)方法的開發(fā)流程為:
解析客戶端請求-〉執(zhí)行業(yè)務(wù)邏輯-〉輸出響應(yīng)頁面到客戶端
get方式和post方式有何區(qū)別
數(shù)據(jù)攜帶上:
GET方式:在URL地址后附帶的參數(shù)是有限制的,其數(shù)據(jù)容量通常不能超過1K。
POST方式:可以在請求的實(shí)體內(nèi)容中向服務(wù)器發(fā)送數(shù)據(jù),傳送的數(shù)據(jù)量無限制。
請求參數(shù)的位置上:
GET方式:請求參數(shù)放在URL地址后面,以?的方式來進(jìn)行拼接
POST方式:請求參數(shù)放在HTTP請求包中
用途上:
GET方式一般用來獲取數(shù)據(jù)
POST方式一般用來提交數(shù)據(jù)
原因:
首先是因?yàn)镚ET方式攜帶的數(shù)據(jù)量比較小,無法帶過去很大的數(shù)量
POST方式提交的參數(shù)后臺更加容易解析(使用POST方式提交的中文數(shù)據(jù),后臺也更加容易解決)
GET方式比POST方式要快
Servlet相關(guān) API
HttpServletRequest:封裝了與請求相關(guān)的信息
HttpServletResponse:封裝了與響應(yīng)相關(guān)的信息
獲取頁面的元素的值有幾種方式,分別說一下
request.getParameter() 返回客戶端的請求參數(shù)的值
request.getParameterNames() 返回所有可用屬性名的枚舉
request.getParameterValues() 返回包含參數(shù)的所有值的數(shù)組
request.getAttribute()和request.getParameter()區(qū)別
用途上:
request.getAttribute(), 一般用于獲取request域?qū)ο蟮臄?shù)據(jù)(在跳轉(zhuǎn)之前把數(shù)據(jù)使用setAttribute來放到request對象上)
request.getParameter(), 一般用于獲取客戶端提交的參數(shù)
存儲數(shù)據(jù)上:
request.getAttribute()可以獲取Objcet對象
request.getParameter()只能獲取字符串(這也是為什么它一般用于獲取客戶端提交的參數(shù))
forward和redirect的區(qū)別
實(shí)際發(fā)生位置不同,地址欄不同
轉(zhuǎn)發(fā)是發(fā)生在服務(wù)器的
轉(zhuǎn)發(fā)是由服務(wù)器進(jìn)行跳轉(zhuǎn)的,細(xì)心的朋友會發(fā)現(xiàn),在轉(zhuǎn)發(fā)的時(shí)候,瀏覽器的地址欄是沒有發(fā)生變化的,在我訪問Servlet111的時(shí)候,即使跳轉(zhuǎn)到了Servlet222的頁面,瀏覽器的地址還是Servlet111的。也就是說瀏覽器是不知道該跳轉(zhuǎn)的動作,轉(zhuǎn)發(fā)是對瀏覽器透明的。通過上面的轉(zhuǎn)發(fā)時(shí)序圖我們也可以發(fā)現(xiàn),實(shí)現(xiàn)轉(zhuǎn)發(fā)只是一次的http請求,一次轉(zhuǎn)發(fā)中request和response對象都是同一個。這也解釋了,為什么可以使用request作為域?qū)ο筮M(jìn)行Servlet之間的通訊。
重定向是發(fā)生在瀏覽器的
重定向是由瀏覽器進(jìn)行跳轉(zhuǎn)的,進(jìn)行重定向跳轉(zhuǎn)的時(shí)候,瀏覽器的地址會發(fā)生變化的。曾經(jīng)介紹過:實(shí)現(xiàn)重定向的原理是由response的狀態(tài)碼和Location頭組合而實(shí)現(xiàn)的。這是由瀏覽器進(jìn)行的頁面跳轉(zhuǎn)實(shí)現(xiàn)重定向會發(fā)出兩個http請求,**request域?qū)ο笫菬o效的,因?yàn)樗皇峭粋€request對象
用法不同:
很多人都搞不清楚轉(zhuǎn)發(fā)和重定向的時(shí)候,資源地址究竟怎么寫。有的時(shí)候要把應(yīng)用名寫上,有的時(shí)候不用把應(yīng)用名寫上。很容易把人搞暈。記住一個原則: 給服務(wù)器用的直接從資源名開始寫,給瀏覽器用的要把應(yīng)用名寫上
request.getRequestDispatcher("/資源名 URI").forward(request,response)
轉(zhuǎn)發(fā)時(shí)"/"代表的是本應(yīng)用程序的根目錄【zhongfucheng】
response.send("/web應(yīng)用/資源名 URI");
重定向時(shí)"/"代表的是webapps目錄
能夠去往的URL的范圍不一樣:
轉(zhuǎn)發(fā)是服務(wù)器跳轉(zhuǎn)只能去往當(dāng)前web應(yīng)用的資源
重定向是服務(wù)器跳轉(zhuǎn),可以去往任何的資源
傳遞數(shù)據(jù)的類型不同
轉(zhuǎn)發(fā)的request對象可以傳遞各種類型的數(shù)據(jù),包括對象
重定向只能傳遞字符串
跳轉(zhuǎn)的時(shí)間不同
轉(zhuǎn)發(fā)時(shí):執(zhí)行到跳轉(zhuǎn)語句時(shí)就會立刻跳轉(zhuǎn)
重定向:整個頁面執(zhí)行完之后才執(zhí)行跳轉(zhuǎn)
典型的應(yīng)用場景:
轉(zhuǎn)發(fā): 訪問 Servlet 處理業(yè)務(wù)邏輯,然后 forward 到 jsp 顯示處理結(jié)果,瀏覽器里 URL 不變
重定向: 提交表單,處理成功后 redirect 到另一個 jsp,防止表單重復(fù)提交,瀏覽器里 URL 變了
SP
JSP:Java Server Page SUN 公司提供的動態(tài)網(wǎng)頁編程技術(shù),是 Java Web 服務(wù)器端的動態(tài)資源。
它相比 html 而言,html 只能為用戶提供靜態(tài)數(shù)據(jù),而 Jsp 技術(shù)允許在頁面中嵌套 java 代碼,為用戶提供動態(tài)數(shù)據(jù)。
相比 servlet 而言,servlet 很難對數(shù)據(jù)進(jìn)行排版,而 jsp 除了可以用 java 代碼產(chǎn)生動態(tài)數(shù)據(jù)的同時(shí),也很容易對數(shù)據(jù)進(jìn)行排版。
不管是 JSP 還是 Servlet,雖然都可以用于開發(fā)動態(tài) web 資源。但由于這 2 門技術(shù)各自的特點(diǎn),在長期的軟件實(shí)踐中,人們逐漸把 servlet 作為 web 應(yīng)用中的控制器組件來使用, 而把 JSP 技術(shù)作為數(shù)據(jù)顯示模板來使用。
其實(shí) Jsp 就是一個 Servlet,當(dāng)我們第一次訪問 Jsp 的時(shí)候,Jsp 引擎都會將這個 Jsp 翻譯 成一個 Servlet,這個文件存放在tomcat(源碼目錄) 中的 work 目錄中。
這一步不是必須的,當(dāng)然由于 編輯器中有些默認(rèn)的配置項(xiàng)我們覺得不是很完美,比如"編碼格式"、頁面模板等。我們可以在新建 JSP 頁面之前就先修改為我們需要的。
1.選擇"File" —> "Settings..."
2.設(shè)置編碼格式。搜索"encode",選擇"File Encoding"
[
3.設(shè)置頁面模板。搜索"template",選擇"File and Code Templates",選擇右側(cè)的"Other",選擇下方的"Jsp File"
在 JSP 中支持兩種注釋的語法操作:
一種是顯示注釋,這種注釋是允許客戶端看見的; 另一種是隱式注釋,此種注釋是客戶端無法看見的
① 顯示注釋語法:從 HTML 風(fēng)格繼承而來
② 隱式注釋語法:從 JAVA 風(fēng)格繼承;JSP 自己的注釋
JSP 的三種注釋方式:
1) // 注釋,單行注釋 /* 多行注釋*/
?
2)<!-- HTML風(fēng)格的注釋 -->
?
3)<%-- JSP注釋 --%>
在 JSP 中最重要的部分就是 Scriptlet(腳本小程序),所有嵌入在 HTML 代碼中的 Java 程序。
在 JSP 中一共有三種 Scriptlet 代碼:都必須使用 Scriptlet 標(biāo)記出來
第一種:<% %>: java 腳本段,可以定義局部變量、編寫語句
?
第二種:<%! %>:聲明,可以定義全局(成員)變量、方法、類
?
第三種:<%= %>:表達(dá)式,數(shù)據(jù)一個變量或具體內(nèi)容
通過觀察解析為 java 文件的 jsp 代碼理解三種小腳本
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE >
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Scriptlet</title>
</head>
<body>
<%
String str = "Hello JSP";
System.out.println(str);
response.getWriter().write(str);
%>
<%!
String memberStr = "a member String";
%>
<%=memberStr%>
<h1>This is a JSP page!!</h1>
</body>
</html>
使用包含操作,可以將一些重復(fù)的代碼包含進(jìn)來繼續(xù)使用,從正常的頁面組成來看,有時(shí)可能分為幾個區(qū)域。而其中的一些區(qū)域可能是一直不需要改變的,改變的就其中的一個具體內(nèi)容區(qū)域?,F(xiàn)在有兩種方法可以實(shí)現(xiàn)上述功能。
方法一:在每個 JSP 頁面(HTML)都包含工具欄、頭部信息、尾部信息、具體內(nèi)容
方法二:將工具欄、頭部信息、尾部信息都分成各個獨(dú)立的文件,使用的時(shí)候直接導(dǎo)入
很明顯,第二種方法比第一種更好,第一種會存在很多重復(fù)的代碼,并且修改很不方便,在 JSP 中如果要想實(shí)現(xiàn)包含的操作,有兩種做法:靜態(tài)包含、動態(tài)包含,靜態(tài)包含使用 include 指令即可,動態(tài)包含則需要使用 include 動作標(biāo)簽。
<%@ include file="要包含的文件路徑" %> <!-- 相對路徑 -->
例如:
<%@include file="include.jsp" %>
或
<%@include file="include.html" %>
靜態(tài)包含就是將內(nèi)容進(jìn)行了直接的替換,就好比程序中定義的變量一樣,是在 servlet 引擎轉(zhuǎn)譯時(shí),就把此文件內(nèi)容包含了進(jìn)去(兩個文件的源代碼整合到一起, 全部放到_jspService 方法中),所以只生成了一個 servlet,所以兩個頁面不能有同名的變量。 運(yùn)行效率高一點(diǎn)點(diǎn)。耦合性較高,不夠靈活。
動態(tài)包含在代碼的編譯階段,包含和被包含部分是兩個獨(dú)立的部分,只有當(dāng)運(yùn)行時(shí),才會動態(tài)包含進(jìn)來,好比方法的調(diào)用。
<jsp:include page="include.jsp"></jsp:include>
注意:動態(tài)包含,中間不要加任何內(nèi)容,包括空格,除非確認(rèn)要使用參數(shù),否則報(bào)錯!
<jsp:include page="include.html"></jsp:include>
<%
String a = "hello.jsp";
%>
<jsp:include page="<%=a %>"></jsp:include>
使用動態(tài)包含還可以通過在頁面之間傳參。
接收參數(shù)通過 request.getParameter(name);
<jsp:include page="hello.jsp" flush="true">
<jsp:param name="uname" value="zhangsan"/>
</jsp:include>
hello.jsp
<!-- 接收參數(shù) -->
<%=request.getParameter("uname")%>
在JSP中提供了四種屬性的保存范圍,所謂的屬性保存范圍,指的就是一個設(shè)置的對象,可以再多少個頁面中保存并可以繼續(xù)使用
方法類型描述public void setAttribute(String name, Object o)普通設(shè)置屬性的名稱及內(nèi)容public Object getAttribute(String name)普通根據(jù)屬性名稱取屬性public void removeAttribute(String name)普通刪除指定的屬性
本頁面取得,服務(wù)器端跳轉(zhuǎn)(<jsp :forward>)后無效
問:使用哪個范圍呢?
答:在合理范圍盡可能小
EL(Expression Language) 是為了使 JSP 寫起來更加簡單。表達(dá)式語言的靈感來自于 ECMAScript 和 XPath 表達(dá)式語言,它提供了在 JSP 中簡化表達(dá)式的方法,讓 Jsp 的代碼更加簡化。
語法結(jié)構(gòu)非常簡單: ${expression}
EL 表達(dá)式一般操作的都是域?qū)ο笾械臄?shù)據(jù),操作不了局部變量。
域?qū)ο蟮母拍钤?JSP 中一共有四個:pageContext, request, session, application;范圍依次是,本頁面,一次請求, 一次會話,整個應(yīng)用程序。
當(dāng)需要指定從某個特定的域?qū)ο笾胁檎覕?shù)據(jù)時(shí)可以使用四個域?qū)ο髮?yīng)的空間對象,分別是:pageScope, requestScope, sessionScope, applicationScope。
而 EL 默認(rèn)的查找方式為從小到大查找,找到即可。當(dāng)域?qū)ο笕彝炅诉€未找到則返回空字符串""。
設(shè)置域?qū)ο笾械臄?shù)據(jù)
<%
pageContext.setAttribute("uname","zhangsan"); // page作用域
request.setAttribute("uname","lisi"); // request作用域
session.setAttribute("uname","wangwu"); // session作用域
application.setAttribute("uname","zaholiu"); // application
%>
獲取域?qū)ο蟮闹?/strong>
<%-- 獲取域?qū)ο笾械臄?shù)據(jù):默認(rèn)查找方式為從小到大,找到即止。若四個范圍都未找到,則返回空字符串。--%>
${uname} <!-- 輸出結(jié)果為:zhangsan -->
獲取指定域?qū)ο蟮闹?/strong>
${pageScope.uname} <!-- page作用域 -->
${requestScope.uname} <!-- request作用域 -->
${sessionScope.uname} <!-- session作用域 -->
${applicationScope.uname} <!-- application作用域 -->
獲取List
<%
List<String> list = new ArrayList<String>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
request.setAttribute("list", list);
%>
<%--
獲取List中指定下標(biāo)的數(shù)據(jù)
${list[下標(biāo)] }
獲取集合的長度
${list.size()}
注:
list代表的是存在域?qū)ο笾械淖兞棵ㄏ抻蜃兞棵?--%>
${list[1] }
獲取Map
<%
Map map = new HashMap();
map.put("aaa", "111");
map.put("bbb", 2222);
map.put("ccc-a", 333);
request.setAttribute("map", map);
%>
<%--
獲取Map中指定值
${map["key"] } 或 ${map.key }
注:
map代表的是存在域?qū)ο笾械淖兞棵ㄏ抻蜃兞棵?--%>
${map.aaa }
${map["bbb"]}
獲取JavaBean對象
User.java
public class User {
?
private Integer userId;
private String uname;
private String upwd;
?
public Integer getUserId() {
return userId;
}
?
public void setUserId(Integer userId) {
this.userId = userId;
}
?
public String getUname() {
return uname;
}
?
public void setUname(String uname) {
this.uname = uname;
}
?
public String getUpwd() {
return upwd;
}
?
public void setUpwd(String upwd) {
this.upwd = upwd;
}
}
<%
User user = new User();
user.setUserId(1);
user.setUname("zhangsan");
user.setUpwd("123456");
request.setAttribute("user",user);
%>
<%-- JavBean中的屬性字段需要提供get方法 --%>
${user} <%-- 獲取對象 --%>
${user.uname} <%--獲取對象中的屬性--%>
<%--
empty
判斷域?qū)ο笫欠駷榭?。為空,返回true;不為空返回false;
${empty 限域變量名 }
判斷對象是否不為空。
${!empty 限域變量名 }
--%>
${empty uname}
${empty list}
${empty map}
${empty user}
<%
request.setAttribute("a", 10);
request.setAttribute("b", 2);
request.setAttribute("c", "aa");
request.setAttribute("d", "bb");
%>
等值判斷
<%--
比較兩個值是否相等,返回true或false
== 或 eq
--%>
${a == b }
${c == d }
${c eq d }
${a == 5 }
${c == 'aa' }
算術(shù)運(yùn)算
<%--
加法: +
減法: -
乘法: *
除法: / 或 div
--%>
${a + b }
${a / b } 或 ${a div b }
大小比較
jsp靜態(tài)包含和動態(tài)包含的區(qū)別
jsp靜態(tài)包含和動態(tài)包含的區(qū)別
<jsp:include page=""/>
jsp有哪些內(nèi)置對象?作用分別是什么?
jsp有哪些內(nèi)置對象?作用分別是什么?
九個內(nèi)置對象:
其中,request、response、session、application、config這五個對象和Servlet的API是一樣的。這5個對象我就不解釋了。
在JSP中,尤其重要的是pageContext對象。
pageContext是內(nèi)置對象中最重要的一個對象,它代表著JSP頁面編譯后的內(nèi)容(也就是JSP頁面的運(yùn)行環(huán)境)!
pageContext對象
pageContext作為域?qū)ο?/blockquote>
- 類似于request,session,ServletContext作為域?qū)ο蠖?strong>都有以下三個方法:
- setAttribute(String name,Objcet o)
- getAttribute(String name)
- removeAttribute(String name)
- 當(dāng)然了,pageContext也不例外,pageContext也有這三個方法!
- pageContext本質(zhì)上代表的是當(dāng)前JSP頁面編譯后的內(nèi)容,作為域?qū)ο蠖?,它就代表著?dāng)前JSP頁面(也就是page)!也就是說:pageContext域?qū)ο笾辉趐age范圍內(nèi)有效,超出了page范圍就無效了!
- 首先來看看在page范圍內(nèi)能不能使用
- 效果如下:
- 我們現(xiàn)在來試驗(yàn)一下是不是超出了page范圍就無效了!
- 在2.jsp中request域?qū)ο笤O(shè)置屬性
- 企圖在1.jsp中pageContext取出request存進(jìn)去的屬性
- 效果如下:
- pageContext本質(zhì)上代表著編譯后JSP的內(nèi)容,pageContext還可以封裝了訪問其他域的方法!
- 上面的pageContext默認(rèn)是page范圍的,但pageContext對象重載了set、get、removeAttribute這三個方法
- getAttribute(String name,int scope)
- setAttribute(String name,Object value,int scope)
- removeAttribute(String name,int scope)
- 多了一個設(shè)置域范圍的一個參數(shù),如果不指定默認(rèn)就是page。當(dāng)然了,pageContext把request、session、application、page這幾個域?qū)ο蠓庋b著了靜態(tài)變量供我們使用。
- PageContext.APPLICATION_SCOPE
- PageContext.SESSION_SCOPE
- PageContext.REQUEST_SCOPE
- PageContext.PAGE_SCOPE
- 剛才我們沒有使用重載方法的時(shí)候,使用pageContext是無法獲取到request域?qū)ο笤O(shè)置的屬性的。現(xiàn)在我們使用重載后的方法看一下能不能獲取得到!
- 效果:
- pageContexst還有這么一個方法:
- findAttribute(String name)
- 該方法會查找各個域的屬性,從小到大開始尋找!也就是page—>request->session->application。
- 我們用此方法看能不能查找出request域?qū)ο蟮膶傩园桑?/li>
- 效果如下:
out對象:
- out對象用于向?yàn)g覽器輸出數(shù)據(jù),與之對應(yīng)的是Servlet的PrintWriter對象。然而這個out對象的類型并不是PrintWriter,是JspWriter
- 我們可以簡單理解為:JspWriter就是帶緩存的PrintWrieter。
- out對象的原理如下:
- 只有向out對象中寫入了內(nèi)容,且滿足如下任何一個條件時(shí),out對象才去調(diào)用ServletResponse.getWriter方法,并通過該方法返回的PrintWriter對象將out對象的緩沖區(qū)中的內(nèi)容真正寫入到Servlet引擎提供的緩沖區(qū)中:
- 設(shè)置page指令的buffer屬性關(guān)閉了out對象的緩存功能
- out對象的緩沖區(qū)已滿
- 整個JSP頁面結(jié)束
- 一般我們在JSP頁面輸出都是用表達(dá)式(<%=%>),所以out對象用得并不是很多!
page對象內(nèi)置對象page是HttpJasPage對象,其實(shí)page對象代表的就是當(dāng)前JSP頁面,是當(dāng)前JSP編譯后的Servlet類的對象。也就是說:page對象相當(dāng)于普通java類的this
exception對象
- 內(nèi)置對象exception是java.lang.Exception類的對象,exception封裝了JSP頁面拋出的異常信息。exception經(jīng)常被用來處理錯誤頁面
- 前面我們已經(jīng)講過了怎么設(shè)置錯誤頁面了,下面我們就來簡單使用一下exception對象吧
- 1.jsp頁面
- error.jsp頁面
- 效果:
總結(jié):
- request 用戶端請求,此請求會包含來自GET/POST請求的參數(shù)
- response 網(wǎng)頁傳回用戶端的回應(yīng)
- pageContext 網(wǎng)頁的屬性是在這里管理,代表的編譯后JSP內(nèi)容
- session 與請求有關(guān)的會話期
- application servlet 正在執(zhí)行的內(nèi)容
- out 用來傳送回應(yīng)的輸出
- config servlet的構(gòu)架部件
- page JSP網(wǎng)頁本身
- exception 針對錯誤網(wǎng)頁,未捕捉的例外
jsp和servlet的區(qū)別、共同點(diǎn)、各自應(yīng)用的范圍?
jsp和servlet的區(qū)別、共同點(diǎn)、各自應(yīng)用的范圍?
- JSP是Servlet技術(shù)的擴(kuò)展,本質(zhì)上就是Servlet的簡易方式。JSP編譯后是“類servlet”。
- Servlet和JSP最主要的不同點(diǎn)在于:Servlet的應(yīng)用邏輯是在Java文件中,并且完全從表示層中的HTML里分離開來。而JSP的情況是Java和HTML可以組合成一個擴(kuò)展名為.jsp的文件。
- JSP側(cè)重于視圖,Servlet主要用于控制邏輯。
屬性作用域范圍
屬性作用域范圍
- page【只在一個頁面中保存屬性,跳轉(zhuǎn)頁面無效】
- requet【只在一次請求中保存屬性,服務(wù)器跳轉(zhuǎn)有效,瀏覽器跳轉(zhuǎn)無效】
- session【在一個會話范圍中保存屬性,無論何種跳轉(zhuǎn)均有效,關(guān)閉瀏覽器后無效】
- application【在整個服務(wù)器中保存,所有用戶都可以使用】
應(yīng)用場景:
- request:如果客戶向服務(wù)器發(fā)請求,產(chǎn)生的數(shù)據(jù),用戶看完就沒用了,像這樣的數(shù)據(jù)就存在request域,像新聞數(shù)據(jù),屬于用戶看完就沒用的
- session:如果客戶向服務(wù)器發(fā)請求,產(chǎn)生的數(shù)據(jù),用戶用完了等一會兒還有用,像這樣的數(shù)據(jù)就存在session域中,像購物數(shù)據(jù),用戶需要看到自己購物信息,并且等一會兒,還要用這個購物數(shù)據(jù)結(jié)帳
- servletContext:如果客戶向服務(wù)器發(fā)請求,產(chǎn)生的數(shù)據(jù),用戶用完了,還要給其它用戶用,像這樣的數(shù)據(jù)就存在servletContext域中,像聊天數(shù)據(jù)
寫出5種JSTL常用標(biāo)簽
寫出5種JSTL常用標(biāo)簽<c:if>,<c:item>,<c:foreach>,<c:out>,<c:set>
寫一個自定義標(biāo)簽要繼承什么類
寫一個自定義標(biāo)簽要繼承什么類我們可以有兩種方式來實(shí)現(xiàn)自定義標(biāo)簽:
- 傳統(tǒng)方式,實(shí)現(xiàn)Tag接口(老方法)
- 簡單方式,繼承SimpleTagSupport類
SimpleTagSupport類的執(zhí)行順序(原理):
- ①WEB容器調(diào)用標(biāo)簽處理器對象的setJspContext方法,將代表JSP頁面的pageContext對象傳遞給標(biāo)簽處理器對象
- ②WEB容器調(diào)用標(biāo)簽處理器對象的setParent方法,將父標(biāo)簽處理器對象傳遞給這個標(biāo)簽處理器對象。【注意,只有在標(biāo)簽存在父標(biāo)簽的情況下,WEB容器才會調(diào)用這個方法】
- ③如果調(diào)用標(biāo)簽時(shí)設(shè)置了屬性,容器將調(diào)用每個屬性對應(yīng)的setter方法把屬性值傳遞給標(biāo)簽處理器對象。如果標(biāo)簽的屬性值是EL表達(dá)式或腳本表達(dá)式,則WEB容器首先計(jì)算表達(dá)式的值,然后把值傳遞給標(biāo)簽處理器對象。
- ④如果簡單標(biāo)簽有標(biāo)簽體,容器將調(diào)用setJspBody方法把代表標(biāo)簽體的JspFragment對象傳遞進(jìn)來
- ⑤執(zhí)行標(biāo)簽時(shí):容器調(diào)用標(biāo)簽處理器的doTag()方法,開發(fā)人員在方法體內(nèi)通過操作JspFragment對象,就可以實(shí)現(xiàn)是否執(zhí)行、迭代、修改標(biāo)簽體的目的。
總結(jié)
SimpleTagSupport,一般調(diào)用doTag方法或者實(shí)現(xiàn)SimpleTag接口
JSP是如何被執(zhí)行的?執(zhí)行效率比SERVLET低嗎?
JSP是如何被執(zhí)行的?執(zhí)行效率比SERVLET低嗎?
- 當(dāng)客戶端向一個jsp頁面發(fā)送請求時(shí),Web Container將jsp轉(zhuǎn)化成servlet的源代碼(只在第一次請求時(shí)),然后編譯轉(zhuǎn)化后的servlet并加載到內(nèi)存中執(zhí)行,執(zhí)行的結(jié)果response到客戶端
- jsp只在第一次執(zhí)行的時(shí)候會轉(zhuǎn)化成servlet,以后每次執(zhí)行,web容器都是直接執(zhí)行編譯后的servlet,所以jsp和servlet只是在第一次執(zhí)行的時(shí)候不一樣,jsp慢一點(diǎn),以后的執(zhí)行都是相同的
如何避免jsp頁面自動生成session對象?為什么要這么做?
如何避免jsp頁面自動生成session對象?為什么要這么做?可以使用頁面指令顯式關(guān)掉,代碼如下:
<%@ page session="false" %>
jsp的缺點(diǎn)?
jsp的缺點(diǎn)?
- 1)不好調(diào)試
- 2)與其他腳本語言的交互(可讀性差)
說出Servlet和CGI的區(qū)別?
說出Servlet和CGI的區(qū)別?
- Servlet處于服務(wù)器進(jìn)程中,只會有一個servlet實(shí)例,每個請求都會產(chǎn)生一個新的線程,而且servlet實(shí)例一般不會銷毀
- CGI:來一個請求就創(chuàng)建一個進(jìn)程,用完就銷毀,效率低于servlet
簡述JSP的設(shè)計(jì)模式。
簡述JSP的設(shè)計(jì)模式。在Web開發(fā)模式中,有兩個主要的開發(fā)結(jié)構(gòu),稱為模式一(Mode I)和模式二(Mode II)
首先我們來理清一些概念吧:
- DAO(Data Access Object):主要對數(shù)據(jù)的操作,增加、修改、刪除等原子性操作。
- Web層:界面+控制器,也就是說JSP【界面】+Servlet【控制器】
- Service業(yè)務(wù)層:將多個原子性的DAO操作進(jìn)行組合,組合成一個完整的業(yè)務(wù)邏輯
- 控制層:主要使用Servlet進(jìn)行控制
- 數(shù)據(jù)訪問層:使用DAO、Hibernate、JDBC技術(shù)實(shí)現(xiàn)對數(shù)據(jù)的增刪改查
- JavaBean用于封裝數(shù)據(jù),處理部分核心邏輯,每一層中都用到!
模式一指的就是在開發(fā)中將顯示層、控制層、數(shù)據(jù)層的操作統(tǒng)一交給JSP或者JavaBean來進(jìn)行處理!
模式一有兩種情況:
完全使用JSP做開發(fā):
- 優(yōu)點(diǎn):
- 開發(fā)速度賊快,只要寫JSP就行了,JavaBean和Servlet都不用設(shè)計(jì)!
- 小幅度修改代碼方便,直接修改JSP頁面交給WEB容器就行了,不像Servlet還要編譯成.class文件再交給服務(wù)器!【當(dāng)然了,在ide下開發(fā)這個也不算是事】
- 缺點(diǎn):
- 程序的可讀性差、復(fù)用性低、代碼復(fù)雜!什么jsp代碼、html代碼都往上面寫,這肯定很難閱讀,很難重用!
使用JSP+JavaBean做開發(fā):
- 優(yōu)點(diǎn):
- 程序的可讀性較高,大部分的代碼都寫在JavaBean上,不會和HTML代碼混合在一起,可讀性還行的。
- 可重復(fù)利用高,核心的代碼都由JavaBean開發(fā)了,JavaBean的設(shè)計(jì)就是用來重用、封裝,大大減少編寫重復(fù)代碼的工作!
- 缺點(diǎn):
- 沒有流程控制,程序中的JSP頁面都需要檢查請求的參數(shù)是否正確,異常發(fā)生時(shí)的處理。顯示操作和業(yè)務(wù)邏輯代碼工作會緊密耦合在一起的!日后維護(hù)會困難
Mode II 中所有的開發(fā)都是以Servlet為主體展開的,由Servlet接收所有的客戶端請求,然后根據(jù)請求調(diào)用相對應(yīng)的JavaBean,并所有的顯示結(jié)果交給JSP完成!,也就是俗稱的MVC設(shè)計(jì)模式!
MVC設(shè)計(jì)模式:
- 顯示層(View):主要負(fù)責(zé)接受Servlet傳遞的內(nèi)容,調(diào)用JavaBean,將內(nèi)容顯示給用戶
- 控制層(Controller):主要負(fù)責(zé)所有用戶的請求參數(shù),判斷請求參數(shù)是否合法,根據(jù)請求的類型調(diào)用JavaBean,將最終的處理結(jié)果交給顯示層顯示!
- 模型層(Mode):模型層包括了業(yè)務(wù)層,DAO層。
總結(jié)
- (1)ModelI,JSP+JavaBean設(shè)計(jì)模式。
- (2)ModelII,MVC設(shè)計(jì)模式。
原文地址:https://dwz.cn/NhBjgHRk作者:Java3y
*請認(rèn)真填寫需求信息,我們會在24小時(shí)內(nèi)與您取得聯(lián)系。