上一節我們總結了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的案例中基本一致)
//首頁:列出所有書 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; } }
從上面程序中可以看出,當用戶點擊購買時,將書的id號帶上,并跳轉到BuyServlet去處理:
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就總結這么多,如有錯誤之處,歡迎留言指正~
文章列表
留言列表