狀態管理概述
HTTP協議是無狀態的,不能保存每次提交的信息,即當服務器返回與請求相對應的應答之後,這次事務的所有信息就丟掉了。
如果用戶發來一個新的請求,服務器無法知道它是否與上次的請求有聯繫。
對於那些需要多次提交數據才能完成的Web操作,比如登錄來說,就成問題了。
什麼是狀態管理
WEB應用中的會話是指一個客戶端瀏覽器與WEB服務器之間連續發生的一系列請求和響應過程。
WEB應用的會話狀態是指WEB服務器與瀏覽器在會話過程中產生的狀態信息,藉助會話狀態,WEB服務器能夠把屬於同一會話中的一系列的請求和響應過程關聯起來。
狀態管理有兩種技術,分別是客戶端狀態管理Cookie技術和服務器狀態管理session技術
Cookie應用
什麼是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
1、創建cookie
Cookie cookie = new Cookie("username","booy");
2、設置屬性
setMaxAge()
:有效期以秒計,默認-1保存在內存中,瀏覽器關閉銷燬,設置0表示立即銷燬
setPath()
:有效路徑,空表示同級目錄,/表示所有項目
setHttpOnly()
:表示只有http協議可讀
cookie.setMaxAge(60*60*24*365);
cookie.setPath("/");
cookie.setHttpOnly(true);
3、添加cookie
response.addCookie(cookie);
如何查詢Cookie
//獲取所有的Cookie
Cookie[] cks=request.getCookies();
//遍歷Cookie
for(Cookie ck:cks){
//檢索出自己的Cookie
if(ck.getName().equals("code"))
{
//記錄Cookie的值
code=ck.getValue();
break;
}
}
如何修改Cookie
只需要保證Cookie的名和路徑一致即可修改
//創建Cookie
Cookie ck=new Cookie("code", code);
ck.setPath("/");//設置Cookie的路徑
ck.setMaxAge(-1);//內存存儲,取值有三種:>0有效期,單位秒;=0失效;<0內存存儲
response.addCookie(ck);//讓瀏覽器添加Cookie
注意:如果改變cookie的name和有效路徑會新建cookie, 而改變cookie值、有效期、和httponly會覆蓋原有cookie
Cookie的編碼與解碼
中文和英文字符不同,中文屬於Unicode字符,在內存中佔用4個字符,而英文屬於ASCII字符,內存中只佔2個字節。Cookie中使用Unicode字符時需要對Unicode字符進行編碼,否則會出現亂碼。編碼可以使用java.net.URLEncoder類的encode(String str,String encoding)方法,解碼使用java.net.URLDecoder類的decode(String str,String encoding)方法
代碼如下:
保存:Servlet類
// 使用中文的 Cookie. name 與 value 都使用 UTF-8 編碼.
Cookie cookie = new Cookie(
URLEncoder.encode("姓名", "UTF-8"),
URLEncoder.encode("老邢", "UTF-8"));
// 發送到客戶端
response.addCookie(cookie);
讀取:Servlet讀取
if(request.getCookies() != null){
for(Cookie cc : request.getCookies()){
String cookieName = URLDecoder.decode(cc.getName(), "UTF-8");
String cookieValue = URLDecoder.decode(cc.getValue(), "UTF-8");
out.println(cookieName + "=");
out.println(cookieValue + "; <br/>");
}
}
else{
out.println("Cookie 已經寫入客戶端. 請刷新頁面. ");
}
發送Cookie的條件
瀏覽器在發送請求之前,首先會根據請求url中的域名在cookie列表中找所有與當前域名一樣的cookie,然後再根據指定的路徑進行匹配,如果當前請求在域匹配的基礎上還與路徑匹配那麼就會將所有匹配的cookie發送給服務器。
Cookie的特點
優點:
可配置到期規則:Cookie 可以在瀏覽器會話結束時到期,或者可以在客戶端計算機上無限期存在,這取決於客戶端的到期規則,不需要任何服務器資源,Cookie 存儲在客戶端並在發送後由服務器讀取。
簡單性:Cookie 是一種基於文本的輕量結構,包含簡單的鍵值對。
數據持久性:雖然客戶端計算機上 Cookie 的持續時間取決於客戶端上的 Cookie 過期處理和用戶干預,Cookie 通常是客戶端上持續時間最長的數據保留形式
缺點:
大小受到限制:大多數瀏覽器對 Cookie 的大小有 4096 字節的限制,儘管在當今新的瀏覽器和客戶端設備版本中,支持 8192 字節的 Cookie 大小已愈發常見。
用戶配置爲禁用:有些用戶禁用了瀏覽器或客戶端設備接收 Cookie 的能力,因此限制了這一功能。
潛在的安全風險:Cookie 可能會被篡改。用戶可能會操縱其計算機上的 Cookie,這意味着會對安全性造成潛在風險或者導致依賴於Cookie 的應用程序失敗。
Session
Session概述
Session用於跟蹤客戶的狀態。Session指的是在一段時間內,單個客戶與Web服務器的一連串相關的交互過程。
在一個Session中,客戶可能會多次請求訪問同一個網頁,也有可能請求訪問各種不同的服務器資源。
Session工作原理
session被用於表示一個持續的連接狀態,在網站訪問中一般指代客戶端瀏覽器的進程從開啓到結束的過程。session其實就是網站分析的訪問(visits)度量,表示一個訪問的過程。
session的常見實現形式是cookie(session cookie),即未設置過期時間的cookie,這個cookie的默認生命週期爲瀏覽器會話期間,只要關閉瀏覽器窗口,cookie就消失了。實現機制是當用戶發起一個請求的時候,服務器會檢查該請求中是否包含sessionid,如果未包含,則系統會創造一個名爲JSESSIONID的輸出 cookie返回給瀏覽器(只放入內存,並不存在硬盤中),並將其以HashTable的形式寫到服務器的內存裏面;當已經包含sessionid時,服務端會檢查找到與該session相匹配的信息,如果存在則直接使用該sessionid,若不存在則重新生成新的 session。這裏需要注意的是session始終是有服務端創建的,並非瀏覽器自己生成的。
獲得Session
//獲取Session對象
HttpSession session=request.getSession();
System.out.println("Id:"+session.getId());//唯一標記,
System.out.println("getLastAccessedTime:"+session.getLastAccessedTime());//最後一次訪問時間,毫秒
System.out.println("getMaxInactiveInterval:"+session.getMaxInactiveInterval());//獲取最大的空閒時間,單位秒
System.out.println("getCreationTime:"+session.getCreationTime());//獲取Session的創建,單位毫秒
使用Session綁定對象
使用HttpSession的setAttribute(屬性名,Object)方法
刪除Session
使用HttpSession的invalidate方法
Session超時
HttpSession的最後一程訪問時間和當前時間的差距大於了指定的最大空閒時間,這時服務器就會銷燬Session對象。默認的空閒時間爲30分鐘。
修改Session的缺省時間限制
1 使用HttpSession的session.setMaxInactiveInterval(20*60);設置,單位秒
2 在web.xml中配置 ,單位分鐘
<session-config>
<session-timeout>20</session-timeout>
</session-config>
登錄示例:
@WebServlet(name = "LoginServlet", value = "/LoginServlet")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//亂碼
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
//接收數據
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println(username+"-->"+password);
if(username.equals("booy") && password.equals("123456")){
//設置session屬性
request.getSession().setAttribute("username",username);
//登錄成功跳轉
response.sendRedirect("index.jsp");
}else{
response.getWriter().write("登錄失敗!");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}
退出示例:
@WebServlet(name = "LoginOutServlet",value = "/LoginOutServlet")
public class LoginOutServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//退出功能
//刪除session
request.getSession().removeAttribute("username");
//銷燬session
request.getSession().invalidate();
//重定向
response.sendRedirect("login.html");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}
html登錄頁
<form action="LoginServlet" method="post">
用戶名:<input type="text" name="username">
<br>
密 碼:<input type="text" name="password">
<br>
<input type="submit" value="提交">
</form>
jsp主頁
<h1>login success! welcome home ${username}.</h1>
<h2><a href="LoginOutServlet" onclick="return confirm('確定要退出嗎?')">退出</a></h2>
Session失效的幾種情況
1、超過了設置的超時時間
2、主動調用了invalidate方法
3、服務器主動或異常關閉
注意:瀏覽器關閉並不會讓Session失效
瀏覽器禁用Cookie的解決方案(瞭解)
瀏覽器禁用Cookie的後果
如果瀏覽器禁用Cookie,session還能用嗎?
答:不能,但有其他的解決方案
服務器在默認情況下,會使用Cookie的方式將sessionID發送給瀏覽器,如果用戶禁止Cookie,則sessionID不會被瀏覽器保存,此時,服務器可以使用如URL重寫這樣的方式來發送sessionID.
使用Session區分每個用戶的方式:
1、使用Cookie
2、作爲隱藏域嵌入HTML表單中,附加在主體的URL中,通常作爲指向其他應用程序頁面的鏈接,即URL重寫。
什麼是URL重寫
瀏覽器在訪問服務器上的某個地址時,不再使用原來的那個地址,而是使用經過改寫的地址(即,在原來的地址後面加上了sessionID)
實現URL重寫
如果是鏈接地址和表單提交,使用
response.encodeURL(String url)
生成重寫後的URL
如果是重定向,使用
response.encodeRedirectURL(String url)
生成重寫的URL
ServletContext對象
ServletContext:Servlet上下文,代表當前整個應用程序。(jsp中application
ServletContext
ServletContext:Servlet上下文。
當WEB服務器啓動時,會爲每一個WEB應用程序(webapps下的每個目錄就是一個應用程序)創建一塊共享的存儲區域
ServletContext也叫做“公共區域”,也就是同一個WEB應用程序中,所有的Servlet和JSP都可以共享同一個區域。
ServletContext在WEB服務器啓動時創建,服務器關閉時銷燬。
獲得Servlet上下文
方式一:GenericServlet
提供了getServletContext()
方法。(推薦)
方式二:HttpServletRequest
提供了getServletContext()
方法。(推薦)
方式三:ServletConfig
提供了getServletContext()
方法。
方式四:HttpSession
提供了getServletContext()
方法。
Servlet上下文的作用及特點
作用:
1、獲取真實路徑
獲取當前項目的發佈路徑
request.getServletContext().getRealPath("/");
2、獲取容器的附加信息
System.out.println(request.getServletContext().getServerInfo());
System.out.println(request.getServletContext().getContextPath());//項目名稱
System.out.println(request.getContextPath());
3、全局容器
//設置信息到全局容器中
request.getServletContext().setAttribute("msg", "共享信息");
//獲取數據
System.out.println(request.getServletContext().getAttribute("msg"));
//移除數據
request.getServletContext().removeAttribute("msg");
特點:
唯一性: 一個應用對應一個servlet上下文。
一直存在: 只要容器不關閉或者應用不卸載,servlet上下文就一直存在。
web.xml文件配置servletContext參數
appname xxx管理系統 appversion 2.0//獲取servlet上下文參數
String appname=application.getInitParameter("appname");
String appversion=application.getInitParameter("appversion");
System.out.println(appname+"..."+appversion);