會(huì)話跟蹤
從打開瀏覽器訪問某個(gè)站點(diǎn)開始谦纱,到關(guān)閉這個(gè)瀏覽器的整個(gè)過程看成,稱為一次會(huì)話。
會(huì)話跟蹤技術(shù)(Cookie跨嘉,Session)的作用
由于HTTP是無狀態(tài)協(xié)議川慌,每次的請求都是獨(dú)立的,不會(huì)影響之前之后的請求應(yīng)答祠乃,從而導(dǎo)致每個(gè)請求間的數(shù)據(jù)無法共享梦重。
會(huì)話跟蹤技術(shù)就是記錄這次會(huì)話中客戶端的狀態(tài)與數(shù)據(jù),實(shí)現(xiàn)請求間的數(shù)據(jù)共享亮瓷。
Cookie | Session | |
---|---|---|
存儲(chǔ)位置 | 客戶端(瀏覽器) | 服務(wù)器端 |
安全性 | 本地可清理琴拧,安全性不好 | 安全性相對好 |
服務(wù)器壓力 | 減少 | 增加 |
1.Cookie
Cookie為客戶端技術(shù),會(huì)將共享數(shù)據(jù)放到客戶端(瀏覽器)中嘱支。
Cookie不支持中文蚓胸,需要編碼和解碼。
瀏覽器中Cookie有數(shù)量限制斗塘,只能保存300個(gè)Cookie信息赢织。
1.服務(wù)端向客戶端發(fā)送一個(gè)Cookie
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//通過Cookie將共享數(shù)據(jù)保存到瀏覽器
//該Cookie會(huì)以響應(yīng)頭的形式發(fā)送給客戶端
Cookie cookie = new Cookie("name", URLEncoder.encode("value", "UTF-8"));
resp.addCookie(cookie);
}
2.服務(wù)端獲取客戶端的Cookie
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
Cookie[] cookies = req.getCookies();
for (Cookie cookie : cookies) {
if ("name".equals(cookie.getName())) {
String value = cookie.getValue();
}
}
}
Cookie持久化
1.如果不設(shè)置持久化時(shí)間,cookie會(huì)存儲(chǔ)在瀏覽器的內(nèi)存中
2.瀏覽器關(guān)閉馍盟,會(huì)話級別的cookie信息會(huì)銷毀
3.如果設(shè)置持久化時(shí)間于置,cookie信息會(huì)被持久化到瀏覽器的磁盤文件里
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
Cookie cookie = new Cookie("name", "value");
cookie.setMaxAge(60 * 1000); //設(shè)置Cookie在客戶端的持久化時(shí)間,參數(shù):時(shí)間秒
cookie.setMaxAge(0); //時(shí)間設(shè)置成0贞岭,代表刪除該Cookie
resp.addCookie(cookie);
}
Cookie設(shè)置范圍路徑
如果不設(shè)置攜帶路徑八毯,當(dāng)請求訪問產(chǎn)生該cookie的web資源所在的路徑時(shí),都會(huì)攜帶cookie信息瞄桨。
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
Cookie cookie = new Cookie("name", "value");
//訪問WEB16應(yīng)用中的任何資源都攜帶cookie
cookie.setPath("/WEB16");
//訪問WEB16中的cookieServlet時(shí)才攜帶cookie信息
cookie.setPath("/WEB16/cookieServlet");
}
2.Session
當(dāng)用戶訪問Web服務(wù)目錄中的一個(gè)頁面時(shí)话速,Tomcat服務(wù)器會(huì)產(chǎn)生一個(gè)Session對象,這個(gè)Session對象被分配了一個(gè)String類型的id號芯侥,Tomcat將這個(gè)id號發(fā)送到客戶端泊交,存放在用戶的Cookie中乳讥,這樣Session對象和用戶間就建立了一一對應(yīng)關(guān)系,即每個(gè)用戶對應(yīng)一個(gè)Session對象廓俭。
不同的Session云石,具有不同的id,當(dāng)用戶再連接該Web服務(wù)目錄其他頁面時(shí)研乒,依舊使用最初創(chuàng)建的Session汹忠,直到Session對象到達(dá)最大生存時(shí)間或服務(wù)器關(guān)閉,才重新創(chuàng)建一個(gè)新的Session雹熬。
Session對象的生命周期
Session的作用范圍默認(rèn)在一次會(huì)話中宽菜,即在一次會(huì)話中任何資源,都共用一個(gè)session對象竿报。
創(chuàng)建
第一次執(zhí)行 request.getSession() 時(shí)創(chuàng)建.
銷毀
服務(wù)器(非正常)關(guān)閉铅乡,或session過期/失效(默認(rèn)30分鐘)。
Session過期時(shí)長烈菌,在web.xml中進(jìn)行配置隆判。
<session-config>
<session-timeout>30</session-timeout>
</session-config>
1.創(chuàng)建Session
HttpSession session = req.getSession();
此方法會(huì)獲得專屬于當(dāng)前會(huì)話的Session對象。
如果服務(wù)器端沒有該會(huì)話的Session對象僧界,將會(huì)創(chuàng)建一個(gè)新的Session返回。
如果已存在屬于該會(huì)話的Session臭挽,將直接返回已有的Session捂襟。
實(shí)質(zhì)就是根據(jù)JSESSIONID判斷該客戶端是否在服務(wù)器上已經(jīng)存在session了)
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
HttpSession session = req.getSession();
session.setAttribute("name", "value");
session.getAttribute("name");
session.removeAttribute("name"); //移除Session
session.invalidate(); //銷毀Session
}
Servlet跳轉(zhuǎn)
1.請求轉(zhuǎn)發(fā)(forward)
請求轉(zhuǎn)發(fā)跳轉(zhuǎn)時(shí),地址欄中的地址不會(huì)改變欢峰,還是第一個(gè)請求資源的路徑葬荷。總共只有一次請求纽帖,因此可以在請求轉(zhuǎn)發(fā)的過程中 共享數(shù)據(jù)宠漩。
最終的響應(yīng)的數(shù)據(jù),由最后的Servlet決定懊直,可以訪問 WEB-INF 中的資源扒吁,不能夠跨域訪問。
下面用一個(gè)簡單的 A 界面輸入用戶名室囊,提交跳轉(zhuǎn)到 B Servlet顯示的例子看一下跳轉(zhuǎn)的流程雕崩。
請求轉(zhuǎn)發(fā)API
req.getRequestDispatcher("跳轉(zhuǎn)目標(biāo)的servlet").forward(req, resp);
@WebServlet(value = "/a")
public class AServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//避免提交數(shù)據(jù)時(shí)中文亂碼
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
String name = req.getParameter("name");
PrintWriter out = resp.getWriter();
//注意:最終的響應(yīng)是由最終跳轉(zhuǎn)到的Servlet響應(yīng)的
//界面輸出的是B的響應(yīng)
//這里A before,alert都不輸出
out.println("A before 不輸出:" + name);
//請求轉(zhuǎn)發(fā)
req.getRequestDispatcher("/b").forward(req, resp);
out.println("A alert 不輸出" + name);
}
}
@WebServlet(value = "/b")
public class BServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
//因?yàn)槭峭粋€(gè)請求所以數(shù)據(jù)共享
String name = req.getParameter("name");
out.println("B Servlet:" + name);
}
}
2.URL重定向(redirect)
重定向跳轉(zhuǎn)時(shí)融撞,地址欄中的地址會(huì)改變盼铁,總共有兩次請求,所以在URL重定向的過程中尝偎,不能共享數(shù)據(jù)饶火,需要用Session或Cookie解決無協(xié)議問題鹏控。
最終的響應(yīng)的數(shù)據(jù),由最后的Servlet決定肤寝,不能訪問 WEB-INF 中的資源当辐,可以請求轉(zhuǎn)發(fā)跨域訪問。
URL重定向API
resp.sendRedirect("跳轉(zhuǎn)目標(biāo)的servlet");
注意
請求轉(zhuǎn)發(fā)為request調(diào)用醒陆,重定向?yàn)閞esponse調(diào)用
@WebServlet(value = "/a")
public class AServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//避免提交數(shù)據(jù)時(shí)中文亂碼
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
//重定向是兩個(gè)請求所以不能共享數(shù)據(jù)
//需要用Session解決無協(xié)議問題
String name = req.getParameter("name");
req.getSession().setAttribute("name", name);
PrintWriter writer = resp.getWriter();
writer.println("A before:"+name);
//重定向
resp.sendRedirect("/b");
//注意:最終的響應(yīng)是由最終跳轉(zhuǎn)到的Servlet響應(yīng)的
//界面輸出的是B的響應(yīng)
//這里A before瀑构,alert都不輸出
writer.println("A alert");
}
}
@WebServlet(value = "/b")
public class BServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
out.println("B Servlet:" + req.getSession().getAttribute("name"));
}
}
2.請求包含(include)
- 使用請求包含跳轉(zhuǎn)時(shí),A包含B的響應(yīng)刨摩,數(shù)據(jù)可以共享寺晌。
請求包含API
req.getRequestDispatcher("跳轉(zhuǎn)目標(biāo)的servlet").include(req, resp);
@WebServlet(value = "/a")
public class AServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//避免提交數(shù)據(jù)時(shí)中文亂碼
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
String name = req.getParameter("name");
//req.getSession().setAttribute("name", name);
PrintWriter writer = resp.getWriter();
writer.println("A before:" + name);
req.getRequestDispatcher("/b").include(req, resp);
writer.println("A alert:" + name);
}
}
@WebServlet(value = "/b")
public class BServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
out.println("B Servlet:" + req.getParameter("name"));
}
}
Servlet四大作用域
作用域的作用,是在不同的范圍內(nèi)澡刹,實(shí)現(xiàn)數(shù)據(jù)共享呻征,往哪個(gè)作用域中存放數(shù)據(jù),就只能從哪個(gè)作用域中獲取罢浇。
類型 | 作用范圍 | 使用 |
---|---|---|
PageContext | 當(dāng)前頁面 | Jsp中使用較多 |
ServletRequest | 一次請求 | 同次請求中的數(shù)據(jù)共享 |
Session | 一次會(huì)話 | 同次會(huì)話中的數(shù)據(jù)共享 |
ServletContext | 一次應(yīng)用 | 服務(wù)器啟動(dòng)時(shí)創(chuàng)建陆赋,關(guān)閉時(shí)銷毀 |
域?qū)ο螅捍鎯?chǔ)數(shù)據(jù)的區(qū)域就是域?qū)ο蟆?/h6>
域?qū)ο蟮耐ㄓ梅椒?
作用域?qū)ο?setAtrribute(String name,Object obj)
作用域?qū)ο?getAtrribute(String name)
作用域?qū)ο?removeAttribute(String name)
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
ServletContext servletContext = getServletContext();
servletContext.setAttribute("key", "value");
req.setAttribute("key", "value");
req.getSession().setAttribute("key", "value");
}
域?qū)ο蟮耐ㄓ梅椒?
作用域?qū)ο?setAtrribute(String name,Object obj)
作用域?qū)ο?getAtrribute(String name)
作用域?qū)ο?removeAttribute(String name)
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
ServletContext servletContext = getServletContext();
servletContext.setAttribute("key", "value");
req.setAttribute("key", "value");
req.getSession().setAttribute("key", "value");
}