HttpServlet
? ? ? ? init:當 tomcat 收到了 /hello 這樣的路徑是請求后就會調用 HelloServlet,于是就需要對 HelloServlet 進行實例化(只實例一次,后續再有請求也不實例了)。
? ? ? ? destory:如果是通過 smart tomcat 的停止按鈕,這個操作本質上是通過 tomcat 的 8005 端口主動停止,能夠觸發 destory。但如果是直接殺進程,此時很可能來不及執行 destory(這種情況比較常見)。
? ? ? ? service:每次收到請求都會先執行 service,然后再根據請求的類型調用對應的 doxxx。
因此:Servlet 的生命周期就可以理解為:1. 一開始的時候,執行 init;2. 每次收到請求,執行 service;3. 銷毀之前,執行 destory。
處理請求
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("/method")
public class MethodServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("doGet");resp.getWriter().write("doGet");}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("doPost");resp.getWriter().write("doPost");}@Overrideprotected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("doPut");resp.getWriter().write("doPut");}@Overrideprotected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("doDelete");resp.getWriter().write("doDelete");}
}
????????這里默認是 get 請求,為了構造別的方法請求可以使用 postman 來構造,也可以通過 Ajax 寫代碼來進行構造
postman
Ajax
首先得在 webapp 目錄下創建一個 .html 的文件
<!doctype html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport"content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title>
</head>
<body><!-- 使用這個頁面來構造 Ajax 請求 --><script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script><script>$.ajax({type: 'post',//這是相對路徑的寫法//url: 'method',//這是絕對路徑的寫法url: '/hello_servlet/method',success: function (body, status) {console.log(body);}});</script>
</body>
</html>
HttpServletRequest
????????當 Tomcat 通過 Socket API 讀取 HTTP 請求(字符串), 并且按照 HTTP 協議的格式把字符串解析成 HttpServletRequest 對象.
:因為 query string 是鍵值對形式(form 表單構造的 body 也是),所以就可以通過 getParameter 放法來根據 key 獲取到 value。
獲取 GET 請求中的參數
????????GET 請求中的參數一般都是通過 query string 傳遞給服務器的. 形如:/getParameter?studentId=10&classId=20
????????此時瀏覽器通過 query string 給服務器傳遞了兩個參數, studentId 和 classId, 值分別是 10?和 11,此時在服務器端就可以通過 getParameter 來獲取到參數的值.
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("/getParameter")
public class GetParameterServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 預期瀏覽器會發一個形如 /getParameter?studentId=10&classId=20 請求.// 借助 req 里的 getParameter 方法就能拿到 query string 中的鍵值對內容了.// getParameter 得到的是 String 類型的結果.String studentId = req.getParameter("studentId");String classId = req.getParameter("classId");resp.setContentType("text/html");resp.getWriter().write("studentId = " + studentId + " classId = " + classId);}
}
????????getParameter 的返回值類型為 String. 必要的時候需要手動把 String 轉成 int 。當沒有 query string的時候, getParameter 獲取的值為 null.
獲取 POST 請求中的參數
????????POST 請求的參數一般通過 body 傳遞給服務器. body 中的數據格式有很多種. 如果是采用 form 表單的形式, 仍然可以通過 getParameter 獲取參數的值(直接可以根據 key 獲取 value)。
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("/postParameter")
public class PostParameterServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String studentId = req.getParameter("studentId");String classId = req.getParameter("classId");resp.setContentType("text/html");resp.getWriter().write("studentId = " + studentId + " classId = " + classId);}
}
創建 testPost.html, 放到 webapp 目錄中:
<form action="postParameter" method="POST"><input type="text" name="userId"><input type="text" name="classId"><input type="submit" value="提交">
</form>
form 表單點擊?提交 一定會發生頁面跳轉的
獲取 POST 請求中的參數(2)
????????如果 POST 請求中的 body 是按照 JSON 的格式來傳遞, 那么獲取參數的代碼就要發生調整。因為通過 json 傳遞數據,服務器這邊默認是把整個 body 都讀過來,即沒有按照鍵值對的方式來處理,也就不能根據 key 獲取 value。
? ? ? ? 因此,要使用第三方庫 “Jackson” 來解析 json 格式。在 maven 倉庫里搜 Jackson,然后選一個版本點進去把 xml 片段粘貼到 pom.xml 的 <dependencies> 中即可。
import com.fasterxml.jackson.databind.ObjectMapper;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;class Student {// 把屬性設為 public 的原因是能讓 外面的Jackson 獲取到這里有什么屬性public int studentId;public int classId;
}@WebServlet("/postParameter2")
public class PostParameter2Servlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 這段注釋的代碼是沒有時候第三方庫 Jackson 的,得到的是沒有被處理過的 json// 通過這個方法來處理 body 為 json 格式的數據.// 直接把 req 對象里 body 完整的讀取出來.// getInputStream// 在流對象中讀多少個字節? 取決于 Content-Length
// int length = req.getContentLength();
// byte[] buffer = new byte[length];
//
// InputStream inputStream = req.getInputStream();
// inputStream.read(buffer);
//
// // 把這個字節數組構造成 String, 打印出來.
// String body = new String(buffer, 0, length, "utf8");
// System.out.println("body = " + body);
// resp.getWriter().write(body);// 使用 jackson 涉及到的核心對象.ObjectMapper objectMapper = new ObjectMapper();// readValue 就是把一個 json 格式的字符串轉成 Java 對象.// writeValue 把一個 java 對象轉成 json 格式字符串Student student = objectMapper.readValue(req.getInputStream(), Student.class);System.out.println(student.studentId + ", " + student.classId);}
}
HttpServletResponse
? ? ? ??Servlet 中的 doXXX 方法的目的就是根據請求計算得到相應, 然后把響應的數據設置到
HttpServletResponse 對象中. 然后 Tomcat 就會把這個 HttpServletResponse 對象按照 HTTP 協議的格式, 轉成一個字符串, 并通過 Socket 寫回給瀏覽器.
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("/redirect")
public class RedirectServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// resp.sendRedirect("https://www.bilibili.com"); // 這是直接構造了重定向響應// 上面的一行代碼也可以分成下面兩行:先設置狀態碼,然后再設置需要跳轉到哪里resp.setStatus(302);resp.setHeader("Location", "https://www.bilibili.com");}
}