Servlet Request常用方法


接下來記錄一下Servlet Request和Response的常用API,以及亂碼問題。

Request

Request即HttpRequest,可以獲取客戶端相關的信息、獲取請求頭以及獲取請求參數等。

獲取客戶端相關的信息

常使用的API有如下

(1)getRequestURL方法 -- 返回客戶端發出請求完整URL
(2)getRequestURI方法 -- 返回請求行中的資源名部分
(3)getQueryString方法 -- 返回請求行中的參數部分
(4)getRemoteAddr方法 -- 返回發出請求的客戶機的IP地址
(5)getMethod -- 得到客戶機請求方式
(6)getContextPath -- 獲得當前web應用虛擬目錄名稱 -- 在寫路徑時不要將web應用的虛擬路徑的名稱寫死, 應該在需要寫web應用的名稱的地方通過getContextPath方法動態獲取

代碼

 1 package com.boe.request;
 2 
 3 import javax.servlet.ServletException;
 4 import javax.servlet.annotation.WebServlet;
 5 import javax.servlet.http.HttpServlet;
 6 import javax.servlet.http.HttpServletRequest;
 7 import javax.servlet.http.HttpServletResponse;
 8 import java.io.IOException;
 9 
10 /**
11  * 獲取客戶端相關信息
12  */
13 @WebServlet("/RequestDemo1")
14 public class RequestDemo1 extends HttpServlet {
15 
16     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
17         /*getRequestURL方法 -- 返回客戶端發出請求完整URL
18         getRequestURI方法 -- 返回請求行中的資源名部分
19         getQueryString方法 -- 返回請求行中的參數部分
20         getRemoteAddr方法 -- 返回發出請求的客戶機的IP地址
21         getMethod -- 得到客戶機請求方式
22         getContextPath -- 獲得當前web應用虛擬目錄名稱 -- 在寫路徑時不要將web應用的虛擬路徑的名稱寫死, 應該在需要寫web應用的名稱的地方通過getContextPath方法動態獲取*/
23 
24         //url
25         StringBuffer requestURL = request.getRequestURL();
26         System.out.println("url:"+requestURL);//統一完整路徑名,包括協議,虛擬主機和資源,url:http://localhost/day09-reqres/RequestDemo1
27         //uri
28         String uri=request.getRequestURI();
29         System.out.println("uri:"+uri);// 統一資源路徑名 uri:/day09-reqres/RequestDemo1
30         //queryString
31         String qs=request.getQueryString();
32         System.out.println("qs:"+qs);
33         //ip
34         String addr = request.getRemoteAddr();//alt+shift+L,可以默認提示變量名
35         System.out.println("addr:"+addr);//addr:127.0.0.1
36         //method
37         String method = request.getMethod();
38         System.out.println(method);//GET
39         //contextpath
40         String contextPath = request.getContextPath();
41         System.out.println(contextPath);///day09-reqres 會動態變化,萬分注意!
42     }
43 
44     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
45         doPost(request, response);
46     }
47 }

訪問后控制台

獲取請求頭信息

上面是獲取客戶端信息的相關api,這個是獲取請求頭的api,就F12 request請求內容比較多的那一部分內容里的信息,它常用的方法如下。

(1)getHeader(name)方法 --- String
(2)getHeaders(String name)方法 --- Enumeration<String>
(3)getHeaderNames方法 --- Enumeration<String>
(4)getIntHeader(name)方法 --- int
(5)getDateHeader(name)方法 --- long(日期對應毫秒)

代碼部分

 1 package com.boe.request;
 2 
 3 import javax.servlet.ServletException;
 4 import javax.servlet.annotation.WebServlet;
 5 import javax.servlet.http.HttpServlet;
 6 import javax.servlet.http.HttpServletRequest;
 7 import javax.servlet.http.HttpServletResponse;
 8 import java.io.IOException;
 9 import java.util.Enumeration;
10 
11 /**
12  * 獲取請求頭的信息
13  */
14 @WebServlet("/RequestDemo2")
15 public class RequestDemo2 extends HttpServlet {
16     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
17         /*name getHeader(name)方法 --- String
18         getHeaders(String name)方法 --- Enumeration<String>
19         getHeaderNames方法 --- Enumeration<String>
20         getIntHeader(name)方法 --- int
21         getDateHeader(name)方法 --- long(日期對應毫秒)*/
22 
23         //獲取請求頭名稱為host的請求頭中包含的信息
24         String host = request.getHeader("host");
25         System.out.println("host:"+host);
26         System.out.println("-------------分割線-------------");
27         //獲取請求頭名稱為host的請求頭們中包含的信息,返回一個枚舉類型
28         Enumeration<String> hosts = request.getHeaders("host");
29         while(hosts.hasMoreElements()){
30             String s = hosts.nextElement();
31             System.out.println("hosts value:"+s);
32         }
33         System.out.println("-------------分割線-------------");
34         //獲取全部請求頭的名稱
35         Enumeration<String> headerNames = request.getHeaderNames();
36         while(headerNames.hasMoreElements()){
37             String head = headerNames.nextElement();
38             String value=request.getHeader(head);
39             System.out.println("head:"+head+", "+"value:"+value);
40         }
41         System.out.println("-------------分割線-------------");
42     }
43 
44     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
45         doPost(request, response);
46     }
47 }

訪問后控制台輸出效果

web中實際信息

可以看出,代碼中獲取的內容和網頁中的信息一致。

獲取請求參數

可以使用request獲取請求參數,這個比較常用,如獲取用戶登錄的用戶名和密碼等,常用的方法如下。

(1)getParameter(String name) --- String 通過name獲得值
(2)getParameterValues(String name) --- String[ ] 通過name獲得多值 checkbox
(3)getParameterMap() --- Map<String,String[ ]> key :name value: 多值 將查詢的參數保存在一個Map中
(5)getParameterNames() --- Enumeration<String> 獲得所有name

提交參數分為POST和GET提交的方式,這里先准備一個頁面進行測試,因此需要Servlet的代碼和html的代碼。

html頁面

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <meta charset="utf-8" /><!---->
 5     </head>
 6     <body>
 7         <h1>GET提交</h1>
 8         <form action="/day09-reqres/RequestDemo3" method="GET">
 9             用戶名: <input type="text" name="username" />
10             昵稱: <input type="text" name="nickname" />
11             <input type="submit" value="提交" />
12         </form>
13         <h1>POST提交</h1>
14         <form action="/day09-reqres/RequestDemo3" method="POST">
15             用戶名: <input type="text" name="username" />
16             昵稱: <input type="text" name="nickname" />
17             愛好: <input type="checkbox" name="like" value="lanqiu" />籃球
18                 <input type="checkbox" name="like" value="zuqiu" />足球
19                 <input type="checkbox" name="like" value="taiqiu" />台球
20             <input type="submit" value="提交" />
21         </form>
22     </body>
23 </html>

servlet代碼

 1 package com.boe.request;
 2 
 3 import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
 4 
 5 import javax.servlet.ServletException;
 6 import javax.servlet.annotation.WebServlet;
 7 import javax.servlet.http.HttpServlet;
 8 import javax.servlet.http.HttpServletRequest;
 9 import javax.servlet.http.HttpServletResponse;
10 import java.io.IOException;
11 import java.util.Arrays;
12 import java.util.Enumeration;
13 import java.util.Map;
14 
15 //請求參數相關的api
16 @WebServlet("/RequestDemo3")
17 public class RequestDemo3 extends HttpServlet {
18     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
19         /*getParameter(String name) --- String 通過name獲得值
20         getParameterValues(String name) --- String[ ] 通過name獲得多值 checkbox
21         getParameterMap() --- Map<String,String[ ]> key :name value: 多值 將查詢的參數保
22         存在一個Map中
23         getParameterNames() --- Enumeration<String> 獲得所有name*/
24 
25         //獲取單個參數值
26         String encoding = request.getCharacterEncoding();
27         System.out.println("服務器默認使用字符集"+encoding);
28         //設置字符集為utf-8 ,只對post請求有效
29         //request.setCharacterEncoding("utf-8");
30         System.out.println("設置完成之后的字符集"+request.getCharacterEncoding());
31 
32         String method = request.getMethod();
33         if("GET".equals(method)){
34             System.out.println("GET請求");
35             //getBytes先編碼,可以指定系統的字符集,執行后返回一個byte[]數組
36             //new String后解碼,需傳入byte[]數組,以及解碼字符集
37             String user=new String(request.getParameter("username").getBytes("iso-8859-1"),"utf-8");
38             String nickname=new String(request.getParameter("nickname").getBytes("iso-8859-1"),"utf-8");
39             System.out.println("user:"+user+":nickname:"+nickname);
40         }
41 
42 
43         String user = request.getParameter("username");
44         String nickname = request.getParameter("nickname");
45         System.out.println("user:"+user+":nickname:"+nickname);
46 
47         //獲取多個參數值,如checkbox
48         String[] likes = request.getParameterValues("like");
49         System.out.println(Arrays.toString(likes));
50 
51         //返回所有的key value,name包括username,nickname和like
52         Map<String, String[]> parameterMap = request.getParameterMap();
53 
54         //得到全部請求參數
55         Enumeration<String> parameterNames = request.getParameterNames();
56         while(parameterNames.hasMoreElements()){
57             String name=parameterNames.nextElement();//獲取參數的名字
58             String parameter = request.getParameter(name);//這個只能拿到一個參數,如果有多個只能拿一個
59             System.out.println("name="+name+",value="+parameter);
60             //獲取多個參數
61             String[] parameters = request.getParameterValues(name);
62             System.out.println("name="+name+",value="+Arrays.toString(parameters));
63         }
64 
65     }
66 
67     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
68         doPost(request, response);
69     }
70 }

准備好后,開始測試。

(1)POST提交

可以看到POST提交英文是沒有任何問題的,並且注意request.getParameter方法一次只能返回有一個參數,就算這個屬性有多個參數也只能返回一個。需要返回多個參數時使用getParameterValues方法。

如果是提交中文,request的請求body里是有中文顯示的,但是到了服務端獲取后,中文部分就變成了亂碼。 

web頁面正常顯示

查看html代碼部分,meta標簽里charset屬性是utf-8,代表瀏覽器使用utf-8來打開頁面,瀏覽器使用什么編碼格式打開瀏覽器,再發送數據到服務器(這里是tomcat服務器)的時候就默認使用什么編碼格式發送,因此瀏覽器發送的是utf-8,這個是可以正常攜帶中文信息的,但是tomcat默認的解碼格式是iso-8859-1,因此首先編解碼格式不一致會造成亂碼,另外一方面因為iso-8859-1因為無法表示中文,也將顯示亂碼。

要想解決這個辦法,可以使用request.setCharacterEncoding方法來解決,但是這個需要寫到獲取參數之前,修改后繼續提交中文發現編碼字符集變成了utf-8,並且可以正常解碼中文。

(2)GET請求

GET請求的話比較特殊,它的請求參數跟POST請求提交的不太一樣,是在請求行里的 ,因此出現亂碼解決的方式也有區別,還是在上面代碼的基礎上進行測試。

如果提交的是英文,正常提交沒問題。

web頁面中請求參數是在請求行里的。

如果提交的是中文,在注釋掉new String部門代碼,並保留request.setCharacterEncoding代碼,發現依然顯示亂碼。

提交顯示亂碼

並且web端request里內容不是中文,而是16進制的形式表示。說明request.setCharacterEncoding設置的編碼格式,對請求行沒有效果,GET請求處理服務端亂碼需要使用另外一種方式,即需要上面紅色方框的內容,即系統默認是iso-8859-1接受數據那就按照它來編碼變成字節數組,然后將字節數組再使用utf-8來解碼變成字符。

 

這樣設置后繼續提交中文,發現服務端可以正常獲得。

請求轉發

請求轉發,是使用RequestDispatcher資源調度,將請求從當前資源交給下一個資源處理,下一個資源可以是servlet,也可以是JSP。轉發的過程中,只有一次請求和一次響應,並且地址不變。下面使用三個servlet,來感受以下請求轉發的特點。

准備了RequestDemo4~6,具體代碼如下,在使用的過程中部分代碼需要修改。

RequestDemo4

 1 package com.boe.request;
 2 
 3 import javax.servlet.RequestDispatcher;
 4 import javax.servlet.ServletException;
 5 import javax.servlet.annotation.WebServlet;
 6 import javax.servlet.http.HttpServlet;
 7 import javax.servlet.http.HttpServletRequest;
 8 import javax.servlet.http.HttpServletResponse;
 9 import java.io.IOException;
10 
11 /**
12  * 重定轉發,和RequestDemo5一組
13  */
14 @WebServlet("/RequestDemo4")
15 public class RequestDemo4 extends HttpServlet {
16     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
17         //創建調度器
18         RequestDispatcher dispatcher = request.getRequestDispatcher("/RequestDemo5");
19         response.getWriter().write("this is demo4");//請求轉發前,向response緩沖區中寫入數據,請求轉發時,會將response緩沖區清空一次
20 
21         //response.flushBuffer();//會報錯,提示IllegalStateException: Cannot forward after response has been committed,默認提交
22         /**
23          * public void flushBuffer() throws java.io.IOException
24          * 強行將緩沖區中的所有內容寫入客戶端。調用此方法會自動提交響應,這意味着將編寫狀態代碼和頭。后面再次轉發會失敗
25          */
26 
27         //利用調度器完成轉發
28         //不允許多次轉發,但是可以多重轉發,可以轉發到demo5,接着demo6這種
29         System.out.println("這是demo4");
30         dispatcher.forward(request,response);
31         //request.getRequestDispatcher("index.jsp").forward(request,response);
32         System.out.println("demo4轉發完成");
33     }
34 
35     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
36         doPost(request, response);
37     }
38 }
View Code

RequestDemo5

 1 package com.boe.request;
 2 
 3 import javax.servlet.RequestDispatcher;
 4 import javax.servlet.ServletException;
 5 import javax.servlet.annotation.WebServlet;
 6 import javax.servlet.http.HttpServlet;
 7 import javax.servlet.http.HttpServletRequest;
 8 import javax.servlet.http.HttpServletResponse;
 9 import java.io.IOException;
10 
11 /**
12  * 重定轉發,和RequestDemo4一組
13  */
14 @WebServlet("/RequestDemo5")
15 public class RequestDemo5 extends HttpServlet {
16     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
17         //response.getWriter().write("this is demo5");
18         RequestDispatcher dispatcher = request.getRequestDispatcher("RequestDemo6");
19         System.out.println("這是demo5");
20         dispatcher.forward(request,response);
21         System.out.println("demo5轉發完成");
22     }
23 
24     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
25         doPost(request, response);
26     }
27 }
View Code

RequestDemo6

 1 package com.boe.request;
 2 
 3 import javax.servlet.ServletException;
 4 import javax.servlet.annotation.WebServlet;
 5 import javax.servlet.http.HttpServlet;
 6 import javax.servlet.http.HttpServletRequest;
 7 import javax.servlet.http.HttpServletResponse;
 8 import java.io.IOException;
 9 
10 @WebServlet("/RequestDemo6")
11 public class RequestDemo6 extends HttpServlet {
12     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
13         System.out.println("這是demo6");
14         response.getWriter().write("<h1 style='font:微軟雅黑;color:blue'>this is demo6</h1>");
15         System.out.println("demo6完成輸出");
16     }
17 
18     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
19         doPost(request, response);
20     }
21 }
View Code

(1)正常轉發,將response.flushBuffer先注釋掉,控制台和web端顯示如下。

可以看到可以多重轉發,請求鏈可以在多個資源上傳遞,並且從控制台輸出順序,可以看到轉發代碼部分執行完成之后,才執行轉發代碼之后的代碼,因此''demo04轉發完成''最后輸出。

最后輸出'this is demo6',而剛開始RequestDemo4中的輸出被覆蓋了。說明在轉發前往response緩存中寫入的數據,在轉發后會被清空

 

(2) response.flushBuffer取消注釋,繼續測試,發現控制台會報錯。提示IllegalStateException: Cannot forward after response has been committed,並且提示在第30行出現問題,第30行是轉發的代碼,為啥這里不能轉發了呢?其實就是flushBuffer的原因,它會在轉發前將寫入response中的緩存強行提交發送給瀏覽器,因此下面再次轉發就不可以了。因此如果在轉發前response緩沖區中就有內容提交了給了瀏覽器,轉發會失敗

(3)測試demo4中轉發給demo05后又轉發給jsp,即測試多次轉發,發現報錯內容跟上面一樣,也是提示IllegalStateException: Cannot forward after response has been committed,因此一個請求也不能多次轉發

域對象

request可以作用域對象使用,所謂域對象就是有一個可以看到的范圍,並且在這個范圍內通過map可以共享資源。request就是一種域對象,此外還有其他幾種域對象,如servletContext、session和pageContext。通過往域對象中設置值,可以在域對象的范圍內都能被訪問到,這里使用request,就能在整條訪問鏈上都能得到存入的數據。

RequestDemo08的代碼,用於發送數據。

 1 package com.boe.request;
 2 
 3 import javax.servlet.ServletException;
 4 import javax.servlet.annotation.WebServlet;
 5 import javax.servlet.http.HttpServlet;
 6 import javax.servlet.http.HttpServletRequest;
 7 import javax.servlet.http.HttpServletResponse;
 8 import java.io.IOException;
 9 
10 /**
11  * 作為域對象使用-在一個范圍內共享數據,這里使用的域對象就是request
12  */
13 @WebServlet("/RequestDemo8")
14 public class RequestDemo8 extends HttpServlet {
15     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
16         //向域中設置數據
17         request.setAttribute("name","clyang");
18         request.getRequestDispatcher("/RequestDemo9").forward(request,response);
19     }
20 
21     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
22         doPost(request, response);
23     }
24 }

RequestDemo09的代碼,用於接收數據。

 1 package com.boe.request;
 2 
 3 import javax.servlet.ServletException;
 4 import javax.servlet.annotation.WebServlet;
 5 import javax.servlet.http.HttpServlet;
 6 import javax.servlet.http.HttpServletRequest;
 7 import javax.servlet.http.HttpServletResponse;
 8 import java.io.IOException;
 9 import java.util.Enumeration;
10 
11 /**
12  * 獲得域數據
13  */
14 @WebServlet("/RequestDemo9")
15 public class RequestDemo9 extends HttpServlet {
16     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
17         //獲取域屬性
18         String name= (String) request.getAttribute("name");
19         System.out.println("name="+name);
20         //獲取域屬性名字
21         Enumeration<String> attributeNames = request.getAttributeNames();
22         while(attributeNames.hasMoreElements()){
23             String s = attributeNames.nextElement();
24             System.out.println("域屬性的名字為:"+s);
25         }
26         response.getWriter().write("<h1 style='font:微軟雅黑;color:blue'>"+name+"</h1>");
27     }
28 
29     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
30         doPost(request, response);
31     }
32 }

控制台和web輸出情況,可以看到轉發后還可以通過request獲取name的屬性值,因為還在域的范圍內,所以可以獲取。

 request作用域的范圍:一個請求鏈。

 request作用域的生命周期:一次請求開始到請求結束。

請求包含

請求包含指的是服務器內部實現資源合並的效果。如果瀏覽器請求ServletA,在A的內部可以通過request.getRequestDispatcher("B的虛擬路徑").include(request, response)將ServletB包含進來,B處理的結果將會並入A處理的結果一起響應給瀏覽器,准備兩個servlet,將數據合並后發送給瀏覽器。
 
RequestDemo11的代碼
 1 package com.boe.request;
 2 
 3 import javax.servlet.RequestDispatcher;
 4 import javax.servlet.ServletException;
 5 import javax.servlet.annotation.WebServlet;
 6 import javax.servlet.http.HttpServlet;
 7 import javax.servlet.http.HttpServletRequest;
 8 import javax.servlet.http.HttpServletResponse;
 9 import java.io.IOException;
10 
11 /**
12  * 請求包含
13  */
14 @WebServlet("/RequestDemo11")
15 public class RequestDemo11 extends HttpServlet {
16     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
17         //創建調度器
18         RequestDispatcher dispatcher = request.getRequestDispatcher("/RequestDemo12");
19         response.getWriter().write("9999 from demo11 ");
20         //利用調度器完成請求包含
21         dispatcher.include(request,response);
22     }
23 
24     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
25         doPost(request, response);
26     }
27 }
RequestDemo12的代碼
 1 package com.boe.request;
 2 
 3 import javax.servlet.ServletException;
 4 import javax.servlet.annotation.WebServlet;
 5 import javax.servlet.http.HttpServlet;
 6 import javax.servlet.http.HttpServletRequest;
 7 import javax.servlet.http.HttpServletResponse;
 8 import java.io.IOException;
 9 
10 @WebServlet("/RequestDemo12")
11 public class RequestDemo12 extends HttpServlet {
12     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
13         response.getWriter().write(" 1 from demo12");
14     }
15 
16     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
17         doPost(request, response);
18     }
19 }

測試結果,可以看到兩次請求的內容會並到一起,發送給瀏覽器。

參考博文:

(1)https://www.cnblogs.com/logsharing/p/8448446.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM