接下來記錄一下Servlet Request和Response的經常使用API,以及亂碼問題。html
Request
Request即HttpRequest,能夠獲取客戶端相關的信息、獲取請求頭以及獲取請求參數等。java
獲取客戶端相關的信息
常使用的API有以下web
(1)getRequestURL方法 -- 返回客戶端發出請求完整URL
(2)getRequestURI方法 -- 返回請求行中的資源名部分
(3)getQueryString方法 -- 返回請求行中的參數部分
(4)getRemoteAddr方法 -- 返回發出請求的客戶機的IP地址
(5)getMethod -- 獲得客戶機請求方式
(6)getContextPath -- 得到當前web應用虛擬目錄名稱 -- 在寫路徑時不要將web應用的虛擬路徑的名稱寫死, 應該在須要寫web應用的名稱的地方經過getContextPath方法動態獲取api
代碼數組
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(日期對應毫秒)tomcat
代碼部分服務器
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 }
訪問後控制檯輸出效果session
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 }
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 }
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 }
(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做用域的生命週期:一次請求開始到請求結束。
請求包含
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 }
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 }
測試結果,能夠看到兩次請求的內容會併到一塊兒,發送給瀏覽器。
參考博文: