1 HttpServletRequest的功能
HttpServletRequest在JavaWeb中非常重要的一個類。它是Servlet的service()方法的參數之一!所以你必須必須要掌握它!
request的功能可以分爲以下幾種:
l 封裝了請求頭數據;
l 封裝了請求正文數據,如果是GET請求,那麼就沒有正文;
l request是一個域對象,可以把它當成Map來添加獲取數據;
l request提供了請求轉發和請求包含功能。
2 request獲取請求頭數據
String value = request.getHeader(“請求頭名稱”);
request對象可以用來獲取請求頭數據,當然,這些請求數據都是Tomcat封裝到request中去的。我們在service()方法中可以直接來獲取!
request與請求頭相關的方法有:
l String getHeader(String name):獲取指定名稱的請求頭;
l Enumeration getHeaderNames():獲取所有請求頭名稱;
l int getIntHeader(String name):獲取值爲int類型的請求頭。
response.setContentType("text/html;charset=utf-8"); Enumeration names = request.getHeaderNames(); while(names.hasMoreElements()) { String name = (String)names.nextElement(); String value = request.getHeader(name); System.out.println(name +": " + value); response.getWriter().println(name +": " + value + "<br/>"); } |
3 request獲取請求相關的其它方法
request中還提供了與請求相關的其他方法,有些方法是爲了我們更加便捷的方法請求頭數據而設計,有些是與請求URL相關的方法。
l int getContentLength():獲取請求正文的字節數,GET請求沒有正文,沒有正文返回-1;
l String getContentType():獲取請求類型,如果請求是GET,那麼這個方法返回null;如果是POST請求,那麼默認爲application/x-www-form-urlencoded,其它類型以後再學;
l String getMethod():返回請求方法,例如:GET
l Locale getLocale():返回當前客戶端瀏覽器支持的Locale。java.util.Locale表示國家和言語,這個東西在國際化中很有用;
l String getCharacterEncoding():獲取請求編碼,如果沒有setCharacterEncoding(),那麼返回null。表示使用ISO-8859-1編碼;
l void setCharacterEncoding(String code):設置請求編碼,只對正文有效!注意,對於GET而言,沒有正文!!!所以此方法只能對POST請求中的參數有效!
l String getContextPath():返回上下文路徑,例如:/hello
l String getQueryString():返回請求URL中的參數,例如:name=zhangSan
l String getRequestURI():返回請求URI路徑,例如:/hello/oneServlet
l StringBuffer getRequestURL():返回請求URL路徑,例如:http://localhost/hello/oneServlet,即返回除了參數以外的路徑信息;
l String getServletPath():返回Servlet路徑,例如:/oneServlet
l String getRemoteAddr():返回當前客戶端的IP地址;
l String getRemoteHost():返回當前客戶端的主機名,但這個方法的實現還是獲取IP地址;
l int getRemotePort():返回客戶端的端口號,每次請求都會變;
l String getSchema():返回請求協議,例如:http;
l String getServerName():返回主機名,例如:localhost
l int getServerPort():返回服務器端口號,例如:80
http://localhost:8080/hello/a/b/c/d.jsp?mame=zhangSan
System.out.println("request.getContentLength(): " + request.getContentLength()); System.out.println("request.getContentType(): " + request.getContentType()); System.out.println("request.getContextPath(): " + request.getContextPath()); System.out.println("request.getMethod(): " + request.getMethod()); System.out.println("request.getLocale(): " + request.getLocale());
System.out.println("request.getQueryString(): " + request.getQueryString()); System.out.println("request.getRequestURI(): " + request.getRequestURI()); System.out.println("request.getRequestURL(): " + request.getRequestURL()); System.out.println("request.getServletPath(): " + request.getServletPath()); System.out.println("request.getRemoteAddr(): " + request.getRemoteAddr()); System.out.println("request.getRemoteHost(): " + request.getRemoteHost()); System.out.println("request.getRemotePort(): " + request.getRemotePort()); System.out.println("request.getScheme(): " + request.getScheme()); System.out.println("request.getServerName(): " + request.getServerName()); System.out.println("request.getServerPort(): " + request.getServerPort()); |
4 request.getRemoteAddr():封IP
可以使用request.getRemoteAddr()方法獲取客戶端的IP地址,然後判斷IP是否爲禁用IP。這種方式可以很方便的對多次密碼的用戶處理。
String ip = request.getRemoteAddr(); System.out.println(ip); if(ip.equals("127.0.0.1")) { response.sendError(500,"您的IP已被禁止!"); } else { response.getWriter().print("Hello!"); } |
HttpServletRequest獲取參數
1 HttpServletRequest獲取參數方法
可以使用HttpServletRequest獲取客戶端的請求參數,相關方法如下:
l String getParameter(String name):通過指定名稱獲取參數值;
l String[] getParameterValues(String[] name):通過指定名稱獲取參數值數組,有可能一個名字對應多個值,例如表單中的多個複選框使用相同的name時;
l Enumeration getParameterNames():獲取所有參數的名字;
l Map getParameterMap():獲取所有參數對應的Map,其中key爲參數名,value爲參數值。
2 傳遞參數的方式
傳遞參數的方式:GET和POST。
GET:
l 地址欄中直接給出參數:http://localhost/param/ParamServlet?p1=v1&p2=v2;
l 超鏈接中給出參數:<a href=” http://localhost/param/ParamServlet?p1=v1&p2=v2”>???</a>
l 表單中給出參數:<form method=”GET” action=”ParamServlet”>…</form>
POST:
l 表單中給出參數:<form method=”POST” action=”ParamServlet”>…</form>
無論是GET還是POST,獲取參數的方法是相同的。
String s1 = request.getParameter(“p1”);//返回v1
String s2 = request.getParameter(“p2”);//返回v2
<formaction="ParamServlet"method="post"> <inputtype="text"name="p1"/><br/> <inputtype="text"name="p2"/><br/> <inputtype="submit"value="提交"/><br/> </form> <ahref="ParamServlet?p1=v1&p2=v2">Param</a> |
String s1 = request.getParameter("p1"); String s2 = request.getParameter("p2"); response.getWriter().print("p1 = " + s1 +"<br/>"); response.getWriter().print("p2 = " + s2 +"<br/>"); |
Enumeration names = request.getParameterNames(); while(names.hasMoreElements()) { String name = (String)names.nextElement(); String value = request.getParameter(name); System.out.println(name +" = " + value); } |
3 多值參數
例如在註冊表單中,如果讓用戶填寫愛好,那麼愛好可能就是多個。那麼hobby參數就會對應多個值:
<formaction="ParamServlet"method="post"> 上網:<inputtype="checkbox"name="hobby"value="netplay"/><br/> 踢球:<inputtype="checkbox"name="hobby"value="football"/><br/> 看書:<inputtype="checkbox"name="hobby"value="read"/><br/> 編程:<inputtype="checkbox"name="hobby"value="programme"/><br/> <inputtype="submit"value="提交"/><br/> </form> |
//獲取所有名爲hoby的參數值 String[] hobbies = request.getParameterValues("hobby"); System.out.println(Arrays.toString(hobbies)); |
4 獲取所有參數,並封裝到Map中
request.getParameterMap()方法返回Map類型,對應所有參數。其中Map的key對應參數的名字;Map的value對應參數的值。
<formaction="ParamServlet"method="post"> 姓名:<inputtype="text"name="name"/><br/> 年齡:<inputtype="text"name="age"/><br/> 性別:<inputtype="text"name="sex"/><br/> <inputtype="submit"value="提交"/><br/> </form> |
Map<String,String[]> map = request.getParameterMap(); Set<String> keys = map.keySet(); for(String key : keys) { String[] value = map.get(key); System.out.println(key +" = " + value[0]); } |
sex = male name = zhangSan age = 23 |
5 BeanUtils:使用Map創建Bean實例
我們知道,可以使用Map來創建Bean實例,我們也知道,可以把表單數據封裝到Map中返回。這樣我們就可以通過BeanUtils把表單數據封裝成Bean實例了。但要注意的是,必須要創建表單中參數的名稱與Bean的屬性名相同!!!
try { Map<String,String[]> map = request.getParameterMap(); Person person = new Person(); BeanUtils.populate(person, map);[崔1] System.out.println(person); } catch (IllegalAccessException e) { thrownew RuntimeException(e); } catch (InvocationTargetException e) { thrownew RuntimeException(e); } |
6 單值參數,也可以使用request.getParameterValues(String)獲取
其實當參數的值是單個的時候,同樣可以使用request.getParameterValues(String)方法來獲取參數值,不過這個參數返回的值爲String[],這時我們需要再去獲取數組下標0的元素。
String name = request.getParameterValues(“name”)[0]; |
HttpServletRequest請求轉發
1 HttpServletRequest可以當作Map來用
JSP一共四個域對象(多出來一個PageContext,等第八天吧!)
在Servlet中有三個對象是域對象,即在不同範圍內傳遞域變量:
l HttpServletRequest:範圍爲請求,在同一請求範圍內傳遞屬性;
l HttpSession:範圍是會話,在同一會話中傳遞屬性。當某個用戶打開某一網站的第一個頁面開始,直到關閉該網站的所有頁面結束,這是一個會話範圍;
l ServletContext:範圍是Context,即項目。在同一個項目中,只有一個ServletContext。
今天我們要使用的是HttpServletRequest的傳遞屬性功能。
所有域對象都有如下四個方法:
l void setAttribute(String name, Object o):設置屬性,其中name爲屬性值,o爲屬性值;
l void removeAttribute(String name):移除指定名字的屬性;
l Object getAttribute(String name):獲取指定名稱的屬性;
l Enumeration getAttibuteNames():獲取所有屬性名稱。
注意,attribute和parameter不同,attribute是我們自己設置的,而parameter是用戶通過表單、超鏈接中傳遞過來,然後由Tomcat封裝到request中的。說白一點,attribute是在服務器端組件中直接設置的,而parameter是由客戶端間接設置的。
2 在同一Servlet中測試域方法
String name = request.getParameter("name")[崔2] ; request.setAttribute("name", name)[崔3] ; String aName = (String)request.getAttribute("name")[崔4] ; System.out.println(aName); |
3 請求轉發
通常一個請求往往會涉及到多個Servlet,也就是說一個Servlet不只獨立完成一個請求,那麼就存在了請求轉發的“故事”。例如:登錄驗證Servlet在完成了驗證之後會把請求轉發給顯示主頁的Servlet。
下面是一段“錯誤的轉發”:
publicclass AServletextends HttpServlet { protectedvoid doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("AServlet的工作"); Servlet bServlet = new BServlet(); bServlet.service(req, resp); } } |
publicclass BServletextends HttpServlet { protectedvoid doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("BServlet的工作"); } } |
上面代碼中,AServlet會創建BServlet對象,然後去調用BServlet的service()方法。這種方式確實可以調用BServlet,但這種方法的問題就太多太多了。
l AServlet知道的太多了,它居然知道BServlet的存在;
l BServlet由AServlet創建,不在是由Tomcat管理Servlet的生命週期;
所以我們在AServlet中不知道BServlet的存在,在AServlet中只知道一個servletName(對應<servlet-name>),然後使用Tomcat的方式,通過servletName完成轉發。
如果在AServlet中需要保存數據給BServlet,那麼可以使用request.setAttribute()方法來設置,然後在BServlet中就可以通過request.getAttribute()方法獲取了。
在AServlet中獲取請求轉發器:
RequestDispatcher rd = request.getRequestDispatcher(“/BServlet”);
RequestDispatcher就是請求轉發器了,獲取它需要使用request對象的getRequestDispatcher()方法,該方法的參數就是BServlet在web.xml文件中的配置名:<servlet-name>BServlet</servlet-name>。
這只是獲取了轉發器,還沒有轉發。轉發需要調用RequestDispatcher對象的forward()方法,該方法需要傳遞request和response兩個參數。
// AServlet內容 Person person = new Person();[崔5] try { BeanUtils.populate(person, request.getParameterMap());[崔6] } catch (IllegalAccessException e) { thrownew RuntimeException(e); } catch (InvocationTargetException e) { thrownew RuntimeException(e); } request.setAttribute("person", person);[崔7] RequestDispatcher rd = request.getRequestDispatcher("/BServlet");[崔8] |
// BServlet內容 Person person = (Person)request.getAttribute("person");[崔10] response.getWriter().print("BServlet:" + person +"<br/>")[崔11] ; |
l 一個請求;
l 在一個請求中可能會執行多個Servlet;
l 多個Servlet中可以共享request!
l 多個Servlet中只有最後可以用來向客戶端響應;
l 其他Servlet如果響應了,有兩種可能:
Ø 數據只寫入到緩衝區中,沒有到客戶端,在轉必之前,Tomcat會清空這些數據;
Ø 數據已經發送到客戶端,Tomcat會拋出異常,不再轉發。
n 緩衝區滿了,就會自動發送到客戶端;
n 調用response.flushBuffer();
n 調用PrintWriter.flush();
4 請求包含
請求包含與請求轉發非常相似,區別在與轉發時AServlet中的響應正文會被清除,只會留下BServlet中的響應正文,但請求包含會保留AServlet中的響應。
請求包含需要調用RequestDispatcher對象的include()方法。請求包含基本上與轉發是相同的,區別在與請求包含時,在AServlet中存在響應正文會保留下來,而請求轉發會清除AServlet所做的響應正文內容。
Person person = new Person(); try { BeanUtils.populate(person, request.getParameterMap()); } catch (IllegalAccessException e) { thrownew RuntimeException(e); } catch (InvocationTargetException e) { thrownew RuntimeException(e); } PrintWriter out = response.getWriter(); //轉發之前的響應,不會被髮送到客戶端瀏覽器上去。 out.println("AServlet: " + person);[崔13] request.setAttribute("person", person); RequestDispatcher rd = request.getRequestDispatcher("/BServlet"); |
Person person = (Person)request.getAttribute("person"); PrintWriter out = response.getWriter(); out.print("BServlet:" + person +"<br/>"); System.out.println("BServlet: " + person); |
AServlet: Person [name=zhangSan, age=23, sex=male] BServlet:Person [name=zhangSan, age=23, sex=male] |
5 理解請求轉發和請求包含
細心的童鞋們已經發現了,當從AServlet轉發到BServlet後,在客戶端的瀏覽器地址欄中的URL還是AServlet,而不是BServlet。也就是說,請求轉發這個“故事”瀏覽器並不知道!!!
你可以把請求轉發當作是一個請求內部調用了多個Servlet的service()方法完成的,而客戶端只是發送了一個請求而已。