基本概念: 指用戶開一個瀏覽器,訪問一個網站,只要不關閉該瀏覽器,無論該用戶點擊多少個超連接,訪問多少資源,直到用戶關閉瀏覽器,整個這個過程咱們稱爲一次會話.html
會話跟蹤技術能夠解決咱們不少不少問題。java
會話跟蹤技術有Cookie和Session,Cookie技術是先出現的。咱們先講Cookie技術吧。mysql
Cookie是由W3C組織提出,最先由netscape社區發展的一種機制web
Cookie的流程:瀏覽器訪問服務器,若是服務器須要記錄該用戶的狀態,就使用response向瀏覽器發送一個Cookie,瀏覽器會把Cookie保存起來。當瀏覽器再次訪問服務器的時候,瀏覽器會把請求的網址連同Cookie一同交給服務器。ajax
經常使用的Cookie方法:算法
//設置response的編碼
response.setContentType("text/html;charset=UTF-8");
//建立Cookie對象,指定名稱和值
Cookie cookie = new Cookie("username", "zhongfucheng");
//向瀏覽器給一個Cookie
response.addCookie(cookie);
response.getWriter().write("我已經向瀏覽器發送了一個Cookie");
複製代碼
//設置Cookie的時間
cookie.setMaxAge(1000);
複製代碼
response.setContentType("text/html;charset=UTF-8");
PrintWriter printWriter = response.getWriter();
String name = "中國";
Cookie cookie = new Cookie("country", name);
cookie.setMaxAge(2000);
response.addCookie(cookie);
printWriter.write("我頒發了一個Cookie,值保存的是中文數據");
複製代碼
//對Unicode字符進行編碼
Cookie cookie = new Cookie("country", URLEncoder.encode(name, "UTF-8"));
複製代碼
Cookie[] cookies = request.getCookies();
for (int i = 0; cookies != null && i < cookies.length; i++) {
String name = cookies[i].getName();
//通過URLEncoding就要URLDecoding
String value = URLDecoder.decode(cookies[i].getValue(), "UTF-8");
printWriter.write(name + "------" + value);
}
複製代碼
Cookie的有效期是經過setMaxAge()來設置的。sql
Cookie的名稱相同,經過response添加到瀏覽器中,會覆蓋原來的Cookie。數據庫
以country爲名保存的是%E4%B8%AD%E5%9B%BD,下面我再以country爲名,把值改變一下。 跨域
String name = "看完博客就點贊";
//對Unicode字符進行編碼
Cookie cookie = new Cookie("country", URLEncoder.encode(name, "UTF-8"));
複製代碼
String name = "看完博客就點贊";
//對Unicode字符進行編碼
Cookie cookie = new Cookie("country", URLEncoder.encode(name, "UTF-8"));
//必定不要忘記添加到瀏覽器中
cookie.setMaxAge(0);
response.addCookie(cookie);
printWriter.write("我刪除了該Cookie");
複製代碼
注意:刪除,修改Cookie時,新建的Cookie除了value、maxAge以外的全部屬性都要與原Cookie相同。不然瀏覽器將視爲不一樣的Cookie,不予覆蓋,致使刪除修改失敗!瀏覽器
咱們來試驗一下把。
String name = "看完博客就點贊";
//對Unicode字符進行編碼
Cookie cookie = new Cookie("country", URLEncoder.encode(name, "UTF-8"));
//必定不要忘記添加到瀏覽器中
cookie.setMaxAge(10000);
response.addCookie(cookie);
複製代碼
//必定不要忘記添加到瀏覽器中
cookie.setPath("/ouzicheng");
cookie.setMaxAge(0);
response.addCookie(cookie);
printWriter.write("刪除一個Cookie");
複製代碼
Cookie的domain屬性決定運行訪問Cookie的域名。domain的值規定爲「.域名」
Cookie的隱私安全機制決定Cookie是不可跨域名的。也就是說www.baidu.com和www.google.com之間的Cookie是互不交接的。即便是同一級域名,不一樣二級域名也不能交接,也就是說:www.goole.com和www.image.goole.com的Cookie也不能訪問
我在本地上配置了3個虛擬主機,localhost,www.zhongfucheng.com,www.image.zhongfucheng.com【若是不知道怎麼配置,在我Tomcat的博客有】
Cookie cookie = new Cookie("name", "zhongfucheng");
cookie.setMaxAge(1000);
response.addCookie(cookie);
printWriter.write("使用www.zhongfucheng.com域名添加了一個Cookie");
複製代碼
Cookie cookie = new Cookie("name", "ouzicheng");
cookie.setMaxAge(1000);
cookie.setDomain(".zhongfucheng.com");
response.addCookie(cookie);
printWriter.write("使用www.zhongfucheng.com域名添加了一個Cookie,只要一級是zhongfucheng.com便可訪問");
複製代碼
使用www.zhongfucheng.com發佈一個Cookie
使用www.image.zhongfucheng.com域名訪問一下。發現能夠獲取到Cookie了
Cookie的path屬性決定容許訪問Cookie的路徑
通常地,Cookie發佈出來,整個網頁的資源均可以使用。如今我只想Servlet1能夠獲取到Cookie,其餘的資源不能獲取。
使用Servlet2頒發一個Cookie給瀏覽器,設置路徑爲"/Servlet1"。
Cookie cookie = new Cookie("username", "java");
cookie.setPath("/Servlet1");
cookie.setMaxAge(1000);
response.addCookie(cookie);
printWriter.write("該Cookie只有Servlet1獲取獲得");
複製代碼
其實就是每次登錄的時候,取到Cookie保存的值,再更新下Cookie的值。
訪問Serlvet有兩種狀況
所有代碼以下:
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
response.setContentType("text/html;charset=UTF-8");
PrintWriter printWriter = response.getWriter();
//獲取網頁上全部的Cookie
Cookie[] cookies = request.getCookies();
//判斷Cookie的值是否爲空
String cookieValue = null;
for (int i = 0; cookies != null && i < cookies.length; i++) {
//獲取到以time爲名的Cookie
if (cookies[i].getName().equals("time")) {
printWriter.write("您上次登錄的時間是:");
cookieValue = cookies[i].getValue();
printWriter.write(cookieValue);
cookies[i].setValue(simpleDateFormat.format(new Date()));
response.addCookie(cookies[i]);
//既然已經找到了就能夠break循環了
break;
}
}
//若是Cookie的值是空的,那麼就是第一次訪問
if (cookieValue == null) {
//建立一個Cookie對象,日期爲當前時間
Cookie cookie = new Cookie("time", simpleDateFormat.format(new Date()));
//設置Cookie的生命期
cookie.setMaxAge(20000);
//response對象回送Cookie給瀏覽器
response.addCookie(cookie);
printWriter.write("您是第一次登錄啊!");
}
複製代碼
可是,按照上面的邏輯是作不到的!由於每次訪問Servlet的時候都會覆蓋原來的Cookie,取到Cookie的值永遠都是當前時間,而不是上次保存的時間。
咱們換一個邏輯寫:先檢查(遍歷)全部Cookie有沒有我要的,若是得不到我想要的Cookie,Cookie的值是null,那麼就是第一次登錄,因而就有了上面的代碼了。
咱們來看下效果吧!當我第一次登錄的時候
private String id ;
private String name ;
private String author;
public Book() {
}
public Book(String id, String name, String author) {
this.id = id;
this.name = name;
this.author = author;
}
...各類set、get方法
複製代碼
private static LinkedHashMap<String, Book> linkedHashMap = new LinkedHashMap();
//簡化開發複雜度,book的id和商品的id相同
static {
linkedHashMap.put("1", new Book("1", "javaweb", "zhong"));
linkedHashMap.put("2", new Book("2", "java", "fu"));
linkedHashMap.put("3", new Book("3", "oracle", "cheng"));
linkedHashMap.put("4", new Book("4", "mysql", "ou"));
linkedHashMap.put("5", new Book("5", "ajax", "zi"));
}
//獲取到全部書籍
public static LinkedHashMap getAll() {
return linkedHashMap;
}
複製代碼
printWriter.write("網頁上全部的書籍:"+"<br/>");
//拿到數據庫全部的書
LinkedHashMap<String, Book> linkedHashMap = DB.getAll();
Set<Map.Entry<String, Book>> entry = linkedHashMap.entrySet();
//顯示全部的書到網頁上
for (Map.Entry<String, Book> stringBookEntry : entry) {
Book book = stringBookEntry.getValue();
printWriter.write(book.getId() +" "+ book.getName()+"<br/>");
}
複製代碼
//顯示全部的書到網頁上
for (Map.Entry<String, Book> stringBookEntry : entry) {
Book book = stringBookEntry.getValue();
printWriter.write("<a href='/ouzicheng/Servlet2?id=" + book.getId() + "''target=_blank' +" + book.getName() + "</a>");
printWriter.write("<br/>");
}
複製代碼
String id = request.getParameter("id");
//因爲book的id和商品的id是一致的。獲取到用戶點擊的書
Book book = (Book) DB.getAll().get(id);
//輸出書的詳細信息
printWriter.write("書的編號是:" + book.getId()+"<br/>");
printWriter.write("書的名稱是:" + book.getName()+"<br/>");
printWriter.write("書的做者是:" + book.getAuthor()+"<br/>");
複製代碼
既然用戶點擊了書籍,那麼服務器就應該頒發Cookie給瀏覽器,記住用戶點擊了該書籍
如今問題來了,Cookie的值應該是什麼呢?試想一下,待會還要把瀏覽過的書籍顯示出來,因此用書籍的id是最好不過的。想到了用書籍的id做爲Cookie的值,咱們還要定義一些規則!
咱們可能有很是多的書籍,不可能把用戶瀏覽過的書籍都顯示出來。因此咱們定義只能顯示3本瀏覽過的書籍
書籍的id都是數字,若是不作任何修改,存到Cookie裏邊可能就是231,345,123此類的數字,這樣取出某一個id的時候就十分費勁而且後面還要判斷該書是否存在Cookie裏邊了,因此咱們要把存儲到Cookie的書籍id分割起來。因此咱們定義」_「做爲分隔符
按上面的應用,咱們的邏輯應該是:先遍歷下Cookie,看下有沒有咱們想要的Cookie。若是找到想要的Cookie,那就取出Cookie的值
String bookHistory = null;
Cookie[] cookies = request.getCookies();
for (int i = 0; cookies != null && i < cookies.length; i++) {
if (cookies[i].getName().equals("bookHistory")) {
bookHistory = cookies[i].getValue();
}
}
複製代碼
取出了Cookie的值也分幾種狀況
if (bookHistory == null) {
return id;
}
//若是Cookie的值不是null的,那麼就分解Cookie的獲得以前的id。
String[] strings = bookHistory.split("\\_");
//爲了增刪容易而且還要判斷id是否存在於該字符串內-----咱們使用LinkedList集合裝載分解出來的id
List list = Arrays.asList(strings);
LinkedList<String> linkedList = new LinkedList<>();
linkedList.addAll(list);
if (linkedList.contains(id)) {
linkedList.remove(id);
linkedList.addFirst(id);
}else {
if (linkedList.size() >= 3) {
linkedList.removeLast();
linkedList.addFirst(id);
} else {
linkedList.addFirst(id);
}
}
複製代碼
StringBuffer stringBuffer = new StringBuffer();
//遍歷LinkedList集合,添加個下劃線「_」
for (String s : linkedList) {
stringBuffer.append(s + "_");
}
//最後一個元素後面就不須要下劃線了
return stringBuffer.deleteCharAt(stringBuffer.length() - 1).toString();
複製代碼
String bookHistory = makeHistory(request, id);
Cookie cookie = new Cookie("bookHistory", bookHistory);
cookie.setMaxAge(30000);
response.addCookie(cookie);
複製代碼
printWriter.write("您曾經瀏覽過的商品:");
printWriter.write("<br/>");
//顯示用戶瀏覽過的商品
Cookie[] cookies = request.getCookies();
for (int i = 0; cookies != null && i < cookies.length; i++) {
if (cookies[i].getName().equals("bookHistory")) {
//獲取到的bookHistory是2_3_1之類的
String bookHistory = cookies[i].getValue();
//拆解成每個id值
String[] ids = bookHistory.split("\\_");
//獲得每個id值
for (String id : ids) {
//經過id找到每一本書
Book book = linkedHashMap.get(id);
printWriter.write(book.getName());
printWriter.write("<br/>");
}
break;
}
}
複製代碼
若是文章有錯的地方歡迎指正,你們互相交流。習慣在微信看技術文章的同窗,能夠關注微信公衆號:Java3y