一.Servlet中處理請(qǐng)求的方式
之前介紹過(guò)Servlet的體系結(jié)構(gòu),廣義上來(lái)說(shuō),Servlet是一個(gè)接口,有實(shí)現(xiàn)類GenericsServlet,而GenericsServlet是一個(gè)抽象類,有直接的子類HttpServlet。
而HttpServlet要比GenericsServlet要強(qiáng)大,因?yàn)樗怯蒅enericsServlet抽象類擴(kuò)展而來(lái)的,并且現(xiàn)在大部分的應(yīng)用程序都是與HTTP結(jié)合起來(lái)使用,而且HTTPServlet封裝了許多,使得我們的開(kāi)發(fā)變得更加簡(jiǎn)潔。
之前當(dāng)我們要實(shí)現(xiàn)Servlet接口時(shí),是需要重寫5個(gè)方法的:init,destroy,service,getServletConfig,getServletInfo,這樣太麻煩,我們可以直接繼承HttpServlet類,因?yàn)镠TTPServlet默認(rèn)已經(jīng)實(shí)現(xiàn)了Servlet接口中的所有方法了,寫代碼時(shí)只需要重寫需要的方法即可。
具體操作方式為:
- 繼承HttpServlet
- 重寫doGet()和doPost()方法,并且在doGet()或者doPost()中寫入一句
this.doPost(req,resp)或this.doGet(req,resp),因?yàn)檫@樣子無(wú)論是Get請(qǐng)求還是POST請(qǐng)求,處理的方式都相同。
二.Request對(duì)象
-
request對(duì)象的原理
- request對(duì)象是由服務(wù)器創(chuàng)建的,我們只需要直接使用就好了。
- request對(duì)象就是將瀏覽器的請(qǐng)求封裝成的對(duì)象,能夠獲取請(qǐng)求文本中的所有內(nèi)容,包括請(qǐng)求頭,請(qǐng)求體和請(qǐng)求行
-
request對(duì)象的繼承體系
ServletRequest -- 接口
| 繼承
HttpServletRequest -- 接口
| 實(shí)現(xiàn)
org.apache.catalina.connector.RequestFacade 類(tomcat) -
request對(duì)象的功能
-
獲取請(qǐng)求行數(shù)據(jù)
-
獲取請(qǐng)求方式
String getMethod() -
獲取虛擬目錄
String getContextPath() -
獲取Servlet路徑
String getServletPath() -
獲取get方式請(qǐng)求參數(shù)
String getQueryString() -
獲取請(qǐng)求URI
String getRequestURI()String getRequestURL() -
獲取協(xié)議和版本
String getProtocol() -
獲取客戶機(jī)的IP地址
String getRemoteAddr()
@WebServlet("/RequestServlet") public class RequestServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 獲取請(qǐng)求方式 String method = request.getMethod(); System.out.println("請(qǐng)求方式為:" + method); // 2. 獲取虛擬目錄 String contextPath = request.getContextPath(); System.out.println("虛擬目錄是:" + contextPath); // 3. 獲取Servlet路徑 String servletPath = request.getServletPath(); System.out.println("Servlet路徑為:" + servletPath); // 4. 獲取get請(qǐng)求參數(shù) String queryString = request.getQueryString(); System.out.println("Get請(qǐng)求參數(shù):" + queryString); // 5. 獲取請(qǐng)求URI String requestURI = request.getRequestURI(); StringBuffer requestURL = request.getRequestURL(); System.out.println("請(qǐng)求URI為:" + requestURI); System.out.println("請(qǐng)求URL為:" + requestURL); // 6. 獲取協(xié)議和版本 String protocol = request.getProtocol(); System.out.println("協(xié)議和版本為:" + protocol); // 7. 獲取客戶機(jī)的IP地址 String remoteAddr = request.getRemoteAddr(); System.out.println("客戶機(jī)IP地址為:" + remoteAddr); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }瀏覽器請(qǐng)求為:http://localhost/BlogTest/RequestServlet?name=zhangsan&age=18 控制臺(tái)輸出為: 請(qǐng)求方式為:GET 虛擬目錄是:/BlogTest Servlet路徑為:/RequestServlet Get請(qǐng)求參數(shù):name=zhangsan&age=18 請(qǐng)求URI為:/BlogTest/RequestServlet 請(qǐng)求URL為:http://localhost/BlogTest/RequestServlet 協(xié)議和版本為:HTTP/1.1 客戶機(jī)IP地址為:0:0:0:0:0:0:0:1 -
-
獲取請(qǐng)求頭數(shù)據(jù)
-
String getHeader(String name):通過(guò)請(qǐng)求頭名字獲取請(qǐng)求頭的值 -
Enumeration<String> getHeaderNames():獲取所有請(qǐng)求頭的名字
@WebServlet("/RequestServlet2") public class RequestServlet2 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 獲取請(qǐng)求頭 -- 獲取User-Agent的值,獲知瀏覽器版本信息 String header = request.getHeader("User-Agent"); System.out.println("請(qǐng)求頭User-Agent:" + header); // 2. 獲取所有的請(qǐng)求頭 Enumeration<String> headerNames = request.getHeaderNames(); System.out.println("所有請(qǐng)求頭列表:"); while (headerNames.hasMoreElements()) { String name = headerNames.nextElement(); // 獲取請(qǐng)求頭數(shù)據(jù) String head = request.getHeader(name); System.out.println(name + ":" + head); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }請(qǐng)求頭User-Agent:Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36 所有請(qǐng)求頭列表: host:localhost connection:keep-alive cache-control:max-age=0 upgrade-insecure-requests:1 user-agent:Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36 accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3 accept-encoding:gzip, deflate, br accept-language:zh-CN,zh;q=0.9,en;q=0.8 cookie:JSESSIONID=2BFDB4BDC8DF9089DEE0BAA90B9EF721; Idea-6b401060=b4304026-b59a-47c6-8b46-5e6042267d2c -
-
獲取請(qǐng)求體數(shù)據(jù)
請(qǐng)求體只有POST請(qǐng)求才有,封裝了post請(qǐng)求的請(qǐng)求參數(shù)。
獲取請(qǐng)求體數(shù)據(jù)的操作步驟為:
-
獲取流對(duì)象
BufferedReader getReader():獲取字符輸入流,只能操作字符數(shù)據(jù)ServletInputStream getInputStream():獲取字節(jié)輸入流,可以操作所有數(shù)據(jù)類型 從流對(duì)象中獲取數(shù)據(jù)
@WebServlet("/RequestServlet3") public class RequestServlet3 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 字節(jié)流 // ServletInputStream inputStream = request.getInputStream(); // // byte[] bytes = new byte[1024]; // int len = 0; // while ((len = inputStream.read(bytes)) != -1) { // System.out.println(new String(bytes,0, len)); // } // 輸出:username=zhangsan&password=12345678 // 字符流 BufferedReader reader = request.getReader(); String line = null; while ((line = reader.readLine()) != null) { System.out.println(line); } // 輸出:username=zhangsan&password=12345678 } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } } -
-
-
request對(duì)象其他功能
-
通用的獲取請(qǐng)求參數(shù)
由上面的可以看出,get方式獲取請(qǐng)求參數(shù)使用的是
getQueryString(),post方式是通過(guò)獲取請(qǐng)求體來(lái)得到請(qǐng)求參數(shù),這樣子太麻煩,還要區(qū)分,所以有以下幾個(gè)方法,不論是get還是post都可以使用來(lái)獲取請(qǐng)求參數(shù),屬于通用的。-
String getParameter(String name):根據(jù)參數(shù)名獲取參數(shù)值 -
String[] getParameterValues(String name):根據(jù)參數(shù)名獲取參數(shù)值的數(shù)組(對(duì)于一些同一個(gè)名字有多個(gè)值的情況,比如復(fù)選框checkbox) -
Enumeration<String> getParameterNames():獲取所有請(qǐng)求參數(shù)的名稱 -
Map<String,String[]> getParameterMap():獲取所有參數(shù)的名稱和值的Map集合
@WebServlet("/RequestServlet4") public class RequestServlet4 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 獲取請(qǐng)求參數(shù)username的值 String username = request.getParameter("username"); System.out.println("username :" + username); System.out.println("--------------------"); // 2. 獲取請(qǐng)求參數(shù)sport的所有值 String[] sports = request.getParameterValues("sport"); for (String sport : sports) { System.out.println("sport : " + sport); } System.out.println("--------------------"); // 3. 獲取所有請(qǐng)求參數(shù)的名字 Enumeration<String> names = request.getParameterNames(); while (names.hasMoreElements()) { String name = names.nextElement(); System.out.println("name: " + name); } System.out.println("--------------------"); // 4. 獲取所有請(qǐng)求參數(shù)的Map集合 Map<String, String[]> parameterMap = request.getParameterMap(); Set<String> keyset = parameterMap.keySet(); for (String name: keyset) { String[] values = parameterMap.get(name); for (String v : values) { System.out.println(name + " ---> " + v); } } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }請(qǐng)求為: http://localhost/BlogTest/RequestServlet4?username=zhangsan&&sport=basketball&&sport=football 控制臺(tái)輸出為: username :zhangsan -------------------- sport : basketball sport : football -------------------- name: username name: sport -------------------- username ---> zhangsan sport ---> basketball sport ---> football -
-
請(qǐng)求轉(zhuǎn)發(fā)
請(qǐng)求轉(zhuǎn)發(fā)是在服務(wù)器內(nèi)的資源跳轉(zhuǎn)方式(還有一種是重定向),具有以下特點(diǎn):
- 瀏覽器的地址欄路徑是不會(huì)發(fā)生變化的。
- 只能轉(zhuǎn)發(fā)到當(dāng)前服務(wù)器的內(nèi)部資源。
- 轉(zhuǎn)發(fā)是一次請(qǐng)求
操作步驟為:
- 通過(guò)request獲取請(qǐng)求轉(zhuǎn)發(fā)器對(duì)象:
RequestDispatcher getRequestDispatcher(String path) - 使用forward方法進(jìn)行轉(zhuǎn)發(fā):
forward(ServletRequest request, ServletResponse response)
-
共享數(shù)據(jù)
在進(jìn)行請(qǐng)求轉(zhuǎn)發(fā)時(shí),請(qǐng)求轉(zhuǎn)發(fā)是一次請(qǐng)求,會(huì)將request和response傳遞給要轉(zhuǎn)發(fā)到的請(qǐng)求中,在這中間,兩個(gè)請(qǐng)求間可能需要共享一些數(shù)據(jù),這些數(shù)據(jù)只存在一次請(qǐng)求的范圍。
主要有以下方法:
-
void setAttribute(String name, Object obj):存儲(chǔ)數(shù)據(jù),以鍵值對(duì)的方式存儲(chǔ) -
Object getAttribute(String name):通過(guò)鍵獲取值 -
void removeAttribute(String name):移除指定的鍵值對(duì)
第一個(gè)Servlet:
@WebServlet("/RequestServlet5") public class RequestServlet5 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("這是RequestServlet5..."); // 設(shè)置共享數(shù)據(jù) request.setAttribute("usernmae", "zhangsan"); // 請(qǐng)求轉(zhuǎn)發(fā) request.getRequestDispatcher("/RequestServlet6").forward(request, response); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }第二個(gè)Servlet:
@WebServlet("/RequestServlet6") public class RequestServlet6 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("這是RequestServlet6..."); // 獲取共享數(shù)據(jù) String username = (String)request.getAttribute("usernmae"); if (username != null) { System.out.println("共享數(shù)據(jù)是: username ---> " + username); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }請(qǐng)求為:http://localhost/BlogTest/RequestServlet5 控制臺(tái)輸出為: 這是RequestServlet5... 這是RequestServlet6... 共享數(shù)據(jù)是: username ---> zhangsan -
-
-
獲取ServletContext(以后再詳解)
ServletContext getServletContext()
-
中文亂碼問(wèn)題
-
對(duì)于get方式,在service中使用的編碼和解碼方式默認(rèn)為:ISO-8859-1,這個(gè)編碼不支持中文,所以會(huì)出現(xiàn)亂碼,需要手動(dòng)修改編碼方式為UTF-8,才能解決中文亂碼問(wèn)題。
使用方式為:
parameter = new String(parameter.getBytes("iso8859-1"), "utf-8");注意:tomcat 8 中g(shù)et方式的中文亂碼問(wèn)題已經(jīng)解決了,可以不用自己去手動(dòng)修改。
-
-
對(duì)于post方式,中文請(qǐng)求會(huì)亂碼
解決方式:在獲取請(qǐng)求參數(shù)前,設(shè)置request的編碼:
request.setCharacterEncoding("utf-8");