HttpServletRequest
在學習一個東西之前,我們首先應該了解它是什么,接下來讓我們來認識一下它吧。
初識HTTPServletRequest
HTTPServletRequest是一個接口,全限定名稱:jakarta.servlet.http.HttpServletRequest
HttpServletRequest接口是Servlet規范中的一員。
HttpServletRequest接口的父接口:ServletRequest
public interface HttpServletRequest extends ServletRequest {}
實現類
HttpServletRequest接口的實現類誰寫的? HttpServletRequest對象是誰給創建的?
通過測試:
org.apache.catalina.connector.RequestFacade 實現了 HttpServletRequest接口
public class RequestFacade implements HttpServletRequest {}
測試結果說明:Tomcat服務器(WEB服務器、WEB容器)實現了HttpServletRequest接口,還是說明了Tomcat服務器實現了Servlet規范。而對于我們javaweb程序員來說,實際上不需要關心這個,我們只需要面向接口編程即可。我們關心的是HttpServletRequest接口中有哪些方法,這些方法可以完成什么功能!!!!
封裝的信息
HttpServletRequest對象中都有什么信息?都包裝了什么信息?
HttpServletRequest對象是Tomcat服務器負責創建的。這個對象中封裝了什么信息?
封裝了HTTP的請求協議。
實際上是用戶發送請求的時候,遵循了HTTP協議,發送的是HTTP的請求協議,Tomcat服務器將HTTP協議中的信息以及數據全部解析出來,然后Tomcat服務器把這些信息封裝到HttpServletRequest對象當中,傳給了我們javaweb程序員。
javaweb程序員面向HttpServletRequest接口編程,調用方法就可以獲取到請求的信息了。
request和response對象的生命周期?
request對象和response對象,一個是請求對象,一個是響應對象。這兩個對象只在當前請求中有效。
一次請求對應一個request。
兩次請求則對應兩個request。
…
HttpServletRequest接口中常用的方法
怎么獲取前端瀏覽器用戶提交的數據?
Map
下面是方法的測試
Enumeration
"); }
//獲取所有name Enumeration
"); } }
思考:
為了幫助大家理解并且更好的記憶上面的方法,我們來思考一下,如果是我們自己,當前端form表單提交了數據以后,我們打算怎么存儲數據
前端提交的數據格式:username=abc&userpwd=111&aihao=s&aihao=d&aihao=tt
我會采用Map集合來存儲:
Map
注意:前端表單提交數據的時候,假設提交了120這樣的“數字”,其實是以字符串"120"的方式提交的,
所以服務器端獲取到的一定是一個字符串的"120",而不是一個數字。(前端永遠提交的是字符串,后端獲取的也永遠是字符串。)
請求域對象
request對象實際上又稱為“請求域”對象。
我們可以把請求域對象和應用域對象對比學習
先來復習一下之前講過的應用域對象
應用域對象
應用域對象是什么?
ServletContext (Servlet上下文對象。)
什么情況下會考慮向ServletContext這個應用域當中綁定數據呢?
第一:所有用戶共享的數據。—假設現在有一張數據庫表,我們把查詢好的數據放在ServletContext中,那么以后如果我們還想要獲得這些數據,就直接從ServletContext當中去取出來,而不需要每次都去連接數據庫,去和數據庫交互,和數據庫的交互,需要使用IO流,大量的IO流,效率很低,IO讀的是硬盤,硬盤上有磁針,它再快也是機械型的行為,通常我們優化系統的時候使用緩存機制
第二:這個共享的數據量很小。—ServletContext是應用域,服務器啟動的時候創建,服務器關閉的時候銷毀,它會一直占用內存
第三:這個共享的數據很少的修改操作。—如果經常修改,會有線程安全問題,為了避免這樣的問題出現,就會使用鎖機制,這樣就導致效率降低
在以上三個條件都滿足的情況下,使用這個應用域對象,可以大大提高我們程序執行效率。
實際上向應用域當中綁定數據,就相當于把數據放到了緩存(Cache)當中,然后用戶訪問的時候直接從緩存中取,減少IO的操作,大大提升系統的性能,所以緩存技術是提高系統性能的重要手段。
你見過哪些緩存技術呢?
字符串常量池
整數型常量池 [-128~127],但凡是在這個范圍當中的Integer對象不再創建新對象,直接從這個整數型常量池中獲取。大大提升系統性能。
- 數據庫連接池(提前創建好N個連接對象,將連接對象放到集合當中,使用連接對象的時候,直接從緩存中拿。省去了連接對象的創建過程。效率提升。)
- 線程池(Tomcat服務器就是支持多線程的。所謂的線程池就是提前先創建好N個線程對象,將線程對象存儲到集合中,然后用戶請求過來之后,直接從線程池中獲取線程對象,直接拿來用。提升系統性能)
- 后期你還會學習更多的緩存技術,例如:redis、mongoDB…
ServletContext當中有三個操作域的方法:
void setAttribute(String name, Object obj); // 向域當中綁定數據。 Object getAttribute(String name); // 從域當中根據name獲取數據。 void removeAttribute(String name); // 將域當中綁定的數據移除 // 以上的操作類似于Map集合的操作。 Map
請求域”對象
請求域”對象要比“應用域”對象范圍小很多。生命周期短很多。請求域只在一次請求內有效。
一個請求對象request對應一個請求域對象。一次請求結束之后,這個請求域就銷毀了。
執行原理
請求域對象方法:
void setAttribute(String name, Object obj); // 向域當中綁定數據。 Object getAttribute(String name); // 從域當中根據name獲取數據。 void removeAttribute(String name); // 將域當中綁定的數據移除
請求域和應用域的選用原則
盡量選擇使用小的域對象,這樣占用的資源比較少
轉發
第一步:獲取請求轉發器對象 RequestDispatcher dispatcher = request.getRequestDispatcher("/b"); 第二步:調用轉發器的forward方法完成跳轉/轉發 dispatcher.forward(request,response); 轉發是一次請求 第一步和第二步代碼可以聯合在一起。 request.getRequestDispatcher("/b").forward(request,response);
兩個Servlet共享數據
將數據放到ServletContext應用域當中,當然是可以的,但是應用域范圍太大,占用資源太多。不建議使用。
可以將數據放到request域當中,然后AServlet轉發到BServlet,保證AServlet和BServlet在同一次請求當中,這樣就可以做到兩個Servlet,或者多個Servlet共享同一份數據。
只要是服務器的合法資源都可以轉發,可以是html,servlet等
注意:轉發的時候,路徑的寫法要注意,轉發的路徑以“/”開始,不加項目名。
容易混淆的方法
uri?username=zhangsan&userpwd=123&sex=1
String username = request.getParameter(“username”);
之前一定是執行過:request.setAttribute(“name”, new Object())
Object obj = request.getAttribute(“name”);
以上兩個方法的區別是什么
第一個方法:獲取的是用戶在瀏覽器上提交的數據.
第二個方法:獲取的是請求域當中綁定的數據。
其他方法和亂碼問題
其他方法
獲取客戶端的IP地址
String remoteAddr = request.getRemoteAddr();
獲取應用的根路徑
String contextPath = request.getContextPath();
獲取請求方式
String method = request.getMethod();
獲取請求的URI
String uri = request.getRequestURI(); // /aaa/testRequest
獲取servlet path
String servletPath = request.getServletPath(); // /testRequest
亂碼問題
有時候,我們程序寫好以后,滿心歡喜,開啟服務器,期待在瀏覽器上的運行結果,結果卻出現了亂碼問題,那我們怎么解決呢
get請求在請求行上提交數據。
post請求在請求體中提交數據。
設置請求體的字符集。(顯然這個方法是處理POST請求的亂碼問題。這種方式并不能解決get請求的亂碼問題。)
Tomcat10之后,request請求體當中的字符集默認就是UTF-8,不需要設置字符集,不會出現亂碼問題。
Tomcat9前(包括9在內),如果前端請求體提交的是中文,后端獲取之后出現亂碼,怎么解決這個亂碼?執行以下代碼。
request.setCharacterEncoding(“UTF-8”);
在Tomcat9之前(包括9),響應中文也是有亂碼的,怎么解決這個響應的亂碼?
response.setContentType(“text/html;charset=UTF-8”);
在Tomcat10之后,包括10在內,響應中文的時候就不在出現亂碼問題了。以上代碼就不需要設置UTF-8了。
注意一個細節
在Tomcat10包括10在內之后的版本,中文將不再出現亂碼。(這也體現了中文地位的提升。)
get請求亂碼問題怎么解決?
get請求發送的時候,數據是在請求行上提交的,不是在請求體當中提交的。
get請求亂碼怎么解決
方案:修改CATALINA_HOME/conf/server.xml配置文件
注意:從Tomcat8之后,URIEncoding的默認值就是UTF-8,所以GET請求也沒有亂碼問題了。
轉發和重定向(重要)
在代碼上的區別
轉發
獲取請求轉發器對象
RequestDispatcherdispatcher=request.getRequestDispatcher("/dept/list")
調用請求轉發器對象的forward方法完成轉發
dispatcher.forward(request, response);
合并一行代碼
request.getRequestDispatcher("/dept/list").forward(request,
response);
轉發的時候是一次請求,不管你轉發了多少次。都是一次請求。
AServlet轉發到BServlet,再轉發到CServlet,再轉發到DServlet,不管轉發了多少次,都在同一個request當中。
這是因為調用forward方法的時候,會將當前的request和response對象傳遞給下一個Servlet。
重定向
注意:路徑上要加一個項目名。為什么?
瀏覽器發送請求,請求路徑上是需要添加項目名的。
以下這一行代碼會將請求路徑“/oa/dept/list”發送給瀏覽器
瀏覽器會自發的向服務器發送一次全新的請求:/oa/dept/list
response.sendRedirect("/oa/dept/list");
形式上的區別
轉發(一次請求)
在瀏覽器地址欄上發送的請求是:http://localhost:8080/servlet10/a ,最終請求結束之后,瀏覽器地址欄上的地址還是這個。沒變。
重定向(兩次請求)
在瀏覽器地址欄上發送的請求是:http://localhost:8080/servlet10/a ,最終在瀏覽器地址欄上顯示的地址是:http://localhost:8080/servlet10/b
在瀏覽器輸入:localhost:8080/servlet09/a結果直接跳轉到b
本質區別
轉發:是由WEB服務器來控制的。A資源跳轉到B資源,這個跳轉動作是Tomcat服務器內部完成的。
重定向:是瀏覽器完成的。具體跳轉到哪個資源,是瀏覽器說了算。
二者如何選擇
轉發和重定向應該如何選擇?什么時候使用轉發,什么時候使用重定向?
如果在上一個Servlet當中向request域當中綁定了數據,希望從下一個Servlet當中把request域里面的數據取出來,使用轉發機制。
剩下所有的請求均使用重定向。(重定向使用較多。)
跳轉的下一個資源有沒有要求呢?必須是一個Servlet嗎?
不一定,跳轉的資源只要是服務器內部合法的資源即可。包括:Servlet、JSP、HTML…
轉發會存在瀏覽器的刷新問題。
比如說我們把數據保存到數據庫中,希望跳轉到成功頁面,當我們使用轉發的時候,只要瀏覽器刷新一次,數據庫就會多出一條數據,這樣是不可取的,所以可以使用重定向
Java Tomcat
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。