會話管理之session技術
上一節我們總結了cookie技術,這節主要總結一下session技術。
1. session物件
在web開發中,伺服器可以為每個使用者瀏覽器建立一個會話物件(session物件),注意:一個瀏覽器獨佔一個session物件(預設情況下)。因此,在需要儲存使用者資料時,伺服器程式可以把使用者資料寫到使用者瀏覽器獨佔的session中,當用戶使用瀏覽器訪問其它程式時,其它程式可以從使用者的session中取出該使用者的資料,為使用者服務。
session和cookie的主要區別在於:cookie是把使用者的資料寫給使用者的瀏覽器(儲存在客戶機);session技術把使用者的資料寫到使用者獨佔的session中(儲存在伺服器)。
session物件由伺服器建立,開發人員可以呼叫request物件的getSession方法得到session物件。
2. session實現原理
瀏覽器A第一次訪問Servlet1,伺服器會建立一個session,每個session都有一個id號,建立好了後,伺服器將id號以cookie的形式回送給客戶機(這些是伺服器自動完成的)。當瀏覽器未關閉前再次發請求訪問Servlet2時,就會帶著這個id號去訪問伺服器,這時候伺服器檢索下記憶體中有沒有與之對應的session,有就用這個session為其服務。
如果想要關掉瀏覽器再開啟還可以使用同一個session,則需要給伺服器回送的cookie設定有效時間(伺服器自動回送的時候是沒有有效期的)。具體做法是通過session物件的getId方法獲得該session的id,然後建立一個cookie,該cookie的名字為"JSESSIONID",值就是剛剛獲得的id,再將該cookie設定下有效期,(也可以設定下Path),並新增到cookie中即可。但是有效期不得超過30分鐘,因為瀏覽器關掉後,session只儲存30分鐘。
下面通過一個案例來說明一下session的使用。
3. session的一個案例
通過三個servlet來實現簡單的購物功能:
IndexServlet顯示首頁,並列出所有書(這個servlet和上一節cookie的案例中基本一致)
從上面程式中可以看出,當用戶點選購買時,將書的id號帶上,並跳轉到BuyServlet去處理://首頁:列出所有書 public class IndexServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); out.write("本網站有如下書:<br/>"); Set<Map.Entry<String,Book>> set = DB.getAll().entrySet(); for(Map.Entry<String, Book> me : set) { Book book = me.getValue(); out.write(book.getName() + "<a href='/test/servlet/BuyServlet?id="+book.getId()+"'>購買</a><br/>"); } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } //寫一個類來模擬資料庫 class DB { private static Map<String,Book> map = new LinkedHashMap(); //靜態程式碼塊中的內容只執行一次,該類在載入時,往map集合中put一系列書,map也需要設定為靜態的 static{ map.put("1", new Book("1", "javaweb開發","老張", "一本好書")); map.put("2", new Book("2", "spring開發","老倪", "一本好書")); map.put("3", new Book("3", "hibernate開發","老童", "一本好書")); map.put("4", new Book("4", "struts開發","老畢", "一本好書")); map.put("5", new Book("5", "ajax開發","老張", "一本好書")); map.put("6", new Book("6", "java基礎","老孫", "一本好書")); } public static Map getAll() { return map; } } class Book { private String id; private String name; private String author; private String description; public Book() { } public Book(String id, String name, String author, String description) { super(); this.id = id; this.name = name; this.author = author; this.description = description; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } }
public class BuyServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String id = request.getParameter("id"); //獲得url中帶過來的引數id
Book book = (Book)DB.getAll().get(id); //在DB中獲得該id號的book
HttpSession session = request.getSession(); //獲得當前session物件
Cookie cookie = new Cookie("JSESSIONID", session.getId()); //設定新的cookie,注意cookie名必須為JSESSIONID,值為該session的id
cookie.setMaxAge(30*60); //設定cookie有效期
cookie.setPath("/test"); //設定cookie的路徑
response.addCookie(cookie); //將cookie新增到cookies中帶給瀏覽器,下次瀏覽器訪問,就會將此cookie帶過來了
//先把書加到容器裡,再把容器加到session中。一般先檢查使用者的session中有沒有儲存書的容器,沒有就建立,有就加
List list = (List)session.getAttribute("list");
if(list == null) {
list = new ArrayList();
session.setAttribute("list", list);
}
list.add(book);
//跳轉到顯示使用者買過哪些商品
// request.getRequestDispatcher("/servlet/ListCartServlet").forward(request, response);
response.sendRedirect("/test/servlet/ListCartServlet");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
從上面的程式可以看出,當用戶點選購買後,會將書的id號帶過來,我們拿到id號後就可以找到相應的書,同時我們將當前session的id儲存到cookie中,再帶給瀏覽器,這樣下次瀏覽器訪問的時候就會將當前session的id帶過來了。拿到相應的書後,放到list中,再把list放到session中,這樣下次跳轉的時候,瀏覽器帶來的cookie中有當前session的id,我們可以通過getSession()獲得當前的session,再把session中儲存的list拿出來,就知道使用者買了哪些書了。這就是購物車的原理,請看下面的ListCartServlet:public class ListCartServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
HttpSession session = request.getSession(); //獲得當前的session
List<Book> list = (List)session.getAttribute("list"); //從session中拿出list
if(list == null || list.size() == 0) {
out.write("對不起,您還沒有購買任何商品!");
return;
}
out.write("您買過如下商品:<br/>");
for(Book book : list) {
out.write(book.getName() + "<br/>");
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
4. 瀏覽器禁用cookie後的session處理
由上文可知,session通過向瀏覽器回送cookie,如果使用者將瀏覽器的cookie禁用了該如何解決?
解決方案:url重寫,讓session的id不以cookie的形式帶過來,以url中帶過來。有兩個url重寫的方法:
response.encodeRedirectURL(java.lang.String url); //用於對sendRedirect方法後的url地址進行重寫。
response.encodeURL(java.lang.String url); //用於對錶單action和超連結的url地址進行重寫。
在BuyServlet.java中,把session的id號寫入cookie的幾行程式碼去掉,將response.sendRedirect("/test/servlet/ListCartServlet");
改為:response.sendRedirect(response.encodeRedirectURL("/test/servlet/ListCartServlet"));
在IndexServlet.java中,把out.write(book.getName() + "<a href='/test/servlet/BuyServlet?id="+book.getId()+"'>購買</a><br/>");
改寫成:String url= "/test/servlet/BuyServlet?id=" + book.getId();
url= response.encodeURL(url);
out.write(book.getName() + "<a href='" + url + "'>購買</a><br/>");
還有最後一步很重要:在out.write("本網站有如下書:<br/>");
之前加上request.getSession();
因為要實現共享一個session,必須首先獲得session。這樣就算瀏覽器禁用了cookie,我們依然可以共享一個session了。
5. 總結
1. 伺服器是如何做到一個session為一個瀏覽器的多次請求而服務的?
伺服器建立session出來後,會把session的id號以cookie的形式回寫給客戶機,這樣,只要客戶機的瀏覽器不關,再去訪問伺服器時,都會帶著session的id號去,伺服器發現客戶機帶session的id過來了,就會使用記憶體中與之對應的session為之服務。
2. 如何做到一個session為多個瀏覽器服務?
伺服器第一次建立session,程式設計師把session的id號手動以cookie的形式回送給瀏覽器,並設定cookie的有效期,這樣即使使用者的瀏覽器關了,開新的瀏覽器時,還會帶著session的id號找伺服器,伺服器從而就可以用記憶體中與之對應的session為第二個瀏覽器視窗服務。
3. 如何做到使用者禁用cookie後,session還能為多次請求而服務?
把使用者可能點選的每一個超連結後面,都跟上使用者的session id號。
4. session物件的建立和銷燬時機
使用者第一次request.getSession時建立。session物件預設在30分鐘沒有使用,則伺服器會自動銷燬session。但是使用者可以在web.xml檔案中手動配置session的失效時間: 下面表示1分鐘失效:
<session-config>
<session-timeout>1</session-timeout>
</session-config>
使用者也可以手動呼叫session.invalidate方法,摧毀session。session就總結這麼多,如有錯誤之處,歡迎留言指正~
_____________________________________________________________________________________________________________________________________________________
-----樂於分享,共同進步!