第二章 Jsp基本语法
本章簡(jiǎn)介
??本章將系統(tǒng)介紹JSP頁(yè)面元素以及內(nèi)置對(duì)象,其中重點(diǎn)介紹了out、request、 response、session等常用內(nèi)置對(duì)象以及Cookie等使用,并且從使用原理上講 解了pageContext、request、session、application等四種范圍對(duì)象的作用域。
回顧第一個(gè)jsp程序,如下,
index.jsp
<html><head><title>First Web Project</title></head><body><%out.print("Hello World");%></body> </html>??其中 <% out.print("Hello World”); %>稱為腳本。可以發(fā)現(xiàn),在JSP文件中,既有HTML標(biāo)簽,又有JAVA代碼,因此我們可以把JSP看成“嵌入JAVA的HTML代碼”。
但是在Eclipse中生成的Jsp內(nèi)容,如下
<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body></body> </html>??Eclipse生成的JSP文件中,除了典型的html元素外,還有很多其他內(nèi)容。這是因?yàn)镴SP頁(yè)面本身就可以包含多種頁(yè)面元素,如腳本、HTML、指令、注釋等。
2.1 JSP頁(yè)面元素
1) 腳本Scriptlet
所有嵌入在HTML中的JAVA代碼都必須使用scriptlet包裹起來(lái)。
在JSP中共有3種Scriptlet:<% … %>,<% ! …%>和<% =…%>。
Scriptlet一般寫(xiě)在<body>標(biāo)簽中。
①<%…%>
<% …%>主要用來(lái)定義局部變量、編寫(xiě)java語(yǔ)句。
scriptlet.jsp
<body> <%String bookName ="瘋狂Java講義";String author = "李剛" ;out.print("書(shū)名:"+bookName+"<br/>作者:"+author);%> </body>運(yùn)行結(jié)果:
其中,out.print();是JSP頁(yè)面的輸出語(yǔ)句。
②<%! … %>
<% ! … %>主要用來(lái)定義全局變量、定義方法。
scriptlet2.jsp
<body><%!public String bookName ; //定義全局變量-書(shū)名public String author ; //定義全局變量-作者public void initInfo(){ //定義一個(gè)方法bookName = "《Java瘋狂講義》";author = "李剛";}%><%initInfo();//調(diào)用方法out.print( "書(shū)名:" + bookName + "</br>" +"作者:"+ author);%> </body>運(yùn)行結(jié)果:
注意:
out.print()只能寫(xiě)在<%…%>里面。寫(xiě)在<%!..%>里面會(huì)報(bào)錯(cuò)的。
③<%=…%>
<%= … %> 用來(lái)輸出=后面的表達(dá)式的值,功能類似out.print()
<body> <%String bookName ="瘋狂Java講義";String author = "李剛" ;%><%="書(shū)名:" + bookName + "</br>" + "作者:" + author %> </body>運(yùn)行結(jié)果同上。
從上面代碼,可以發(fā)現(xiàn):
out.print()和<%=… >不僅能輸出變量,還可解析”<br/>”等html代碼。
<%= …>中沒(méi)有“;”。
2) 指令
JSP指令用來(lái)設(shè)置整個(gè)JSP頁(yè)面相關(guān)的屬性,如網(wǎng)頁(yè)的編碼方式和腳本語(yǔ)言。
JSP指令寫(xiě)在 <%@ …%> 中
指令可以有很多個(gè)屬性,它們以鍵值對(duì)的形式存在,并用逗號(hào)隔開(kāi)。
JSP中的三種指令標(biāo)簽:
| <%@ page … %> | 定義網(wǎng)頁(yè)依賴屬性,比如腳本語(yǔ)言、error頁(yè)面、緩存需求等等 |
| <%@ include … %> | 包含其他文件 |
| <%@ taglib … %> | 引入標(biāo)簽庫(kù)的定義 |
①page指令
Page指令為容器提供當(dāng)前頁(yè)面的使用說(shuō)明。
一個(gè)JSP頁(yè)面可以包含多個(gè)page指令。
Page指令的語(yǔ)法格式:
<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>| language | 指定JSP頁(yè)面使用的腳本語(yǔ)言,默認(rèn)是java,一般不用修改。 |
| import | 與java中import的用法一致,可以執(zhí)行導(dǎo)包操作 |
| pageEncoding | 指定JSP文件本身的編碼方式 |
| contentType | 指定服務(wù)器發(fā)送給客戶端的內(nèi)容的編碼方式,通常與pageEncoding保持一致 |
| errorPage | 指定當(dāng)JSP頁(yè)面發(fā)生異常時(shí)需要轉(zhuǎn)向的錯(cuò)誤處理頁(yè)面 |
| isErrorPage | 指定當(dāng)前頁(yè)面是否可以作為另一個(gè)JSP頁(yè)面的錯(cuò)誤處理頁(yè)面 |
| extends | 指定servlet從哪一個(gè)類繼承 |
| info | 定義JSP頁(yè)面的描述信息 |
| session | 指定JSP頁(yè)面是否使用session |
| isThreadSafe | 指定對(duì)JSP頁(yè)面的訪問(wèn)是否為線程安全 |
| isELIgnored | 指定是否執(zhí)行EL表達(dá)式 |
page.jsp
<%@page import="java.util.Date"%> <%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>page指令</title> </head> <body> <%Date date = new Date();out.print(date);%> </body> </html>運(yùn)行結(jié)果:
②include指令
JSP可以通過(guò)include指令來(lái)包含其他文件。被包含的文件可以是JSP文件、HTML文件或文本文件。包含的文件就好像是該JSP文件的一部分,會(huì)被同時(shí)編譯執(zhí)行。
Include指令的語(yǔ)法格式如下:
<%@ include file="文件相對(duì) url 地址" %>include 指令中的文件名實(shí)際上是一個(gè)相對(duì)的 URL 地址。
如果您沒(méi)有給文件關(guān)聯(lián)一個(gè)路徑,JSP編譯器默認(rèn)在當(dāng)前路徑下尋找。
③taglib指令
JSP API允許用戶自定義標(biāo)簽,一個(gè)自定義標(biāo)簽庫(kù)就是自定義標(biāo)簽的集合。
Taglib指令引入一個(gè)自定義標(biāo)簽集合的定義,包括庫(kù)路徑、自定義標(biāo)簽。
Taglib指令的語(yǔ)法:
<%@ taglib uri="uri" prefix="prefixOfTag" %>uri屬性確定標(biāo)簽庫(kù)的位置,prefix屬性指定標(biāo)簽庫(kù)的前綴。
3) 注釋
前面講過(guò),基本的JSP包含了HTML和JAVA兩種代碼。因此,JSP的注釋既包括HTML的注釋,又包含JAVA的注釋,此外還擁有JSP自己獨(dú)有的注釋
| <!-- --> | HTML注釋。可以用來(lái)注釋HTML代碼,但要注意此種注釋能通過(guò)客戶端(瀏覽器)查看到,因此是不安全的。 |
| <%-- --%> | JSP注釋。如果想讓注釋不被瀏覽器所查看到,就可以使用JSP注釋。 |
| <% //單行注釋 %> <% /*多行注釋 */ %> | JAVA注釋。<% %>中放置的是JAVA代碼,所以可以在<% %>使用//和/…/來(lái)對(duì)其中的JAVA代碼進(jìn)行注釋。 |
note.jsp
<body> <!-- HTML注釋 --> <%--jsp注釋 --%> <% //java單行注釋 /*java多行注釋 */ %> </body>運(yùn)行結(jié)果:
鼠標(biāo)右鍵網(wǎng)頁(yè)空白處,查看源代碼,如圖:
可以發(fā)現(xiàn)HTML的注釋能被瀏覽器所查看到,而JSP注釋和JAVA注釋不能被查看。
2.2 九大內(nèi)置對(duì)象
<% out.print("Hello World"); %>在上面的代碼中,像out這樣,沒(méi)有定義和實(shí)例化(new)就可以直接使用的對(duì)象,就稱為內(nèi)置對(duì)象。JSP還提供了9個(gè)內(nèi)置對(duì)象,如下表
| page | Context javax.servlet.jsp.PageContext | JSP頁(yè)面容器 |
| request | javax.servlet.http.HttpServletRequest | 客戶端向服務(wù)端發(fā)送的請(qǐng)求信息 |
| response | javax.servlet.http.HttpServletResponse | 服務(wù)器端向客戶端的響應(yīng)信息 |
| session | javax.servlet.http.HttpSession | 客戶端與服務(wù)器端的一次會(huì)話 |
| application | javax.servlet.ServletContext | 可存放全局變量,實(shí)現(xiàn)用戶間數(shù)據(jù)的共享 |
| config | javax.servlet.ServletConfig | 服務(wù)器配置信息,可以取得初始化參數(shù) |
| out | javax.servlet.jsp.JspWriter | 向客戶端輸出內(nèi)容 |
| page | java.lang.Object | 當(dāng)前JSP頁(yè)面本身,類似于Java類中的this關(guān)鍵字. |
| exception | java.lang.Throwable | 當(dāng)一個(gè)頁(yè)面在運(yùn)行過(guò)程中發(fā)生了異常,就產(chǎn)生這個(gè)對(duì)象 |
1) out
out用于向客戶端輸出數(shù)據(jù),最常用的是out.print();
需要注意的是,out.println()或者out.print(“\n”)均不能實(shí)現(xiàn)在客戶端的換行功能
out.jsp
<body><%out.println("hello");out.print("world\n");out.print("hello world"); %> </body>運(yùn)行結(jié)果:
若要實(shí)現(xiàn)換行,必須借助于HTML的<br/>或者</br>標(biāo)簽
out2.jsp
<body><%out.println("hello</br>");out.print("world"); %> </body>運(yùn)行結(jié)果:
2) request
request對(duì)象主要用于存儲(chǔ)“客戶端發(fā)送給服務(wù)端的請(qǐng)求信息”
因此我們可以通過(guò)request對(duì)象來(lái)獲取用戶發(fā)送的相關(guān)數(shù)據(jù),request對(duì)象的常用方法如下表:
| public String getParameter(String name) | 獲取客戶端發(fā)送給服務(wù)端的參數(shù)值(由name指定的唯一參數(shù)值,如單選框、密碼框的值) |
| public String[] getParameterValues(String name) | 獲取客戶端發(fā)送給服務(wù)端的參數(shù)值(由name指定的多個(gè)參數(shù)值,如復(fù)選框的值) |
| public void setCharacterEncoding(String env) throws java.io.UnsupportedEncodingException | 指定請(qǐng)求的編碼,用于解決亂碼問(wèn)題 |
| public RequestDispatcher getRequestDispatcher(String path) | 返回RequestDispatcher對(duì)象,該對(duì)象的forward()方法用于轉(zhuǎn)發(fā)請(qǐng)求 |
| public HttpSession getSession() | 返回和請(qǐng)求相關(guān)Session |
| public ServletContext getServletContext() | 獲取web應(yīng)用的ServletContext對(duì)象 |
下面通過(guò)一個(gè)簡(jiǎn)單的注冊(cè)及顯示功能,演示上述部分方法的使用:
①register.jsp
<body><form action="show.jsp" method="post">用戶名:<input type="text" name="username"></br>密碼:<input type="password" name="userpwd"></br>愛(ài)好:<input type="checkbox" name="hobby" value="足球">足球<input type="checkbox" name="hobby" value="籃球">籃球<input type="checkbox" name="hobby" value="羽毛球">羽毛球</br><input type="submit" name="注冊(cè)"></form> </body>運(yùn)行結(jié)果:
②show.jsp
運(yùn)行結(jié)果:
??上述代碼中,通過(guò)request.setCharacterEncoding("UTF-8")將POST方式的編碼設(shè)置為UTF-8,,并通過(guò)request.getParameter()和request.getParameterValues()方法獲取到了從表單傳來(lái)的數(shù)據(jù)。
??需要注意的是,客戶端的數(shù)據(jù)不一定必須從表單傳遞過(guò)來(lái),也可以通過(guò)URL地址進(jìn)行傳遞,格式如下:
頁(yè)面地址?參數(shù)名1=參數(shù)內(nèi)容1&參數(shù)名2=參數(shù)內(nèi)容2&…??即通過(guò)“?”將頁(yè)面地址和參數(shù)分離,然后按照“參數(shù)名=參數(shù)內(nèi)容”的格式來(lái)傳遞數(shù)據(jù),并且多個(gè)參數(shù)之間用“&”分隔。
??例如,上例中,我們可以不運(yùn)行注冊(cè)頁(yè)register.jsp,而直接在瀏覽器中輸入 http://localhost:8080/JspProject/register/show.jsp?username=李四&userpwd=123&hobby=足球&hobby=籃球
也能正常運(yùn)行程序,并得到結(jié)果,如圖
補(bǔ)充:Get與Post請(qǐng)求
??我們仔細(xì)觀察一下表單提交和URL地址提交兩種方式的地址欄,
表單提交方式的地址欄: http://localhost:8080/JspProject/register/show.jsp
URL地址提交方式的地址欄: http://localhost:8080/JspProject/register/show.jsp?uname=李四&upwd=123&hobby=足球&hobby=籃球
??這兩種地址不同的本質(zhì)原因,在于表單的的提交方式,在register.jsp中有一行代碼 <form action="show.jsp" method="post" >其中method就可以用來(lái)指定表單的提交方式,常用屬性值有g(shù)et和post兩種。
當(dāng)method=”post”時(shí),表示以post方式請(qǐng)求表單,請(qǐng)求后的地址為 http://localhost:8080/JspProject/register/show.jsp
當(dāng)method=”get”時(shí),再次提交表單,則地址欄就會(huì)顯示 http://localhost:8080/JspProject/register/show.jsp?username=張三&userpwd=123&hobby=足球&hobby=籃球
??因此,可以發(fā)現(xiàn)用get方式提交表單,實(shí)際就是通過(guò)URL地址提交的方式向服務(wù)器端發(fā)送數(shù)據(jù)。
說(shuō)明:
??如果 “URL地址傳遞”中的值是中文,而JSP頁(yè)面編碼是UTF-8時(shí),則會(huì)顯示亂碼。
原因是“URL地址傳遞”使用的是GET方式傳遞數(shù)據(jù),而GET方式的默認(rèn)編碼是ISO-8859-1,與JSP頁(yè)面編碼UTF-8不一致。
解決方法就是將GET方式提交的數(shù)據(jù),進(jìn)行統(tǒng)一字符編碼,詳見(jiàn)后文。
??除了地址欄的不同以外,get和post方式在提交的數(shù)據(jù)大小上也有區(qū)別。因?yàn)間et方式會(huì)在地址欄上顯示數(shù)據(jù)信息,而地址欄中能容納的信息長(zhǎng)度是有限制的(一般是4-5KB); 與之不同的是,post方式不會(huì)在地址欄中顯示數(shù)據(jù)信息,所以能提交更多的數(shù)據(jù)內(nèi)容。因此,如果表單中有一些大文本、圖文、文件、視頻等數(shù)據(jù),就必須使用post的方式提交。 request的其余方法,我們會(huì)在后面詳細(xì)講述。
補(bǔ)充:統(tǒng)一字符集編碼
??了解完get方式和post方式的區(qū)別后,我們?cè)賮?lái)看看兩種方式如何解決字符亂碼問(wèn)題。
解決Web項(xiàng)目亂碼問(wèn)題的基本步驟如下(以將編碼統(tǒng)一為UTF-8為例):
1.將所有JSP文件的編碼設(shè)置為UTF-8,如下,
<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%> <html><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> …此步驟,也可通過(guò)Eclipse來(lái)設(shè)置,詳細(xì)步驟參見(jiàn)第一章。
2.對(duì)于GET或POST方式,實(shí)施不同的統(tǒng)一編碼操作。
我們首先要知道tomcat服務(wù)器,默認(rèn)使用的編碼方式是ISO-8859-1。
(1)如果是以get方式提交表單(或URL地址傳遞的方式),則有兩種方式處理編碼:
方法①:分別把每一個(gè)變量的編碼方式,從ISO-8859-1轉(zhuǎn)為UTF-8
如以下代碼:
//將name的編碼方式,從ISO-8859-1轉(zhuǎn)為UTF-8String name = request.getParameter("uname");name = new String(name.getBytes("ISO-8859-1"), "UTF-8");//將pwd的編碼方式,從ISO-8859-1轉(zhuǎn)為UTF-8String pwd = request.getParameter("upwd");pwd = new String(pwd.getBytes("ISO-8859-1"), "UTF-8");方法②:修改tomcat配置
??一次性的,將所有通過(guò)get方式傳遞的變量編碼都設(shè)置為UTF-8(推薦)。具體修改如下:打開(kāi)tomcat的conf目錄,在server.xml的64行附近的元素中,加入U(xiǎn)RIEncoding=”UTF-8”,如下
server.xml
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8" />說(shuō)明:
要使修改的server.xml生效,必須把Eclipse的tomat服務(wù)器設(shè)置成本地Tomcat托管模式,設(shè)置托管模式方法如下:
??我們使用Eclipse配置完Tomcat后,會(huì)在左側(cè)項(xiàng)目導(dǎo)航欄多出一個(gè)Servers項(xiàng)目,該項(xiàng)目中就有Tomcat的一些配置文件,如context.xml,server.xml等。為了使Servers項(xiàng)目中的配置文件,與我們本地安裝的Tomcat目錄中的配置文件保持一致,我們可以雙擊控制臺(tái)Servers下的Tomcat V9.0。在雙擊后打開(kāi)的頁(yè)面里,將Server Locations指定為第二項(xiàng),如圖
??之后,我們只需要在Servers項(xiàng)目中修改配置文件,修改結(jié)果就會(huì)同步到我們本地安裝的Tomcat配置文件中。因此,以后如果要對(duì)Tomcat進(jìn)行操作,就只需要對(duì)Servers項(xiàng)目進(jìn)行操作。
注意,如果發(fā)現(xiàn)Server Locations中的選項(xiàng)是灰色不可選,則需要將現(xiàn)有的Tomcat從Servers面板中刪除,然后重新創(chuàng)建Tomcat服務(wù)后再選擇。
(2)如果是以post方式提交表單,可以通過(guò)在服務(wù)器端加入request.setCharacterEncoding(“UTF-8”)來(lái)設(shè)置編碼,詳見(jiàn)前面的show.jsp。
3) response
我們已經(jīng)知道,客戶端可以通過(guò)request向服務(wù)端發(fā)送請(qǐng)求數(shù)據(jù),那反過(guò)來(lái)呢?
當(dāng)服務(wù)器端接收到請(qǐng)求的數(shù)據(jù)后,如何向客戶端響應(yīng)呢?答案就是response,即服務(wù)端可以通過(guò)response向客戶端做出響應(yīng)
response也提供了一些方法用來(lái)處理響應(yīng),如下表所示,
| public void addCookie(Cookie cookie) | 服務(wù)端向客戶端增加Cookie對(duì)象 |
| public void sendRedirect(String location) throws IOException | 將客戶端發(fā)來(lái)的請(qǐng)求,重新定位(跳轉(zhuǎn))到另一個(gè)URL上(習(xí)慣上稱為“重定向”) |
| public void setContentType(String type) | 設(shè)置服務(wù)器端響應(yīng)的contentType類型 |
??我們先來(lái)了解一下重定向方法sendRedirect()的使用。 這次我們實(shí)現(xiàn)一個(gè)登陸功能:用戶輸入用戶名和密碼,如果驗(yàn)證正確,則跳轉(zhuǎn)到歡迎頁(yè),如下:
login.jsp(輸入用戶名:admin,密碼:123)
<body><form action="check.jsp" method="post">用戶名:<input type="text" name="username"></br>密碼:<input type="password" name="userpwd"></br><input type="submit" name="登錄"></form> </body>運(yùn)行結(jié)果:
驗(yàn)證頁(yè): check.jsp
若登陸成功,則跳轉(zhuǎn)到成功提示頁(yè): success.jsp
<body> <%String userName = request.getParameter("username"); %> 歡迎你,<%=userName%> </body>運(yùn)行結(jié)果:
從“運(yùn)行結(jié)果”可以發(fā)現(xiàn)兩點(diǎn):
1.如果用戶名和密碼驗(yàn)證成功,確實(shí)跳轉(zhuǎn)到了歡迎頁(yè)success.jsp,但數(shù)據(jù)卻丟失了,用戶名name的值為null。
2.重定向到success.jsp后,地址欄也變成了success.jsp頁(yè)面的地址。
補(bǔ)充:請(qǐng)求轉(zhuǎn)發(fā)與重定向
send:發(fā)送
redirect:改變方向
request:請(qǐng)求
dispatcher:調(diào)度員
??為了解決重定向以后數(shù)據(jù)丟失的問(wèn)題,我們先來(lái)回憶一下request對(duì)象中的一個(gè)方法: public RequestDispatcher getRequestDispatcher(String path)
之前說(shuō)過(guò),此方法的返回值為RequestDispatcher(請(qǐng)求調(diào)度員)對(duì)象,有一個(gè)forward()方法可以用于轉(zhuǎn)發(fā)請(qǐng)求,也就是說(shuō),request的getRequestDispatcher()方法和response的sendRedirect()方法有相同之處:都可以實(shí)現(xiàn)頁(yè)面之間的跳轉(zhuǎn)。
我們將check.jsp中的response.sendRedirect("success.jsp")改為request.getRequestDispatcher("success.jsp").forward(request, response),其他代碼均不變,再次運(yùn)行程序,可以看到success.jsp的結(jié)果如圖:
??可以發(fā)現(xiàn), 采用了request.getRequestDispatcher("success.jsp").forward(request, response)來(lái)跳轉(zhuǎn)頁(yè)面后:
1.成功頁(yè)面就可以獲取到客戶端發(fā)送的表單數(shù)據(jù);
2.頁(yè)面內(nèi)容確實(shí)跳轉(zhuǎn)到了success.jsp中編寫(xiě)的內(nèi)容,但地址欄卻仍然停留在check.jsp,即采用請(qǐng)求轉(zhuǎn)發(fā)方式,地址欄不會(huì)發(fā)生改變。
??關(guān)于請(qǐng)求轉(zhuǎn)發(fā)(request.getRequestDispatcher(“xx”).forward(request, response))和重定向response.sendRedirect(“xx”)的區(qū)別,經(jīng)常會(huì)在面試中被提到,我們?cè)诖俗鲆粋€(gè)總結(jié),如下表:
| 請(qǐng)求服務(wù)器次數(shù) | 1次 | 2次 |
| 是否保留第一次請(qǐng)求時(shí)request范圍中的屬性 | 保留 | 不保留 |
| 地址欄里的請(qǐng)求URL,是否改變 | 不變 | 改變?yōu)橹囟ㄏ蛑蟮男履繕?biāo)URL。 |
關(guān)于“請(qǐng)求服務(wù)器次數(shù)”的問(wèn)題,再做以下詳盡分析:
請(qǐng)求轉(zhuǎn)發(fā):客戶端(瀏覽器)向服務(wù)器的資源A發(fā)起一次請(qǐng)求,服務(wù)器的資源A接收到該請(qǐng)求后,將該請(qǐng)求轉(zhuǎn)發(fā)到內(nèi)部的其他資源B,資源B處理完請(qǐng)求后,最終給客戶端做出響應(yīng)。
重定向:客戶端(瀏覽器)向服務(wù)器的資源A發(fā)起一次請(qǐng)求,服務(wù)器的資源A接收到該請(qǐng)求后,給客戶端做出響應(yīng),告訴客戶端去重新訪問(wèn)資源B的地址 ,客戶端收到資源B的地址后再次向服務(wù)器的資源B發(fā)出第二次請(qǐng)求,服務(wù)器資源B處理完該請(qǐng)求并做出響應(yīng)。
情景模擬:
請(qǐng)求轉(zhuǎn)發(fā):張三去銀行的A窗口辦理業(yè)務(wù),A窗口的業(yè)務(wù)員發(fā)現(xiàn)該業(yè)務(wù)自己辦不了,就將張三的業(yè)務(wù)請(qǐng)求轉(zhuǎn)發(fā)給其他同事辦理,最后將辦理完的業(yè)務(wù)返回給張三。也就是說(shuō),張三只是給銀行的A窗口發(fā)送了一次請(qǐng)求,而該業(yè)務(wù)辦理人員之間的換人工作,是銀行內(nèi)部處理的。即張三只發(fā)出了一次請(qǐng)求,更換窗口業(yè)務(wù)員(跳轉(zhuǎn))是銀行的行為。
重定向:張三去銀行的A窗口辦理業(yè)務(wù),A窗口的業(yè)務(wù)員發(fā)現(xiàn)該業(yè)務(wù)自己辦不了,然后告訴張三應(yīng)該重新去窗口B辦理,張三收到該消息后,又重新向銀行的窗口B再次請(qǐng)求辦理業(yè)務(wù),最終銀行的窗口B處理完張三的請(qǐng)求,并將辦理完的業(yè)務(wù)返回給張三。也就是說(shuō),張三分別向銀行的窗口A、窗口B各發(fā)送了一次請(qǐng)求(共2次請(qǐng)求),更換窗口業(yè)務(wù)員(跳轉(zhuǎn))是張三的行為。
4)cookie和內(nèi)置對(duì)象session
??在學(xué)習(xí)session之前,我們有必要先來(lái)了解一下cookie。
??注意:cookie不是內(nèi)置對(duì)象
① cookie
??cookie對(duì)象是先由服務(wù)端產(chǎn)生,再發(fā)送給客戶端(瀏覽器)的,并且瀏覽器會(huì)將該cookie保存在客戶端的某個(gè)文件中。也就是說(shuō),cookie技術(shù)能將服務(wù)器端的一些數(shù)據(jù),保存在用戶使用的客戶端計(jì)算機(jī)中。這樣一來(lái),用戶下次就可以直接通過(guò)自己的計(jì)算機(jī)訪問(wèn)到該數(shù)據(jù),而不必再訪問(wèn)服務(wù)器。因而cookie技術(shù)可以提高網(wǎng)頁(yè)處理的效率,也能減少服務(wù)器端的負(fù)載。但是由于cookie是服務(wù)器端保存在客戶端的信息,所以其安全性相對(duì)較差。
(1)cookie的使用:
??一個(gè)Cookie對(duì)象包含一個(gè)鍵值對(duì),即key=value。cookie不是JSP的內(nèi)置對(duì)象,需要通過(guò)JSP提供的javax.servlet.http.Cookie類來(lái)創(chuàng)建,Cookie類提供的常用方法如下表:
| public Cookie(String name, String value) | 構(gòu)造方法,用來(lái)實(shí)例化Cookie對(duì)象,同時(shí)設(shè)置Cookie對(duì)象的屬性名和屬性值 |
| public String getName() | 獲取Cookie對(duì)象的名稱 |
| public String getValue() | 獲取Cookie對(duì)象的內(nèi)容 |
| public void setMaxAge(int expiry) | 設(shè)置Cookie的保存時(shí)間,以秒為單位 |
??服務(wù)器端可以通過(guò)response對(duì)象的addCookie()方法,將Cookie對(duì)象設(shè)置到客戶端;
而客戶端也可以通過(guò)request對(duì)象的getCookies()方法來(lái)獲取全部的Cookie對(duì)象,如下:
服務(wù)器端 response_addCookie.jsp:
<body> <%Cookie cookie1 = new Cookie("name","zhangSan");//創(chuàng)建一個(gè)cookie存nameCookie cookie2 = new Cookie("age","15");//創(chuàng)建一個(gè)cookie存ageresponse.addCookie(cookie1);//服務(wù)端將cookie1添加到客戶端response.addCookie(cookie2);//服務(wù)端將cookie2添加到客戶端response.sendRedirect("temp.jsp"); %>跳轉(zhuǎn)頁(yè)面 temp.jsp
<body> <a href="request_getCookie.jsp">跳轉(zhuǎn)到客戶端</a> </body>客戶端 request_getCookie.jsp
<body> <%Cookie[] cookies = request.getCookies();for(int i = 0 ; i< cookies.length; i++){out.print(cookies[i].getName()+","+cookies[i].getValue()+" ");} %> </body>??先執(zhí)行response_addCookie.jsp,并在跳轉(zhuǎn)后的頁(yè)面temp.jsp里點(diǎn)擊超鏈接,運(yùn)行結(jié)果:
??可以發(fā)現(xiàn),temp.jsp中的超鏈接并沒(méi)有攜帶任何參數(shù),但跳轉(zhuǎn)后的客戶端response_addCookie.jsp頁(yè)面卻依然能獲取到Cookie對(duì)象。這是因?yàn)?#xff0c;在客戶端發(fā)送的請(qǐng)求中(超鏈接請(qǐng)求、表單請(qǐng)求等)包含著非常豐富的內(nèi)容,除了可以攜帶URL參數(shù)、表單數(shù)據(jù)意外,還會(huì)傳遞豐富的請(qǐng)求頭信息,如圖
??可以發(fā)現(xiàn),請(qǐng)求頭信息中包含著多個(gè)Cookie對(duì)象,每個(gè)Cookie對(duì)象都是以“鍵=值”的形式存在的,并且鍵為JSESSIONID的Cookie對(duì)象是由服務(wù)器自動(dòng)產(chǎn)生的。
??實(shí)際上,在客戶端每一次訪問(wèn)服務(wù)器時(shí),服務(wù)器為了區(qū)分各個(gè)不同的客戶端,就會(huì)自動(dòng)在每個(gè)客戶端的Cookie里設(shè)置一個(gè)JSESSIONID,表示該客戶端的唯一標(biāo)示符。
(2)補(bǔ)充:谷歌瀏覽器查看所有cookie信息
設(shè)置–>高級(jí)–>隱私設(shè)置和安全性–>網(wǎng)站設(shè)置–>cookie–>所有 Cookie 和網(wǎng)站數(shù)據(jù)
(3)通過(guò)Cookie來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的“記住用戶名”功能:
登錄頁(yè)login_cookie.jsp
<body> <%!String username ;String pwd; %> <%Cookie[] cookies = request.getCookies();if(cookies!=null){for ( int i = 0 ; i< cookies.length; i++){if("username".equals(cookies[i].getName())){username = cookies[i].getValue();}if("pwd".equals(cookies[i].getName())){pwd = cookies[i].getValue();}}} %><form action="check.jsp"><input type="text" name="username" value="<%=username == null ?"":username%>"></br> <input type="password" name="pwd" value="<%=pwd == null ?null :pwd%>"></br> <input type="submit" value="登錄"></form> </body>登錄驗(yàn)證頁(yè)check_cookie.jsp
<body> <%String username = request.getParameter("username");//獲取用戶名String pwd = request.getParameter("pwd");//獲取密碼Cookie cookie = new Cookie("username",username);Cookie cookie2 = new Cookie("pwd",pwd);response.addCookie(cookie);response.addCookie(cookie2); %> </body>運(yùn)行結(jié)果:
第一次訪問(wèn)登錄頁(yè)login_cookie.jsp:
輸入用戶名“張三”及密碼并點(diǎn)擊登錄,之后如果再次訪問(wèn)登錄頁(yè)login_cookie.jsp,就會(huì)看到頁(yè)面已經(jīng)保存了用戶名和密碼,如圖
(5)cookie的有效期
??需要注意的是,Cookie在客戶端保存的時(shí)間不是永久性的,它也是有生命周期的,我們可以通過(guò)setMaxAge(int expiry)方法設(shè)置cookie的有效期。
??例如以下代碼,我們先通過(guò)setCookieAge.jsp頁(yè)面設(shè)置一個(gè)Cookie對(duì)象,然后再嘗試通過(guò)getCookie.jsp頁(yè)面來(lái)獲取該Cookie對(duì)象,
生成cookie頁(yè)面:setCookieAge.jsp
<body> <%Cookie cookie = new Cookie("user","韓梅梅");//生成一個(gè)cookiecookie.setMaxAge(10);//設(shè)置cookie在10秒鐘后失效response.addCookie(cookie);//服務(wù)端把cookie發(fā)送給客戶端response.sendRedirect("getCookie.jsp"); %> </body>獲取cookie頁(yè)面:getCookie.jsp
<body> <%Cookie[] cookie = request.getCookies();//客戶端獲取cookieboolean flag = false;//cookie存在的標(biāo)識(shí),false為失效,true為有效for(int i = 0; i< cookie.length; i++){if("user".equals(cookie[i].getName())){out.print("歡迎你,"+cookie[i].getValue());flag = true;//把cookie設(shè)置為有效}}if(!flag){out.print("cookie失效了!");} %> </body>先執(zhí)行setCookieAge.jsp來(lái)設(shè)置Cookie對(duì)象。之后,如果在10秒以內(nèi)運(yùn)行g(shù)etCookie.jsp,則運(yùn)行結(jié)果:
10秒鐘之后,執(zhí)行g(shù)etCookie.jsp,運(yùn)行結(jié)果:
即,我們可以通過(guò)setMaxAge(秒數(shù))來(lái)設(shè)置Cookie對(duì)象的有效期。
2)session
??session通常被翻譯成“會(huì)話”。一個(gè)會(huì)話是指:用戶通過(guò)瀏覽器(客戶端)與服務(wù)器之間進(jìn)行的一系列的交互過(guò)程,交互期間可以包含瀏覽器與服務(wù)器之間的多次請(qǐng)求、響應(yīng)。以下是3個(gè)常見(jiàn)的session使用情景:
①用戶在瀏覽某個(gè)網(wǎng)站時(shí),從進(jìn)入網(wǎng)站到關(guān)閉這個(gè)網(wǎng)站所經(jīng)過(guò)的這段時(shí)間,也就是用戶瀏覽這個(gè)網(wǎng)站的整個(gè)過(guò)程,就是一個(gè)session。
②在電子郵件應(yīng)用中,從一個(gè)客戶登錄到電子郵件系統(tǒng)開(kāi)始,經(jīng)過(guò)收信、寫(xiě)信和發(fā)信等一系列操作,直至最后退出郵件系統(tǒng),整個(gè)過(guò)程為一個(gè)session。
③在購(gòu)物網(wǎng)站應(yīng)用中,從一個(gè)客戶開(kāi)始購(gòu)物,到瀏覽商品、結(jié)算等,直至最后的結(jié)賬,整個(gè)過(guò)程為一個(gè)session。
session運(yùn)行機(jī)制:
??當(dāng)用戶(瀏覽器)向Web應(yīng)用第一次發(fā)送請(qǐng)求時(shí),服務(wù)器會(huì)創(chuàng)建一個(gè)session對(duì)象并分配給該用戶;該session對(duì)象中包含著一個(gè)唯一標(biāo)識(shí)符sessionId,并且服務(wù)器會(huì)在第一次響應(yīng)用戶時(shí),將此sessionId作為jsessionid保存在瀏覽器的Cookie對(duì)象中;這個(gè)session將一直延續(xù)到用戶訪問(wèn)結(jié)束(瀏覽器關(guān)閉或用戶長(zhǎng)時(shí)間不訪問(wèn)Web應(yīng)用)。
客戶端(用戶)每次都是帶著自己的jsessionid去訪問(wèn)服務(wù)端。
①當(dāng)客戶端沒(méi)有jsessionid的時(shí)候,服務(wù)端會(huì)創(chuàng)建一個(gè)session對(duì)象,然后將這個(gè)session對(duì)象發(fā)送給客戶端,客戶端會(huì)用jsessionid去保存這個(gè)session對(duì)象,存在cookie中。
②當(dāng)客戶端有jsessionid的時(shí)候,服務(wù)端就會(huì)通過(guò)客戶端傳來(lái)的jsessionId找到對(duì)應(yīng)的session,以確定是這個(gè)用戶在訪問(wèn)服務(wù)器。
??如果客戶端禁用了Cookie,則服務(wù)器會(huì)自動(dòng)使用URL-rewriting(URL重寫(xiě),URL中包含session ID的信息)的技術(shù)來(lái)保存sessionId。
??session內(nèi)置對(duì)象是javax.servlet.ServletContext.HttpSession接口的實(shí)例化對(duì)象,常用方法如下表:
| public String getId() | 獲取sessionId |
| public boolean isNew() | 判斷是否是新的session(新用戶) |
| public void invalidate() | 使session失效 |
| public void setAttribute(String name, Object value) | 設(shè)置session對(duì)象名和對(duì)象值 |
| public Object getAttribute(String name) | 根據(jù)session對(duì)象名,獲取session對(duì)象值 |
| public void setMaxInactiveInterval(int interval) | 設(shè)置session的有效非活動(dòng)時(shí)間, 單位是秒 |
| public int getMaxInactiveInterval() | 獲取session的有效非活動(dòng)時(shí)間,單位是秒 |
??下面來(lái)驗(yàn)證一下服務(wù)端生成的sessionId和客戶端生成的JSESSIONID相同。
createSession.jsp
showSession.jsp
<body> <%out.print("sessionID:"+session.getId()+"</br>");//輸出sessionIDCookie[] cookies = request.getCookies();out.print(cookies[0].getName()+":"+cookies[0].getValue()); %> </body>運(yùn)行結(jié)果:
下面通過(guò)一個(gè)登陸的案例來(lái)演示session在開(kāi)發(fā)中的應(yīng)用:
登陸界面:login.jsp
<body> <form action="check.jsp" method="post">用戶姓名:<input type="text" name="username" ></br>用戶密碼:<input type="password" name="password" ></br><input type="submit" value="登陸"> </form> </body>登陸判斷:check.jsp
<body> <%String username = request.getParameter("username");//獲取用戶名String password = request.getParameter("password");//獲取密碼if("admin".equals(username) && "123456".equals(password)){//驗(yàn)證通過(guò)session.setAttribute("username", username);//將用戶名添加到sessionsession.setMaxInactiveInterval(60*10) ;//設(shè)置session最大存活時(shí)間為10分鐘response.sendRedirect("welcome.jsp");}else{//驗(yàn)證不通過(guò)response.sendRedirect("login.jsp");//重新跳轉(zhuǎn)到登陸界面} %> </body>歡迎頁(yè)面:welcome.jsp
<body> <%String username = (String)session.getAttribute("username");//從session獲取usernameif(username == null ){response.sendRedirect("login.jsp");}else{out.print("歡迎您,"+ username ) ;out.print("<a href='logout.jsp' >注銷</a>");} %> </body>注銷頁(yè)面:logout.jsp
<body> <%String username = (String)session.getAttribute("username");if(username == null){response.sendRedirect("login.jsp");}else{session.invalidate();response.sendRedirect("login.jsp");} %> </body>??可以發(fā)現(xiàn),如果輸入正確的用戶名和密碼(admin/123456),則直接跳轉(zhuǎn)到歡迎頁(yè),如圖
??如果用戶名或密碼輸入有誤,則返回登錄頁(yè)。而且,如果用戶沒(méi)有登錄,直接訪問(wèn)welcome.jsp或logout.jsp,也會(huì)因?yàn)閟ession作用域中的“username”為null而直接跳轉(zhuǎn)返回登錄頁(yè),從而實(shí)現(xiàn)訪問(wèn)權(quán)限的控制。
解釋一下:
對(duì)于session.setMaxInactiveInterval(10);,括號(hào)中的參數(shù)單位是是秒,表示session的有效最大非活動(dòng)時(shí)間是10秒鐘,意思就是只要在同一個(gè)瀏覽器下,最后一次訪問(wèn)同一個(gè)項(xiàng)目的時(shí)間在10秒鐘之內(nèi),session就不會(huì)失效。只有超過(guò)10秒鐘不操作該項(xiàng)目,session才會(huì)失效。
最后,再說(shuō)明一下cookie和session的幾點(diǎn)區(qū)別:
| 保存信息的位置 | 客戶端 | 服務(wù)器端 |
| 保存的內(nèi)容 | 字符串 | 對(duì)象 |
| 安全性 | 不安全 | 安全 |
5)application
??application對(duì)象是javax.servlet.ServletContext接口的實(shí)例化對(duì)象,代表了整個(gè)web項(xiàng)目,所以application對(duì)象的數(shù)據(jù)可以在整個(gè)web項(xiàng)目中共享,用法上類似于“全局變量”的概念。application對(duì)象的常用方法如下表:
| public String getContextPath() | 獲取相對(duì)路徑(默認(rèn)是"/項(xiàng)目名稱") |
| public String getRealPath(String path) | 獲取虛擬路徑對(duì)應(yīng)的絕對(duì)路徑 |
我們先直接通過(guò)一段代碼,看一下運(yùn)行結(jié)果,
applicationDemo.jsp
運(yùn)行結(jié)果:
??可以發(fā)現(xiàn),相對(duì)路徑就是“/項(xiàng)目名”,而絕對(duì)路徑是完整的本地路徑。
相對(duì)路徑和絕對(duì)路徑都可以修改,可以在第一章的“配置Web應(yīng)用的虛擬路徑”一節(jié)中查看。
2.3 四大作用域
??在JSP的內(nèi)置對(duì)象中,包含著四種范圍對(duì)象(或稱為“域?qū)ο蟆?#xff09;,簡(jiǎn)介如下
| pageContext | 數(shù)據(jù)只在當(dāng)前自身的頁(yè)面有效 |
| request | 數(shù)據(jù)在一次請(qǐng)求中有效 |
| session | 數(shù)據(jù)在一次會(huì)話中有效;但若是新開(kāi)瀏覽器,則無(wú)效 |
| application | 數(shù)據(jù)在當(dāng)前Web項(xiàng)目有效,可供所有用戶共享 |
以上的四個(gè)范圍對(duì)象,都可以用以下的方法:
| public void setAttribute(String name, Object o) | 設(shè)置屬性名和屬性值 |
| public Object getAttribute(String name) | 根據(jù)屬性名,獲取對(duì)應(yīng)的屬性值 |
| public void removeAttribute(String name) | 根據(jù)屬性名,刪除對(duì)應(yīng)的屬性值 |
1) pageContext作用域
??我們創(chuàng)建一個(gè)頁(yè)面 pageDemo.jsp,然后通過(guò)pageContext.setAttribute()添加兩個(gè)屬性(每個(gè)屬性都由鍵值對(duì)組成),再通過(guò)pageContext.getAttribute()將屬性的值取出,代碼如下:
<body> <%//設(shè)置pageContext屬性pageContext.setAttribute("username", "admin");pageContext.setAttribute("password", "123"); %>用戶:<%=pageContext.getAttribute("username") %></br>密碼:<%=pageContext.getAttribute("password") %> </body>運(yùn)行結(jié)果:
??因?yàn)閜ageContext對(duì)象中的屬性的作用域是“在當(dāng)前自身的頁(yè)面內(nèi)有效”,所以能夠正常顯示。
??但如果將上述頁(yè)面進(jìn)行修改,將增加屬性放在page_scope_one.jsp中執(zhí)行,再通過(guò)請(qǐng)求轉(zhuǎn)發(fā)跳轉(zhuǎn)到page_scope_two.jsp頁(yè)面,并在page_scope_two.jsp中顯示屬性的值,如下代碼:
page_scope_one.jsp
<body> <%//設(shè)置pageContext屬性pageContext.setAttribute("username", "admin");pageContext.setAttribute("password", "123");request.getRequestDispatcher("page_scope_two.jsp").forward(request, response); %> </body>page_scope_two.jsp
<body> 姓名:<%=pageContext.getAttribute("usernmae") %></br> 密碼:<%=pageContext.getAttribute("password") %> </body>??執(zhí)行page_scope_one.jsp,運(yùn)行結(jié)果:
??因?yàn)轫?yè)面從page_scope_one.jsp,通過(guò)請(qǐng)求轉(zhuǎn)發(fā)跳轉(zhuǎn)到page_scope_two.jsp后,就已經(jīng)不再是同一個(gè)頁(yè)面了,所以無(wú)法再通過(guò)pageContext對(duì)象獲取到數(shù)據(jù)。
2) request作用域
??要想在請(qǐng)求轉(zhuǎn)發(fā)后的page_scope_two.jsp頁(yè)面獲取到屬性值,可以使用request的作用域。
request的作用域是“在客戶端向服務(wù)器端,發(fā)送的一次請(qǐng)求中有效”。我們將上面的例子修改如下:
request_scope_one.jsp
<body> <%//設(shè)置request屬性request.setAttribute("username", "admin");request.setAttribute("password", "123");request.getRequestDispatcher("request_scope_two.jsp").forward(request, response); %> </body>request_scope_two.jsp
<body> 姓名:<%=request.getAttribute("username") %></br> 密碼:<%=request.getAttribute("password") %> </body>執(zhí)行request_scope_one.jsp,運(yùn)行結(jié)果:
??因?yàn)閺?strong>request_scope_one.jsp到request_scope_two.jsp的跳轉(zhuǎn)是“請(qǐng)求轉(zhuǎn)發(fā)”,即仍然是同一次請(qǐng)求,而request的作用范圍就是“在一次請(qǐng)求中有效”。
3) session作用域
??如果希望在增加屬性以后,能夠在跳轉(zhuǎn)后的任何頁(yè)面(無(wú)論是請(qǐng)求轉(zhuǎn)發(fā)、重定向或超鏈接跳轉(zhuǎn)),甚至是項(xiàng)目中任何一個(gè)頁(yè)面都能獲取到該屬性值,就可以使用session的作用域來(lái)實(shí)現(xiàn)。
現(xiàn)在將上例的作用域從request改為session,如以下代碼:
session_scope_one.jsp
<body><%session.setAttribute("username","admin");session.setAttribute("password","1234");response.sendRedirect("session_scope_two.jsp");%> </body>session_scope_two.jsp
<body>書(shū)名:<%=session.getAttribute("username") %> <br/>作者:<%=session.getAttribute("password") %></body>執(zhí)行session_scope_one.jsp,運(yùn)行結(jié)果:
??此外,如果我們重新打開(kāi)一個(gè)瀏覽器標(biāo)簽(一定要相同瀏覽器),然后在新標(biāo)簽里直接輸入request_scope_two.jsp,也能獲取到數(shù)據(jù),如圖,
??但是,如果我們換一個(gè)其他瀏覽器(比如從火狐換成IE),再次直接訪問(wèn)request_scope_two.jsp,就無(wú)法再獲取到數(shù)據(jù)了。如圖是Safari瀏覽器直接運(yùn)行http://localhost:8080/JspProject/session_scope_two.jsp的結(jié)果:
??我們發(fā)現(xiàn),無(wú)法從session中獲取值了。因?yàn)镾afari瀏覽器的session并沒(méi)有set書(shū)名和作者的值,所以在獲取的時(shí)候才會(huì)是空值。
??我們可以聯(lián)想一下平日的網(wǎng)購(gòu)經(jīng)驗(yàn),如果通過(guò)谷歌瀏覽器登錄淘寶,那么只要登錄一次以后,在短時(shí)間內(nèi)即使我們重新開(kāi)啟一個(gè)火狐標(biāo)簽,也會(huì)以“已登錄”的身份訪問(wèn)淘寶;但如果換成IE瀏覽器,則又需要我們重新登錄了。所以網(wǎng)站中的登錄功能,就可以通過(guò)session來(lái)實(shí)現(xiàn)。
4) application作用域
??繼續(xù)上面的討論,如果想實(shí)現(xiàn)這樣一個(gè)功能“只要在一個(gè)頁(yè)面中增加了屬性,那么即使重新?lián)Q一個(gè)新瀏覽器,也要能訪問(wèn)到該屬性值”,該如何實(shí)現(xiàn)呢?答案就是applicaton的作用域。
我們?cè)賹⑸侠械淖饔糜?#xff0c;從session改為application,如以下代碼:
application_scope_one.jsp
<body><%application.setAttribute("username","admin");application.setAttribute("password","1234");response.sendRedirect("application_scope_two.jsp");%> </body>application_scope_two.jsp
<body>書(shū)名:<%=application.getAttribute("username") %> <br/>作者:<%=application.getAttribute("password") %> </body>??此外,讀者可以發(fā)現(xiàn),只要運(yùn)行過(guò)一次application_scope_one.jsp以后,無(wú)論是新開(kāi)一個(gè)瀏覽器標(biāo)簽,或者是更換新的瀏覽器,直接再運(yùn)行application_scope_two.jsp,也都能獲取到數(shù)據(jù)。如圖是谷歌上執(zhí)行了application_scope_one.jsp以后,在IE瀏覽器直接運(yùn)行application_scope_two.jsp的運(yùn)行結(jié)果:
??即只要是通過(guò)application.setAttribute()增加的屬性,那么任何瀏覽器的任何頁(yè)面都可以獲取到該屬性值。但是如果將tomcat服務(wù)器關(guān)閉,application中的屬性值就全部消失了。
我們可以利用applicatoin作用域的這一特性,來(lái)實(shí)現(xiàn)一個(gè)網(wǎng)頁(yè)計(jì)數(shù)器功能:
webCounterDemo.jsp
<body><%Integer count = (Integer)application.getAttribute("count");//從application里面獲取count值if(count == null){//如果是第一次訪問(wèn),將count賦值為1 count = 1;}else{ //如果不是第一次訪問(wèn),則累加一次訪問(wèn)次數(shù)count = 1 + count; }application.setAttribute("count",count); //將訪問(wèn)次數(shù)的變量count保存在application的屬性count中out.println("您是第 " + application.getAttribute("count") +" 位訪問(wèn)本網(wǎng)站的用戶" );%></body>??之后,無(wú)論是刷新當(dāng)前頁(yè),還是新開(kāi)一個(gè)瀏覽器標(biāo)簽,或者打開(kāi)一個(gè)其他瀏覽器再次訪問(wèn),每訪問(wèn)一次,訪問(wèn)次數(shù)就會(huì)累加一次。
??需要說(shuō)明的是,雖然四種作用域的大小依次是pageContext<request<session<application,但我們不能為了方便就隨便使用范圍較大的范圍對(duì)象,因?yàn)榉秶酱笤斐傻男阅軗p耗就越大。因此,如果多個(gè)作用域都能完成相同的功能,我們一般會(huì)使用范圍小的那個(gè)對(duì)象。
2.4 本章練習(xí)
一、選擇題
1.下列關(guān)于HTTP響應(yīng)中狀態(tài)碼的描述,錯(cuò)誤的是( )。(選擇一項(xiàng))
A.3**表示重定向,表示需要客戶端采取進(jìn)一步的操作才能完成請(qǐng)求
B.2**表示成功,表示請(qǐng)求已被成功接收、理解、接受
C.4**表示客戶端錯(cuò)誤,請(qǐng)求有語(yǔ)法錯(cuò)誤或請(qǐng)求無(wú)法實(shí)現(xiàn)
D.5**表示數(shù)據(jù)庫(kù)端錯(cuò)誤,服務(wù)器未能實(shí)現(xiàn)合法的請(qǐng)求
2.下列( )方法可以獲取請(qǐng)求的字符編碼方式。(選擇一項(xiàng))
A.request.getCharacterEncoding()
B.request.getProtocol()
C.request.getRequestURI()
D.request.getQueryString()
3.請(qǐng)求轉(zhuǎn)發(fā)的forward(request,response)方法是( )的方法。(選擇一項(xiàng))
A.request對(duì)象
B.response對(duì)象
C.RequestDispatcher對(duì)象
D.session對(duì)象
4.下列( )不是JSP九大內(nèi)置對(duì)象之一。(選擇一項(xiàng))
A.out對(duì)象
B.exception對(duì)象
C.cookie對(duì)象
D.session對(duì)象
5.<%page language=”java” import=”java.util.ArrayList;java.sql.*” contentType=”text/html; charset=UTF-8” %>
以上指令共存在()處錯(cuò)誤。
A:1
B:2
C:3
D:4
6.以下page指令的描述中,正確的是()。
A:可以通過(guò)<%@page include=”java.util.*”%>導(dǎo)入java.util下所有的類
B:可以通過(guò)<%@page include=”java.util.Date;java.util”%>導(dǎo)入java.util下所有的類
C:可以通過(guò)<%@page contentType=”text/html;charset=UTF-8”%>設(shè)置頁(yè)面編碼為UTF-8
D:可以通過(guò)<%@page version=”1.6”%>指定采用什么版本的jdk編譯頁(yè)面
7.以下JSP代碼的運(yùn)行結(jié)果是()。
A:i8
B:88
C:16
D:編譯錯(cuò)誤
<%@ page language=”java” contentType=”text/html; charset=UTF-8”%><% out.println("hello lanqiao"); %>對(duì)于以上代碼,描述正確的是()。
A:此段代碼沒(méi)有錯(cuò)誤,能夠正確向頁(yè)面打印出“hello,lanqiao!”
B:此段代碼沒(méi)有錯(cuò)誤,但是不向頁(yè)面輸出任何語(yǔ)句
C:此段代碼缺少引用,應(yīng)該在page指令中添加import=”java.util.*”
D:此段代碼存在錯(cuò)誤,應(yīng)改為:response.out.println(“hello,lanqiao!”);
9.<%@ page __=”text/html; __=UTF-8”%>
使用page指令設(shè)置頁(yè)面的字符集,橫線處應(yīng)填寫(xiě)()。
A:content_Type、charsetEncoding
B:contentType、charset
C:type、charset
D:contentType、pageEncoding
10.<% ing num = 10 ;%>這段代碼在JSP中稱為()。
A:小腳本
B:表達(dá)式
C:JSP注釋
D:JSP指令
<% int[] scores = new int[2]{89,87}; %> 最高分:<% Math.max(scores[0],scores[1]) %>最低分:<% out.print(Math.min(scores[0],scores[1])) %>以上代碼共有()處錯(cuò)誤。
A:1
B:2
C:3
D:4
12.以下()不是JSP頁(yè)面的page指令。
A:language=”java”
B:import=”java.util.*”
C:http-equiv=”keywords”
D:contentType=”text/html; charset=UTF-8”
13.有關(guān)會(huì)話跟蹤技術(shù)描述正確的是()
A. Cookie是Web服務(wù)器發(fā)送給客戶端的一小段信息,客戶端請(qǐng)求時(shí),可以讀取該信息發(fā)送到服務(wù)器端
B. 關(guān)閉瀏覽器意味著會(huì)話ID丟失,但所有與原會(huì)話關(guān)聯(lián)的會(huì)話數(shù)據(jù)仍保留在服務(wù)器上,直至?xí)掃^(guò)期
C. 在禁用Cookie時(shí)可以使用URL重寫(xiě)技術(shù)跟蹤會(huì)話
D. 隱藏表單域?qū)⒆侄翁砑拥紿TML表單并在客戶端瀏覽器中顯示
14.在J2EE中,重定向到另一個(gè)頁(yè)面,以下()語(yǔ)句是正確的
A. request . sendRedirect(“http:// www . baidu.com”);
B. request . sendRedirect();
C. response . sendRedirect(“http: // www . baidu.com”);
D. response .sendRedirect();
二、簡(jiǎn)答題
1.JSP中有幾種Scriptlet,各自的作用是什么?
2.JSP中有幾種注釋,各有什么特點(diǎn)?
3.對(duì)于GET請(qǐng)求和POST請(qǐng)求,各如何設(shè)置編碼?
4.簡(jiǎn)述pageContext、request、session、application等四個(gè)內(nèi)置對(duì)象的作用域范圍。
5.簡(jiǎn)述請(qǐng)求轉(zhuǎn)發(fā)與重定向的區(qū)別。
6.如何更改Tomcat端口號(hào)。
7.簡(jiǎn)述Session和Cookie的區(qū)別。
8.什么情況下會(huì)造成“表單重復(fù)提交”?如何解決?
三、編程題
1.在一個(gè)JSP中提供一組復(fù)選框,可以讓用戶選擇自己喜愛(ài)的水果,提交后,在另一個(gè)JSP頁(yè)面輸出用戶的所有選擇項(xiàng)。
2.在index.jsp中編寫(xiě)兩個(gè)輸入框,用于接收用戶輸入的兩個(gè)數(shù),然后通過(guò)表單提交跳轉(zhuǎn)到result.jsp。再在result.jsp中比較判斷出較大的數(shù)字,并顯示。
3.實(shí)現(xiàn)以下表單,并在用戶單擊“注冊(cè)”后,在另一個(gè)JSP中獲取各個(gè)表單元素的值:
4.<a href=”showStudents.jsp?page=2&size=10”>學(xué)生信息,獲取超鏈接中的page、size參數(shù)值。
5.demo01.jsp的部分內(nèi)容如下:
<body><%Student stu = new Student("張三",23);...%> </body>將demo01.jsp中的stu對(duì)象傳遞到demo02.jsp。
6.實(shí)現(xiàn)登陸功能,要求:在客戶端保存用戶名,在服務(wù)端保存登錄信息。
7.禁止從外部網(wǎng)站提交數(shù)據(jù)(即服務(wù)端只接受本項(xiàng)目中傳來(lái)的數(shù)據(jù))。
8.(1)實(shí)現(xiàn)以下功能的網(wǎng)頁(yè)記錄器:
(2)實(shí)現(xiàn)IP計(jì)數(shù)器,如下:
統(tǒng)計(jì)用戶在站點(diǎn)的停留時(shí)間,如下:
總結(jié)
以上是生活随笔為你收集整理的第二章 Jsp基本语法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 文章编辑数据结构课程设计
- 下一篇: 工作171:阅读账号里面的新增调用接口操