請求&響應
請求物件介紹
請求:獲取資源。在BS架構中,就是客戶端瀏覽器向伺服器發出詢問
請求物件:就是在專案當中用於傳送請求的物件
ServletRequest 和 HttpServletRequest
請求物件的常用方法-獲取各種路徑
返回值 方法名 說明
String getContextPath() 獲取虛擬目錄名稱
String getServletPath() 獲取Servlet對映路徑
String getRemoteAddr() 獲取訪問者ip地址
String getQueryString() 獲取請求的訊息資料
String getRequestURI() 獲取統一資源識別符號
StringBuffer getRequestURL() 獲取統一資源定位符
package com.itheima.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/ServletDemo01") public class ServletDemo01 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //getContextPath() 獲取虛擬目錄名稱 String contextPath = request.getContextPath(); System.out.println(contextPath); //getServletPath() 獲取Servlet對映路徑 String servletPath = request.getServletPath(); System.out.println(servletPath); //getRemoteAddr() 獲取訪問者ip地址 String remoteAddr = request.getRemoteAddr(); System.out.println(remoteAddr); //getQueryString() 獲取請求的訊息資料 (瞭解) String queryString = request.getQueryString(); System.out.println(queryString); //getRequestURI() 獲取統一資源識別符號 /request/ServletDemo01 共和國 String requestURI = request.getRequestURI(); System.out.println(requestURI); //getRequestURL() 獲取統一資源定位符 http://localhost:8080/request/ServletDemo01 中華人民共和國 StringBuffer requestURL = request.getRequestURL(); System.out.println(requestURL); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
請求物件常用方法-獲取請求頭資訊
返回值 方法名 說明
String getHeader(String name) 根據請求頭名稱獲取一個值
Enumeration<String> getHeaders(String name) 根據請求頭名稱獲取多個值
Enumeration<String> getHeaderNames() 根據所有請求頭名稱
package com.itheima.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Enumeration; /* * 獲取請求頭資訊的相關方法 * */ @WebServlet("/ServletDemo02") public class ServletDemo02 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //getHeader(String name) 根據請求頭名稱獲取一個值 String connection = request.getHeader("connection"); System.out.println(connection); System.out.println("----------"); //getHeaders(String name) 根據請求頭名稱獲取多個值 Enumeration<String> values = request.getHeaders("Accept-Encoding"); while(values.hasMoreElements()){ String value = values.nextElement(); System.out.println(value); } System.out.println("----------"); //getHeaderNames() 根據所有請求頭名稱 Enumeration<String> names = request.getHeaderNames(); while(names.hasMoreElements()){ String name = names.nextElement(); String value = request.getHeader(name); System.out.println(name+","+value); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
2.3.3 請求物件常用方法3-獲取請求引數(非常重要)
返回值 方法名 說明
String getParameter(String name) 根據名稱獲取資料
String[] getParameterValues(String name) 根據名稱獲取所有資料
Enumeration<String> getParameterNames() 獲取所有名稱
Map<String,String[]> getParameterMap() 獲取所有引數鍵值對
package com.itheima.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Enumeration; import java.util.Map; /* * 獲取請求資訊的相關方法 * */ @WebServlet("/ServletDemo03") public class ServletDemo03 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.根據名稱獲取資料 getParameter() String username = request.getParameter("username"); System.out.println(username); String password = request.getParameter("password"); System.out.println(password); System.out.println("----------------------"); //2.根據名稱獲取所有資料 getParameterValues() String[] hobbies = request.getParameterValues("hobby"); for (String hobby : hobbies) { System.out.println(hobby); } System.out.println("----------------------"); //3.獲取所有名稱 getParameterNames() Enumeration<String> names = request.getParameterNames(); while(names.hasMoreElements()){ String name = names.nextElement(); System.out.println(name); } System.out.println("----------------------"); //4.獲取所有引數的鍵值對 getParameterMap() Map<String, String[]> map = request.getParameterMap(); for (String key : map.keySet()) { String[] values = map.get(key); System.out.print(key+":"); for (String value : values) { System.out.print(value+" "); } System.out.println(); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
第一種:最簡單直接的封裝方式
bean/Student
package com.itheima.bean; import java.util.Arrays; public class Student { private String username; private String password; private String[] hobby; public Student() { } public Student(String username, String password, String[] hobby) { this.username = username; this.password = password; this.hobby = hobby; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String[] getHobby() { return hobby; } public void setHobby(String[] hobby) { this.hobby = hobby; } @Override public String toString() { return "Student{" + "username='" + username + '\'' + ", password='" + password + '\'' + ", hobby=" + Arrays.toString(hobby) + '}'; } }
ServletDemo04:
package com.itheima.servlet; import com.itheima.bean.Student; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Enumeration; import java.util.Map; /* * 封裝物件-手動封裝 * */ @WebServlet("/ServletDemo04") public class ServletDemo04 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.獲取所有的資料 String username = request.getParameter("username"); String password = request.getParameter("password"); String[] hobbies = request.getParameterValues("hobby"); //2.封裝學生物件 Student stu=new Student(username,password,hobbies); //輸出物件 System.out.println(stu); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
第二種:使用反射方式封裝
package com.itheima.servlet; import com.itheima.bean.Student; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.io.IOException; import java.lang.reflect.Method; import java.util.Map; /* * 封裝物件-反射方式 * */ @WebServlet("/ServletDemo05") public class ServletDemo05 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.獲取所有的資料 Map<String, String[]> map = request.getParameterMap(); //2.封裝學生物件 Student stu=new Student(); //2.1.遍歷集合 for (String name : map.keySet()) { String[] value = map.get(name); //2.2獲取Student物件的屬性描述器,根據名稱拿到 stu裡面的get/set方法 try { PropertyDescriptor pd=new PropertyDescriptor(name,stu.getClass()); //2.3獲取對應的setXXX方法 Method writeMethod = pd.getWriteMethod(); //2.4執行方法 if (value.length >1) { writeMethod.invoke(stu,(Object) value); }else{ writeMethod.invoke(stu,value); } } catch (Exception e) { e.printStackTrace(); } } //輸出物件 System.out.println(stu); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
當我們寫完此種封裝方式之後,同學們可以發現,我們絕大多數封裝都可以使用這段程式碼來實現。並且,無論是誰來寫這段通用的封裝程式碼,其程式碼內容都是大同小異的。那麼,我們就可以得出一個很有趣的結論:一般遇到這種情況時,肯定有人幫我們寫好了,我們只需要用就行了。我們後面還會遇到類似這樣的情況。
此時,幫我們寫好這段封裝程式碼的是apache軟體基金會,我們前面學習的tomcat也是它提供的。它裡面有一個開源工具包集合commons,裡面有很多開源工具類,今天我們就來講解第一個:commons-beanutils。
第三種:使用工具類封裝方式
匯入這兩個包
package com.itheima.servlet; import com.itheima.bean.Student; import org.apache.commons.beanutils.BeanUtils; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.beans.PropertyDescriptor; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Map; /* * 封裝物件-工具類方式 * */ @WebServlet("/ServletDemo06") public class ServletDemo06 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.獲取所有的資料 Map<String, String[]> map = request.getParameterMap(); //2.封裝學生物件 Student stu=new Student(); try { BeanUtils.populate(stu,map); } catch (Exception e) { e.printStackTrace(); } //輸出物件 System.out.println(stu); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
通過流物件獲取請求資訊
返回值 方法名 說明
BufferReader getReader() 獲取字元輸入流
ServletInputStream getInputStream() 獲取位元組輸入流
package com.itheima.servlet; import com.itheima.bean.Student; import org.apache.commons.beanutils.BeanUtils; import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.io.IOException; import java.util.Map; /* * 流物件獲取資料 * */ @WebServlet("/ServletDemo07") public class ServletDemo07 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //字元流(必須是post方式) /* BufferedReader br = request.getReader(); String line; while((line=br.readLine())!=null){ System.out.println(line); }*/ //br.close(); //位元組流 ServletInputStream is = request.getInputStream(); byte[] arr=new byte[1024]; int len; while((len= is.read(arr))!=-1){ System.out.println(new String(arr,0,len)); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
2.3.5請求正文中中文編碼問題
關於請求中文亂碼問題,我們需要分開討論,第一是POST請求方式,第二是GET方式。
1)POST方式請求
在POST方式請求中,我們的亂碼問題可以用如下程式碼解決:
request.setCharacterEncoding("UTF-8");
GET方式請求的正文是在位址列中,在Tomcat8.5版本及以後,Tomcat伺服器已經幫我們解決了,所以不會有亂碼問題了。
而如果我們使用的不是Tomcat伺服器,或者Tomcat的版本是8.5以前,那麼GET方式仍然會有亂碼問題,解決方式如下:(以下程式碼瞭解即可,因為我們現在使用的是Tomcat9.0.27版本)
/** * 在Servlet的doGet方法中新增如下程式碼 */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /* * GET方式:正文在位址列 * username=%D5%C5%C8%FD * %D5%C5%C8%FD是已經被編過一次碼了 * * 解決辦法: * 使用正確的碼錶對已經編過碼的資料進行解碼。 * 就是把取出的內容轉成一個位元組陣列,但是要使用正確的碼錶。(ISO-8859-1) * 再使用正確的碼錶進行編碼 * 把位元組陣列再轉成一個字串,需要使用正確的碼錶,是看瀏覽器當時用的是什麼碼錶 */ String username = request.getParameter("username"); byte[] by = username.getBytes("ISO-8859-1"); username = new String(by,"GBK"); //輸出到瀏覽器:注意響應的亂碼問題已經解決了 response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); out.write(username); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }
請求物件
請求域(request域):可以在一次請求範圍內進行共享資料
請求物件操作共享資料方法
返回值 方法名 說明
void setAttribute(String name,Object value) 向請求域物件中儲存資料
Object getAttribute(String name) 通過名稱獲取請求域物件中的資料
void removeAttribute(String name) 通過名稱一處請求域物件中的資料
2.3.6 請求轉發(與重定向的區別)
在實際開發中,重定向和請求轉發都是我們要用到的響應方式,那麼他們有什麼區別呢?我們通過下面的示例來看一下:
請求轉發:客戶端的一次請求到達後,發現需要藉助其他Servlet來實現功能
特點:
- 瀏覽器位址列不變
- 域物件中的資料不丟失
- 負責轉發的Servlet轉發前後的相應正文會丟失
- 有轉發的目的地來響應客戶端
返回值 方法名 說明
RequestDispatcher getRequestDispatcher(String name) 獲取請求排程物件
返回值 方法名 說明
void forward(ServletRequest req,ServletResponse resp) 實現轉發
ServletDemo09
package com.itheima.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /* * 請求轉發 * */ @WebServlet("/ServletDemo09") public class ServletDemo09 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); //設定共享資料 request.setAttribute("encoding","gbk"); //獲取請求排程物件 request.getRequestDispatcher("/ServletDemo10").forward(request,response); } }
ServletDemo10
package com.itheima.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /* * 請求轉發 * */ @WebServlet("/ServletDemo10") public class ServletDemo10 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //獲取共享資料 Object encoding = request.getAttribute("encoding"); System.out.println(encoding); System.out.println("ServletDemo10執行了"); } }
2.3.7 請求包含
在實際開發中,我們可能需要把兩個Servlet的內容合併到一起來響應瀏覽器,而同學們都知道HTTP協議的特點是一請求,一響應的方式。所以絕對不可能出現有兩個Servlet同時響應方式。那麼我們就需要用到請求包含,把兩個Servlet的響應內容合併輸出。我們看具體使用示例:
請求包含:可以合併其他Servlet中的功能一起響應給客戶端