1. 程式人生 > 實用技巧 >JavaWeb - Respnse響應訊息、ServletContext物件

JavaWeb - Respnse響應訊息、ServletContext物件

1.響應訊息資料格式

   1. 響應行

    1. 組成:協議 / 版本 響應狀態碼 狀態碼描述 如:HTTP/1.1 200 OK

    2. 響應狀態碼:伺服器告訴客戶端瀏覽器本次請求和響應的一個狀態

      1. 狀態碼都是3位數字

      2. 分類:

        1. 1xx:伺服器接收客戶端訊息,但沒有接收完成,等待一段時間後,傳送1xx多狀態碼

        2. 2xx:成功。代表:200

        3. 3xx:重定向。代表:302(重定向) 304(訪問快取)

        4. 4xx:客戶端錯誤。代表:404(請求路徑沒有對應的資源)405(請求方式沒有對應的doXxx方法)

        5. 5xx:伺服器端錯誤。代表:500(伺服器內部出現異常)

  2. 響應頭

    1. 格式:頭名稱:值

    2. 常見的響應頭:

      1. Content - Type:伺服器告訴客戶端本次響應訊息體資料格式以及編碼格式

      2. Content - disposition:伺服器告訴客戶端以什麼格式開啟響應體資料

        * 值:

          * in - line:預設值,在當前頁面內開啟

          * attachment(filename=xxx):以附件形式開啟響應體。檔案下載時使用

  3. 響應空行

  4. 響應體

  * 字串格式:

2.Response

  * 功能:設定相應訊息

    1. 設定響應行

      1. 格式: HTTP/1.1 200 ok

      2. 設定狀態碼:setStatus(int sc)

    2. 設定響應頭

      1. setHeader(String name,String value)

    3. 設定響應體

      * 使用步驟:

        1. 獲取輸出流

          * 字元輸出流:PrintWriter getWriter()

          * 位元組輸出流:ServletOutputStream getOutputStream()

        2. 使用輸出流,將資料輸出到客戶端瀏覽器

response.setStatus(302);
response.setHeader("location","/web_servlet/respnseDemo01")

  ### 簡單的重定向方法:sendRedirect()

  * 重定向的特點:

    1. 位址列發生變化

    2. 重定向可以訪問其他站點(伺服器)的資源

    3. 重定向是兩次請求。不能使用request域來共享資料了

  * 轉發的特點:

    1. 轉發位址列路徑不變

    2. 轉發只能訪問當前伺服器下的資源

    3. 轉發是一次請求,可以使用request物件來共享資料

  * 面試題:forward和redirect的區別,既轉發和重定向的區別

  * 路徑寫法:

    1. 路徑分類

      1. 相對路徑:通過相對路徑不可以確定唯一資源

        * 如: . / index.html 或 ../ index.html

        * 不以 / 開頭,以 . 開頭

        * 規則:找到訪問當前資源和目標資源的相對位置關係 . / 代表當前目錄 . . / 代表後退一級的目錄

      2. 絕對路徑:通過絕對路徑可以確定唯一資源

        * 如: http://localhost/web_servlet/ResponseDemo01 或 /web_servlet/ResponseDemo01

        * 以 / 開頭的路徑

        * 規則:判斷定義的路徑是給誰用的?判斷請求將來從哪發出

          * 給客戶端瀏覽器使用:需要加虛擬目錄(專案的訪問路徑),重定向就是客戶端發出的,需要加虛擬目錄

            * 建議:之後動態獲取虛擬目錄 request.getContextPath() 來獲取

            * 如:<a> <href> 重定向

          * 給伺服器使用:不需要加虛擬目錄 如:轉發路徑

          

3. 伺服器輸出字元資料到瀏覽器

  * 步驟:

    1. 獲取字元輸出流

    2. 輸出資料

  * 注意:

    * 亂碼問題:

      1. PrintWriter pw = response.getWriter(); 獲取的流的預設編碼是ISO-8859-1的拉丁編碼

      2. 設定該流的預設編碼和響應體資料使用的編碼:response.setContentType("text/html;charset=utf-8"); 在獲取流之前設定

 @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //告訴瀏覽器,伺服器傳送的訊息體資料的編碼
        response.setHeader("Content-type","text/html;charset=utf-8");

        //簡單形式設定編碼
        response.setContentType("text/html;charset=utf-8");

        //1.獲取字元輸出流
        PrintWriter pw = response.getWriter();

        //2.輸出資料
        pw.write("hello response");
    }

4. 案例:驗證碼

  1. 本質:圖片

  2. 目的:防止惡意表單註冊

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script>
        window.onload = function () {
            // 1.獲取圖片物件
            var img = document.getElementById("checkcode");
            // 2.繫結單擊事件
            img.onclick = function () {
                //加時間戳
                var date = new Date().getTime();
                //因為瀏覽器會從快取裡拿圖片,而不是重新請求,所以我們修改路徑,通過傳參,達到修改了路徑
                img.src= "/servlet3/checkCode?" + date;
            };

            document.getElementById("change").onclick = function () {
                // 1.獲取圖片物件
                var img = document.getElementById("checkcode");
                //加時間戳
                var date = new Date().getTime();
                //因為瀏覽器會從快取裡拿圖片,而不是重新請求,所以我們修改路徑,通過傳參,達到修改了路徑
                img.src= "/servlet3/checkCode?" + date;
            }
        }

    </script>
</head>
<body>
    <img id="checkcode" src="/servlet3/checkCode">
    <a id="change" href="">看不清,換一張</a>
</body>
</html>
註冊頁面
package web.servlet;

import javax.imageio.ImageIO;
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.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

@WebServlet("/checkCode")
public class CheckCode extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        int width = 100;
        int height = 50;
        // 1.建立一物件,在記憶體中的圖片(驗證碼圖片物件)
        BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);

        // 2. 美化圖片
        // 2.1 填充背景色
        Graphics graphics = image.getGraphics(); //畫筆物件
        // 設定畫筆填充顏色
        graphics.setColor(Color.PINK);
        graphics.fillRect(0,0,width,height);

        // 2.2 畫邊框
        graphics.setColor(Color.BLUE);
        graphics.drawRect(0,0,width-1,height-1);


        String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        // 生產隨機角標
        Random random = new Random();

        for (int i = 1; i <= 4; i++) {
            int index = random.nextInt(str.length());
            // 獲取字元
            char random_char = str.charAt(index);
            // 2.3 寫驗證碼
            graphics.drawString(random_char+"",width/5*i,height/2);
        }

        // 2.4畫干擾線
        graphics.setColor(Color.GREEN);

        for (int i = 0; i < 10; i++) {
            // 隨機生成座標點
            int x1 = random.nextInt(width);
            int x2 = random.nextInt(width);
            int y1 = random.nextInt(height);
            int y2 = random.nextInt(height);
            graphics.drawLine(x1,y1,x2,y2);
        }

        // 3.將圖片輸出到頁面展示
        ImageIO.write(image,"jpg",response.getOutputStream());

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}
驗證碼生產的Servlet

5. ServletContext物件

  1. 概念:代表整個web應用,可以和程式的容器(伺服器)來通訊

  2. 獲取:

    1. 通過request物件來獲取

      request.getServletContext();

    2. 通過HttpServlet獲取

      this.getServletContext();

  3. 功能:

    1. 獲取MIME型別:

      * MIME型別:在網際網路通訊過程中定義的一種檔案資料型別

        * 格式:大型別 / 小型別 text / html image / jpeg

      * 獲取:String getMimeType(String file)

    2. 域物件:共享資料

      1. setAttribute(String name,Object value)

      2. getAttribute(String name)

      3. removeAttribute(String name)

      * ServletContext物件範圍:可共享所有使用者所有請求的資料

    3. 獲取檔案的真實(伺服器)路徑(檢視檔案的工作空間路徑)Using CATALINA_BASE 對應的路徑去找 conf / Catalina / localhost 下的xml文件中

      1. 方法:String getRealPath(String path)

        * web目錄下的資源路徑寫法:/ a.txt

        * WEB - INF目錄下的資源路徑寫法:/ WEB - INF / a.txt

        * src目錄下的資源路徑寫法:WEB - INF / classes / a.txt

6. 案例:圖片及任何檔案下載

  * 使用響應頭設定資源的開啟方式:

    * content - dispostion:attachment;filename=xxx

  * 步驟:

    1. 定義頁面,編輯超連結的href屬性,指向servlet,傳遞資源名稱filename

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>圖片下載</title>
</head>
<body>
    <a href="img/九尾.jpg">九尾圖片</a>
    <hr/>
    <a href="/case_download/downloadServlet?filename=九尾.jpg">九尾圖片</a>
</body>
</html>
下載頁面

    2. 定義servlet

      1. 獲取檔名稱

      2. 使用位元組輸入流載入檔案進記憶體

      3. 指定response的響應頭:content - dispostion:attachment;filename=xxx

      4. 將資料寫出到response的輸出流

package download;

import utils.DownLoadUtils;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;

@WebServlet("/downloadServlet")
public class DownloadServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.獲取請求引數,檔名稱
        String filename = request.getParameter("filename");

        // 2. 使用位元組輸入流載入檔案進記憶體
        // 2.1 找到檔案的伺服器路徑
        ServletContext servletContext = this.getServletContext();
        String realPath = servletContext.getRealPath("/img/" + filename);
        // 2.2 用位元組流關聯
        FileInputStream fis = new FileInputStream(realPath);

        //3. 設定response的響應頭
        //3.1 設定響應頭型別:content-type
        String mimeType = servletContext.getMimeType(filename);//獲取檔案的mime型別
        response.setHeader("content-type",mimeType);

        //3.2 設定響應頭開啟方式 content-disposition

        //解決中文檔名問題
        //1. 獲取user-agent請求頭
        //2. 使用工具類方法編碼檔名
        String agent = request.getHeader("user-agent");
        filename = DownLoadUtils.getFileName(agent, filename);

        response.setHeader("content-disposition","attachment;filename="+filename);

        //4. 將輸入流的資料寫入到輸出流中
        ServletOutputStream sos = response.getOutputStream();
        byte[] buff = new byte[1024*8];
        int len = 0;
        while ((len = fis.read(buff))!=-1){
            sos.write(buff,0,len);
        }
        fis.close();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}
下載的Servlet

  * 問題:

    * 中文檔名問題:

      * 解決思路:

        1. 獲取客戶端使用的瀏覽器版本資訊

        2. 根據不同的版本資訊,響應不同的資料,設定filename的編碼格式不同

package utils;

import sun.misc.BASE64Encoder;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Base64;


public class DownLoadUtils {

    public static String getFileName(String agent, String filename) throws UnsupportedEncodingException {
        if (agent.contains("MSIE")) {
            // IE瀏覽器
            filename = URLEncoder.encode(filename, "utf-8");
            filename = filename.replace("+", " ");
        } else if (agent.contains("Firefox")) {
            // 火狐瀏覽器
            BASE64Encoder base64Encoder = new BASE64Encoder();
            filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
        } else {
            // 其它瀏覽器
            filename = URLEncoder.encode(filename, "utf-8");
        }
        return filename;
    }
}
中文亂碼utils包,jdk8用,jdk9要轉換