一、Servlet之Request
Web服務器會對收到的每一次客戶端http請求分別創建一個用於代表請求的request對象和代表響應的response對象。要獲取客戶端提交的數據需通過request,要想容器輸出數據需通過response。
1、HttpServletRequest
HttpServletRequest對象代表客戶端的請求,當客戶端通過HTTP協議訪問服務器時,HTTP請求頭中的所有信息都封裝在這個對象中,開發人員通過這個對象的方法可以會的客戶的相關信息。
2、Request常用方法(參考官方API)
獲得客戶機信息:
getRequestURL,返回客戶端發出請求時的完整URL
getRequestURI, 返回請求行中的資源名部分
getQueryString, 返回請求行中的查詢字符串,通常為?后邊攜帶的參數信息
getRemoteAddr, 返回客戶端IP地址
getRemoteHost, 返回客戶端的主機名
getRemotePort, 返回客戶端的網絡端口號
getLocalAddr, 返回Web服務器的IP地址
getLocalName, 返回Web服務器的主機名
getMethod, 返回客戶端的請求方式(get/post)
獲得客戶機請求頭:
getHeader()
getHeaders()
getHeaderNames()
獲得客戶機請求參數:
getParameter()
getParameterValues()
getParameterNames
3、Request請求參數的中文亂碼問題
一般瀏覽器使用什么編碼,則傳送的數據就以什么編碼,但有許多Web瀏覽器不發送帶有“content-type”頭信息的字符編碼限定符,而由讀取http請求的代碼類決定自讀的編碼方式。
默認情況下,如果客戶端請求未定義編碼限定符,容器(如Tomcat)會用“ISO-8859-1”去創建request reader 和解析post數據。
注意:自從Tomcat5.x開始,GET和POST方法提交的信息,Tomcat采用了不同的方式來處理編碼,對於POST請求,Tomcat會仍然使用request.setCharacterEncoding方法所設置的編碼來處理,如果未設置,則使用默認的"ISO-8859-1"編碼。而對GET請求,並不會考慮使用request.setCharacterEncoding方法設置編碼,而會永遠使用“ISO-8859-1”編碼。
所以,一般的解決方式為:
POST方式:在最開始設置request.setCharacterEncoding("UTF-8")
GET方式: new String(username.getBytes("ISO-8859-1"),"UTF-8")
修改Tomcat的配置可以解決URL中中文編碼問題:<Connector URIEncoding="UTF-8"/>
4、轉發和包含
一個Servlet對象無法獲得另一個Servlet對象的引用,如果需要多個Servlet組件共同協作(數據傳遞),只能使用Servlet規范提供的請求轉發和包含這兩種方式:
請求轉發:Servlet(源組件)先對客戶請求最初一些預處理操作,然后把請求轉發給其他web組件(目標組件)來完成包括生成響應結果在內的后續操作。
包含: Servlet(源組件)把其他web組件(目標組件)生成的響應結果包含到自身的響應結果中。
兩者共同點:
源組件和目標組件處理的都是同一個酷虎請求,源組件和目標組件共享同一個ServletRequest和ServletResponse對象。
目標組件可以為Servlet、JSP、HTML文檔等
都依賴javax.servlet.RequestDispatcher接口。
5、RequestDispatcher請求分發器
它包含兩個方法:
forward():把請求轉發給目標組件
include():包含目標組件的響應結果
得到RequestDispatcher對象
1、ServletContext對象的getRequestDispatcher(String path1)。path1必須用絕對路徑,即以‘/’開頭,若用相對路徑會拋出IllegalArgumentException異常
2、ServletRequest對象的getRequestDispatcher(String path2)。 path2可以用絕對路徑也可以用相對路徑。
如果使用forward()方法,只會返回目標組件的響應結果,所以不應該在源組件中提交響應結果,而且,如果在源組件調用了Response的flush或close方法,會拋出IllegalStateException異常
如果使用include()方法,則源組件與目標組件的輸出都會被添加到響應結果中,在目標組件對響應頭做的修改會被忽略
6、請求范圍
web應用范圍內的共享數據作為ServletContext對象的屬性而存在,只要共享ServletContext對象也就共享了其屬性。
請求范圍內的共享數據作為ServletRequest對象的屬性而存在,只要共享了ServletRequest對象,也就共享了其數據。
二、Servlet之Response
1、HttpServletResponse
HttpServletResponse對象代表服務器的響應,這個對象中封裝了向客戶端發送數據、發送響應頭,發送響應狀態碼的方法。
2、Response常用方法
setStatus();設置狀態碼
setHeader();設置響應頭
getWriter();返回一個響應的打印流
getOutputStream();返回一個響應的字節輸出流
注意:getWriter與getOutputStream兩個方法相互排斥,調用了其中一個方法后就不能再調用另一個,否側會拋出異常,Servlet引擎會檢查輸出流是否關閉,並調用close方法,所以不需要自己關閉。
3、Response中的中文問題
通過設置響應頭告知客戶端編碼方式:response.setHeader("Content-Type","text/html;charset=UTF-8")
通過meta標簽模擬請求頭::out.write("<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />".getBytes())
通過直接方法:response.setContentType("text/html;charset=UTF-8");這條語句的作用是將自己的編碼設置為UTF-8,並告訴瀏覽器使用UTF-8解碼
4、Response常見應用
控制瀏覽器定時刷新:response.setHeader("Refresh","2");也可以定時刷新到某一個URL
控制瀏覽器緩存當前文檔:
response.addDateHeader("Expires",System.currentTimeMillis()+1000*60*60);//緩存一小時,對於一些不怎么變化的數據,利用緩存能減輕服務器的負擔
請求重定向:response.sendRedirect(location);
重定向特點:
Servlet源組件生成的響應結果不會被發送到客戶端,response.sendRedirect(location)方法一律返回狀態碼為302的響應結果。
如果源組件在進行重定向之前,已經提交了響應結果,會拋出IllegalStateException異常,所以,不應該在元組件中提交響應結果。
Servlet源組件重定向語句后面的代碼也會執行。
源組件和目標組件不共享一個ServletRequest對象。
對於response.sendRedirect(location)方法的參數,如果以"/"開頭,表示相當於當前服務器根路徑的URL。以"http://"開頭,表示一個完整路徑。
目標組件不必是同一個服務器上的同一個web應用的組件,它可以是任意一個有效的網頁。
三、Cookie&Session
1、什么是會話:
用戶開一個瀏覽器,點擊對個超鏈接,訪問服務器多個Web資源,然后關閉瀏覽器,整個過程稱之為一個會話。
每個用戶在使用瀏覽器與服務器進行會話的過程中,不可避免各自會產生一些數據,程序要想辦法為每個用戶保存這些數據。
2、保存會話數據的兩種技術:
Cookie:Cookie是客戶端技術,程序把每個用戶的數據以cookie的形式寫給用戶各自的瀏覽器。當用戶使用瀏覽器再去訪問服務器中的Web資源時,就會帶着各自的數據去。這樣,web資源處理的就是用戶各自的數據了。
HttpSession:Session是服務器端技術,利用這個技術,服務器在運行時可以為每一個用戶的瀏覽器 創建一個其獨享的HttpSession對象,由於session為用戶瀏覽器獨享,所以用戶在訪問服務器的web資源時,可以把各自的數據放在各自的session中,當用戶再去訪問服務器中的其他web資源是,其他web資源在從用戶各自的session中取出數據為用戶服務。
3、Cookie API
javax.servlet.http.Cookie類用於創建一個Cookie,response接口中定義了一個addCookie方法,它用於在其響應頭中增加一個相應的Set-Cookie頭字段。同樣,request接口中也定義了一個個頭Cookie方法,它用於獲取客戶端提交的Cookie。Cookie類的方法:
public Cookie(String name,String value);
setValue與getValue方法
setMaxAge與getMaxAge方法
setPath與getPath方法
setDomain與getDomain方法
getName方法
由於Cookie保存在客戶端,所有,給不給傳Cookie是由瀏覽器決定的,取決於MYURL.startWith(domain+path)完全匹配。domain是主機名加端口號,path是從第一個"/"開始的文件路徑。
cookie.setPath("/");可以讓該cookie在同一個服務器下的多個項目共享。
4、Cookie細節
一個Cookie只能表示一種信息,它至少患有一個標識該信息的名稱(name)和設置值(value)。
一個Web應用可以給一個瀏覽器發送多個Cookie;一個瀏覽器也可以存儲多個Web網站的Cookie。
每個瀏覽器有自己默認的存放Cookie個數,並限制每個站點存放Cookie的個數,每個Cookie的大小限制為4kb。
如果創建了一個cookie,並將它發送到瀏覽器,默認情況下它是一個會話級別的cookie(即存儲在瀏覽器的內存中),用戶退出瀏覽器之后即被刪除,若希望瀏覽器將該cookie存儲在磁盤上,則需要使用maxAge,並給出一個以秒為單位的時間。將最大時效設為0則是命令瀏覽器刪除該cookie。
注意,刪除cookie是,path必須一致,否則不會刪除。
5、Session
在web開發中,服務器可以為每個用戶瀏覽器創建一個會話對象(Session對象),把用戶數據寫到用戶瀏覽器獨占的Session中,當前用戶使一個瀏覽器獨占一個Session對象。因此,需要保存用戶數據時,服務器程序可以用Session保存,統一瀏覽器可以從用戶的Session中取出該用戶的數據,為用戶服務。
Session對象有服務器創建,開發人員可以調用request對象的getSession方法得到Session對象。
瀏覽器第一次請求時,服務器會在響應頭中加入Set-Cookie: JSESSIONID=022841F4A201530430481C66F0D29FB8; Path=/Day28ServletResponse/; HttpOnly。當瀏覽器下次請求時會攜帶這個Session的唯一標識,Cookie: JSESSIONID=022841F4A201530430481C66F0D29FB8。服務器就之后是同一個用戶的行為了。
服務器內存中的每個Session都有一個32位的id作為唯一標識,Tomcat為每個Session默認的生存時間為30分中。
6、瀏覽器禁用Cookie之后的Session處理
瀏覽器禁用Cookie之后,就無法再請求中攜帶JSESSIONID內容,所以導致服務器共享出問題。Java提供URL重寫方案:
response.encodeRedirectURL(url);對sendRedirect方法的URL地址進行重寫。
response.encodeURL(url);對表單action和超鏈接的url地址進行重寫。
如果用戶瀏覽器沒有禁用Cookie,重寫方法什么也不做;如果用戶瀏覽器禁用了Cookie,則重寫方法在每個URL地址中攜帶JSESSIONID,服務器保證了一個用戶的每一個請求行為攜帶SessionID,從而保證Session的作用。
Session的invalidate()方法使Session立刻失效。
可以在項目的web.xml中配置Session失效時間。
四、Servlet高級特性--過濾器
1、過濾器概述:
過濾器是Servlet2.3規范新增的功能,也是Servlet容器管理的對象,其結構同Servlet很類似,比如init()方法,destory()方法, 但是功能不同,過濾器主要是在源數據與目的數據之間起過濾作用的中間組件。
2、過濾器鏈
在一個Web應用中,可以一次編寫多個過濾器,這些過濾器組合起來,稱為一個過濾器鏈,其執行順序為注冊順序,先注冊的會先執行
3、編碼轉換過濾器
在JavaWeb開發中,初學者經常會遇到java亂碼的問題,統一字符編碼,是解決亂碼問題非常有效的手段,在Web開發中,可以使用過濾器對請求中的參數信息進行編碼轉換。
4、權限校驗過濾器(清楚整個處理流程)
根據不同的權限,用戶分別能夠訪問不同的頁面。