Servlet 容器(Tomcat/Jetty/Undertow)將 HTTP 請求封裝為 `HttpServletRequest`,響應封裝為 `HttpServletResponse`。掌握這兩個介面的核心 API,等於掌握了 Java Web 開發的「手腳」。本文通過實戰場景,系統梳理動態頁面生成、表單處理、Header/Cookie/Session 操作、重定向與轉發、MIME 類型與狀態碼控制。
@WebServlet("/time")
public class TimeServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8"); // 必須先設定,否則中文亂碼
PrintWriter out = resp.getWriter(); // 字符流,適用文本
String html = "當前時間: " + new Date() + "
";
out.println(html);
}
}
關鍵點:
@WebServlet("/register")
public class RegisterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 1. 設置請求編碼 (必須在 getParameter 前)
req.setCharacterEncoding("UTF-8");
// 2. 獲取參數
String username = req.getParameter("username");
String password = req.getParameter("password");
// 3. 業務邏輯 (省略:驗證、加密、入庫)
// 4. 響應
resp.setContentType("text/html;charset=UTF-8");
resp.getWriter().println("註冊成功,歡迎 " + username + "!
");
}
}
| 需求 | API | 示例 |
|---|---|---|
| 獲取請求方法 | `getMethod()` | `"GET"`, `"POST"`, `"PUT"` |
| 獲取請求 URL | `getRequestURL()` / `getRequestURI()` | `/app/register` |
| 獲取查詢字串 | `getQueryString()` | `username=zhang&age=20` |
| 獲取單個參數 | `getParameter(name)` | `req.getParameter("username")` |
| 獲取同名多值參數 | `getParameterValues(name)` | `String[] hobbies = req.getParameterValues("hobby")` |
| 獲取所有參數 Map | `getParameterMap()` | `Map |
| 獲取 Header | `getHeader(name)` / `getHeaders(name)` | `req.getHeader("User-Agent")` |
| 獲取 Cookie | `getCookies()` | `Cookie[] cookies = req.getCookies()` |
| 獲取 Session | `getSession()` / `getSession(false)` | `HttpSession session = req.getSession()` |
| 獲取輸入流 (文件上傳/JSON) | `getInputStream()` / `getReader()` | `InputStream is = req.getInputStream()` |
| 獲取客戶端 IP | `getRemoteAddr()` | `String ip = req.getRemoteAddr()` |
| 屬性作用域 (請求轉發共享) | `setAttribute(name, obj)` / `getAttribute(name)` | `req.setAttribute("user", userObj)` |
| 需求 | API | 示例 |
|---|---|---|
| 設置內容類型 | `setContentType(type)` | `resp.setContentType("application/json;charset=UTF-8")` |
| 設置狀態碼 | `setStatus(code)` | `resp.setStatus(HttpServletResponse.SC_NOT_FOUND)` |
| 發送重定向 | `sendRedirect(location)` | `resp.sendRedirect("/login.html")` (客戶端跳轉,地址欄變化) |
| 設置 Header | `setHeader(name, value)` / `addHeader` | `resp.setHeader("X-Custom", "value")` |
| 設置 Cookie | `addCookie(Cookie)` | `resp.addCookie(new Cookie("token", "abc123"))` |
| 設置 Content-Length | `setContentLength(len)` / `setContentLengthLong` | `resp.setContentLengthLong(file.length())` |
| 獲取輸出流 (二進制) | `getOutputStream()` | `ServletOutputStream os = resp.getOutputStream()` |
| 獲取字符流 (文本) | `getWriter()` | `PrintWriter out = resp.getWriter()` |
@WebServlet("/download")
public class DownloadServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String filename = "report.pdf";
File file = new File("/data/reports", filename);
resp.setContentType("application/pdf");
resp.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
resp.setContentLengthLong(file.length());
try (FileInputStream fis = new FileInputStream(file);
ServletOutputStream os = resp.getOutputStream()) {
fis.transferTo(os); // Java 9+ 高效傳輸
}
}
}
@WebServlet("/api/user")
public class UserApiServlet extends HttpServlet {
private final ObjectMapper mapper = new ObjectMapper();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
User user = userService.findById(req.getParameter("id"));
resp.setContentType("application/json;charset=UTF-8");
mapper.writeValue(resp.getOutputStream(), user); // 直接寫流,無中間字串
}
}
| 特性 | 請求轉發 `RequestDispatcher.forward()` | 重定向 `sendRedirect()` |
|---|---|---|
| 發起方 | 服務端內部 | 客戶端 (瀏覽器) |
| 地址欄 | 不變 | 改變 |
| 請求對象 | 共享同一 request/response | 新請求,舊 request 失效 |
| 可訪問資源 | WEB-INF 內部資源 | 僅公開 URL |
| 適用場景 | MVC Controller → JSP、內部流程跳轉 | 登入成功跳首頁、POST 後重定向 (PRG 模式) |
// 轉發
req.getRequestDispatcher("/WEB-INF/views/success.jsp").forward(req, resp);
// 重定向 (PRG 模式防重複提交)
resp.sendRedirect(req.getContextPath() + "/order/success");
`HttpServletRequest`/`HttpServletResponse` 是 Java Web 開發的「方向盤與踏板」。熟練掌握參數獲取、流操作、Header/Cookie/Session 控制、轉發重定向、MIME 與狀態碼,配合編碼過濾器、基類封裝、異常統一處理,即可構建清晰、健壯、高效的 Web 應用。下一篇將進階《Filter 與 Listener:攔截鏈與生命週期監聽實戰》。