一、HttpServletRequest介紹
HttpServletRequest對象代表客戶端的請求,當客戶端通過HTTP協議訪問服務器時,HTTP請求頭中的所有信息都封裝在這個對象中,通過這個對象提供的方法,可以獲得客戶端請求的所有信息。
二、Request常用方法
2.1、獲得客戶機信息
getRequestURL方法返回客戶端發出請求時的完整URL。
getRequestURI方法返回請求行中的資源名部分。
getQueryString 方法返回請求行中的參數部分。
getPathInfo方法返回請求URL中的額外路徑信息。額外路徑信息是請求URL中的位於Servlet的路徑之后和查詢參數之前的內容,它以“/”開頭。
getRemoteAddr方法返回發出請求的客戶機的IP地址。
getRemoteHost方法返回發出請求的客戶機的完整主機名。
getRemotePort方法返回客戶機所使用的網絡端口號。
getLocalAddr方法返回WEB服務器的IP地址。
getLocalName方法返回WEB服務器的主機名。
范例:通過request對象獲取客戶端請求信息
1 package gacl.request.study;
2 import java.io.IOException;
3 import java.io.PrintWriter;
4 import javax.servlet.ServletException;
5 import javax.servlet.http.HttpServlet;
6 import javax.servlet.http.HttpServletRequest;
7 import javax.servlet.http.HttpServletResponse;
8 /**
9 * @author gacl
10 * 通過request對象獲取客戶端請求信息
11 */
12 public class RequestDemo01 extends HttpServlet {
13
14 public void doGet(HttpServletRequest request, HttpServletResponse response)
15 throws ServletException, IOException {
16 /**
17 * 1.獲得客戶機信息
18 */
19 String requestUrl = request.getRequestURL().toString();//得到請求的URL地址
20 String requestUri = request.getRequestURI();//得到請求的資源
21 String queryString = request.getQueryString();//得到請求的URL地址中附帶的參數
22 String remoteAddr = request.getRemoteAddr();//得到來訪者的IP地址
23 String remoteHost = request.getRemoteHost();
24 int remotePort = request.getRemotePort();
25 String remoteUser = request.getRemoteUser();
26 String method = request.getMethod();//得到請求URL地址時使用的方法
27 String pathInfo = request.getPathInfo();
28 String localAddr = request.getLocalAddr();//獲取WEB服務器的IP地址
29 String localName = request.getLocalName();//獲取WEB服務器的主機名
30 response.setCharacterEncoding("UTF-8");//設置將字符以"UTF-8"編碼輸出到客戶端瀏覽器
31 //通過設置響應頭控制瀏覽器以UTF-8的編碼顯示數據,如果不加這句話,那么瀏覽器顯示的將是亂碼
32 response.setHeader("content-type", "text/html;charset=UTF-8");
33 PrintWriter out = response.getWriter();
34 out.write("獲取到的客戶機信息如下:");
35 out.write("<hr/>");
36 out.write("請求的URL地址:"+requestUrl);
37 out.write("<br/>");
38 out.write("請求的資源:"+requestUri);
39 out.write("<br/>");
40 out.write("請求的URL地址中附帶的參數:"+queryString);
41 out.write("<br/>");
42 out.write("來訪者的IP地址:"+remoteAddr);
43 out.write("<br/>");
44 out.write("來訪者的主機名:"+remoteHost);
45 out.write("<br/>");
46 out.write("使用的端口號:"+remotePort);
47 out.write("<br/>");
48 out.write("remoteUser:"+remoteUser);
49 out.write("<br/>");
50 out.write("請求使用的方法:"+method);
51 out.write("<br/>");
52 out.write("pathInfo:"+pathInfo);
53 out.write("<br/>");
54 out.write("localAddr:"+localAddr);
55 out.write("<br/>");
56 out.write("localName:"+localName);
57 }
58
59 public void doPost(HttpServletRequest request, HttpServletResponse response)
60 throws ServletException, IOException {
61 doGet(request, response);
62 }
63
64 }
運行結果:

2.2、獲得客戶機請求頭
getHeader(string name)方法:String
getHeaders(String name)方法:Enumeration
getHeaderNames()方法
范例:通過request對象獲取客戶端請求頭信息
1 package gacl.request.study;
2 import java.io.IOException;
3 import java.io.PrintWriter;
4 import java.util.Enumeration;
5 import javax.servlet.ServletException;
6 import javax.servlet.http.HttpServlet;
7 import javax.servlet.http.HttpServletRequest;
8 import javax.servlet.http.HttpServletResponse;
9 /**
10 * @author gacl
11 * 獲取客戶端請求頭信息
12 * 客戶端請求頭:
13 *
14 */
15 public class RequestDemo02 extends HttpServlet {
16
17 public void doGet(HttpServletRequest request, HttpServletResponse response)
18 throws ServletException, IOException {
19 response.setCharacterEncoding("UTF-8");//設置將字符以"UTF-8"編碼輸出到客戶端瀏覽器
20 //通過設置響應頭控制瀏覽器以UTF-8的編碼顯示數據
21 response.setHeader("content-type", "text/html;charset=UTF-8");
22 PrintWriter out = response.getWriter();
23 Enumeration<String> reqHeadInfos = request.getHeaderNames();//獲取所有的請求頭
24 out.write("獲取到的客戶端所有的請求頭信息如下:");
25 out.write("<hr/>");
26 while (reqHeadInfos.hasMoreElements()) {
27 String headName = (String) reqHeadInfos.nextElement();
28 String headValue = request.getHeader(headName);//根據請求頭的名字獲取對應的請求頭的值
29 out.write(headName+":"+headValue);
30 out.write("<br/>");
31 }
32 out.write("<br/>");
33 out.write("獲取到的客戶端Accept-Encoding請求頭的值:");
34 out.write("<hr/>");
35 String value = request.getHeader("Accept-Encoding");//獲取Accept-Encoding請求頭對應的值
36 out.write(value);
37
38 Enumeration<String> e = request.getHeaders("Accept-Encoding");
39 while (e.hasMoreElements()) {
40 String string = (String) e.nextElement();
41 System.out.println(string);
42 }
43 }
44
45 public void doPost(HttpServletRequest request, HttpServletResponse response)
46 throws ServletException, IOException {
47 doGet(request, response);
48 }
49
50 }
運行結果如下:

2.3、獲得客戶機請求參數(客戶端提交的數據)
- getParameter(String)方法(常用)
- getParameterValues(String name)方法(常用)
- getParameterNames()方法(不常用)
- getParameterMap()方法(編寫框架時常用)
比如現在有如下的form表單
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
2 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
3 <html>
4 <head>
5 <title>Html的Form表單元素</title>
6 </head>
7 <fieldset style="width:500px;">
8 <legend>Html的Form表單元素</legend>
9 <!--form表單的action屬性規定當提交表單時,向何處發送表單數據,method屬性指明表單的提交方式,分為get和post,默認為get-->
10 <form action="${pageContext.request.contextPath}/servlet/RequestDemo03" method="post">
11 <!--輸入文本框,SIZE表示顯示長度,maxlength表示最多輸入長度-->
12 編 號(文本框):
13 <input type="text" name="userid" value="NO." size="2" maxlength="2"><br>
14 <!--輸入文本框,通過value指定其顯示的默認值-->
15 用戶名(文本框):<input type="text" name="username" value="請輸入用戶名"><br>
16 <!--密碼框,其中所有輸入的內容都以密文的形式顯示-->
17 密 碼(密碼框):
18 <!-- 表示的是一個空格-->
19 <input type="password" name="userpass" value="請輸入密碼"><br>
20 <!--單選按鈕,通過checked指定默認選中,名稱必須一樣,其中value為真正需要的內容-->
21 性 別(單選框):
22 <input type="radio" name="sex" value="男" checked>男
23 <input type="radio" name="sex" value="女">女<br>
24 <!--下拉列表框,通過<option>元素指定下拉的選項-->
25 部 門(下拉框):
26 <select name="dept">
27 <option value="技術部">技術部</option>
28 <option value="銷售部" SELECTED>銷售部</option>
29 <option value="財務部">財務部</option>
30 </select><br>
31 <!--復選框,可以同時選擇多個選項,名稱必須一樣,其中value為真正需要的內容-->
32 興 趣(復選框):
33 <input type="checkbox" name="inst" value="唱歌">唱歌
34 <input type="checkbox" name="inst" value="游泳">游泳
35 <input type="checkbox" name="inst" value="跳舞">跳舞
36 <input type="checkbox" name="inst" value="編程" checked>編程
37 <input type="checkbox" name="inst" value="上網">上網
38 <br>
39 <!--大文本輸入框,寬度為34列,高度為5行-->
40 說 明(文本域):
41 <textarea name="note" cols="34" rows="5">
42 </textarea>
43 <br>
44 <!--隱藏域,在頁面上無法看到,專門用來傳遞參數或者保存參數-->
45 <input type="hidden" name="hiddenField" value="hiddenvalue"/>
46 <!--提交表單按鈕,當點擊提交后,所有填寫的表單內容都會被傳輸到服務器端-->
47 <input type="submit" value="提交(提交按鈕)">
48 <!--重置表單按鈕,當點擊重置后,所有表單恢復原始顯示內容-->
49 <input type="reset" value="重置(重置按鈕)">
50 </form>
51 <!--表單結束-->
52 </fieldset>
53 </body>
54 <!--完結標記-->
55 </html>
56 <!--完結標記-->
在Form表單中填寫數據,然后提交到RequestDemo03這個Servlet進行處理,填寫的表單數據如下:

在服務器端使用getParameter方法和getParameterValues方法接收表單參數,代碼如下:
1 package gacl.request.study;
2 import java.io.IOException;
3 import java.text.MessageFormat;
4 import javax.servlet.ServletException;
5 import javax.servlet.http.HttpServlet;
6 import javax.servlet.http.HttpServletRequest;
7 import javax.servlet.http.HttpServletResponse;
8 /**
9 * @author gacl
10 * 獲取客戶端通過Form表單提交上來的參數
11 */
12 public class RequestDemo03 extends HttpServlet {
13
14 public void doGet(HttpServletRequest request, HttpServletResponse response)
15 throws ServletException, IOException {
16 //客戶端是以UTF-8編碼提交表單數據的,所以需要設置服務器端以UTF-8的編碼進行接收,否則對於中文數據就會產生亂碼
17 request.setCharacterEncoding("UTF-8");
18 /**
19 * 編 號(文本框):
20 <input type="text" name="userid" value="NO." size="2" maxlength="2">
21 */
22 String userid = request.getParameter("userid");//獲取填寫的編號,userid是文本框的名字,<input type="text" name="userid">
23 /**
24 * 用戶名(文本框):<input type="text" name="username" value="請輸入用戶名">
25 */
26 String username = request.getParameter("username");//獲取填寫的用戶名
27 /**
28 * 密 碼(密碼框):<input type="password" name="userpass" value="請輸入密碼">
29 */
30 String userpass = request.getParameter("userpass");//獲取填寫的密碼
31 String sex = request.getParameter("sex");//獲取選中的性別
32 String dept = request.getParameter("dept");//獲取選中的部門
33 //獲取選中的興趣,因為可以選中多個值,所以獲取到的值是一個字符串數組,因此需要使用getParameterValues方法來獲取
34 String[] insts = request.getParameterValues("inst");
35 String note = request.getParameter("note");//獲取填寫的說明信息
36 String hiddenField = request.getParameter("hiddenField");//獲取隱藏域的內容
37
38 String instStr="";
39 /**
40 * 獲取數組數據的技巧,可以避免insts數組為null時引發的空指針異常錯誤!
41 */
42 for (int i = 0; insts!=null && i < insts.length; i++) {
43 if (i == insts.length-1) {
44 instStr+=insts[i];
45 }else {
46 instStr+=insts[i]+",";
47 }
48 }
49
50 String htmlStr = "<table>" +
51 "<tr><td>填寫的編號:</td><td>{0}</td></tr>" +
52 "<tr><td>填寫的用戶名:</td><td>{1}</td></tr>" +
53 "<tr><td>填寫的密碼:</td><td>{2}</td></tr>" +
54 "<tr><td>選中的性別:</td><td>{3}</td></tr>" +
55 "<tr><td>選中的部門:</td><td>{4}</td></tr>" +
56 "<tr><td>選中的興趣:</td><td>{5}</td></tr>" +
57 "<tr><td>填寫的說明:</td><td>{6}</td></tr>" +
58 "<tr><td>隱藏域的內容:</td><td>{7}</td></tr>" +
59 "</table>";
60 htmlStr = MessageFormat.format(htmlStr, userid,username,userpass,sex,dept,instStr,note,hiddenField);
61
62 response.setCharacterEncoding("UTF-8");//設置服務器端以UTF-8編碼輸出數據到客戶端
63 response.setContentType("text/html;charset=UTF-8");//設置客戶端瀏覽器以UTF-8編碼解析數據
64 response.getWriter().write(htmlStr);//輸出htmlStr里面的內容到客戶端瀏覽器顯示
65 }
66
67 public void doPost(HttpServletRequest request, HttpServletResponse response)
68 throws ServletException, IOException {
69 doGet(request, response);
70 }
71 }
運行結果如下:

在服務器端使用getParameterNames方法接收表單參數,代碼如下:
1 Enumeration<String> paramNames = request.getParameterNames();//獲取所有的參數名
2 while (paramNames.hasMoreElements()) {
3 String name = paramNames.nextElement();//得到參數名
4 String value = request.getParameter(name);//通過參數名獲取對應的值
5 System.out.println(MessageFormat.format("{0}={1}", name,value));
6 }
運行結果如下:

在服務器端使用getParameterMap方法接收表單參數,代碼如下:
1 //request對象封裝的參數是以Map的形式存儲的
2 Map<String, String[]> paramMap = request.getParameterMap();
3 for(Map.Entry<String, String[]> entry :paramMap.entrySet()){
4 String paramName = entry.getKey();
5 String paramValue = "";
6 String[] paramValueArr = entry.getValue();
7 for (int i = 0; paramValueArr!=null && i < paramValueArr.length; i++) {
8 if (i == paramValueArr.length-1) {
9 paramValue+=paramValueArr[i];
10 }else {
11 paramValue+=paramValueArr[i]+",";
12 }
13 }
14 System.out.println(MessageFormat.format("{0}={1}", paramName,paramValue));
15 }
運行結果如下:

三、request接收表單提交中文參數亂碼問題
3.1、以POST方式提交表單中文參數的亂碼問題
例如有如下的form表單頁面:
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <title>request接收中文參數亂碼問題</title> 7 </head> 8 9 <body> 10 <form action="<%=request.getContextPath()%>/servlet/RequestDemo04" method="post"> 11 用戶名:<input type="text" name="userName"/> 12 <input type="submit" value="post方式提交表單"> 13 </form> 14 </body> 15 </html>

此時在服務器端接收中文參數時就會出現中文亂碼,如下所示:

3.2、post方式提交中文數據亂碼產生的原因和解決辦法

可以看到,之所以會產生亂碼,就是因為服務器和客戶端溝通的編碼不一致造成的,因此解決的辦法是:在客戶端和服務器之間設置一個統一的編碼,之后就按照此編碼進行數據的傳輸和接收。
由於客戶端是以UTF-8字符編碼將表單數據傳輸到服務器端的,因此服務器也需要設置以UTF-8字符編碼進行接收,要想完成此操作,服務器可以直接使用從ServletRequest接口繼承而來的"setCharacterEncoding(charset)"方法進行統一的編碼設置。修改后的代碼如下:
1 public void doPost(HttpServletRequest request, HttpServletResponse response)
2 throws ServletException, IOException {
3 /**
4 * 客戶端是以UTF-8編碼傳輸數據到服務器端的,所以需要設置服務器端以UTF-8的編碼進行接收,否則對於中文數據就會產生亂碼
5 */
6 request.setCharacterEncoding("UTF-8");
7 String userName = request.getParameter("userName");
8 System.out.println("userName:"+userName);
9 }
使用request.setCharacterEncoding("UTF-8");設置服務器以UTF-8的編碼接收數據后,此時就不會產生中文亂碼問題了,如下所示:

3.3、以GET方式提交表單中文參數的亂碼問題
例如有如下的form表單頁面:
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
2
3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
4 <html>
5 <head>
6 <title>request接收中文參數亂碼問題</title>
7 </head>
8
9 <body>
10 <form action="${pageContext.request.contextPath}/servlet/RequestDemo04" method="get">
11 姓名:<input type="text" name="name"/>
12 <input type="submit" value="get方式提交表單">
13 </form>
14 </body>
15 </html>

此時在服務器端接收中文參數時就會出現中文亂碼,如下所示:

那么這個中文亂碼問題又該如何解決呢,是否可以通過request.setCharacterEncoding("UTF-8");設置服務器以UTF-8的編碼進行接收這種方式來解決中文亂碼問題呢,注意,對於以get方式傳輸的中文數據,通過request.setCharacterEncoding("UTF-8");這種方式是解決不了中文亂碼問題,如下所示:

3.4、get方式提交中文數據亂碼產生的原因和解決辦法
對於以get方式傳輸的數據,request即使設置了以指定的編碼接收數據也是無效的(至於為什么無效我也沒有弄明白),默認的還是使用ISO8859-1這個字符編碼來接收數據,客戶端以UTF-8的編碼傳輸數據到服務器端,而服務器端的request對象使用的是ISO8859-1這個字符編碼來接收數據,服務器和客戶端溝通的編碼不一致因此才會產生中文亂碼的。解決辦法:在接收到數據后,先獲取request對象以ISO8859-1字符編碼接收到的原始數據的字節數組,然后通過字節數組以指定的編碼構建字符串,解決亂碼問題。代碼如下:
1 public void doGet(HttpServletRequest request, HttpServletResponse response)
2 throws ServletException, IOException {
3 /**
4 *
5 * 對於以get方式傳輸的數據,request即使設置了以指定的編碼接收數據也是無效的,默認的還是使用ISO8859-1這個字符編碼來接收數據
6 */
7 String name = request.getParameter("name");//接收數據
8 name =new String(name.getBytes("ISO8859-1"), "UTF-8") ;//獲取request對象以ISO8859-1字符編碼接收到的原始數據的字節數組,然后通過字節數組以指定的編碼構建字符串,解決亂碼問題
9 System.out.println("name:"+name);
10 }
運行結果如下:

3.5、以超鏈接形式傳遞中文參數的亂碼問題
客戶端想傳輸數據到服務器,可以通過表單提交的形式,也可以通過超鏈接后面加參數的形式,例如:
1 <a href="${pageContext.request.contextPath}/servlet/RequestDemo05?userName=gacl&name=徐達沛">點擊</a>
點擊超鏈接,數據是以get的方式傳輸到服務器的,所以接收中文數據時也會產生中文亂碼問題,而解決中文亂碼問題的方式與上述的以get方式提交表單中文數據亂碼處理問題的方式一致,如下所示:
1 String name = request.getParameter("name");
2 name =new String(name.getBytes("ISO8859-1"), "UTF-8");
另外,需要提的一點就是URL地址后面如果跟了中文數據,那么中文參數最好使用URL編碼進行處理,如下所示:
1 <a href="${pageContext.request.contextPath}/servlet/RequestDemo05?userName=gacl&name=<%=URLEncoder.encode("徐達沛", "UTF-8")%>">點擊</a>
3.6、提交中文數據亂碼問題總結
1、如果提交方式為post,想不亂碼,只需要在服務器端設置request對象的編碼即可,客戶端以哪種編碼提交的,服務器端的request對象就以對應的編碼接收,比如客戶端是以UTF-8編碼提交的,那么服務器端request對象就以UTF-8編碼接收(request.setCharacterEncoding("UTF-8"))
2、如果提交方式為get,設置request對象的編碼是無效的,request對象還是以默認的ISO8859-1編碼接收數據,因此要想不亂碼,只能在接收到數據后再手工轉換,步驟如下:
1).獲取獲取客戶端提交上來的數據,得到的是亂碼字符串,data="???è?????"
String data = request.getParameter("paramName");
2).查找ISO8859-1碼表,得到客戶機提交的原始數據的字節數組
byte[] source = data.getBytes("ISO8859-1");
3).通過字節數組以指定的編碼構建字符串,解決亂碼
data = new String(source, "UTF-8");
通過字節數組以指定的編碼構建字符串,這里指定的編碼是根據客戶端那邊提交數據時使用的字符編碼來定的,如果是GB2312,那么就設置成data = new String(source, "GB2312"),如果是UTF-8,那么就設置成data = new String(source, "UTF-8")
四、Request對象實現請求轉發
4.1、請求轉發的基本概念
請求轉發:指一個web資源收到客戶端請求后,通知服務器去調用另外一個web資源進行處理。
請求轉發的應用場景:MVC設計模式
在Servlet中實現請求轉發的兩種方式:
1、通過ServletContext的getRequestDispatcher(String path)方法,該方法返回一個RequestDispatcher對象,調用這個對象的forward方法可以實現請求轉發。
例如:將請求轉發的test.jsp頁面
1 RequestDispatcher reqDispatcher =this.getServletContext().getRequestDispatcher("/test.jsp");
2 reqDispatcher.forward(request, response);
2、通過request對象提供的getRequestDispatche(String path)方法,該方法返回一個RequestDispatcher對象,調用這個對象的forward方法可以實現請求轉發。
例如:將請求轉發的test.jsp頁面
1 request.getRequestDispatcher("/test.jsp").forward(request, response);
request對象同時也是一個域對象(Map容器),開發人員通過request對象在實現轉發時,把數據通過request對象帶給其它web資源處理。
例如:請求RequestDemo06 Servlet,RequestDemo06將請求轉發到test.jsp頁面
1 package gacl.request.study;
2
3 import java.io.IOException;
4 import javax.servlet.ServletException;
5 import javax.servlet.http.HttpServlet;
6 import javax.servlet.http.HttpServletRequest;
7 import javax.servlet.http.HttpServletResponse;
8
9 public class RequestDemo06 extends HttpServlet {
10
11 public void doGet(HttpServletRequest request, HttpServletResponse response)
12 throws ServletException, IOException {
13
14 String data="大家好,我是孤傲蒼狼,我正在總結JavaWeb";
15 /**
16 * 將數據存放到request對象中,此時把request對象當作一個Map容器來使用
17 */
18 request.setAttribute("data", data);
19 //客戶端訪問RequestDemo06這個Servlet后,RequestDemo06通知服務器將請求轉發(forward)到test.jsp頁面進行處理
20 request.getRequestDispatcher("/test.jsp").forward(request, response);
21 }
22
23 public void doPost(HttpServletRequest request, HttpServletResponse response)
24 throws ServletException, IOException {
25 doGet(request, response);
26 }
27 }
test.jsp頁面代碼如下:
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
2
3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
4 <html>
5 <head>
6 <title>Request對象實現請求轉發</title>
7 </head>
8
9 <body>
10 使用普通方式取出存儲在request對象中的數據:
11 <h3 style="color:red;"><%=(String)request.getAttribute("data")%></h3>
12 使用EL表達式取出存儲在request對象中的數據:
13 <h3 style="color:red;">${data}</h3>
14 </body>
15 </html>
運行結果如下:

request對象作為一個域對象(Map容器)使用時,主要是通過以下的四個方法來操作
- setAttribute(String name,Object o)方法,將數據作為request對象的一個屬性存放到request對象中,例如:request.setAttribute("data", data);
- getAttribute(String name)方法,獲取request對象的name屬性的屬性值,例如:request.getAttribute("data")
- removeAttribute(String name)方法,移除request對象的name屬性,例如:request.removeAttribute("data")
- getAttributeNames方法,獲取request對象的所有屬性名,返回的是一個,例如:Enumeration<String> attrNames = request.getAttributeNames();
4.2、請求重定向和請求轉發的區別
一個web資源收到客戶端請求后,通知服務器去調用另外一個web資源進行處理,稱之為請求轉發/307。
一個web資源收到客戶端請求后,通知瀏覽器去訪問另外一個web資源進行處理,稱之為請求重定向/302。

