首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java Web 核心技術精華:Servlet 請求響應、資源訪問、編碼處理、轉發重定向完全指南

     編輯:Java 綜合教學

Java Web 核心技術精華:Servlet 請求響應、資源訪問、編碼處理、轉發重定向完全指南

Servlet 是 Java Web 開發的基石,掌握其請求處理、響應控制、資源加載、編碼處理、頁面跳轉等核心機制,是構建穩健 Web 應用的前提。本文系統整理 Servlet 核心知識點,涵蓋資源訪問差異、響應編碼最佳實踐、文件下載、請求參數獲取、轉發與重定向本質區別、路徑寫法規範等實戰高頻場景。

一、Web 資源訪問:Servlet vs 普通類

場景訪問方式核心 API優缺點
Servlet 內部ServletContextgetServletContext().getResourceAsStream("/path")標準、支持大文件、實時讀取更新
普通 Java 類類加載器Xxx.class.getClassLoader().getResourceAsStream("path")文件不能太大;類加載器緩存導致更新不生效

關鍵差異演示

// 1. ServletContext 方式 (推薦用於 Web 資源)
InputStream is1 = getServletContext().getResourceAsStream("/WEB-INF/config.properties");

// 2. 類加載器方式 (適用於 classpath 資源)
InputStream is2 = UserDao.class.getClassLoader().getResourceAsStream("config.properties");

// 3. 類加載器緩存問題演示
// 修改 properties 文件後:
// 方式1:讀取到最新內容
// 方式2:仍讀取舊內容 (類已加載進內存,不會重新加載)

// 4. 靜態代碼塊單次加載優化
static {
    // 僅首次加載類時執行,適合加載配置文件、初始化連接池
    loadConfig();
}

資源訪問方式對比

類加載器緩存問題

二、響應編碼與亂碼終極解決方案

1. 兩大核心設置

  • 服務端編碼:`response.setCharacterEncoding("UTF-8")` — 控制服務端以什麼編碼寫出數據
  • 客戶端解碼:`response.setHeader("Content-Type", "text/html;charset=UTF-8")` — 告訴瀏覽器以什麼編碼解析

2. 三種等效寫法

// 方式一:分別設置 (最底層)
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "text/html;charset=UTF-8");

// 方式二:meta 標籤模擬響應頭 (JSP 頁面用)
out.write("");

// 方式三:一行搞定 (推薦,內部調用上述兩個方法)
response.setContentType("text/html;charset=UTF-8");

響應編碼設置

3. 輸出流選擇

流類型獲取方式適用場景注意
PrintWriterresponse.getWriter()字符輸出:HTML、JSON、文本調用前必須先 setCharacterEncoding
ServletOutputStreamresponse.getOutputStream()字節輸出:文件下載、圖片、二進制不能與 getWriter() 混用

輸出流選擇

三、文件下載完整實現

1. 核心響應頭

// 強制瀏覽器彈出下載對話框,而非直接打開
response.setHeader("Content-Disposition", "attachment;filename=" + encodedFileName);

// 關鍵:中文文件名必須 URL 編碼
String encodedFileName = URLEncoder.encode(fileName, "UTF-8");

2. 完整下載 Servlet

@WebServlet("/download")
public class DownloadServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String fileName = req.getParameter("fileName");
        String realPath = getServletContext().getRealPath("/files/" + fileName);
        
        File file = new File(realPath);
        if (!file.exists()) {
            resp.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
        
        // 1. 設置響應頭
        resp.setContentType(getServletContext().getMimeType(fileName));
        resp.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
        resp.setContentLengthLong(file.length());
        
        // 2. 流式傳輸 (避免大文件 OOM)
        try (InputStream in = new BufferedInputStream(new FileInputStream(file));
             OutputStream out = resp.getOutputStream()) {
            byte[] buffer = new byte[8192];
            int len;
            while ((len = in.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }
        }
    }
}

四、請求參數獲取完全指南

1. 單值參數

String username = request.getParameter("username");

2. 多值參數 (checkbox、多選框)

String[] hobbies = request.getParameterValues("hobby");

3. 所有參數名

Enumeration names = request.getParameterNames();

4. 參數 Map (含多值)

Map paramMap = request.getParameterMap();

請求參數獲取

參數 Map 結構

5. 請求體原始數據 (JSON、XML)

五、轉發 vs 重定向:本質區別與選型

維度請求轉發重定向
APIrequest.getRequestDispatcher(path).forward(req, resp)response.sendRedirect(path)
請求次數1 次2 次 (服務端 302 → 瀏覽器新請求)
地址欄變化不變變為目標 URL
request 域對象共享同一 request新 request,數據丟失
訪問範圍僅限當前 Web 應用內部可跨應用、跨域、外部網站
路徑寫法相對 Web 應用根目錄相對容器根目錄 (需加項目名)
響應提交狀態forward 前未提交可轉發;已提交拋異常隨時可重定向
典型場景登錄校驗失敗回登錄頁、MVC 邏輯跳轉登錄成功跳首頁、支付完成跳結果頁、防表單重複提交

代碼對比

// 轉發
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
// 或
request.getRequestDispatcher("login.jsp").forward(request, response); // 相對當前路徑

// 重定向
response.sendRedirect(request.getContextPath() + "/index.jsp");
// 手動設置 302 (等效)
response.setStatus(302);
response.setHeader("Location", "/index.jsp");

關鍵點:轉發前 `response` 已提交內容會導致 `IllegalStateException`;轉發會清空 `response` 緩衝區但保留響應頭。

Web 路徑寫法規範

六、Web 應用中路徑寫法規範總結

場景參考基準寫法示例
請求轉發Web 應用根目錄/WEB-INF/jsp/xxx.jsp 或 相對路徑
重定向容器根目錄 (需項目名)/projectName/xxx.jsp 或 ${pageContext.request.contextPath}/xxx.jsp
Servlet @WebServletWeb 應用根目錄/user/login
jsp/includeWeb 應用根目錄/header.jsp
form action / a href容器根目錄 (瀏覽器發請求)/projectName/xxx.do
CSS/JS/圖片引用容器根目錄${pageContext.request.contextPath}/static/xxx.css

七、Servlet 與 JSP 協作最佳實踐

  1. Servlet 做控制器:接收請求、調用 Service、設置 request 屬性、轉發 JSP
  2. JSP 做視圖:EL 表達式 ``、`${user.name}` 渲染數據,無 Java 代碼
  3. 轉發後必須 return:防止繼續執行後續代碼導致異常或重複轉發
  4. 請求域傳遞數據:`request.setAttribute("key", value)`,轉發後 JSP 可取
@WebServlet("/user/show")
public class UserServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String id = req.getParameter("id");
        User user = userService.findById(Integer.parseInt(id));
        req.setAttribute("user", user);
        req.getRequestDispatcher("/WEB-INF/jsp/user/detail.jsp").forward(req, resp);
        return; // 關鍵!
    }
}

總結

Java Web 核心技術看似基礎,實則暗藏諸多坑點:資源訪問方式選擇影響配置熱更新;編碼設置順序決定中文是否亂碼;轉發重定向混用導致數據丟失或地址欄異常;路徑寫法不規範引發 404。建立「請求-響應-域對象-跳轉」完整心智模型,熟練掌握 `ServletContext`、`HttpServletRequest`、`HttpServletResponse` 三大核心對象的協作邊界,是從「能跑通」進階到「寫得穩、改得快、排錯準」的關鍵一步。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved