【JavaWeb】Cookie和Session


會話技術

什么是會話

從瀏覽器訪問服務器開始,到訪問服務器結束,瀏覽器關閉為止的這段時間內容產生的多次請求和響應,合起來叫做瀏覽器和服務器之間的一次會話

會話管理作用

共享數據用的,並且是在不同請求間實現數據共享。

會話技術是為了解決客戶端瀏覽器和服務端的通信問題。用戶在網頁上的操作會產生很多重要的並且需要被保存的數據。比如購物車信息,可能我們此時不會清空購物車,那么購物車的信息需要被完整的保存下來。再比如登陸網站只需要登陸一次,再登陸網站的其他網頁時就不需要重復登陸了,這是因為用戶信息被保存了。

數據能否用HttpServletRequest或者ServletContext保存呢?

不能用 HttpServletRequest 的原因:我們的一次會話中,存在多次請求和響應,而瀏覽器客戶端的每一次請求都會產生一個 HttpServletRequest 對象,它只會保存此次請求的信息,例如放入購物車與購買付款是不同的請求,很顯然數據沒有得到很好的保存處理

不能用 ServletContext 的原因:ServletContext對象是被整個web應用所共享的,將數據都存到這里,無疑會無法區分具體信息的歸屬

會話管理分類

客戶端會話管理技術

它是把要共享的數據保存到了客戶端(也就是瀏覽器端)。每次請求時,把會話信息帶到服務器,從而實現多次請求的數據共享。

服務端會話管理技術

它本質仍是采用客戶端會話管理技術,只不過保存到客戶端的是一個特殊的標識,並且把要共享的數據保存到了服務端的內存對象中。每次請求時,把這個標識帶到服務器端,然后使用這個標識,找到對應的內存空間,從而實現數據共享。

Cookie

Cookies是服務器在本地機器上存儲的小段文本並隨每一個請求發送至同一服務器,是在客戶端保持狀態的方案,是客戶端瀏覽器的緩存文件,里面記錄了客戶瀏覽器訪問網站的一些內容。同時,也是HTTP協議請求和響應消息頭的一部分

常用API

屬性名稱 屬性作用 是否重要
name cookie的名稱 必要屬性
value cookie的值(不能是中文) 必要屬性
path cookie的路徑 重要
domain cookie的域名 重要
maxAge cookie的生存時間。 重要
version cookie的版本號。 不重要
comment cookie的說明。 不重要

注意細節

Cookie有大小,個數限制。每個網站最多只能存20個cookie,且大小不能超過4kb。同時,所有網站的cookie總數不超過300個。

當刪除Cookie時,設置maxAge值為0。當不設置maxAge時,使用的是瀏覽器的內存,當關閉瀏覽器之后,cookie將丟失。設置了此值,就會保存成緩存文件(值必須是大於0的,以秒為單位)。

常用方法

返回值 方法 作用
String getName() 返回cookie的name
String getValue() 返回當前cookie的value
void setMaxAge() 設置Cookie最大存活時間

構造方法

Cookie(String name, String value)
  • 通過指定的名稱和值構造一個Cookie
  • Cookie的名稱必須遵循RFC 2109規范。這就意味着,它只能包含ASCII字母數字字符,
  • 不能包含逗號、分號或空格或以$字符開頭。
  • 創建后無法更改cookie的名稱。
  • 該值可以是服務器選擇發送的任何內容。
  • 它的價值可能只有服務器才感興趣。
  • 創建之后,可以使用setValue方法更改cookie的值。

向瀏覽器添加Cookie

public void addCookie(Cookie cookie);
  • 添加Cookie到響應中。此方法可以多次調用,用以添加多個Cookie。

從服務器端獲取Cookie:

 public Cookie[] getCookies();
  • 這是HttpServletRequest中的方法。
  • 它返回一個Cookie的數組,包含客戶端隨此請求發送的所有Cookie對象。
  • 如果沒有符合規則的cookie,則此方法返回null。

Cookie的路徑限制

取自第一次訪問的資源路徑前綴
只要以這個前綴為開頭(包括子級路徑),可以獲取到
反之獲取不到

舉例:

@WebServlet("/servlet/servletDemo02")
public class ServletDemo02 extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //創建Cookie並添加
        Cookie cookie = new Cookie("username","zhangsan");
        cookie.setMaxAge(3600);
        resp.addCookie(cookie);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}
@WebServlet("/servlet/servletDemo03")
public class ServletDemo03 extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //獲取Cookie
        Cookie[] arr = req.getCookies();
        for(Cookie c : arr) {
            if("username".equals(c.getName())) {
                String value = c.getValue();
                resp.getWriter().write(value);
            }
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}
@WebServlet("/servlet/aaa/servletDemo04")
public class ServletDemo04 extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //獲取Cookie
        Cookie[] arr = req.getCookies();
        for(Cookie c : arr) {
            if("username".equals(c.getName())) {
                String value = c.getValue();
                resp.getWriter().write(value);
            }
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}
@WebServlet("/bbb/servletDemo05")
public class ServletDemo05 extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //獲取Cookie
        Cookie[] arr = req.getCookies();
        for(Cookie c : arr) {
            if("username".equals(c.getName())) {
                String value = c.getValue();
                resp.getWriter().write(value);
            }
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

第一次訪問的路徑是/servlet/servletDemo02
前綴是/servlet
/servlet/servletDemo03/servlet/aaa/servletDemo04可以獲取到Cookie的值
/bbb/servletDemo05不能獲得Cookie的值,因為前綴不同

/*
    Cookie的使用
 */
@WebServlet("/servletDemo01")
public class ServletDemo01 extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.通過響應對象寫出提示信息
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter pw = resp.getWriter();
        pw.write("歡迎訪問本網站,您的最后訪問時間為:<br>");

        //2.創建Cookie對象,用於記錄最后訪問時間
        Cookie cookie = new Cookie("time",System.currentTimeMillis()+"");

        //3.設置最大存活時間
        //cookie.setMaxAge(3600);
        cookie.setMaxAge(0);    // 立即清除

        //4.將cookie對象添加到客戶端
        resp.addCookie(cookie);

        //5.獲取cookie
        Cookie[] arr = req.getCookies();
        for(Cookie c : arr) {
            if("time".equals(c.getName())) {
                //6.獲取cookie對象中的value,進行寫出
                String value = c.getValue();
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                pw.write(sdf.format(new Date(Long.parseLong(value))));
            }
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

Session

Session概述

Cookie 在客戶端瀏覽器保存Session標識JSESSIONID,而每一個JSESSIONID對應的數據存儲在服務器,客戶端每次發出請求時會一塊把JSESSIONID發送給服務器,服務器通過這個標識尋找對應的數據並把其響應給客戶端。
當用戶在應用程序的 Web頁間跳轉時,存儲在 Session 對象中的變量不會丟失而是在整個用戶會話中一直存在下去。

HttpSession 對象

它是Servlet規范中提供的一個接口。該接口的實現由Servlet規范的實現提供商提供。我們使用的是Tomcat服務器,它對Servlet規范進行了實現,所以HttpSession接口的實現由Tomcat提供。該對象用於提供一種通過多個頁面請求或訪問網站來標識用戶並存儲有關該用戶的信息的方法。簡單說它就是一個服務端會話對象,用於存儲用戶的會話數據。

同時,它也是Servlet規范中四大域對象之一的會話域對象。並且它也是用於實現數據共享的。

域對象 作用范圍 使用場景
ServletContext 整個應用范圍 當前項目中需要數據共享時,可以使用此域對象。
ServletRequest 當前請求范圍 在請求或者當前請求轉發時需要數據共享可以使用此域對象。
HttpSession 會話返回 在當前會話范圍中實現數據共享。它可以在多次請求中實現數據共享。

HttpSession 常用方法

獲取HttpSession對象的方法:

public HttpSession getSession();
public HttpSession getSeesion(boolean create);

image

image

Session 使用案例

/*
    Session的基本使用
 */
@WebServlet("/servletDemo01")
public class ServletDemo01 extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.獲取請求的用戶名
        String username = req.getParameter("username");

        //2.獲取HttpSession的對象
        HttpSession session = req.getSession();
        System.out.println(session);
        System.out.println(session.getId());

        //3.將用戶名信息添加到共享數據中
        session.setAttribute("username",username);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}
/*
    Session的基本使用
 */
@WebServlet("/servletDemo02")
public class ServletDemo02 extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.獲取HttpSession對象
        HttpSession session = req.getSession();
        System.out.println(session);
        System.out.println(session.getId());

        //2.獲取共享數據
        Object username = session.getAttribute("username");

        //3.將數據響應給瀏覽器
        resp.getWriter().write(username+"");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

Cookie禁用時的處理方案

方案一(推薦)
直接提示Cookie被禁用了

/*
    Cookie的禁用
 */
@WebServlet("/servletDemo03")
public class ServletDemo03 extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.獲取HttpSession對象
        HttpSession session = req.getSession(false); //若JSESSIONID不存在,則不創建新HttpSession對象
        System.out.println(session);
        if(session == null) {
            resp.setContentType("text/html;charset=UTF-8");
            resp.getWriter().write("為了不影響正常的使用,請不要禁用瀏覽器的Cookie~");
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

方案二(重寫URL)

客戶端瀏覽器如果關閉Cookie權限,就無法把JSESSIONID傳給服務器,如果想實現頁面共享,就需要把JSESSIONID通過URL傳遞給服務器。也就是把JSESSIONID直接附加在URL路徑的后面。

String encodeURL(String url)

Encodes the specified URL by including the session ID, or, if encoding is not needed, returns the URL unchanged. The implementation of this method includes the logic to determine whether the session ID needs to be encoded in the URL. For example, if the browser supports cookies, or session tracking is turned off, URL encoding is unnecessary.

@WebServlet("/servletDemo01")
public class ServletDemo01 extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.獲取請求的用戶名
        String username = req.getParameter("username");

        //2.獲取HttpSession的對象
        HttpSession session = req.getSession();
        System.out.println(session);
        System.out.println(session.getId());

        //3.將用戶名信息添加到共享數據中	
        session.setAttribute("username",username);

        //實現url重寫  相當於在地址欄后面拼接了一個jsessionid
        resp.getWriter().write("<a href='"+resp.encodeURL("http://localhost:8080/session/servletDemo03")+"'>go servletDemo03</a>");

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

點擊連接以后,發現URL顯示http://localhost:8080/ServletDemo13;jsessionid=AEAFBD306F72BF3379A660596277E4C9
encodeURL方法使地址自動附加了JSESSIONID

HttpSession的鈍化和活化

什么是持久態

​ 把長時間不用,但還不到過期時間的HttpSession進行序列化,寫到磁盤上。

​ 我們把HttpSession持久態也叫做鈍化。(與鈍化相反的,我們叫活化。)

什么時候使用持久化

​ 第一種情況:當訪問量很大時,服務器會根據getLastAccessTime來進行排序,對長時間不用,但是還沒到過期時間的HttpSession進行持久化。

​ 第二種情況:當服務器進行重啟的時候,為了保持客戶HttpSession中的數據,也要對HttpSession進行持久化

注意

​ HttpSession的持久化由服務器來負責管理,我們不用關心。

​ 只有實現了序列化接口的類才能被序列化,否則不行。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM