文章目錄
- 1. 介紹
- 2. Request對象
- 2.1 Request繼承體系
- 2.2 Request獲取請求數據
- 1.獲取請求行
- 2.獲取請求頭
- 3.獲取請求體
- 4. 請求參數的通用方式
- 5. 解決中文亂碼問題
- 2.3 Request請求轉發
- 請求轉發資源間共享數據:
- 3. Response對象
- 3.0 Response 繼承體系
- 3.1 Response設置響應數據的功能介紹
- 1.設置響應行
- 2.設置響應頭
- 3.設置響應體
- 3.2 Response完成重定向
- 3.3 設置響應數據
- 1. Response響應字符數據
- 2. Response響應字節數據
- 4.案例:用戶登錄/用戶注冊
1. 介紹
Request+Response
Request是請求對象,Response是響應對象
- request: 獲取請求數據
- 瀏覽器會發送HTTP請求到后臺服務器[Tomcat]
- HTTP的請求中會包含很多請求數據[請求行+請求頭+請求體]
- 后臺服務器[Tomcat]會對HTTP請求中的數據進行解析并把解析結果存入到一個對象中
- 所存入的對象即為request對象,所以我們可以從request對象中獲取請求的相關參數
- 獲取到數據后就可以繼續后續的業務,比如獲取用戶名和密碼就可以實現登錄操作的相關業務
- response:設置響應數據
- 業務處理完后,后臺就需要給前端返回業務處理的結果即響應數據
- 把響應數據封裝到response對象中
- 后臺服務器[Tomcat]會解析response對象,按照[響應行+響應頭+響應體]格式拼接結果
- 瀏覽器最終解析結果,把內容展示在瀏覽器給用戶瀏覽
@WebServlet("/demo3")
public class ServletDemo3 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//使用request對象 獲取請求數據String name = request.getParameter("name");//url?name=zhangsan//使用response對象 設置響應數據response.setHeader("content-type","text/html;charset=utf-8");response.getWriter().write("<h1>"+name+",歡迎您!</h1>");}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("Post...");}
}
2. Request對象
2.1 Request繼承體系
- Tomcat需要解析請求數據,封裝為request對象并且創建request對象傳遞到service方法中;
Q1: ServletRequest和HttpServletRequest的關系?
- ServletRequest是Java Servlet規范中定義的一個接口,它是所有Servlet請求對象的頂級接口
- HttpServletRequest是ServletRequest的子接口,它擴展了ServletRequest接口,提供了更多與HTTP協議相關的方法和功能。
- 當Servlet類實現的是Servlet接口的時候,service方法中的參數是ServletRequest和ServletResponse
- 當Servlet類繼承的是HttpServlet類的時候,doGet和doPost方法中的參數就變成HttpServletRequest和HttpServletReponse
2.2 Request獲取請求數據
HTTP請求數據總共分為三部分內容,分別是 請求行、請求頭、請求體
1.獲取請求行
請求行包含三塊內容,分別是
請求方式
、請求資源路徑
、HTTP協議及版本
請求行 方法 | 說明 |
---|---|
String getMethod() | 獲取請求方式: GET |
String getContextPath() | 獲取虛擬目錄(項目訪問路徑): /request-demo |
StringBuffer getRequestURL() | 獲取URL(統一資源定位符): http://localhost:8080/request-demo/req1 |
String getRequestURI() | 獲取URI(統一資源標識符): /request-demo/req1 |
String getQueryString() | 獲取請求參數(GET方式): username=zhangsan&password=123 |
//獲取請求行
@WebServlet("/demo3")
public class ServletDemo3 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// String getMethod():獲取請求方式: GETString method = req.getMethod();System.out.println(method);//GET// String getContextPath():獲取虛擬目錄(項目訪問路徑):/request-demoString contextPath = req.getContextPath();System.out.println(contextPath);// StringBuffer getRequestURL(): 獲取URL(統一資源定位符):http://localhost:8080/request-demo/req1StringBuffer url = req.getRequestURL();System.out.println(url.toString());// String getRequestURI():獲取URI(統一資源標識符): /request-demo/req1String uri = req.getRequestURI();System.out.println(uri);// String getQueryString():獲取請求參數(GET方式): username=zhangsanString queryString = req.getQueryString();System.out.println(queryString);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {}}
2.獲取請求頭
請求頭 方法 | 說明 |
---|---|
String getHeader(String name) | 獲取指定名稱的請求頭 |
```java
/*** request 獲取請求數據*/
@WebServlet("/req1")
public class RequestDemo1 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//獲取請求頭: user-agent: 瀏覽器的版本信息String agent = req.getHeader("user-agent");System.out.println(agent);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {}
}
3.獲取請求體
請求體: 注意get請求沒有請求體,post有
請求體 方法 | 說明 |
---|---|
ServletInputStream getInputStream() | 獲取字節輸入流,如果前端發送的是字節數據,比如傳遞的是文件數據,則使用該方法 |
BufferedReader getReader() | 獲取字符輸入流,如果前端發送的是純文本數據,則使用該方法 |
具體實現的步驟如下:
1.準備一個頁面,在頁面中添加form表單,用來發送post請求
2.在Servlet的doPost方法中獲取請求體數據
3.在doPost方法中使用request的getReader()或者getInputStream()來獲取
4.訪問測試
package com.itheima.web;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.BufferedReader;
import java.io.IOException;@WebServlet("/demo4")
public class ServletDemo4 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//獲取post 請求體:請求參數//1. 獲取字符輸入流BufferedReader br = req.getReader();//2. 讀取數據String line = br.readLine();System.out.println(line);}
}
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>測試獲取請求體信息</title>
</head>
<body>
<h5>hello</h5>
<form action="/demo4" method="post"><input type="text" name="username"><input type="password" name="password"><input type="submit"></form></body>
</html>
4. 請求參數的通用方式
請求參數的獲取方式:
- GET方式:
String getQueryString()
- POST方式:
BufferedReader getReader();
案例:
(1)發送一個GET請求并攜帶用戶名,后臺接收后打印到控制臺
(2)發送一個POST請求并攜帶用戶名,后臺接收后打印到控制臺
//實現
@WebServlet("/req1")
public class RequestDemo1 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String result = req.getQueryString();System.out.println(result);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {BufferedReader br = req.getReader();String result = br.readLine();System.out.println(result);}
}
Q:既然實現的功能一樣,是否可以統一doGet和doPost方法內的代碼?
解決方案一:
@WebServlet("/req1")
public class RequestDemo1 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//獲取請求方式String method = req.getMethod();//獲取請求參數String params = "";if("GET".equals(method)){params = req.getQueryString();}else if("POST".equals(method)){BufferedReader reader = req.getReader();params = reader.readLine();}//將請求參數進行打印控制臺System.out.println(params);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {this.doGet(req,resp);}
}
解決方案二:
request對象已經將上述獲取請求參數的方法進行了封裝,并且request提供的方法實現的功能更強大
步驟:
(1)根據不同的請求方式獲取請求參數
(2)把獲取到的內容進行分割
(3)把分割后端數據,存入到一個Map集合中
方法 | 說明 |
---|---|
Map<String,String[]> getParameterMap() | 獲取所有參數Map集合 |
String[] getParameterValues(String name) | 根據名稱獲取參數值(數組) |
String getParameter(String name) | 根據名稱獲取參數值(單個值) |
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<form action="/req" method="get"><input type="text" name="username"><br><input type="password" name="password"><br><input type="checkbox" name="hobby" value="1"> 游泳<input type="checkbox" name="hobby" value="2"> 爬山 <br><input type="submit"></form>
</body>
</html>
//使用get獲取請求信息
@WebServlet("/req")
public class ServletDemo5 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//GET請求邏輯System.out.println("get....");//1. 獲取所有參數的Map集合Map<String, String[]> map = req.getParameterMap();for (String key : map.keySet()) {// username:zhangsan lisiSystem.out.print(key+":");//獲取值String[] values = map.get(key);for (String value : values) {System.out.print(value + " ");}System.out.println();//2.根據key獲取值System.out.println("------------");String[] hobbies = req.getParameterValues("hobby");for (String hobby : hobbies) {System.out.println(hobby);}//3.根據key獲取單個參數值String username = req.getParameter("username");String password = req.getParameter("password");System.out.println(username);System.out.println(password);}}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doPost(req, resp);}
}
IDEA模板創建Servlet:102
https://www.bilibili.com/video/BV1Qf4y1T7Hx
5. 解決中文亂碼問題
- GET請求獲取請求參數的方式是
request.getQueryString()
- POST請求獲取請求參數的方式是
request.getReader()
post:
req.setCharacterEncoding("UTF-8");
解決:https://blog.csdn.net/yiqieanhaowzq/article/details/126279078
username = new String(username.getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8);
2.3 Request請求轉發
請求轉發是指將當前請求轉發給另一個Servlet或JSP頁面進行處理,轉發后的Servlet或JSP頁面會繼續處理請求并生成響應。
方法 | 說明 |
---|---|
request.getRequestDispatcher(“/destination”); | 獲取RequestDispatcher對象 |
dispatcher.forward(request, response); | 請求轉發 |
package com.itheima.web;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("/demo6")
public class ServletDemo6 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("demo6...get");//請求轉發req.getRequestDispatcher("/demo7").forward(req,resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doPost(req, resp);}
}
package com.itheima.web;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("/demo7")
public class ServletDemo7 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("demo7...get");}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doPost(req, resp);}
}
請求轉發資源間共享數據:
請求轉發資源間共享數據是指在Java
Servlet中,通過請求轉發,將請求從一個Servlet或JSP頁面轉發到另一個Servlet或JSP頁面時,可以在它們之間共享數據。
- 當一個請求被轉發到另一個資源(Servlet或JSP頁面)時,原始請求的數據,例如請求參數、屬性等,可以通過設置和獲取request對象的屬性來在轉發的資源之間傳遞和共享。這種方式允許在不暴露數據給客戶端的情況下,在服務器端的多個組件之間傳遞信息。
請求轉發特點:
- 瀏覽器地址欄路徑不發生變化
- 只轉發當前服務器內部資源
- 一次請求,可以在轉發的資源間使用request共享數據
需要使用request對象提供的三個方法:
方法 | 說明 |
---|---|
void setAttribute(String name,Object o) | 存儲數據到request域中 |
Object getAttribute(String name); | 根據key,獲取值 |
void removeAttribute(String name); | 根據key,刪除該鍵值對 |
@WebServlet("/demo6")
public class ServletDemo6 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("demo6...get");//存儲數據req.setAttribute("msg","hello");//請求轉發req.getRequestDispatcher("/demo7").forward(req,resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doPost(req, resp);}
}
@WebServlet("/demo7")
public class ServletDemo7 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("demo7...get");//獲取數據Object msg = req.getAttribute("msg");System.out.println(msg);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doPost(req, resp);}
}
3. Response對象
- Request:使用request對象來獲取請求數據
- Response:使用response對象來設置響應數據
3.0 Response 繼承體系
3.1 Response設置響應數據的功能介紹
HTTP響應數據總共分為三部分內容,分別是響應行、響應頭、響應體,對于這三部分內容的數據
1.設置響應行
響應行:
- 狀態行包含了HTTP協議版本號、狀態碼和相應的狀態信息。
- 它的格式為:HTTP版本號 狀態碼 狀態信息。
- 例如:HTTP/1.1 200 OK。
方法 | 說明 |
---|---|
void setStatus(int sc); | 設置響應狀態碼 |
2.設置響應頭
響應頭部:
響應頭部包含了關于響應的附加信息,如服務器類型、日期、內容類型等。 它由多個鍵值對組成,每個鍵值對占據一行。常見的響應頭部字段包括:
- Content-Type:指定響應體的媒體類型。
- Content-Length:指定響應體的長度。
- Date:指定響應的日期和時間。
- Server:指定響應的服務器軟件類型。
方法 | 說明 |
---|---|
void setHeader(String name,String value) | 設置響應頭鍵值對 |
3.設置響應體
響應體:
響應體包含了具體的響應內容。它可以是HTML、JSON、圖片等數據。響應體的格式和內容根據具體的請求和服務器的處理結果而定。
方法 | 說明 |
---|---|
PrintWriter getWriter(); | 獲取字符輸出流 |
ServletOutputStream getOutputStream(); | 獲取字節輸出流 |
3.2 Response完成重定向
在HTTP協議中,重定向(Redirect)是一種服務器響應的行為,它告訴客戶端要求的資源已經被移動到另一個位置,并提供了新的資源位置(URL)供客戶端重新請求。
重定向狀態碼:
- 301:資源已永久移動到新的URL,客戶端應更新其鏈接。
- 302 :資源臨時移動到新的URL,客戶端應使用新的URL重新發起請求。
- 307 :資源臨時移動到新的URL,客戶端應保持請求方法不變重新發起請求。
- 308 :資源已永久移動到新的URL,客戶端應保持請求方法不變重新發起請求
重定向特點:
- 瀏覽器地址欄發生變化
- 可以重定向到任意位置的資源(服務器內部外部均可)
- 兩次請求,不能在多個資源使用request共享資源
resp.setStatus(302);
resp.setHeader("location","資源B的訪問路徑");
Q:Response重定向和Request請求轉發有什么區別?
- 重定向是一種服務器響應行為,要求客戶端重新發起請求。客戶端會接收到新的URL信息,并據此發起新的請求。
- 請求轉發是一種服務器內部行為,將客戶端的請求轉發給其他資源或處理程序來處理。客戶端對此轉發過程是不可見的。
- 重定向會向客戶端發送額外的響應,通常包含重定向的狀態碼和新的URL信息。請求轉發不需要額外的響應,客戶端不知道請求被轉發了。
- 重定向可以用于資源移動、負載均衡和認證授權等場景。請求轉發通常用于服務器內部組織和處理請求的需要。
- 重定向瀏覽器地址欄會發生變化,請求轉發地址欄不會發生變化
//重定向
@WebServlet("/resp1")
public class ResponseDemo1 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("resp1......");//重定向//1.設置響應狀態碼302resp.setStatus(302);//2. 設置響應頭resp.setHeader("Location","/resp2");//簡化方式重定向resp.sendRedirect("/resp2");}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doPost(req, resp);}
}
@WebServlet("/resp2")
public class ResponseDemo2 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("resp2......");}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doPost(req, resp);}
}
3.3 設置響應數據
方法 | 說明 |
---|---|
PrintWriter getWriter(); | 獲取字符輸出流 |
ServletOutputStream getOutputStream(); | 獲取字節輸出流 |
1. Response響應字符數據
設置響應的內容類型為text/html//resp.setHeader("content-type","text/html");
resp.setContentType("text/html");
resp.setContentType("text/html";charset=utf-8);設置響應的狀態碼
resp.setStatus(HttpServletResponse.SC_OK);設置響應的字符編碼:
resp.setCharacterEncoding("UTF-8");設置響應的頭部信息:
resp.setHeader("Cache-Control", "no-cache");
resp.setHeader("Expires", "0");設置響應的重定向:
resp.sendRedirect("https://www.example.com");設置響應的Cookie:
Cookie cookie = new Cookie("name", "value");
cookie.setMaxAge(3600); // 設置Cookie的有效期
cookie.setPath("/"); // 設置Cookie的作用路徑
resp.addCookie(cookie); // 將Cookie添加到響應中設置響應的內容長度:
resp.setContentLength(content.length());設置響應的響應類型:
resp.setContentType("application/json");
@WebServlet("/resp3")
public class ResponseDemo3 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("resp3......");//1.獲取字符輸出流PrintWriter writer = resp.getWriter();//2.設置響應的內容類型為text/html//resp.setHeader("content-type","text/html");resp.setContentType("text/html");//3.向客戶端輸出文本內容writer.write("aaa");//4.向客戶端輸出HTML標簽writer.write("<h1>aaa</h1>");//5.刷新緩沖區,確保所有內容都被寫入響應writer.flush();//6.關閉輸出流writer.close();}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doPost(req, resp);}
}
2. Response響應字節數據
//響應字節數據:設置字節數據響應體
@WebServlet("/resp4")
public class ResponseDemo4 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("resp4......");//0.讀取文件FileInputStream fileInputStream = new FileInputStream("C:\\Users\\11445\\Pictures\\Saved Pictures\\頭像.jpg");//1.獲取字節輸出留,用于向客戶端發送響應的字節數據。ServletOutputStream outputStream = resp.getOutputStream();//2.完成流的copybyte[] bytes = new byte[1024]; //創建一個字節數組,用于存儲文件內容。int len = 0; //定義一個變量 len,用于記錄每次讀取的字節長度。//循環讀取文件內容,每次最多讀取 1024 個字節,直到文件末尾while ((len = fileInputStream.read(bytes) )!= -1){outputStream.write(bytes,0,len); //將讀取到的字節數據寫入到輸出流中,發送給客戶端。}fileInputStream.close();}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doPost(req, resp);}
}
簡化流的copy
Apache Commons IO 是一個開源的 Java 庫,提供了許多實用的 IO
操作工具類,用于簡化文件和流的操作。它包含了各種用于文件操作、流操作、拷貝、比較、過濾、監聽等功能的工具類。
<dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version></dependency>
//2.完成流的copyIOUtils.copy(fileInputStream,outputStream);
4.案例:用戶登錄/用戶注冊
登錄注冊案例:https://blog.csdn.net/meini32/article/details/132305323