什麼是會話:用戶打開瀏覽器,點擊多個超連接,訪問服務器的多個web資源,而後關閉瀏覽器,整個過程就稱爲一個會話;html
會話過程須要解決的問題:每一個用戶在使用瀏覽器與服務器進行會話的過程當中,均可能會產生一些數據,這些輸入如何來進行保存?好比用戶在購物網站瀏覽的商品記錄,用戶添加購物車的記錄等等這些信息如何進行存儲?在程序中會話跟蹤是一件很是重要的事情,一個用戶的全部請求操做都應該屬於同一個會話,而另外一我的的全部請求操做應該屬於另外一我的,兩者不能混淆!當想到須要在保存數據時,咱們首先確定會想到使用域對象,這些數據是否可使用Request或者ServletContext對象來保存呢?java
首先咱們舉例說明:登陸的場景git
1 Context對象:web
小張: 輸入「張三」 (保存數據: context.setAttribute("name","張三")) -> 用戶主頁(顯示「張三」)算法
小李: 輸入「李四」(保存數據:context.setAttribute("name","李四")) -> 用戶主頁(顯示「李四」)數據庫
context是全部用戶公有的資源,所以當小李登陸後,用戶主頁將所有顯示爲「李四」,新的數據將會覆蓋原有的數據,所以不可以使用context對象;瀏覽器
2 Request對象:該對象只在同一個頁面有效,當須要進行頁面跳轉的時候,顯然必須使用轉發技術來實現,所以Request對象也不可以有效解決該問題。緩存
爲了解決上述的問題,這裏引入了會話技術,其中會話技術主要分爲兩個部分,cookie技術和session技術,前者將數據保存在客戶端,後者將數據保存在服務器。服務器
Cookie類:用於存儲會話數據cookie
1)構造Cookie對象
2)設置cookie
3)發送cookie到瀏覽器端保存
4)服務器接收cookie:
1)服務器建立cookie對象,把會話數據存儲到cookie對象中。
2)服務器發送cookie信息到瀏覽器
舉例: set-cookie: name=Infaraway ( 隱藏發送了一個set-cookie名稱的響應頭 )
3)瀏覽器獲得服務器發送的cookie,而後保存在瀏覽器端。
4)瀏覽器在下次訪問服務器時,會帶着cookie信息
舉例: cookie: name=Infaraway (隱藏帶着一個叫cookie名稱的請求頭)
5)服務器接收到瀏覽器帶來的cookie信息
1 package com.infaraway.servlet; 2 3 import javax.servlet.ServletException; 4 import javax.servlet.http.Cookie; 5 import javax.servlet.http.HttpServletRequest; 6 import javax.servlet.http.HttpServletResponse; 7 import java.io.IOException; 8 9 /** 10 * Created by :Infaraway 11 * DATE : 2017/3/25 12 * Time : 22:08 13 * Funtion : cookie測試 14 */ 15 public class CreateCookie { 16 public void doGet(HttpServletRequest request, HttpServletResponse response) 17 throws ServletException, IOException { 18 //1.建立Cookie對象 19 Cookie cookie1 = new Cookie("name","Infaraway"); 20 //Cookie cookie2 = new Cookie("email","Infaraway@qq.com"); 21 //Cookie cookie1 = new Cookie("email","Infaraway@qq.com"); 22 23 /** 24 * 1)設置cookie的有效路徑。默認狀況:有效路徑在當前web應用下。 /cookie 25 */ 26 //cookie1.setPath("/cookie"); 27 //cookie2.setPath("/basisJavaWeb"); 28 /** 29 * 2)設置cookie的有效時間 30 * 正整數:表示cookie數據保存瀏覽器的緩存目錄(硬盤中),數值表示保存的時間。 31 * 負整數:表示cookie數據保存瀏覽器的內存中。瀏覽器關閉cookie就丟失了! 32 * 零:表示刪除同名的cookie數據 33 */ 34 //cookie1.setMaxAge(20); //20秒,從最後不調用cookie開始計算 35 cookie1.setMaxAge(-1); //cookie保存在瀏覽器內存(會話cookie) 36 //cookie1.setMaxAge(0); 37 38 //2.把cookie數據發送到瀏覽器(經過響應頭髮送: set-cookie名稱) 39 //response.setHeader("set-cookie", cookie.getName()+"="+cookie.getValue()+",email=eric@qq.com"); 40 //推薦使用這種方法,避免手動發送cookie信息 41 response.addCookie(cookie1); 42 //response.addCookie(cookie2); 43 //response.addCookie(cookie1); 44 45 //3.接收瀏覽器發送的cookie信息 46 /*String name = request.getHeader("cookie"); 47 System.out.println(name);*/ 48 Cookie[] cookies = request.getCookies(); 49 //注意:判斷null,不然空指針 50 if(cookies!=null){ 51 //遍歷 52 for(Cookie c:cookies){ 53 String name = c.getName(); 54 String value = c.getValue(); 55 System.out.println(name+"="+value); 56 } 57 }else{ 58 System.out.println("沒有接收cookie數據"); 59 } 60 } 61 }
1)void setPath(java.lang.String uri) :設置cookie的有效訪問路徑。有效路徑指的是cookie的有效路徑保存在哪裏,那麼瀏覽器在有效路徑下訪問服務器時就會帶着cookie信息,不然不帶cookie信息。
2)void setMaxAge(int expiry) : 設置cookie的有效時間。
3)Cookie數據類型只能保存非中文字符串類型的。能夠保存多個cookie,可是瀏覽器通常只容許存放300個Cookie,每一個站點最多存放20個Cookie,每一個Cookie的大小限制爲4KB。
首先是商品的實體類:
1 package com.infaraway.entity; 2 3 4 /** 5 * Created by :Infaraway 6 * DATE : 2017/3/25 7 * Time : 14:34 8 * Funtion : 商品類 9 */ 10 public class Product { 11 12 private String id; 13 private String proName; 14 private String proType; 15 private double price; 16 public String getId() { 17 return id; 18 } 19 public void setId(String id) { 20 this.id = id; 21 } 22 public String getProName() { 23 return proName; 24 } 25 public void setProName(String proName) { 26 this.proName = proName; 27 } 28 public String getProType() { 29 return proType; 30 } 31 public void setProType(String proType) { 32 this.proType = proType; 33 } 34 public double getPrice() { 35 return price; 36 } 37 public void setPrice(double price) { 38 this.price = price; 39 } 40 public Product(String id, String proName, String proType, double price) { 41 super(); 42 this.id = id; 43 this.proName = proName; 44 this.proType = proType; 45 this.price = price; 46 } 47 public Product() { 48 super(); 49 // TODO Auto-generated constructor stub 50 } 51 @Override 52 public String toString() { 53 return "Product [id=" + id + ", price=" + price + ", proName=" 54 + proName + ", proType=" + proType + "]"; 55 } 56 57 }
這裏咱們使用list集合來模擬數據庫,使用dao層進行增刪改查操做
1 package com.infaraway.dao; 2 3 4 import com.infaraway.entity.Product; 5 6 import java.util.ArrayList; 7 import java.util.List; 8 9 10 /** 11 * Created by :Infaraway 12 * DATE : 2017/3/25 13 * Time : 14:34 14 * Funtion : 商品的增刪改查操做 15 */ 16 public class ProductDao { 17 //模擬數據庫,存儲全部的商品信息 18 private static List<Product> data = new ArrayList<Product>(); 19 20 /** 21 * 靜態代碼塊,初始化 22 */ 23 static{ 24 //初始化 25 for(int i=1;i<=10;i++){ 26 data.add(new Product(""+i,"筆記本"+i,"LN00"+i,334.0+i)); 27 } 28 } 29 30 31 /** 32 * 顯示全部的商品 33 */ 34 public List<Product> findAll(){ 35 return data; 36 } 37 38 /** 39 * 根據id查找商品 40 */ 41 public Product findById(String id){ 42 for(Product p:data){ 43 if(p.getId().equals(id)){ 44 return p; 45 } 46 } 47 return null; 48 } 49 50 }
而後給出商品列表界面,由用戶點擊選擇瀏覽的商品,而且給出了用戶的瀏覽記錄
1 package com.infaraway.servlet; 2 3 import com.infaraway.dao.ProductDao; 4 import com.infaraway.entity.Product; 5 6 import javax.servlet.ServletException; 7 import javax.servlet.http.Cookie; 8 import javax.servlet.http.HttpServlet; 9 import javax.servlet.http.HttpServletRequest; 10 import javax.servlet.http.HttpServletResponse; 11 import java.io.IOException; 12 import java.io.PrintWriter; 13 import java.util.List; 14 15 /** 16 * Created by :Infaraway 17 * DATE : 2017/3/25 18 * Time : 14:34 19 * Funtion : 20 */ 21 public class ListServlet extends HttpServlet { 22 @Override 23 public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 24 25 resp.setContentType("text/html;charset=utf-8"); 26 ProductDao dao = new ProductDao(); 27 List<Product> productList = dao.findAll(); 28 29 //2.把商品顯示到瀏覽器 30 PrintWriter writer = resp.getWriter(); 31 String html = ""; 32 33 html += "<html>"; 34 html += "<head>"; 35 html += "<title>顯示商品列表</title>"; 36 html += "</head>"; 37 html += "<body>"; 38 html += "<table border='1' align='center' width='600px'>"; 39 html += "<tr>"; 40 html += "<th>編號</th><th>商品名稱</th><th>商品型號</th><th>商品價格</th>"; 41 html += "</tr>"; 42 //遍歷商品 43 if(productList!=null){ 44 for(Product p:productList){ 45 html += "<tr>"; 46 // /day11_hist/DetailServlet?id=1 訪問DetailSErvlet的servlet程序,同時傳遞 名爲id,值爲1 的參數 47 html += "<td>"+p.getId()+"</td><td><a href='"+req.getContextPath()+"/DetailServlet?id="+p.getId()+"'>"+p.getProName()+"</a></td><td>"+p.getProType()+"</td><td>"+p.getPrice()+"</td>"; 48 html += "<tr>"; 49 } 50 } 51 html += "</table>"; 52 53 54 /** 55 * 顯示瀏覽過的商品 56 */ 57 html += "最近瀏覽過的商品:<br/>"; 58 //取出prodHist的cookie 59 Cookie[] cookies = req.getCookies(); 60 if(cookies!=null){ 61 for (Cookie cookie : cookies) { 62 if(cookie.getName().equals("prodHist")){ 63 String prodHist = cookie.getValue(); // 3,2,1 64 String[] ids = prodHist.split(","); 65 //遍歷瀏覽過的商品id 66 for (String id : ids) { 67 //查詢數據庫,查詢對應的商品 68 Product p = dao.findById(id); 69 //顯示到瀏覽器 70 html += ""+p.getId()+" "+p.getProName()+" "+p.getPrice()+"<br/>"; 71 } 72 } 73 } 74 } 75 76 77 html += "</body>"; 78 html += "</html>"; 79 80 writer.write(html); 81 82 } 83 84 @Override 85 public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 86 super.doGet(req, resp); 87 } 88 }
最後給出商品詳情界面
1 package com.infaraway.servlet; 2 3 4 import com.infaraway.dao.ProductDao; 5 import com.infaraway.entity.Product; 6 7 import java.io.IOException; 8 import java.io.PrintWriter; 9 import java.util.Arrays; 10 import java.util.Collection; 11 import java.util.LinkedList; 12 13 import javax.servlet.ServletException; 14 import javax.servlet.http.Cookie; 15 import javax.servlet.http.HttpServlet; 16 import javax.servlet.http.HttpServletRequest; 17 import javax.servlet.http.HttpServletResponse; 18 /** 19 * Created by :Infaraway 20 * DATE : 2017/3/25 21 * Time : 14:34 22 * Funtion : 商品信息詳細頁面 23 */ 24 public class DetailServlet extends HttpServlet { 25 26 public void doGet(HttpServletRequest request, HttpServletResponse response) 27 throws ServletException, IOException { 28 response.setContentType("text/html;charset=utf-8"); 29 //1.獲取傳來的商品id 30 String id = request.getParameter("id"); 31 32 //2. 建立dao,進行商品的操做 33 ProductDao dao = new ProductDao(); 34 Product product = dao.findById(id); 35 36 //3.將商品信息打印到瀏覽器頁面 37 PrintWriter writer = response.getWriter(); 38 String html = ""; 39 40 html += "<html>"; 41 html += "<head>"; 42 html += "<title>商品詳情</title>"; 43 html += "</head>"; 44 html += "<body>"; 45 html += "<table border='1' align='center' width='300px'>"; 46 if(product!=null){ 47 html += "<tr><th>編號:</th><td>"+product.getId()+"</td></tr>"; 48 html += "<tr><th>商品名稱:</th><td>"+product.getProName()+"</td></tr>"; 49 html += "<tr><th>商品類型:</th><td>"+product.getProType()+"</td></tr>"; 50 html += "<tr><th>商品價格:</th><td>"+product.getPrice()+"</td></tr>"; 51 } 52 53 html += "</table>"; 54 html += "<center><a href='"+request.getContextPath()+"/ListServlet'>[返回列表]</a></center>"; 55 html += "</body>"; 56 html += "</html>"; 57 58 writer.write(html); 59 60 61 /** 62 * 將瀏覽過的商品存入cookie 63 */ 64 //1.建立cookie 65 Cookie cookie = new Cookie("prodHist",createValue(request,id)); 66 cookie.setMaxAge(1*30*24*60*60);//設置cookie有效時間(單位:s) 67 //2.保存cookie 68 response.addCookie(cookie); 69 } 70 71 /** 72 * 生成cookie的值信息 73 * 當前cookie值 --> 傳入的商品id --> 最終的cookie值 74 * null或沒有prodHist 1 1 (算法: 直接返回傳入的id ) 75 * 1 2 2,1 (沒有重複且小於3個。算法:直接把傳入的id放最前面 ) 76 * 2,1 1 1,2(有重複且小於3個。算法:去除重複id,把傳入的id放最前面 ) 77 * 3,2,1 2 2,3,1(有重複且3個。算法:去除重複id,把傳入的id放最前面) 78 * 3,2,1 4 4,3,2(沒有重複且3個。算法:去最後的id,把傳入的id放最前面) 79 */ 80 private String createValue(HttpServletRequest request,String id) { 81 82 Cookie[] cookies = request.getCookies(); 83 String prodHist = null; 84 if(cookies!=null){ 85 for (Cookie cookie : cookies) { 86 if(cookie.getName().equals("prodHist")){ 87 prodHist = cookie.getValue(); 88 break; 89 } 90 } 91 } 92 93 94 // null或沒有prodHist 95 if(cookies==null || prodHist==null){ 96 //直接返回傳入的id 97 return id; 98 } 99 100 // 3,21 2 101 //String -> String[] -> Collection :爲了方便判斷重複id 102 String[] ids = prodHist.split(","); 103 Collection<String> colls = Arrays.asList(ids); //<3,21> 104 // LinkedList 方便地操做(增刪改元素)集合 105 // Collection -> LinkedList 106 LinkedList<String> list = new LinkedList<String>(colls); 107 108 109 //不超過3個 110 if(list.size()<3){ 111 //id重複 112 if(list.contains(id)){ 113 //去除重複id,把傳入的id放最前面 114 list.remove(id); 115 list.addFirst(id); 116 }else{ 117 //直接把傳入的id放最前面 118 list.addFirst(id); 119 } 120 }else{ 121 //等於3個 122 //id重複 123 if(list.contains(id)){ 124 //去除重複id,把傳入的id放最前面 125 list.remove(id); 126 list.addFirst(id); 127 }else{ 128 //去最後的id,把傳入的id放最前面 129 list.removeLast(); 130 list.addFirst(id); 131 } 132 } 133 134 // LinedList -> String 135 StringBuffer sb = new StringBuffer(); 136 for (Object object : list) { 137 sb.append(object+","); 138 } 139 //去掉最後的逗號 140 String result = sb.toString(); 141 result = result.substring(0, result.length()-1); 142 return result; 143 } 144 145 public void doPost(HttpServletRequest request, HttpServletResponse response) 146 throws ServletException, IOException { 147 doGet(request, response); 148 } 149 150 }
上述代碼能夠在這裏找到:https://git.oschina.net/infaraway/basisJavaWeb/tree/master/cookie
2.1 引入
Cookie的侷限:
若是要保存非字符串,超過4kb內容,只能使用session技術!
Session特色:會話數據保存在服務器端。(內存中)
2.2 Session技術核心
HttpSession類:用於保存會話數據
1)建立或獲得session對象
2)設置session對象
3)保存會話數據到session對象
2.3 Session原理
問題: 服務器可以識別不一樣的瀏覽者!
關鍵: 在哪一個session域對象保存數據,就必須從哪一個域對象取出!
代碼解讀:HttpSession session = request.getSession();
1)第一次訪問建立session對象,給session對象分配一個惟一的ID,叫JSESSIONID
new HttpSession();
2)把JSESSIONID做爲Cookie的值發送給瀏覽器保存
Cookie cookie = new Cookie("JSESSIONID", sessionID);
response.addCookie(cookie);
3)第二次訪問的時候,瀏覽器帶着JSESSIONID的cookie訪問服務器
4)服務器獲得JSESSIONID,在服務器的內存中搜索是否存放對應編號的session對象。
if(找到){
return map.get(sessionID);
}
Map<String,HttpSession>
5)若是找到對應編號的session對象,直接返回該對象
6)若是找不到對應編號的session對象,建立新的session對象,繼續走1的流程
結論:經過JSESSION的cookie值在服務器找session對象!
1 import java.io.IOException; 2 3 import javax.servlet.ServletException; 4 import javax.servlet.http.Cookie; 5 import javax.servlet.http.HttpServlet; 6 import javax.servlet.http.HttpServletRequest; 7 import javax.servlet.http.HttpServletResponse; 8 import javax.servlet.http.HttpSession; 9 /** 10 * Created by :Infaraway 11 * DATE : 2017/3/25 12 * Time : 14:34 13 * Funtion : session對象的建立 14 */ 15 public class CreateSession extends HttpServlet { 16 17 public void doGet(HttpServletRequest request, HttpServletResponse response) 18 throws ServletException, IOException { 19 //1.建立session對象 20 HttpSession session = request.getSession(); 21 //獲得session編號 22 System.out.println("id="+session.getId()); 23 //修改session的有效時間 24 //session.setMaxInactiveInterval(20); 25 26 //手動發送一個硬盤保存的cookie給瀏覽器 27 Cookie c = new Cookie("JSESSIONID",session.getId()); 28 c.setMaxAge(60*60); 29 response.addCookie(c); 30 31 //2.保存會話數據 32 session.setAttribute("name", "Infaraway"); 33 } 34 }
1 package com.infaraway.servlet; 2 3 import javax.servlet.ServletException; 4 import javax.servlet.http.Cookie; 5 import javax.servlet.http.HttpServlet; 6 import javax.servlet.http.HttpServletRequest; 7 import javax.servlet.http.HttpServletResponse; 8 import java.io.IOException; 9 10 /** 11 * Created by :Infaraway 12 * DATE : 2017/3/25 13 * Time : 22:17 14 * Funtion : 15 */ 16 public class DeleteCookie extends HttpServlet { 17 18 public void doGet(HttpServletRequest request, HttpServletResponse response) 19 throws ServletException, IOException { 20 /** 21 * 需求: 刪除cookie 22 */ 23 Cookie cookie = new Cookie("name","xxxx"); 24 cookie.setMaxAge(0);//刪除同名的cookie 25 response.addCookie(cookie); 26 System.out.println("刪除成功"); 27 28 } 29 }
1)java.lang.String getId() : 獲得session編號
2)兩個getSession方法:
3)void setMaxInactiveInterval(int interval) : 設置session的有效時間
session對象銷燬時間:
1 <!-- 修改session全局有效時間:分鐘 --> 2 <session-config> 3 <session-timeout>1</session-timeout> 4 </session-config>
void invalidate() : 銷燬session對象
4)如何避免瀏覽器的JSESSIONID的cookie隨着瀏覽器關閉而丟失的問題?
瀏覽器關閉而丟失cookie的緣由是cookie的有效時間設置中參數爲負整數致使,所以需求使用setMaxAge()函數將時間修正爲正整數便可。
1 /** 2 * 手動發送一個硬盤保存的cookie給瀏覽器 3 */ 4 Cookie c = new Cookie("JSESSIONID",session.getId()); 5 c.setMaxAge(60*60); 6 response.addCookie(c);
上述代碼能夠在這裏找到:https://git.oschina.net/infaraway/basisJavaWeb/tree/master/session
1)會話管理: 瀏覽器和服務器會話過程當中的產生的會話數據的管理。
2)Cookie技術:
3)Session技術