Java Web(3)HttpServletRequest和HttpServletResponse

servlet入門教程

1. request和response的實(shí)現(xiàn)結(jié)構(gòu)

request.png

ServletRequest接口是所有Request類的父類菌瘫,HttpServletRequest是用于http請求的Request接口鸡号。這兩者都是接口愧口,不進(jìn)行具體的實(shí)現(xiàn)气嫁。ServletRequestHttpServletRequest都屬于servelt-api.jar,為J2EE的標(biāo)準(zhǔn)規(guī)范膜楷。
所有廠商要想實(shí)現(xiàn)具體的Request和Response旭咽,無論怎么實(shí)現(xiàn)都沒關(guān)系,但是必須遵守J2EE標(biāo)準(zhǔn)規(guī)范赌厅。catalina.jar就是tomcat apache的實(shí)現(xiàn)方式穷绵。
打開tomcat的lib目錄就可以看到catalina.jar
catalina.jar

2. HttpServletRequest

HttpServletRequest 接口繼承自 ServletRequest 接口,其主要作用是封裝 HTTP 請求消息特愿。由于 HTTP 請求消息分為請求行仲墨、請求消息頭和請求消息體三部分。因此揍障,在 HttpServletRequest 接口中定義了獲取請求行目养、請求頭請求消息體的相關(guān)方法。

2.1 請求行

請求消息的請求行中包含請求方法毒嫡、請求資源名癌蚁、請求路徑等信息,為了獲取這些信息兜畸,
HttpServletRequest 接口定義了一系列方法:

方法聲明 功能描述
String getMethod() 該方法用于獲取 HTTP 請求消息中的請求方式(如 GET努释、POST 等)
String getRequestURI() 該方法用于獲取請求行中的資源名稱部分即位于 URL 的主機(jī)和端門之后、參數(shù)部分之前的部分
String getQueryString() 該方法用于獲取請求行中的參數(shù)部分咬摇,也就是資源路徑后問號(伐蒂?)以后的所有內(nèi)容
String getContextPath() 該方法用于獲取請求 URL 中屬于 Web 應(yīng)用程序的路徑,這個路徑以 / 開頭肛鹏,表示相對于整個 Web 站點(diǎn)的根目錄逸邦,路徑結(jié)尾不含 /恩沛。如果請求 URL 屬于 Web 站點(diǎn)的根目錄,那么返回結(jié)果為空字符串("")
String getServletPath() 該方法用于獲取 Servlet 的名稱或 Servlet 所映射的路徑
String getRemoteAddr() 該方法用于獲取請求客戶端的 IP 地址缕减,其格式類似于 192.168.0.3
String getRemoteHost() 該方法用于獲取請求客戶端的完整主機(jī)名雷客,其格式類似于 pcl.mengma.com。需要注意的是烛卧,如果無法解析出客戶機(jī)的完整主機(jī)名佛纫,那么該方法將會返回客戶端的 IP 地址
int getRemotePort() 該方法用于獲取請求客戶端網(wǎng)絡(luò)連接的端口號
String getLocaIAddr() 該方法用于獲取 Web 服務(wù)器上接收當(dāng)前請求網(wǎng)絡(luò)連接的 IP 地址
String getLocalName() 該方法用于獲取 Web 服務(wù)器上接收當(dāng)前網(wǎng)絡(luò)連接 IP 所對應(yīng)的主機(jī)名
int getLocalPort() 該方法用于獲取 Web 服務(wù)器上接收當(dāng)前網(wǎng)絡(luò)連接的端口號
String getServerName() 該方法用于獲取當(dāng)前請求所指向的主機(jī)名,即 HTTP 請求消息中 Host 頭字段所對應(yīng)的主機(jī)名部分
int gctServcrPort() 該方法用于獲取當(dāng)前請求所連接的服務(wù)器端口號总放,即 HTTP 請求消息中 Host 頭字段所對應(yīng)的端口號部分
StringBuffcr getRequestURL() 該方法用于獲取客戶端發(fā)出請求時的完整 URL,包括協(xié)議好爬、服務(wù)器名局雄、端口號、 資源路徑等信息存炮,但不包括后面的査詢參數(shù)部分炬搭。注意,getRequcstURL() 方法返冋的結(jié)果是 StringBuffer 類型穆桂,而不是 String 類型宫盔,這樣更便于對結(jié)果進(jìn)行修改

2.2 請求頭

當(dāng)瀏覽器發(fā)送 Servlet 請求時,需要通過請求消息頭向服務(wù)器傳遞附加信息享完,例如灼芭,客戶端可以接收的數(shù)據(jù)類型、壓縮方式般又、語言等彼绷。為此,在 HttpServletRequest 接口中定義了一系列用于獲取 HTTP 請求頭字段的方法

方法聲明 功能描述
String getHeader(String name) 該方法用于獲取一個指定頭字段的值茴迁,如果請求消息中沒有包含指定的頭字段寄悯,則 getHeader() 方法返回 null;如果請求消息中包含多個指定名稱的頭字段堕义,則 getHeader() 方法返回其中第一個頭字段的值
Enumeration getHeaders(String name) 該方法返回一個 Enumeration 集合對象猜旬,該集合對象由請求消息中出現(xiàn)的某個指定名稱的所有頭字段值組成。在多數(shù)情況下倦卖,一個頭字段名在請求消息中只出現(xiàn)一次洒擦,但有時可能會出現(xiàn)多次
Enumeration getHeaderNames() 該方法用于獲取一個包含所有請求頭字段的 Enumeration 對象
int getIntHeader(String name) 該方法用于獲取指定名稱的頭字段,并且將其值轉(zhuǎn)為 int 類型糖耸。需要注意的是秘遏,如果指定名稱的頭字段不存在,則返回值為 -1嘉竟;如果獲取到的頭字段的值不能轉(zhuǎn)為 int 類型邦危,則將發(fā)生 NumberFormatException 異常
long getDateHeader(String name) 該方法用于獲取指定頭字段的值洋侨,并將其按 GMT 時間格式轉(zhuǎn)換為一個代表日期/時間的長整數(shù),該長整數(shù)是自 1970 年 1 月 1 日 0 時 0 分 0 秒算起的以毫秒為單位的時間值
String getContentType() 該方法用于獲取 Content-Type 頭字段的值倦蚪,結(jié)果為 String 類型
int getContentLength() 該方法用于獲取 Content-Length 頭字段的值希坚,結(jié)果為 int 類型
String getCharacterEncoding() 該方法用于返回請求消息的實(shí)體部分的字符集編碼,通常是從 Content-Type 頭字段中進(jìn)行提取陵且,結(jié)果為 String 類型

content-type

2.3 獲取請求參數(shù)及對象

2.3.1 獲取請求參數(shù)

為了方便獲取表單中的請求參數(shù)裁僧,在 HttpServletRequest 接口的父類 ServletRequest中定義了一系列獲取請求參數(shù)的方法

方法聲明 功能描述
String getParameter(String name) 該方法用于獲取某個指定名稱的參數(shù)值。如果請求消息中沒有包含指定名稱的參數(shù)慕购,則 getParameter() 方法返回 null聊疲。如果指定名稱的參數(shù)存在但沒有設(shè)置值,則返回一個空串沪悲。 如果請求消息中包含多個該指定名稱的參數(shù)获洲,則 getParameter() 方法返回第一個出現(xiàn)的參數(shù)值。
String [] getParameterValues (String name) HTTP 請求消息中可以有多個相同名稱的參數(shù)(通常由一個包含多個同名的字段元素的 form 表單生成)殿如,如果要獲得 HTTP 請求消息中的同一個參數(shù)名所對應(yīng)的所有參數(shù)值贡珊,那么就應(yīng)該使用 getParameterValues() 方法,該方法用于返回一個 String 類型的數(shù)組涉馁。
Enumeration getParameterNames() 方法用于返回一個包含請求消息中所有參數(shù)名的 Enumeration 對象门岔,在此基礎(chǔ)上,可以對請求消息中的所有參數(shù)進(jìn)行遍歷處理烤送。
Map getParameterMap() getParameterMap() 方法用于將請求消息中的所有參數(shù)名和值裝入一個 Map 對象中返回寒随。

2.3.1 獲取請求對象

Request 對象不僅可以獲取一系列數(shù)據(jù),還可以通過屬性傳遞數(shù)據(jù)胯努。ServletRequest 接口中定義了一系列操作屬性的方法牢裳。

方法聲明 功能描述
void setAttribute(String name, Object o) 方法用于將一個對象與一個名稱關(guān)聯(lián)后存儲到 ServletRequest 對象中
Object getAttribute(String name) 從 ServletRequest 對象中返回指定名稱的屬性對象
void removeAttribute(String name); 該方法用于從 ServletRequest 對象中刪除指定名稱的屬性

3. HttpServletResponse

HttpServletResponse 接口繼承自 ServletResponse 接口,主要用于封裝 HTTP 響應(yīng)消息叶沛。由于 HTTP 響應(yīng)消息分為狀態(tài)行蒲讯、響應(yīng)消息頭、消息體三部分灰署。因此判帮,在 HttpServletResponse 接口中定義了向客戶端發(fā)送響應(yīng)狀態(tài)碼響應(yīng)消息頭溉箕、響應(yīng)消息體的方法

3.1 響應(yīng)狀態(tài)碼

當(dāng) Servlet 向客戶端回送響應(yīng)消息時晦墙,需要在響應(yīng)消息中設(shè)置狀態(tài)碼。因此肴茄,HttpServletResponse 接口定義了兩個發(fā)送狀態(tài)碼的方法晌畅。
1)setStatus(int status)方法
該方法用于設(shè)置 HTTP 響應(yīng)消息的狀態(tài)碼,并生成響應(yīng)狀態(tài)行寡痰。由于響應(yīng)狀態(tài)行中的狀態(tài)描述信息直接與狀態(tài)碼相關(guān)抗楔,而 HTTP 版本由服務(wù)器確定棋凳,因此,只要通過 setStatus(int status)方法設(shè)置了狀態(tài)碼连躏,即可實(shí)現(xiàn)狀態(tài)行的發(fā)送剩岳。需要注意的是,在正常情況下入热,Web 服務(wù)器會默認(rèn)產(chǎn)生一個狀態(tài)碼為 200 的狀態(tài)行拍棕。
2)sendError(int sc)方法
該方法用于發(fā)送表示錯誤信息的狀態(tài)碼。例如勺良,404 狀態(tài)碼表示找不到客戶端請求的資源绰播。response 對象提供了兩個重載的 sendError(int sc)方法,具體如下:

public void sendError(int code) throws java.io.IOException
public void sendError(int code,String message)throws java.io.IOException

在上面重載的兩個方法中尚困,第一個方法只發(fā)送錯誤信息的狀態(tài)碼幅垮,而第二個方法除了發(fā)送狀態(tài)碼以外,還可以增加一條用于提示說明的文本信息尾组,該文本信息將出現(xiàn)在發(fā)送給客戶端的正文內(nèi)容中。

3.2 響應(yīng)消息體body

由于在 HTTP 響應(yīng)消息中示弓,大量的數(shù)據(jù)都是通過響應(yīng)消息體傳遞的讳侨,因此,ServletResponse 遵循以 I/O 流傳遞大量數(shù)據(jù)的設(shè)計理念奏属。在發(fā)送響應(yīng)消息體時跨跨,定義了兩個與輸出流相關(guān)的方法。
1)getOutputStream() 方法
該方法所獲取的字節(jié)輸出流對象為 ServletOutputStream 類型囱皿。由于 ServletOutputStream是OutputStream 的子類勇婴,它可以直接輸出字節(jié)數(shù)組中的二進(jìn)制數(shù)據(jù)。因此嘱腥,要想輸出二進(jìn)制格式的響應(yīng)正文耕渴,就需要使用 getOutputStream() 方法。
2)getWriter()方法
該方法所獲取的字符輸出流對象為 PrintWriter 類型齿兔。由于 PrintWriter 類型的對象可以直接輸出字符文本內(nèi)容橱脸,因此,要想輸出內(nèi)容全部為字符文本的網(wǎng)頁文檔分苇,則需要使用 getWriter() 方法添诉。

注意:雖然 response 對象的 getOutputStream() 和 getWriter() 方法都可以發(fā)送響應(yīng)消息體,但是医寿,它們之間互相排斥栏赴,不可同時使用,否則會發(fā)生 IllegalStateException 異常靖秩。

3.3 響應(yīng)消息頭header

Servlet 向客戶端發(fā)送的響應(yīng)消息中包含響應(yīng)頭字段须眷,由于 HTTP 協(xié)議的響應(yīng)頭字段有很多種竖瘾,因此,HttpServletResponse 接口定義了一系列設(shè)置 HTTP 響應(yīng)頭字段的方法柒爸,如表 2 所示准浴。

方法聲明 功能描述
void addHeader/setHeader(String name,String value) 這兩個方法都是用于設(shè)置 HTTP 協(xié)議的響應(yīng)頭字段。其中捎稚,參數(shù) name 用于指定響應(yīng)頭字段的名稱乐横,參數(shù) value 用于指定響 應(yīng)頭字段的值。不同的是今野,addHeader() 方法可以增加同名的響應(yīng)頭字段葡公,而 setHeader() 方法則會覆蓋同名的頭字段
void addIntHeader/setIntHeader(String name,int value) 這兩個方法專門用于設(shè)置包含整數(shù)值的響應(yīng)頭,避免了使用 addHeader() 與 setHeader() 方法時需要將 int 類型的設(shè)置值轉(zhuǎn)換為 String 類型的麻煩
void setContentType(String type) 該方法用于設(shè)置 Servlet 輸出內(nèi)容的 MIME 類型条霜,對于 HTTP 協(xié)議來說催什,就是設(shè)置 Content-Type 響應(yīng)頭字段的值。例如宰睡,如果發(fā)送到客戶端的內(nèi)容是 jpeg 格式的圖像數(shù)據(jù),就需要將響應(yīng)頭字段的類型設(shè)置為 image/jpeg蒲凶。需要注意的是,如果響應(yīng)的內(nèi)容為文本拆内,setContentType() 方法還可以設(shè)置字符編碼旋圆,如 text/html;charset = UTF-8
void setLocale (Locale loc) 該方法用于設(shè)置響應(yīng)消息的本地化信息。對 HTTP 來說麸恍,就是設(shè)置 Content-Language 響應(yīng)頭字段和 Content-Type 頭字段中的字符集編碼部分灵巧。需要注意的是,如果 HTTP 消息沒有設(shè)置 Content-Type 頭字段抹沪,則 setLocale() 方法設(shè)置的字符集編碼不會出現(xiàn)在 HTTP 消息的響應(yīng)頭中刻肄,如果調(diào)用 setCharacterEncoding() 或 setContentType() 方法指定了響應(yīng)內(nèi) 容的字符集編碼,則 setLocale() 方法將不再具有指定字符集編碼的功能
void setCharacterEncoding(String charset) 該方法用于設(shè)置輸出內(nèi)容使用的字符編碼融欧,對 HTTP 協(xié)議來說敏弃,就是設(shè)置 Content-Type 頭字段中的字符集編碼部分。如果沒有設(shè)置 Content-Type 頭字段蹬癌,則 setCharacterEncoding 方法設(shè) 置的字符集編碼不會出現(xiàn)在 HTTP 消息的響應(yīng)頭中权她。setCharacterEncoding() 方法比 setContentType() 和 setLocale() 方法的優(yōu)先權(quán)高,它的設(shè)置結(jié)果將覆蓋 setContentType() 和 setLocale() 方法所設(shè)置的字符碼表

需要注意的是逝薪,在一系列方法中隅要,addHeader()、setHeader()董济、addIntHeader()步清、setIntHeader() 方法都用于設(shè)置各種頭字段,而 setContetType()、setLoacale() 和 setCharacterEncoding() 方法用于設(shè)置字符編碼廓啊,這些設(shè)置字符編碼的方法可以有效解決亂碼問題欢搜。

4 請求轉(zhuǎn)發(fā)與重定向

轉(zhuǎn)發(fā)是服務(wù)器行為,重定向是客戶端行為谴轮。

4.1 請求轉(zhuǎn)發(fā)forward

是服務(wù)器請求資源,服務(wù)器直接訪問目標(biāo)地址的URL,把那個URL的響應(yīng)內(nèi)容讀取過來,然后把這些內(nèi)容再發(fā)給瀏覽器.瀏覽器根本不知道服務(wù)器發(fā)送的內(nèi)容從哪里來的,因?yàn)檫@個跳轉(zhuǎn)過程實(shí)在服務(wù)器實(shí)現(xiàn)的炒瘟,并不是在客戶端實(shí)現(xiàn)的所以客戶端并不知道這個跳轉(zhuǎn)動作,所以它的地址欄還是原來的地址.

 //Servlet里處理get請求的方法
 public void doGet(HttpServletRequest request , HttpServletResponse response){
     //獲取請求轉(zhuǎn)發(fā)器對象第步,該轉(zhuǎn)發(fā)器的指向通過getRequestDisPatcher()的參數(shù)設(shè)置
   RequestDispatcher requestDispatcher =request.getRequestDispatcher("資源的URL");
    //調(diào)用forward()方法疮装,轉(zhuǎn)發(fā)請求     
   requestDispatcher.forward(request,response);   
}

4.2 重定向redirect

是服務(wù)端根據(jù)邏輯,發(fā)送一個狀態(tài)碼,告訴瀏覽器重新去請求那個地址.所以地址欄顯示的是新的URL.

//Servlet中處理get請求的方法
public void doGet(HttpServletRequest request,HttpServletResponse response){
//請求重定向到另外的資源
    response.sendRedirect("資源的URL");
}

4.3 區(qū)別

  • 重定向是兩次請求,轉(zhuǎn)發(fā)是一次請求粘都,因此轉(zhuǎn)發(fā)的速度要快于重定向
  • 重定向之后地址欄上的地址會發(fā)生變化廓推,變化成第二次請求的地址,轉(zhuǎn)發(fā)之后地址欄上的地址不會變化翩隧,還是第一次請求的地址
  • 轉(zhuǎn)發(fā)是服務(wù)器行為樊展,重定向是客戶端行為。重定向時瀏覽器上的網(wǎng)址改變 ,轉(zhuǎn)發(fā)是瀏覽器上的網(wǎng)址不變
  • 重定向是兩次request堆生,轉(zhuǎn)發(fā)只有一次請求
  • 重定向時的網(wǎng)址可以是任何網(wǎng)址专缠,轉(zhuǎn)發(fā)的網(wǎng)址必須是本站點(diǎn)的網(wǎng)址.
  • 重定向時的根目錄為webapps,請求轉(zhuǎn)發(fā)的根目錄為本項目的根目錄
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市淑仆,隨后出現(xiàn)的幾起案子藤肢,更是在濱河造成了極大的恐慌,老刑警劉巖糯景,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異省骂,居然都是意外死亡蟀淮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進(jìn)店門钞澳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來怠惶,“玉大人,你說我怎么就攤上這事轧粟〔咧危” “怎么了?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵兰吟,是天一觀的道長通惫。 經(jīng)常有香客問我,道長混蔼,這世上最難降的妖魔是什么履腋? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上遵湖,老公的妹妹穿的比我還像新娘悔政。我一直安慰自己,他們只是感情好延旧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布谋国。 她就那樣靜靜地躺著,像睡著了一般迁沫。 火紅的嫁衣襯著肌膚如雪芦瘾。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天弯洗,我揣著相機(jī)與錄音旅急,去河邊找鬼。 笑死牡整,一個胖子當(dāng)著我的面吹牛藐吮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播逃贝,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼谣辞,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了沐扳?” 一聲冷哼從身側(cè)響起泥从,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎沪摄,沒想到半個月后躯嫉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡杨拐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年祈餐,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哄陶。...
    茶點(diǎn)故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡帆阳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出屋吨,到底是詐尸還是另有隱情蜒谤,我是刑警寧澤,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布至扰,位于F島的核電站鳍徽,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏敢课。R本人自食惡果不足惜旬盯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧胖翰,春花似錦接剩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至培他,卻和暖如春鹃两,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背舀凛。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工俊扳, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人猛遍。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓馋记,卻偏偏與公主長得像,于是被迫代替她去往敵國和親懊烤。 傳聞我的和親對象是個殘疾皇子梯醒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評論 2 355