文章出處

   上一節我們總結了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就總結這么多,如有錯誤之處,歡迎留言指正~


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()