【Servlet教科書】Servlet之狀態管理總結(Cookie、Session、ServletContext、Request大總結)

文章目錄

一、狀態管理介紹

1.1 什麼是狀態管理

WEB應用中的會話是指一個客戶端瀏覽器與WEB服務器之間連續發生的一系列請求和響應過程。
WEB應用的會話狀態是指WEB服務器與瀏覽器在會話過程中產生的狀態信息,藉助會話狀態,WEB服務器能夠把屬於同一會話中的一系列的請求和響應過程關聯起來並達成數據共享

1.2 爲什麼需要狀態管理

HTTP協議是無狀態的,不能保存每次提交的信息,即當服務器返回與請求相對應的應答之後,這次事務的所有信息就丟掉了。 如果用戶發來一個新的請求,服務器無法知道它是否與上次的請求有聯繫。 對於那些需要多次提交數據才能完成的Web操作,比如登錄來說,就成問題了。通俗一點的例子就是,我們登錄了在Github頁面登錄了,關閉頁面之後,再次打開頁面是不是發現你的Github還是保持你的賬號登錄的狀態呢?這就是狀態管理的作用!

1.3 狀態管理的兩種常見模式

客戶端狀態管理技術:將狀態保存在客戶端。代表性的是Cookie技術。

服務器狀態管理技術:將狀態保存在服務器端。代表性的是Session技術(服務器傳遞SessionID時需要使用Cookie的方式)。

二、狀態管理之Cookie應用

2.1 什麼是Cookie

​ Cookie是在瀏覽器訪問WEB服務器的某個資源時,由WEB服務器在HTTP響應消息頭中附帶傳送給瀏覽器的一小段數據,WEB服務器傳送給各個客戶端瀏覽器的數據是可以各不相同的。
一旦WEB瀏覽器保存了某個Cookie,那麼它在以後每次訪問該WEB服務器時,都應在HTTP請求頭中將這個Cookie回傳給WEB服務器。
WEB服務器通過在HTTP響應消息中增加Set-Cookie響應頭字段將Cookie信息發送給瀏覽器,瀏覽器則通過在HTTP請求消息中增加Cookie請求頭字段將Cookie回傳給WEB服務器。
一個Cookie只能標識一種信息,它至少含有一個標識該信息的名稱(NAME)和設置值(VALUE)。
一個WEB站點可以給一個WEB瀏覽器發送多個Cookie,一個WEB瀏覽器也可以存儲多個WEB站點提供的Cookie。
瀏覽器一般只允許存放300個Cookie,每個站點最多存放20個Cookie,每個Cookie的大小限制爲4KB。但是要知道現在的技術可以傳輸數據的方式有很多,而且瀏覽器也可以對Cookie存放的最大數量做擴容機制,所以改限制不是一成不變的!

2.2 創建Cookie對象

		/**
         * 創建一個Cookie對象
         * 默認生命週期爲:瀏覽器關閉
         */
        Cookie cookie = new Cookie("username", "ziph");
        /**
         * 更新Cookie的生命週期:負數->瀏覽器內存裏  0->失效   正數->過期時間
         * </p>
         * 過期時間以秒爲單位,如下表示:
         * 瀏覽器請求後Cookie存活60秒,60秒過後就會過期
         */
        cookie.setMaxAge(60);
        /**
         * 設置Cookie的共享範圍: 默認同一項目下   /->當前服務器下
         */
        cookie.setPath("/");
        /**
         * 將Cookie對象響應給瀏覽器
         */
        response.addCookie(cookie);
2.2.1 關於Cookie生命週期的設置

設置Cookie生命週期時間核心代碼:cookie.setMaxAge(); (設置生命週期爲60秒)

  • 設置時間值說明:
    • 正數:有效期(單位:秒)
    • 0:失效
    • 負數:內存存儲
		/**
         * 更新Cookie的生命週期:負數->瀏覽器內存裏  0->失效   正數->過期時間
         * </p>
         * 過期時間以秒爲單位,如下表示:
         * 瀏覽器請求後Cookie存活60秒,60秒過後就會過期
         */
        cookie.setMaxAge(60);
2.2.2 關於Cookie共享範圍的設置

cookie 一般都是由於用戶訪問頁面而被創建的,可是並不是只有在創建 cookie 的頁面纔可以訪問這個cookie。在默認情況下,出於安全方面的考慮,只有與創建 cookie 的頁面處於同一個目錄或在創建cookie頁面的子目錄下的網頁纔可以訪問。那麼此時如果希望其父級或者整個網頁都能夠使用cookie,就需要進行路徑的設置。

關於Cookie的共享範圍,默認是同一項目下。而設置"/"可以在同意服務器下共享

		/**
         * 設置Cookie的共享範圍: 默認同一項目下   /->當前服務器下
         */
        cookie.setPath("/");
2.2.3 遍歷查詢Cookie
        /**
         * 1.獲取所有Cookie
         * 2.非空判斷
         * 3.遍歷Cookies數組
         * 4.檢查遍歷Cookie並獲取name值是否爲username
         * 5.檢查遍歷Cookie並獲取value值是否爲ziph
         * 6.兩步檢查都沒有問題,則打印提示信息
         */
        Cookie[] cookies = request.getCookies();
        if (cookies != null && cookies.length != 0) {
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals("username")) {
                    if (cookie.getValue().equals("ziph")) {
                        System.out.println("您已登錄!不用重新登錄!");
                    }
                }
            }
        }

2.3 Cookie的編碼與解碼問題

中文和英文字符不同,中文屬於Unicode字符,在內存中佔用4個字符,而英文屬於ASCII字符,內存中只佔2個字節。Cookie中使用Unicode字符時需要對Unicode字符進行編碼,否則會出現亂碼。編碼可以使用java.net.URLEncoder類的encode(String str,String encoding)方法,解碼使用java.net.URLDecoder類的decode(String str,String encoding)方法

		/**
         * Cookie的編碼
         * URLEncoder.encode("username", "utf-8")
         */
        Cookie cookie = new Cookie(URLEncoder.encode("username", "utf-8"), URLEncoder.encode("ziph", "utf-8"));
        /**
         * Cookie的解碼
         * URLDecoder.decode(cookie.getName(), "utf-8")
         */
        if (cookies.length != 0) {
            for (Cookie cookie : cookies) {
                if (URLDecoder.decode(cookie.getName(), "utf-8").equals("username")) {
                    if (URLDecoder.decode(cookie.getValue(), "utf-8").equals("ziph")) {
                        System.out.println("您已登錄!不用重新登錄!");
                    }
                }
            }
        }

2.4 發送Cookie的條件

瀏覽器在發送請求之前,首先會根據請求url中的域名在cookie列表中找所有與當前域名一樣的cookie,然後再根據指定的路徑進行匹配,如果當前請求在域匹配的基礎上還與路徑匹配那麼就會將所有匹配的cookie發送給服務器。

2.5 設置Cookie路徑

通過Cookie的setPath方法設置路徑

2.5 Cookie的優缺點

2.5.1 Cookie的優點

可配置到期規則: Cookie 可以在瀏覽器會話結束時到期,或者可以在客戶端計算機上無限期存在,這取決於客戶端的到期規則,不需要任何服務器資源,Cookie 存儲在客戶端並在發送後由服務器讀取。
簡單性: Cookie 是一種基於文本的輕量結構,包含簡單的鍵值對。
數據持久性: 雖然客戶端計算機上 Cookie 的持續時間取決於客戶端上的 Cookie 過期處理和用戶干預,Cookie 通常是客戶端上持續時間最長的數據保留形式

2.5.2 Cookie的缺點

大小受到限制: 大多數瀏覽器對 Cookie 的大小有 4096 字節的限制,儘管在當今新的瀏覽器和客戶端設備版本中,支持 8192 字節的 Cookie 大小已愈發常見。
用戶配置爲禁用: 有些用戶禁用了瀏覽器或客戶端設備接收 Cookie 的能力,因此限制了這一功能。
潛在的安全風險: Cookie 可能會被篡改。用戶可能會操縱其計算機上的 Cookie,這意味着會對安全性造成潛在風險或者導致依賴於Cookie 的應用程序失敗。

2.6 Cookie綜合案例之站點獲取上一次訪問時間

關於訪問站點,每一次訪問都可以使用Cookie來記錄時間,功能實現爲本次訪問獲取上一次訪問的系統時間。(注意:第一次訪問時是沒有上一次訪問時間的,我們記錄並打印第一次訪問時間即可!)

代碼展示在下面,註釋中記載着詳細步驟:

package com.mylifes1110.java.demo.cookievisit;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 獲取上一次訪問的時間案例
 */
@WebServlet(name = "CookieVisitServlet", value = "/cv")
public class CookieVisitServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /**
         * 1.獲取Cookie對象的數組
         * 2.非空判斷
         * 3.遍歷Cookie對象數組
         * 4.尋找lastTime相同名字的Cookie對象
         * 5.保存到臨時cookie_avl中
         */
        Cookie[] cookies = request.getCookies();
        Cookie cookie_avl = null;
        if (cookies != null && cookies.length != 0) {
            for (Cookie cookie : cookies) {
                if ("lastTime".equals(cookie.getName())) {
                    cookie_avl = cookie;
                }
            }
        }
        /**
         * 1.創建時間格式化對象並指定格式
         * 2.判斷臨時cookie_avl對象是否爲空
         * 3.cookie_avl對象爲空,證明該站點是被第一次訪問
         * 4.獲取當前時間對象
         * 5.打印第一次訪問時間(第一次訪問肯定沒有上一次訪問時間啊)
         * 6.獲取當前時間毫秒值(因爲Cookie是需要傳入字符串,我們這裏用空字符串做拼接,轉換爲字符串傳入參數)存入cookie_avl對象
         * 7.操作cookie_avl對象併發出響應
         */
        SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");
        if (cookie_avl == null) {
            Date currentDate = new Date();
            System.out.println("第一次訪問時的時間爲:" + format.format(currentDate));
            cookie_avl = new Cookie("lastTime", currentDate.getTime() + "");
        } else {
            /**
             * 1.獲取上一次cookie_avl對象中的時間字符串,並將字符串轉換爲毫秒值
             * 2.把毫秒值轉換爲該時間格式化的時間對象
             * 3.打印上一次訪問的時間對象
             * 4.獲取當前時間對象的毫秒值,並傳入cookie_avl對象中保存
             * 5.操作cookie_avl對象併發出響應
             */
            long currentTimeMills = Long.parseLong(cookie_avl.getValue());
            Date lastDate = new Date(currentTimeMills);
            String lastDateStr = format.format(lastDate);
            System.out.println("上一次訪問時間爲:" + lastDateStr);
            Date currentDate = new Date();
            cookie_avl.setValue(currentDate.getTime() + "");
        }
        response.addCookie(cookie_avl);
    }
}

2.7 Cookie綜合案例之顯示瀏覽記錄

頁面顯示商品,加入瀏覽記錄放到Cookie中,通過顯示瀏覽記錄響應瀏覽器

HTML頁面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>圖書商城</title>
</head>
<body>
<h1>商品列表</h1>
<a href="/reqweb/history?id=0">《Java編程思想》</a><br>
<a href="/reqweb/history?id=1">《Java核心卷》</a><br>
<a href="/reqweb/history?id=2">《算法》</a><br>
<a href="/reqweb/history?id=3">《Ziph的博客》</a><br>
</body>
</html>

商品記錄的Servlet

package com.mylifes1110.java.books.servlet;

import com.mylifes1110.java.books.utils.CookieUtils;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 商品瀏覽記錄
 * 注意:我們將瀏覽記錄存儲在cookie_val對象中,以便後續展示頁面取出加工後響應展示給瀏覽器
 */
@WebServlet(name = "HistoryBooksServlet", value = "/history")
public class HistoryBooksServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /**
         * 封裝工具類的使用
         */
        Cookie cookie_val = CookieUtils.getCookie(request.getCookies(), "history");

        /**
         * 1.獲得一個Cookie數組對象
         * 2.非空判斷
         * 3.遍歷Cookie數組
         * 4.查詢cookie的名字爲history的Cookie對象
         * 5.把查詢到的該Cookie對象賦值給臨時cookie_val中,以便後續使用
         * <p>
         * 注意:該方法被註釋掉,是因爲我們使用了封裝好的工具類來實現複用性
         */
//        Cookie cookie_val = null;
//        Cookie[] cookies = request.getCookies();
//        if (cookies != null && cookies.length != 0) {
//            for (Cookie cookie : cookies) {
//                if ("history".equals(cookie.getName())) {
//                    cookie_val = cookie;
//                }
//            }
//        }

        /**
         * 第一次瀏覽,沒有任何瀏覽記錄
         * <p>
         * 1.獲取請求參數對應的值(字符串)
         * 2.如果cookie_val中爲空,那就證明站點的該內容目前沒有訪問記錄,也就是說這是該內容的第一次訪問
         * 3.第一次訪問作爲該內容的瀏覽記錄存儲到Cookie對象中,以便後續有瀏覽記錄的條件下從Cookie數組對象中取出
         * 4.操作cookie_val對象併發起響應
         * 5.轉發至顯示瀏覽記錄的頁面(展示頁面來做提示沒有瀏覽記錄的操作)
         */
        String id = request.getParameter("id");
        if (cookie_val == null) {
            cookie_val = new Cookie("history", id);
        } else {
            /**
             * 已經有了一些記錄,但是不包含當前瀏覽內容的記錄
             * <p>
             * 1.獲取cookie_val書名對應的值,也就是說獲取記錄中的id
             * 2.判斷記錄中的id是否包含目前瀏覽的id,沒有包含的話,執行以下操作
             * 3.沒有執行的話,將新id拼接到原記錄id後(注意:使用“-”是爲了後續拆分)
             * 4.將拼接好的記錄字符串繼續存儲到cookie_val中
             * 5.操作cookie_val對象併發起響應
             * 6.轉發至顯示瀏覽記錄的頁面(展示頁面來展示瀏覽記錄信息操作)
             */
            String historyStr = cookie_val.getValue();
            if (!historyStr.contains(id)) {
                historyStr += "-" + id;
                cookie_val.setValue(historyStr);
            } else {
                /**
                 * 已經有了一些記錄,但是包含當前瀏覽器瀏覽的內容記錄
                 * <p>
                 * 不做任何操作!
                 */
            }
        }
        /**
         * 1.操作cookie_val對象併發起響應
         * 2.轉發至顯示瀏覽記錄的頁面
         */
        response.addCookie(cookie_val);
        request.getRequestDispatcher("/show").forward(request, response);
    }
}

顯示商品的Servlet

package com.mylifes1110.java.books.servlet;

import com.mylifes1110.java.books.utils.CookieUtils;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 顯示瀏覽記錄
 * 注意:訪問記錄是從我們之前存儲的瀏覽記錄的cookie_val對象中取出並做加工處理響應瀏覽器
 */
@WebServlet(name = "ShowHistoryServlet", value = "/show")
public class ShowHistoryServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /**
         * 封裝工具類的使用
         */
        Cookie cookie_val = CookieUtils.getCookie(request.getCookies(), "history");

        /**
         * 1.獲得一個Cookie數組對象
         * 2.非空判斷
         * 3.遍歷Cookie數組
         * 4.查詢cookie的名字爲history的Cookie對象
         * 5.把查詢到的該Cookie對象賦值給臨時cookie_val中,以便後續使用
         * <p>
         * 注意:該方法被註釋掉,是因爲我們使用了封裝好的工具類來實現複用性
         */
//        Cookie cookie_val = null;
//        Cookie[] cookies = request.getCookies();
//        if (cookies != null && cookies.length != 0) {
//            for (Cookie cookie : cookies) {
//                if ("history".equals(cookie.getName())) {
//                    cookie_val = cookie;
//                }
//            }
//        }

        /**
         * 1.創建可變長字符串以便後續將cookie_val中的字符串拆分使用
         * 2.判斷cookie_val爲空,提示沒有瀏覽記錄,並跳轉書城主頁進行瀏覽
         * 3.將最後拼接的可變長字符串調用toString方法響應給瀏覽器
         */
        StringBuffer buffer = new StringBuffer();
        if (cookie_val == null) {
            buffer.append("<font color='red'>您沒有瀏覽記錄</font><br>");
            buffer.append("<a href='books.html'>書城主頁</a><br>");
        } else {
            /**
             * 1.cookie_val不爲空,意爲有了瀏覽記錄字符串,需要加工處理返回每個id對應的書名並響應給客戶端
             * 2.得到cookie_val中的字符串值
             * 3.把字符串值以“-”做拆分,拆分成單個id數字字符串(id數字字符串是以數組的形式存儲的)
             * 4.可變長字符串拼接瀏覽記錄提示語
             * 5.創建一個對應id的書名數組,以便後續我們通過拆分後的id來獲取對應的書名
             * 5.遍歷拆分後的數組將id字符串轉換爲數值(int)作爲下標並取出該下標在書名數組中對應的書名
             * 6.可變長字符串拼接書名
             * 7.將最後拼接的可變長字符串調用toString方法響應給瀏覽器
             */
            String[] books = {"《Java編程思想》", "《Java核心卷》", "《算法》", "《Ziph的博客》"};
            String historyStr = cookie_val.getValue();
            String[] history = historyStr.split("-");
            buffer.append("您的瀏覽記錄如下:<br>");
            for (String s : history) {
                String book = books[Integer.parseInt(s)];
                buffer.append(book + "<br>");
            }
        }
        /**
         * 解決響應給瀏覽器的中文亂碼問題
         */
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().println(buffer.toString());
    }
}

封裝工具類

package com.mylifes1110.java.books.utils;

import javax.servlet.http.Cookie;

/**
 * 封裝工具類
 * 將重複代碼獲取Cookie對象並判斷是否爲該名的cookie對象做了封裝,實現了複用
 */
public class CookieUtils {
    public static Cookie getCookie(Cookie[] cookies, String cookieName) {
        if (cookies != null && cookies.length != 0) {
            for (Cookie cookie : cookies) {
                if (cookieName.equals(cookie.getName())) {
                    return cookie;
                }
            }
        }
        return null;
    }
}

三、認識域對象

3.1 什麼是域對象

可以存儲數據的對象,從而實現從對象中存儲和取出

3.2 常見的域對象有什麼?

  1. Session (Session域)
  2. Request (Request域)
  3. ServletContext (ServletContext域)

注意:前面章節提到過,Session也是一個狀態管理技術

四、狀態管理之Sesstion應用

4.1 什麼是Session

Session用於跟蹤客戶端的狀態。Session指的是在一段時間內,單個客戶與Web服務器的一連串相關的交互過程。
在一個Session中,客戶可能會多次請求訪問同一個網頁,也有可能請求訪問各種不同的服務器資源。

4.2 Session的工作原理

​ session被用於表示一個持續的連接狀態,在網站訪問中一般指代客戶端瀏覽器的進程從開啓到結束的過程。session其實就是網站分析的訪問(visits)度量,表示一個訪問的過程。

​ session的常見實現形式是cookie(session cookie),即未設置過期時間的cookie,這個cookie的默認生命週期爲瀏覽器會話期間,只要關閉瀏覽器窗口,cookie就消失了。實現機制是當用戶發起一個請求的時候,服務器會檢查該請求中是否包含sessionid,如果未包含,則Tomcat會創造一個名爲JSESSIONID的輸出 cookie返回給瀏覽器(只放入內存,並不存在硬盤中),並將其以HashTable(鍵值對)的形式寫到服務器的內存裏面;當已經包含sessionid時,服務端會檢查找到與該session相匹配的信息,如果存在則直接使用該sessionid,若不存在則重新生成新的 session。這裏需要注意的是session始終是由服務端創建的,並非瀏覽器自己生成的。

4.3 如何獲取Session

        /**
         * 獲取Session對象中的id(唯一標記)
         * A827D88EE704FE070A912BE908E64954
         */
        HttpSession session = request.getSession();
        System.out.println("SessionID爲:"+session.getId());

        /**
         * 獲取Session對象的空閒時間(單位:秒)
         * 默認Session失效時間爲1800(30分鐘)
         * 1800
         */
        System.out.println("此Session對象"+session.getMaxInactiveInterval()+"秒後失效!");

        /**
         * 獲取Session對象的創建時間(單位:毫秒)
         */
        System.out.println("Session的創建時間:" + session.getCreationTime());

        /**
         * 獲取Session對象的最後一次訪問時間(單位:毫秒)
         */
        System.out.println("Session的最後一次訪問時間:"+session.getLastAccessedTime());

如下是我獲取的Session的內容:

SessionID爲:C8F34002131D14631E15BA7DF5C47C49
此Session對象1800秒後失效!
Session的創建時間:1587201492030
Session的最後一次訪問時間:1587201557924
SessionID爲:C8F34002131D14631E15BA7DF5C47C49
此Session對象1800秒後失效!
Session的創建時間:1587201492030
Session的最後一次訪問時間:1587201620359

注意:如下圖片找到了打開Google的SessionID,並確定它仍然生效!(如何打開Google查詢Cookie,下一章節,我介紹給大家!)

在這裏插入圖片描述

4.4 關於Google怎麼查看Cookie

查看步驟: 以前步驟可以查看Google的Cookie(我已用圖解的方法展示給大家了!)

網址欄直接跳轉訪問查看Cookie: chrome://settings/content/cookies

在這裏插入圖片描述

在這裏插入圖片描述

在這裏插入圖片描述

在這裏插入圖片描述

4.5 使用Session綁定對象

使用HttpSession的setAttribute(屬性名,Object)方法實現綁定對象

		//第一個Servlet代碼
		HttpSession session = request.getSession();
        System.out.println("SessionID爲:" + session.getId());
		/**
         * 使用Session來綁定對象
         */
        Test test = new Test();
        test.name = "Ziph";
        test.age = 18;
        session.setAttribute("name", test);

//第一個Servlet代碼中的測試類
/**
 * 使用Session來綁定對象的測試類
 */
class Test {
    String name;
    int age;

    @Override
    public String toString() {
        return "Test{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

		//第二個Servlet代碼
		HttpSession session = request.getSession();
        System.out.println("SessionID爲:" + session.getId());
        Object name = session.getAttribute("name");
        System.out.println(name);

注意:結果可驗證SessionID都是相同的,可以綁定對象

SessionID爲:804218657264AD72C75196B4C0121C38

SessionID爲:804218657264AD72C75196B4C0121C38
Test{name=‘Ziph’, age=18}

4.6 刪除Session對象

使用HttpSession的invalidate方法

注意:Session對象刪除之後,查看瀏覽器Cookie,Session並沒有一下子刪除消失掉,得等一段時間瀏覽器纔會顯示沒有的!如果想驗證Session是否被刪除,你可以在項目中獲取一下Session對象,查看是否爲空!

		//第一個Servlet代碼
		HttpSession session = request.getSession();
        System.out.println("SessionID爲:" + session.getId());
		/**
         * 刪除Session對象
         */
        session.invalidate();

		//第二個Servlet代碼
		HttpSession session = request.getSession();
        System.out.println("SessionID爲:" + session.getId());

控制檯獲取SessionID如下: (注意:所獲取的SessionID不一樣了,證明第一個Session對象被刪除了!)

SessionID爲:42F4DC652DD812772DA8B591A5CA4C2E

SessionID爲:7C7BBEC30188C4D1744D0A41EE9D9AEB

4.7 Session超時

4.7.1 什麼是Session超時

HttpSession的最後一次訪問時間和當前時間的差距大於了指定的最大空閒時間,這時服務器就會銷燬Session對象。默認的空閒時間爲30分鐘。(生命週期結束)

4.7.2 如何修改Session的缺省時間限制
  1. 使用HttpSession的session.setMaxInactiveInterval(60);設置,(單位:秒)
  2. 修改xml配置信息(單位:分鐘)

注意:兩者設置不衝突,xml配置是在服務器初始化的時候配置起到了作用,而如果再在代碼中設置時間限制的話,該時間限制則覆蓋xml配置的時間限制。

  <session-config>
  	<session-timeout>10</session-timeout>
  </session-config>
4.7.3 Session失效的幾種情況
  1. 超過了設置的超時時間
  2. 主動調用了刪除Session的方法invalidate()
  3. 服務器主動或異常關閉

注意:瀏覽器關閉並不會讓Session失效!(在4.7.4中特別講解了這句話!)

4.7.4 解釋瀏覽器關閉不會讓Session失效

如果有小夥伴試過的話,這個注意也許會對你們產生一種困惑!

當我們在測試的時候,獲取並查看當前SessionID。關閉瀏覽器後,重新發起請求,則看到再一次獲取的SessionID變了!到看到發生的這一幕的時候,你們是不是會質疑這個結論呢?怎麼瀏覽器關閉並不會讓Session失效呢?它不是已經變了嗎?那就讓我來回答這個問題,我感覺這個問題還是有必要去說一下的!

我們第一次在瀏覽器發起請求,獲取一個SessionID,我們在這裏用①表示。這時候關閉瀏覽器,重新打開瀏覽器重新發起請求,在獲取當前SessionID,我們在這裏獲取的是②。大家有沒有發現①並不是和我們的②是同一個對象呢?Sesssion對象是存儲再服務器中的,第一次發起請求獲得①,關閉後重新發起請求獲得②,這時候就有聰明的小夥伴發現了我兩次加重標記了重新發起請求這幾個字,你是不是找出其中的端倪了呢?(找不出也沒事,我來給你答案!)

答案: 瀏覽器關閉並不會讓Session失效,這裏所指的Session對象是服務器端的Session對象沒有失效!你想我們第一次發起請求獲得一個Session對象,而當我們關閉瀏覽器重新發起請求時,這就是一個新的請求(Request),它會創建一個新的Session對象,所以我們看到的表面現象是改變的。而我們看不到的服務器內的Session對象是沒有發生改變的!

4.8 關於瀏覽器禁用Cookie的解決方案【瞭解】

4.8.1 怎麼主動禁用瀏覽器Cookie

在我們查看瀏覽器Cookie的頁面裏,會有禁用Cookie的按鈕,我們可以自行添加禁用某個站點的Cookie!

在這裏插入圖片描述

4.8.2 瀏覽器禁用Cookie的後果

如果瀏覽器禁用Cookie,session還能用嗎?
答:不能,但有其他的解決方案
服務器在默認情況下,會使用Cookie的方式將sessionID發送給瀏覽器,如果用戶禁止Cookie,則sessionID不會被瀏覽器保存。此時,服務器可以使用如URL重寫這樣的方式來發送sessionID。

4.8.3 使用Session區分每個用戶的方式
  1. 使用Cookie
  2. 作爲隱藏域嵌入HTML表單中,附加在主體的URL中,通常作爲指向其他應用程序頁面的鏈接,即URL重寫。
4.8.3 什麼是URL重寫

瀏覽器在訪問服務器上的某個地址時,不再使用原來的那個地址,而是使用經過改寫的地址(即:在原來的地址後面加上了sessionID)

4.8.4 如何實現URL重寫

如果是鏈接地址和表單提交,使用response.encodeURL(String url)生成重寫後的URL
如果是重定向,使用response.encodeRedirectURL(String url)生成重寫的URL

PrintWriter writer = response.getWriter();
HttpSession session = request.getSession();
/**
 * 重定向方式(地址不能爲空!)
 */
String s1 = response.encodeRedirectURL("/項目名稱/index.html");
response.sendRedirect(s1);

/**
 * 鏈接地址方式(地址可以爲空!)
 * 注意:下面的是打印手寫a超鏈接標籤並附跳轉鏈接
 */
String s2 = response.encodeURL("/項目名稱/index.html");
writer.println("<a href='"+ s2 +"'>" + "跳轉" + "</a>");

4.9 Session綜合案例值登錄(驗證碼)

JDBC連接數據庫,數據庫中創建用戶名、密碼等信息。利用Session來獲取瀏覽器請求參數,並存儲參數及驗證碼參數,用以驗證是否登錄成功!成功和失敗給予適當處理!(比如:重定向、轉發等)

本案例使用了c3p0連接池,大體框架結構如圖所示: (注意:驗證碼工具類和非工具類選其一即可)

在這裏插入圖片描述

c3p0連接池配置文件
    c3p0.driverClass=com.mysql.jdbc.Driver
    c3p0.jdbcUrl=jdbc:mysql://localhost:3306/temp?useUnicode=true&characterEncoding=utf-8
    c3p0.user=root
    c3p0.password=Mylifes1110
庫表操作
    create table user
    (
        id       int primary key auto_increment,
        username varchar(30),
        password varchar(30)
    ) charset = utf8;
    
    insert into user
        (id, username, password)
    values (1, 'ziph', '123456');
    
    insert into user (id, username, password)
    VALUES (2, 'join', '123456');
login登錄頁面
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>登錄頁面</title>
    </head>
    <body>
    <form action="/uweb/login" method="post">
        賬戶:<input type="text" name="username"><br>
        密碼:<input type="password" name="password"><br>
        驗證碼 &nbsp; <input type="text" name="validateCode"><img src="/uweb/create">
        <button type="submit">登錄</button>
    </form>
    </body>
    </html>
User實體類
    package com.mylifes1110.java.entity;
    
    /**
     * 用戶實體類
     */
    public class User {
        private Integer id;
        private String username;
        private String password;
    
        public User() {
        }
    
        public User(Integer id, String username, String password) {
            this.id = id;
            this.username = username;
            this.password = password;
        }
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", username='" + username + '\'' +
                    ", password='" + password + '\'' +
                    '}';
        }
    }
DBUtils連接池工具類
    package com.mylifes1110.java.utils;
    
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    
    /**
     * 獲取連接池工具類
     */
    public class DBUtils {
        private static ComboPooledDataSource dataSource;
    
        static {
            dataSource = new ComboPooledDataSource();
        }
    
        public static ComboPooledDataSource getDataSource() {
            return dataSource;
        }
    }
驗證碼工具類
    package com.mylifes1110.java.utils;
    
    import java.awt.*;
    import java.awt.image.BufferedImage;
    import java.util.Random;
    
    /**
     * 獲取驗證碼工具類
     */
    public class CaptchaUtils {
        public static BufferedImage createCaptcha(int width, int height, int numbers, int interferenceLines, boolean flag) {
            int widths = width;//定義圖片寬度
            int heights = height;//定義圖片高度
            //創建圖片對象
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            //創建畫筆對象(swing組件)
            Graphics graphics = image.getGraphics();
            //設置背景顏色
            graphics.setColor(new Color(0xDCDCDC));
            //設置填充背景爲實心矩形
            graphics.fillRect(0, 0, width, height);
            //設置邊框顏色
            graphics.setColor(Color.black);
            //畫一個空心矩形邊框
            graphics.drawRect(0, 0, width - 1, height - 1);
            //創建隨即對象
            Random random = new Random();
            //畫干擾線(準確來說是干擾橢圓)
            for (int i = 0; i < interferenceLines; i++) {
                int x = random.nextInt(width);
                int y = random.nextInt(height);
                graphics.drawOval(x, y, 0, 0);
            }
            //產生隨機數並把隨機數轉換爲十六進制字符串
            String s = Integer.toHexString(random.nextInt());
            //生成四位隨機驗證碼
            String captcha = s.substring(0, numbers);
    
            if (flag) {
                //控制檯打印驗證碼查看
                System.out.println(captcha);
            }
    
            //爲畫筆設置顏色
            graphics.setColor(new Color(0, 100, 0));
            //爲畫筆設置字體格式
            graphics.setFont(new Font("Candara", Font.BOLD, 24));
            //畫四位隨機數
            graphics.drawString(captcha, 8, 24);
            graphics.dispose();
            return image;
        }
    }
UserDao數據訪問層接口
    package com.mylifes1110.java.dao;
    
    import com.mylifes1110.java.entity.User;
    
    import java.sql.SQLException;
    
    /**
     * 數據訪問層接口
     */
    public interface UserDao {
        User login(User user) throws SQLException;
    }
UserDaoImpl數據訪問層實現類
    package com.mylifes1110.java.dao.impl;
    
    import com.mylifes1110.java.dao.UserDao;
    import com.mylifes1110.java.entity.User;
    import com.mylifes1110.java.utils.DBUtils;
    import org.apache.commons.dbutils.QueryRunner;
    import org.apache.commons.dbutils.handlers.BeanHandler;
    
    import java.sql.SQLException;
    
    /**
     * 數據訪問層實現類
     */
    public class UserDaoImpl implements UserDao {
        @Override
        public User login(User user)  {
            QueryRunner queryRunner = new QueryRunner(DBUtils.getDataSource());
            User loginUser = null;
            try {
                loginUser = queryRunner.query("select id, username, password from user where username = ? and password = ?",
                        new BeanHandler<User>(User.class),
                        user.getUsername(),
                        user.getPassword());
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            return loginUser;
        }
    }
登錄校驗Servlet
    package com.mylifes1110.java.servlet;
    
    import com.mylifes1110.java.dao.UserDao;
    import com.mylifes1110.java.dao.impl.UserDaoImpl;
    import com.mylifes1110.java.entity.User;
    
    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;
    import java.sql.SQLException;
    
    /**
     * 登錄校驗過程
     */
    @WebServlet(name = "LoginServlet", value = "/login")
    public class LoginServlet extends HttpServlet {
        private UserDao userDao = new UserDaoImpl();
    
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            /**
             * 獲取瀏覽器請求參數:username和password
             */
            String username = request.getParameter("username");
            String password = request.getParameter("password");
            /**
             * 創建User對象,並將獲取到的傳入對象中封裝,以便後登錄校驗傳入
             */
            User user = new User();
            user.setUsername(username);
            user.setPassword(password);
            User loginUser = null;
            try {
                /**
                 * 進行登錄校驗
                 */
                loginUser = userDao.login(user);
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            /**
             * 類似服務器端做記錄(控制檯打印)
             */
            System.out.println(loginUser);
            /**
             * 與登錄校驗後返回的結果判斷是否爲空
             * 1.校驗後爲空,則意爲登錄失敗(該用戶名或密碼在數據庫中不匹配或不存在)
             * 2.校驗後不爲空,即登錄成功
             */
            if (loginUser == null) {
                /**
                 * 登錄失敗,請求轉發到登陸頁面
                 */
                request.getRequestDispatcher("/login.html").forward(request, response);
            } else {
                /**
                 * 把即將登錄成功的用戶信息存儲到Session中
                 * 登錄成功,重定向並顯示用戶信息(Servlet)
                 */
                request.getSession().setAttribute("user", user);
                response.sendRedirect("/uweb/show");
            }
        }
    
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doPost(request, response);
        }
    }
使用工具來獲取驗證碼
    package com.mylifes1110.java.servlet;
    
    import com.mylifes1110.java.utils.CaptchaUtils;
    
    import javax.imageio.ImageIO;
    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.awt.*;
    import java.awt.image.BufferedImage;
    import java.io.IOException;
    import java.util.Random;
    
    /**
     * 獲取驗證碼,並把驗證碼寫入瀏覽器中顯示
     * <p>
     * int width = 60;//默認定義圖片寬度
     * int height = 32;//默認定義圖片高度
     * numbers = 4;//默認驗證碼個數
     * interferenceLines = 50;//默認干擾線條數
     * flag = true/false;是否在控制檯打印驗證碼查看
     */
    @WebServlet(name = "CreateCaptchaServlet", value = "/create")
    public class CreateCaptchaServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            BufferedImage image = CaptchaUtils.createCaptcha(60, 32, 4, 200, true);
            response.setContentType("image/jpeg");
            //使用字節流把圖片寫出到瀏覽器
            ServletOutputStream stream = response.getOutputStream();
            ImageIO.write(image, "jpeg", stream);
            //關閉字節流
            stream.close();
    
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doPost(request, response);
        }
    }
非工具類獲取驗證碼
    package com.mylifes1110.java.servlet;
    
    import javax.imageio.ImageIO;
    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.awt.*;
    import java.awt.image.BufferedImage;
    import java.io.IOException;
    import java.util.Random;
    
    /**
     * 驗證碼
     */
    @WebServlet(name = "CaptchaServlet", value = "/create1")
    public class CaptchaServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            int width = 60;//定義圖片寬度
            int height = 32;//定義圖片高度
            //創建圖片對象
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            //創建畫筆對象(swing組件)
            Graphics graphics = image.getGraphics();
            //設置背景顏色
            graphics.setColor(new Color(0xDCDCDC));
            //設置填充背景爲實心矩形
            graphics.fillRect(0, 0, width, height);
            //設置邊框顏色
            graphics.setColor(Color.black);
            //畫一個空心矩形邊框
            graphics.drawRect(0, 0, width - 1, height - 1);
            //創建隨即對象
            Random random = new Random();
            //畫干擾線(準確來說是干擾橢圓)
            for (int i = 0; i < 50; i++) {
                int x = random.nextInt(width);
                int y = random.nextInt(height);
                graphics.drawOval(x, y, 0, 0);
            }
            //產生隨機數並把隨機數轉換爲十六進制字符串
            String s = Integer.toHexString(random.nextInt());
            //生成四位隨機驗證碼
            String captcha = s.substring(0, 4);
            //將產生的驗證碼存儲到Session中,方便以後進行驗證碼校驗從Session中取出
            request.getSession().setAttribute("existCode", captcha);
            //控制檯打印驗證碼查看
            System.out.println(captcha);
            //爲畫筆設置顏色
            graphics.setColor(new Color(0, 100, 0));
            //爲畫筆設置字體格式
            graphics.setFont(new Font("Candara", Font.BOLD, 24));
            //畫四位隨機數
            graphics.drawString(captcha, 8, 24);
            graphics.dispose();
            //將圖片響應到瀏覽器(多媒體圖片類型-mimeType)
            response.setContentType("image/jpeg");
            //使用字節流把圖片寫出到瀏覽器
            ServletOutputStream stream = response.getOutputStream();
            ImageIO.write(image, "jpeg", stream);
            //關閉字節流
            stream.close();
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doPost(request, response);
        }
    }
登錄展示
    package com.mylifes1110.java.servlet;
    
    import com.mylifes1110.java.entity.User;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.*;
    import java.io.IOException;
    
    /**
     * 登錄結構展示
     */
    @WebServlet(name = "ShowServlet", value = "/show")
    public class ShowServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            /**
             * 1.解決亂碼問題
             * 2.獲取Session對象中的user對象參數
             * 3.判斷user對象是否爲空
             * 4.不爲空則展示登錄成功頁面(歡迎頁面)
             * 5.爲空則提示登錄或直接跳轉到登錄頁面
             */
            response.setContentType("text/html;charset=utf-8");
            User user = (User) request.getSession().getAttribute("user");
            if (user != null) {
                response.getWriter().println("<h1>歡迎" + user.getUsername() + "回家!</h1>");
            } else {
                response.getWriter().println("不好意思您還沒有登錄!還請您<a href='/uweb/login.html'>登錄</a>");
            }
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doPost(request, response);
        }
    }

五、Request作爲域對象

5.1 Request域對象的生命週期

Request的作用範圍是一次訪問的過程,生命週期隨着訪問開始而開始,隨着服務器的響應完畢而結束。所以更多的數據會添加到這個域對象

5.2 再次理解重定向和轉發的區別

  1. 轉發會攜帶這第一次的ServletRequest的信息傳遞到下一個文件,而重定向是重新開啓了一次訪問(發起請求),所以並不會攜帶
  2. 轉發上面的地址欄不會發生改變就訪問了別的內容,重定向會發生改變
  3. 轉發只能存在於服務器內部,重定向可以訪問任何其他網頁
  4. 因爲轉發只創建了一次客戶端和服務器的鏈接,所以相對而言轉發會比較節省網絡資源

5.3 Request域對象作用在重定向和轉發中的區別

鑑於重定向是重新開啓訪問,這個訪問即是重新發起了一次請求。再來看我們Request域對象的生命週期是一次訪問的過程。所以我們的數據存在Request域對象中,是不能應用再重定向中的。假如我們應用在重定向中,取出來的即是null。(域對象生命週期已經結束!)

鑑於轉發是服務器內部操作,我們用的時候即是當前的這一次請求。再想到Request域對象的聲明週期的時候,正是符合轉發操作。所以我們應用在轉發中,可以正常存取數據。

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /**
         * Reuqest域對象應用於轉發
         */
        String message = "Ziph is Very Good!";
        request.setAttribute("message", message);
        request.getRequestDispatcher("/test5").forward(request, response);
        /**
         * Request域對象應用於重定向(不能正常存取)
         * request.getContextPath():獲取根路徑
         * 根路徑拼接Servlet中的urlPatterns即是需要重定向過去的路徑
         */
        response.sendRedirect(request.getContextPath() + "/test5");
    }

六、ServletContext對象

6.1 什麼是ServletContext對象

ServletContext對象泛指Servlet上下文,代表當前整個應用程序。(jsp中application)

  • 當WEB服務器啓動時,會爲每一個WEB應用程序(webapps下的每個目錄就是一個應用程序)創建一塊共享存儲區域
  • ServletContext也叫做“公共區域”,也就是同一個WEB應用程序中,所有的Servlet和JSP都可以共享同一個區域
  • ServletContext在WEB服務器啓動時創建,服務器關閉時銷燬

6.2 如何獲取ServletContext對象

  1. ServletConfig提供了getServletContext()方法。
    • ServletContext servletContext1 = this.getServletConfig().getServletContext();
  2. GenericServlet提供了getServletContext()方法。(推薦)
    • ServletContext servletContext2 = this.getServletContext();
  3. HttpServletRequest提供了getServletContext()方法。(推薦)
    • ServletContext servletContext3 = request.getServletContext();
  4. HttpSession提供了getServletContext()方法。
    • ServletContext servletContext4 = request.getSession().getServletContext();
  5. 注意的點,我寫在了代碼的註釋中!
		/**
         * 通過ServletConfig獲取
         * 注意:ServletConfig是生命在GenericServlet類中
         */
        ServletContext servletContext1 = this.getServletConfig().getServletContext();
        /**
         * 通過GenericServlet獲取(推薦使用)
         * 注意:GenericServlet是HttpServlet的父類
         */
        ServletContext servletContext2 = this.getServletContext();
        /**
         * 通過HttpServletRequest對象獲取(推薦使用)
         * 注意:ServletRequest是HTTPServlet的父類
         */
        ServletContext servletContext3 = request.getServletContext();
        /**
         * 通過HttpSession對象獲取
         */
        ServletContext servletContext4 = request.getSession().getServletContext();
        /**
         * 打印四個對象並查看是否獲取的是同一對象(答案在下方)
         * <p>
         * org.apache.catalina.core.ApplicationContextFacade@74fd7a4f
         * org.apache.catalina.core.ApplicationContextFacade@74fd7a4f
         * org.apache.catalina.core.ApplicationContextFacade@74fd7a4f
         * org.apache.catalina.core.ApplicationContextFacade@74fd7a4f
         */
        System.out.println(servletContext1);
        System.out.println(servletContext2);
        System.out.println(servletContext3);
        System.out.println(servletContext4);

6.3 Servlet上下文的作用及特點

6.3.1 Servlet上下文的作用
  1. 獲取當前項目的發起路徑
    • request.getServletContext().getRealPath("/");
  2. 獲取容器的附加信息
    • 獲取Servlet信息
      • request.getServletContext().getServerInfo()
    • 獲取上下文路徑
      • request.getServletContext().getContextPath()
    • 獲取請求路徑
      • request.getContextPath()
  3. 全局容器
    • 將數據存儲在ServletContext域中
      • request.getServletContext().setAttribute(“username”, “Ziph”);
    • 獲取ServletContext域中的數據
      • request.getServletContext().getAttribute(“username”)
    • 把ServletContext域中的數據移除掉
      • request.getServletContext().removeAttribute(“username”);
  4. 代碼如下:
		//第一個Servlet代碼
		/**
		 * 獲取ServletContext對象
         */
		ServletContext servletContext = request.getServletContext();
        /**
         * 獲取當前項目的發佈路徑(這是我IDEA中的war包存放路徑)
         * D:\Code\web\testrequest\out\artifacts\reqweb_war_exploded\
         */
        System.out.println(servletContext.getRealPath("/"));
        /**
         * 獲取容器的附加信息
         * 1.獲取Servlet信息 : Apache Tomcat/8.5.45
         * 2.獲取上下文路徑 : /reqweb
         * 3.獲取請求路徑 : /reqweb
         */
        System.out.println(servletContext.getServerInfo());
        System.out.println(servletContext.getContextPath());
        System.out.println(request.getContextPath());
        /**
         * 1.將數據存儲到ServletContext域中
         * 2.從域中獲取數據並查看
         * 3.從域中移除該數據並查看
         */
        servletContext.setAttribute("username", "ziph");
        /**
         * 移除ServletContext域中的數據
         */
        servletContext.removeAttribute("username");

		//第二個Servlet代碼
		/**
         * 獲取ServletContext域中的數據
         */
        System.out.println(request.getServletContext().getAttribute("username"));
6.3.2 Servlet上下文的特點

唯一性: 一個應用對應一個servlet上下文。

一直存在: 只要服務器不關閉或者應用不卸載,Servlet上下文就一直存在。

6.3.3 xml文件配置ServletContext參數

xml配置文件信息: (可以寫多對參數)

  <context-param>
  	<param-name>username</param-name>
  	<param-value>Ziph</param-value>
  </context-param>
    
  <context-param>
  	<param-name>password</param-name>
  	<param-value>123456</param-value>
  </context-param>

Java代碼:

	/**
	 * 獲取Servlet上下文參數
	 */
	String appname=application.getInitParameter("username");
	String appversion=application.getInitParameter("password");

注意:配置文件是隨着項目初始化而初始化的,我們是不可以人工干預該Servlet上下文參數的,這裏指定的不可以干預是不可以移除該參數!

6.4 使用ServletContext域來完成站點訪問次數案例

  1. 獲取一個ServletContext對象
  2. 利用對象獲取域中的一個count(計數器)
  3. 使用if判空,爲空初始化count爲次數1,並將訪問次數存儲到域中的count
  4. 如果不爲空,那就開始計數,並將訪問次數更新到域中的count
  5. 顯示訪問次數(響應給瀏覽器或控制檯打印)
package com.mylifes1110.java.contextservlet;

import javax.servlet.ServletContext;
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(name = "VisitsServlet", value = "/visits")
public class VisitsServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");
        ServletContext servletContext = request.getServletContext();
        Integer count = (Integer) servletContext.getAttribute("count");
        if (count == null) {
            count = 1;
            servletContext.setAttribute("count", count);
        } else {
            count++;
            servletContext.setAttribute("count", count);
        }
        /**
         * 瀏覽器顯示訪問站點次數
         * 控制檯顯示訪問站點次數
         */
        response.getWriter().println("該站點訪問次數爲:" + count);
        System.out.println("該站點訪問次數爲:" + count);
    }
}

下一篇教科書系列【Servlet之Filter過濾器】,期待你的到來!謝謝大家!我將持續分享…

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章