詳解Javaweb狀態(tài)管理的Session和Cookie
問題引入
- HTTP協(xié)議是無轉態(tài)的,不能保存提交的信息
- 如果用戶發(fā)來一個新的請求,服務器無法知道它是否與上次的請求聯(lián)系
- 對于那些需要多次提交數(shù)據(jù)才能完成的web操作,比如登錄,就難以完成
概念
將瀏覽器與web服務器之間多次交互當做一個整體來處理,并且多次交互所涉及的數(shù)據(jù)(狀態(tài))保存下來
狀態(tài)管理分類
- 客戶端狀態(tài)管理技術:將轉態(tài)保存在客戶端,代表性的是Cooklie技術
- 服務器狀態(tài)管理技術:將狀態(tài)保存在服務器端,代表性的是session技術(服務器傳遞session時需要使用Cookie的方式)和application
Cookie
- Cookie是瀏覽器訪問Web服務器某個資源時,由Web服務器在HTTP響應消息頭中附帶傳送給瀏覽器的小段數(shù)據(jù)
- 一旦Web服務器保存了某個Cookie,那么它在以后每次訪問該Web服務器時,都應在HTTP請求中將這個Cookie回傳給Web服務器
- 一個Cookie主要由標識該信息的名稱name和值value組成
Cookie的創(chuàng)建、獲取、修改
Cookie創(chuàng)建
@WebServlet(value = "/cs") public class CookieServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //服務端創(chuàng)建Cookie對象 Cookie cookie = new Cookie("username","weishuo"); //設置Cookie的訪問路徑 cookie.setPath("/Servlet_Projects_war/get"); //設置Cookie的有效期 >0有效期,單位秒 =0瀏覽器關閉 <0內存存儲 默認-1 cookie.setMaxAge(60*60); //1小時 //添加到response對象中,將Cookie響應給客戶端 resp.addCookie(cookie); //將Cookie添加到response對象中,響應給客戶端 } }
Cookie獲取
@WebServlet(value = "/get") public class GetServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //通過request對象獲取所有的cookie Cookie[] cookies = req.getCookies(); if (cookies!=null){ //判斷cookies數(shù)組是否為空,避免空指針異常 //通過循環(huán)遍歷Cookie for (Cookie cookie : cookies) { System.out.println(cookie.getName() + ":" + cookie.getValue()); } } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
Cookie修改
如果修改Cookie的name和有效路徑會新建cookie,而改變Cookie值,有效期會覆蓋原有的Cookie
@WebServlet(value = "/cs2") public class CookieServlet2 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //服務端創(chuàng)建Cookie對象 Cookie cookie = new Cookie("username","given"); //設置Cookie的訪問路徑 cookie.setPath("/Servlet_Projects_war/get"); //設置Cookie有效期 cookie.setMaxAge(60*60*24*7); //7天 //添加到response對象中,將Cookie響應給客戶端 resp.addCookie(cookie); } }
Cookie編碼與解碼
Cookie默認不支持中文
,只能包含ASCII字符
,所以Cookie需要對Unicode字符進行編碼,否則會出現(xiàn)亂碼
- 編碼可以使用
java.net.URLEncoder類
的encode(String str,String encoding)
方法- 解碼使用
java.net.URLDecoder類
的decode(String str,String encoding)
方法
//Cookie設置 @WebServlet(value = "/cs3") public class CookieServlet3 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //服務端創(chuàng)建Cookie對象,使用Cookie編碼 Cookie cookie = new Cookie(URLEncoder.encode("姓名","UTF-8"),URLEncoder.encode("張三","UTF-8")); //設置Cookie的訪問路徑 cookie.setPath("/Servlet_Projects_war/get"); //設置Cookie有效期 cookie.setMaxAge(600); //添加到response對象中,將Cookie響應給客戶端 resp.addCookie(cookie); } } //Cookie讀取 @WebServlet(value = "/get") public class GetServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //通過request對象獲取所有的cookie Cookie[] cookies = req.getCookies(); if (cookies!=null){ //判斷cookies數(shù)組是否為空,避免空指針異常 //通過循環(huán)遍歷Cookie for (Cookie cookie : cookies) { //使用Cookie解碼 System.out.println(URLDecoder.decode(cookie.getName(),"UTF-8") + ":" + URLDecoder.decode(cookie.getValue(),"UTF-8")); } } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
總結
Cookie優(yōu)點
可配置到期規(guī)則Cookie是一種基于文本的輕量級結構,包含簡單的鍵值對Cookie默認在過期之前是可以一直存在在客戶端瀏覽器上
Cookie的缺點
大小受到限制,瀏覽器對Cookie大小有4K,8K字節(jié)限制用戶配置為禁用,用戶禁用了瀏覽器或客戶端接受Cookie的能力Cookie可能被篡改,存在潛在風險
Session
概述
- Session用于記錄用戶的狀態(tài),Session指的是一段時間,單個客戶端與web服務器的一連串交互過程
- 一個Session中,客戶可能會多次請求訪問同一個資源,也可能請求訪問各種不同的服務器資源
原理
Tip:
Session和Cookie都是由服務器端創(chuàng)建
- 服務器為每一次會話分配一個Session對象
- 同一個瀏覽器發(fā)起的多次請求,同屬于一次會話(Session)
- 首次使用Session,服務器自動創(chuàng)建Session,并且創(chuàng)建Cookie存儲SessionID發(fā)送回客戶端
session使用
Session作用域:擁有存儲數(shù)據(jù)的空間,作用范圍是一次會話有效
- 一次會話是使用同一瀏覽器發(fā)送到多次請求,瀏覽器關閉則會話結束
- 可以將數(shù)據(jù)存入Session中,一次會話的任意位置進行獲取
- 可以傳遞任何數(shù)據(jù)(基本數(shù)據(jù)類型、對象、集合、數(shù)組)
獲取session
//獲取Session對象 HttpSession session = request.getSession(); System.out.println("id"+session.getId()); //唯一標識
package com.woniu.sessions; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; import java.io.IOException; @WebServlet(name = "Servlet", value = "/ss") public class Servlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //通過request對象獲取session對象 HttpSession session = request.getSession(); System.out.println(session.getId()); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
Session保存數(shù)據(jù)
- 保存數(shù)據(jù)到session中
setAttribute(屬性名,Objects);
session.setAttribute("key",value);//以鍵值對形式存儲在session作用域中
Session獲取數(shù)據(jù)
- 獲取session中數(shù)據(jù)
getAttribute(屬性名);
session.getAttribute("key"); //通過String類型的key訪問Object類型的value
Session移除數(shù)據(jù)
- 從Session中刪除數(shù)據(jù)
removeAttribute(屬性名);
session.removeAttribute("key");//通過移除session作用域中的值
應用
- Servlet類
@WebServlet(name = "Servlet", value = "/ss") public class Servlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //通過request對象獲取session對象 HttpSession session = request.getSession(); //使用session保存數(shù)據(jù) session.setAttribute("username","given"); //通過產生的session對象獲取sessionId System.out.println(session.getId()); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
- GetValueServlet類
@WebServlet(name = "GetValueServlet", value = "/getValue") public class GetValueServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(); String username = (String) session.getAttribute("username"); System.out.println("從session中獲得了" + username); //從session中獲得了given } }
- RemoveServlet類
@WebServlet(name = "RemoveServlet", value = "/remove") public class RemoveServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(); session.removeAttribute("username"); } }
- 結果
543D0EA33CB586691A02C00564E34CEA
從session中獲得了given
從session中獲得了null
Session & Request 區(qū)別
- request是一次請求有效,請求改變,則request改變
- session是一次會話有效,瀏覽器改變,則session改變
SessionServlet類
@WebServlet(name = "Servlet", value = "/ss") public class SessionServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //通過request對象獲取session對象 HttpSession session = request.getSession(); //使用session保存數(shù)據(jù) session.setAttribute("username","given"); //使用request保存數(shù)據(jù) request.setAttribute("password",123456); //重定向跳轉到/getValue response.sendRedirect("/Servlet_Projects_war/getValue"); //通過產生的session對象獲取sessionId System.out.println(session.getId()); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
GetValueServlet類
@WebServlet(name = "GetValueServlet", value = "/getValue") public class GetValueServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(); String password = (String) request.getAttribute("password"); System.out.println("從request中獲得了" + password); String username = (String) session.getAttribute("username"); System.out.println("從session中獲得了" + username); //從session中獲得了given } }
結果
從request中獲得了null 從session中獲得了given
總結
sendRedirect跳轉時,地址欄發(fā)生改變,代表客戶端重新發(fā)送請求,屬于兩次請求;response沒有作用域,兩次request請求中的數(shù)據(jù)無法共享;而session只要瀏覽器不關閉屬于一次會話,一次會話中瀏覽器數(shù)據(jù)可以共享
Session生命周期
- 開始:第一次使用到Session的請求產生,則創(chuàng)建Session
- 結束
- 瀏覽器關閉,則失效
- Session超時,則失效
- session.SetMaxInactivelnterval(seconds); 設置最大有效時間(單位/秒)
- 手工銷毀,則失效
- session.invalidate(); 登錄退出、注銷
- Session超時,則失效
LifeSessionServlet類
@WebServlet(name = "LifeSessionServlet", value = "/life") public class LifeSessionServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //獲取session HttpSession session = request.getSession(); //設置session有效過期時間為10s session.setMaxInactiveInterval(10); //通過產生的session對象獲取sessionId System.out.println(session.getId()); } }
GetSessionServlet類
@WebServlet(name = "GetSessionServlet", value = "/getSession") public class GetSessionServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //獲取session HttpSession session = request.getSession(); System.out.println(session.getId()); //手工銷毀,立即失效 //session.invalidate(); } }
結果
瀏覽器輸入/life,獲取到的sessionId 71A9B2141F22840E0BE7EA67B49EC9B3 10秒內,瀏覽器輸入/getSession,獲取到的sessionId 71A9B2141F22840E0BE7EA67B49EC9B3 10秒后,瀏覽器輸入/getSession,獲取到的sessionId EDF2E31978DE8295486C2657016F5202
瀏覽器禁用Cookie解決方案
瀏覽器禁用Cookie后果
服務器在默認情況下,會使用Cookie的方式將sessionID發(fā)送給服務器,如果用戶禁止Cookie,則sessionID不會被瀏覽器保存,此時,服務器使用如URL重寫這樣的方式來發(fā)送sessionID
URL重寫
瀏覽器在訪問服務器上的某個地址時,不再使用原來的那個地址,而是使用經(jīng)過改寫的地址(即在原來的地址后面加上sessionID)
實現(xiàn)URL重寫
- response.encodeRedirectURL(String url); //生成重寫的URL
//實現(xiàn)URL重寫 String url = response.encodeRedirectURL("/Servlet_Projects_war/getSession"); //輸出URL重寫地址 System.out.println(url); //重定向轉發(fā) response.sendRedirect(url);
結果
重寫URL地址 /Servlet_Projects_war/getSession;jsessionid=A38B1C92B9CDE10F6ED5E7AA19E919F0 瀏覽器輸入/life,獲取到的sessionId A38B1C92B9CDE10F6ED5E7AA19E919F0 重定向轉發(fā)地址:/Servlet_Projects_war/getSession,獲取到的sessionId A38B1C92B9CDE10F6ED5E7AA19E919F0
到此這篇關于詳解Javaweb狀態(tài)管理的Session和Cookie的文章就介紹到這了,更多相關Javaweb的Session和Cookie內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Mybatis的TypeHandler加解密數(shù)據(jù)實現(xiàn)
在我們數(shù)據(jù)庫中有些時候會保存一些用戶的敏感信息,所以就需要對這些數(shù)據(jù)進行加密,那么本文就介紹了Mybatis的TypeHandler加解密數(shù)據(jù)實現(xiàn),感興趣的可以了解一下2021-06-06Mybatis如何實現(xiàn)@Select等注解動態(tài)組合SQL語句
這篇文章主要介紹了Mybatis如何實現(xiàn)@Select等注解動態(tài)組合SQL語句,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07Spring?Security實現(xiàn)用戶名密碼登錄詳解
這篇文章主要為大家詳細介紹了Spring Security如何實現(xiàn)用戶名密碼登錄功能,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起了解一下2022-10-10Java和C++通過new創(chuàng)建的對象有何區(qū)別?
Java和C++都是面向對象的編程語言,然而Java和C++在創(chuàng)建對象時卻存在不同的方式,由于方式的不同導致在內存中管理的不同。這篇文章主要給大家介紹了關于Java和C++通過new創(chuàng)建對象區(qū)別的相關資料,需要的朋友可以參考借鑒,下面來一起看看吧。2017-11-11UniApp?+?SpringBoot?實現(xiàn)微信支付和退款功能
這篇文章主要介紹了UniApp?+?SpringBoot?實現(xiàn)微信支付和退款功能,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-06-06