2.4 Java Servlet 会话管理 通过HttpSession对象 在所有的会话跟踪技术中,HttpSession 对象是最强大和最通用的。一个用户可以有且最多有一个HttpSession,并且不会被其他用户访问到。
谁创建HttpSession对象 HttpSession对象在用户第一次访问网站的时候自动被创建。
如何获取HttpSession对象 你可以通过调用HttpServletRequest的getSession方法获取该对象。getSession有两个重载方法:
1 2 HttpSession getSession ()  HttpSession getSession (boolean  create)  
 
没有参数的getSession方法会返回当前的HttpSession,若当前没有,则创建一个并返回。getSession(false)返回当前HttpSession,如当前不存在,则返回null。getSession(true)返回当前HttpSession,若当前没有,则创建一个并返回,getSession(true)同getSession()的效果一致.
如何往HttpSession中存入数据 可以通过HttpSession的setAttribute方法将值放入HttpSession,该方法的方法签名如下:
1 void  setAttribute (java.lang.String name, java.lang.Object value) 
 
请注意,不同于URL重新、隐藏域或cookie,放入到HttpSession 的值,是存储在内存中的 ,因此,不要往HttpSession放入太多对象或放入大对象。  尽管现代的Servlet容器在内存不够用的时候会将保存在HttpSessions的对象转储到二级存储上,但这样有性能问题,因此小心存储。
HttpSession中的数据要满足的条件 此外,放到HttpSession的值不限于String类型,可以是任意实现java.io.Serializable的java对象,因为在内存不够用的时候,Servlet容器会将这些对象放入文件或数据库中,当然你也可以将不支持序列化的对象放入HttpSession,只是这样,当Servlet容器进行序列化的时候会失败并报错。调用setAttribute方法时,若传入的name参数此前已经使用过,则会用新值覆盖旧值。 
从HttpSession对象中取出数据 通过调用HttpSession的getAttribute方法可以取回之前放入HttpSession中的对象,该方法的签名如下:
1 java.lang.Object getAttribute (java.lang.String name)  
 
从HttpSession对象中批量取出数据 HttpSession还有一个非常有用的方法,名为getAttributeNames,该方法会返回一个Enumeration对象来迭代访问保存在HttpSession中的所有值:
1 java.util.Enumeration<java.lang.String> getAttributeNames() 
 
注意,所有保存在HttpSession的数据不会被发送到客户端,不同于其他会话管理技术,**Servlet容器为每个HttpSession生成唯一的标识,并将该标识发送给浏览器**,或创建一个名为JSESSIONID的cookie,或者在URL后附加一个名为jsessionid 的参数。在后续的请求中,浏览器会将标识提交给服务端,这样服务器就可以识别该请求是由哪个用户发起的。Servlet容器会自动选择一种方式传递会话标识,无须开发人员介入。提示 :
隐藏域技术会往浏览器发送带隐藏域的表单. 
Cookie技术会往浏览器发送Cookie. 
 
获取Http对象的标识 可以通过调用 HttpSession的getId方法来读取该标识:
1 java.lang.String getId ()  
 
此外,HttpSession.还定义了一个名为invalidate 的方法。该方法强制会话过期,并清空其保存的对象。默认情况下,HttpSession 会在用户不活动一段时间后自动过期,该时间可以通过部署描述符的 session-timeout元素配置,若设置为30,则会话对象会在用户最后一次访问30分钟后过期,如果部署描述符没有配置,则该值取决于Servlet容器的设定。 大部分情况下,你应该主动销毁无用的HttpSession,以便释放相应的内存。
查看设置超时时间 可以通过调用HttpSession 的getMaxInactiveInterval方法来查看会话多久会过期。该方法返回一个数字类型,单位为秒。调用setMaxInactiveInterval 方法来单独对某个HttpSession 设定其超时时间:
1 void  setMaxInactiveInterval (int  seconds) 
 
若设置为0,则该HttpSession 永不过期。通常这不是一个好的设计,因为该 HttpSession 所占用的堆内存将永不释放,直到应用重加载或Servlet容器关闭。
Demo 一个简单的购物Demo,具有显示商品列表,商品详情页面,购物车页面.并且在商品详情页面提供添加到购物车的功能.
Product 商品类用来存储商品的信息,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 package  session.management.httpsession;public  class  Product {          private  int  id;          private  String name;          private  String description;          private  float  price;     public  Product (    int  id,String name,String description,float  price)      {         this .id = id;         this .name = name;         this .description = description;         this .price = price;     }     public  int  getId ()      {         return  id;     }     public  void  setId (int  id)      {         this .id = id;     }     public  String getName ()      {         return  name;     }     public  void  setName (String name)      {         this .name = name;     }     public  String getDescription ()      {         return  description;     }     public  void  setDescription (String description)      {         this .description = description;     }     public  float  getPrice ()      {         return  price;     }     public  void  setPrice (float  price)      {         this .price = price;     } } 
 
购物车中光有商品而已是不行的,还要知道用户买了几个商品,商品和对应的数量构成了购物车中记录的数据结构。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package  session.management.httpsession;public  class  ShoppingItem {          private  Product product;          private  int  quantity;     public  ShoppingItem (Product product,int  quantity)      {         this .product = product;         this .quantity = quantity;     }     public  Product getProduct ()      {         return  product;     }     public  void  setProduct (Product product)      {         this .product = product;     }     public  int  getQuantity ()      {         return  quantity;     }     public  void  setQuantity (int  quantity)      {         this .quantity = quantity;     } } 
 
有了商品,有了记录,下面就来写功能代码了.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 package  session.management.httpsession;import  java.io.IOException;import  java.io.PrintWriter;import  java.text.NumberFormat;import  java.util.ArrayList;import  java.util.List;import  java.util.Locale;import  javax.servlet.ServletException;import  javax.servlet.annotation.WebServlet;import  javax.servlet.http.HttpServlet;import  javax.servlet.http.HttpServletRequest;import  javax.servlet.http.HttpServletResponse;import  javax.servlet.http.HttpSession;@WebServlet(     name = "ShoppingCartServlet",     urlPatterns =     {"/products", "/viewProductDetails", "/addToCart", "/viewCart"} ) public  class  ShoppingCartServlet  extends  HttpServlet {     private  static  final  long  serialVersionUID  =  -20L ;          private  static  final  String     CART_ATTRIBUTE     =  "cart" ;     private  static  final  String     tableStyle         =  "<style>table{border-right:1px solid #F00;border-bottom:1px solid #F00}\r\n"          + "table td{border-left:1px solid #F00;border-top:1px solid #F00}</style>" ;          private  List<Product>    products        = new  ArrayList <Product>();     private  NumberFormat     currencyFormat     =  NumberFormat         .getCurrencyInstance(Locale.CHINA);     @Override      public  void  init ()  throws  ServletException     {         products.add(new  Product (1 , "苹果" , "新鲜上市的苹果" , 5.5F ));         products.add(new  Product (2 , "香蕉" , "新鲜上市的香蕉" , 6.5F ));         products.add(new  Product (3 , "菠萝" , "新鲜上市的菠萝" , 4.8F ));         products.add(new  Product (4 , "草莓" , "新鲜上市的草莓" , 12.5F ));     }     @Override      public  void  doGet (HttpServletRequest request, HttpServletResponse response)          throws  ServletException, IOException     {         response.setCharacterEncoding("utf-8" );         String  uri  =  request.getRequestURI();         if  (uri.endsWith("/products" )) {             sendProductList(response);         } else  if  (uri.endsWith("/viewProductDetails" )) {             sendProductDetails(request, response);         } else  if  (uri.endsWith("/viewCart" )) {             showCart(request, response);         }     }     @Override      public  void  doPost (HttpServletRequest request, HttpServletResponse response)          throws  ServletException, IOException     {         response.setCharacterEncoding("utf-8" );                  int  productId  =  0 ;         int  quantity  =  0 ;         try  {                          productId = Integer.parseInt(request.getParameter("id" ));                          quantity = Integer.parseInt(request.getParameter("quantity" ));         } catch  (NumberFormatException e) {}                  Product  product  =  getProduct(productId);         if  (product != null  && quantity >= 0 ) {                          ShoppingItem  shoppingItem  =  new  ShoppingItem (product, quantity);                          HttpSession  session  =  request.getSession();             @SuppressWarnings(                  "unchecked"             )                          List<ShoppingItem> cart = (List<ShoppingItem>) session                 .getAttribute(CART_ATTRIBUTE);                          if  (cart == null ) {                                  cart = new  ArrayList <ShoppingItem>();                                  session.setAttribute(CART_ATTRIBUTE, cart);             }                          cart.add(shoppingItem);         }         sendProductList(response);     }     private  void  sendProductList (HttpServletResponse response)          throws  IOException     {         response.setContentType("text/html" );         PrintWriter  writer  =  response.getWriter();         writer.println("<html><head><title>商品列表</title>"  + tableStyle             + "</head><body><h2>商品列表</h2>" );         writer.println("<ul>" );         for  (Product product : products) {             writer.println("<li>"  + product.getName() + "("                  + currencyFormat.format(product.getPrice()) + ") ("                  + "<a href='viewProductDetails?id="  + product.getId()                 + "'>宝贝详情</a>)" );         }         writer.println("</ul>" );         writer.println("<a href='viewCart'>查看购物车</a>" );         writer.println("</body></html>" );     }          private  Product getProduct (int  productId)      {         for  (Product product : products) {             if  (product.getId() == productId) {                 return  product;             }         }         return  null ;     }          private  void  sendProductDetails (HttpServletRequest request,          HttpServletResponse response)  throws  IOException    {         response.setContentType("text/html" );         PrintWriter  writer  =  response.getWriter();         int  productId  =  0 ;         try  {                          productId = Integer.parseInt(request.getParameter("id" ));         } catch  (NumberFormatException e) {}                  Product  product  =  getProduct(productId);         if  (product != null ) {             writer.println("<html><head>"  + "<title>商品详情</title>"  + tableStyle                 + "</head>"  + "<body><h2>商品详情</h2>"                  + "<form method='post' action='addToCart'>" );             writer.println("<input type='hidden' name='id' "  + "value='"                  + productId + "'/>" );             writer.println("<table>" );             writer.println(                 "<tr><td>商品名称:</td><td>"  + product.getName() + "</td></tr>" );             writer.println("<tr><td>商品描述:</td><td>"  + product.getDescription()                 + "</td></tr>" );             writer.println(                 "<tr><td>购买数量:</td><td><input name='quantity'/>斤</td></tr>"                      + "<tr><td colspan='2'><input type='submit' value='加入购物车'/>"                      + "</td>"  + "</tr>" );             writer.println("<tr><td colspan='2'>"                  + "<a href='products'>返回商品列表</a>"  + "</td></tr>" );             writer.println("</table>" );             writer.println("</form></body></html>" );         } else  {             writer.println("<h2>找不到该商品</h2>" );         }     }          private  void  showCart (HttpServletRequest request,          HttpServletResponse response)  throws  IOException    {         response.setContentType("text/html" );         PrintWriter  writer  =  response.getWriter();         writer             .println("<html><head><title>购物车</title>"  + tableStyle + "</head>" );         writer.println("<body><a href='products'>"  + "返回商品列表</a>" );         HttpSession  session  =  request.getSession();         @SuppressWarnings(              "unchecked"         )         List<ShoppingItem> cart = (List<ShoppingItem>) session             .getAttribute(CART_ATTRIBUTE);         if  (cart != null ) {             writer.println("<table>" );             writer.println("<tr><td style='width:150px'>数量"  + "</td>"                  + "<td style='width:150px'>商品名称</td>"                  + "<td style='width:150px'>单品价格</td>"  + "<td>合计</td></tr>" );                          double  total  =  0.0 ;                          for  (ShoppingItem shoppingItem : cart) {                                  Product  product  =  shoppingItem.getProduct();                                  int  quantity  =  shoppingItem.getQuantity();                 if  (quantity != 0 ) {                     float  price  =  product.getPrice();                     writer.println("<tr>" );                     writer.println("<td>"  + quantity + "</td>" );                     writer.println("<td>"  + product.getName() + "</td>" );                     writer.println(                         "<td>"  + currencyFormat.format(price) + "</td>" );                     double  subtotal  =  price * quantity;                     writer.println(                         "<td>"  + currencyFormat.format(subtotal) + "</td>" );                     total += subtotal;                     writer.println("</tr>" );                 }             }             writer.println("<tr><td colspan='4' "  + "style='text-align:right'>"                  + "总价格:"  + currencyFormat.format(total) + "</td></tr>" );             writer.println("</table>" );         }         writer.println("</table></body></html>" );     } } 
 
代码详解 创建并初始化商品列表 1 2 3 4 5 6 7 8 9 10 private  List<Product>    products        = new  ArrayList <Product>();@Override public  void  init ()  throws  ServletException{     products.add(new  Product (1 , "苹果" , "新鲜上市的苹果" , 5.5F ));     products.add(new  Product (2 , "香蕉" , "新鲜上市的香蕉" , 6.5F ));     products.add(new  Product (3 , "菠萝" , "新鲜上市的菠萝" , 4.8F ));     products.add(new  Product (4 , "草莓" , "新鲜上市的草莓" , 12.5F )); } 
 
从商品列表中查找出一个商品 1 2 3 4 5 6 7 8 9 10 private  Product getProduct (int  productId) {     for  (Product product : products) {         if  (product.getId() == productId) {             return  product;         }     }     return  null ; } 
 
匹配URL 1 2 3 4 5 @WebServlet(     name = "ShoppingCartServlet",     urlPatterns =     {"/products", "/viewProductDetails", "/addToCart", "/viewCart"} ) 
 
doGet方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Override public  void  doGet (HttpServletRequest request, HttpServletResponse response)     throws  ServletException, IOException {     response.setCharacterEncoding("utf-8" );     String  uri  =  request.getRequestURI();          if  (uri.endsWith("/products" )) {         sendProductList(response);     }          else  if  (uri.endsWith("/viewProductDetails" )) {         sendProductDetails(request, response);     }          else  if  (uri.endsWith("/viewCart" )) {         showCart(request, response);     } } 
 
显示产品列表 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 private  void  sendProductList (HttpServletResponse response)     throws  IOException {     response.setContentType("text/html" );     PrintWriter  writer  =  response.getWriter();     writer.println("<html><head><title>商品列表</title>"  + tableStyle         + "</head><body><h2>商品列表</h2>" );     writer.println("<ul>" );     for  (Product product : products) {         writer.println("<li>"  + product.getName() + "("              + currencyFormat.format(product.getPrice()) + ") ("              + "<a href='viewProductDetails?id="  + product.getId()             + "'>宝贝详情</a>)" );     }     writer.println("</ul>" );     writer.println("<a href='viewCart'>查看购物车</a>" );     writer.println("</body></html>" ); } 
 
显示商品详情 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 private  void  sendProductDetails (HttpServletRequest request,     HttpServletResponse response)  throws  IOException{     response.setContentType("text/html" );     PrintWriter  writer  =  response.getWriter();     int  productId  =  0 ;     try  {                  productId = Integer.parseInt(request.getParameter("id" ));     } catch  (NumberFormatException e) {}          Product  product  =  getProduct(productId);     if  (product != null ) {         writer.println("<html><head>"  + "<title>商品详情</title>"  + tableStyle             + "</head>"  + "<body><h2>商品详情</h2>"              + "<form method='post' action='addToCart'>" );         writer.println("<input type='hidden' name='id' "  + "value='"              + productId + "'/>" );         writer.println("<table>" );         writer.println(             "<tr><td>商品名称:</td><td>"  + product.getName() + "</td></tr>" );         writer.println("<tr><td>商品描述:</td><td>"  + product.getDescription()             + "</td></tr>" );         writer.println(             "<tr><td>购买数量:</td><td><input name='quantity'/>斤</td></tr>"                  + "<tr><td colspan='2'><input type='submit' value='加入购物车'/>"                  + "</td>"  + "</tr>" );         writer.println("<tr><td colspan='2'>"              + "<a href='products'>返回商品列表</a>"  + "</td></tr>" );         writer.println("</table>" );         writer.println("</form></body></html>" );     } else  {         writer.println("<h2>找不到该商品</h2>" );     } } 
 
显示商品详情页,表单属性如下:
1 <form  method ='post'  action ='addToCart' > 
 
当用户点击加入购物车时,会使用POST方法把表单发送给.\addToCart这个URL.
doPost方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 @Override public  void  doPost (HttpServletRequest request, HttpServletResponse response)     throws  ServletException, IOException {     response.setCharacterEncoding("utf-8" );          int  productId  =  0 ;     int  quantity  =  0 ;     try  {                  productId = Integer.parseInt(request.getParameter("id" ));                  quantity = Integer.parseInt(request.getParameter("quantity" ));     } catch  (NumberFormatException e) {}          Product  product  =  getProduct(productId);     if  (product != null  && quantity >= 0 ) {                  ShoppingItem  shoppingItem  =  new  ShoppingItem (product, quantity);                  HttpSession  session  =  request.getSession();         @SuppressWarnings(              "unchecked"         )                  List<ShoppingItem> cart = (List<ShoppingItem>) session             .getAttribute(CART_ATTRIBUTE);                  if  (cart == null ) {                          cart = new  ArrayList <ShoppingItem>();                          session.setAttribute(CART_ATTRIBUTE, cart);         }                  cart.add(shoppingItem);     }     sendProductList(response); } 
 
显示购物车 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 private  void  showCart (HttpServletRequest request,     HttpServletResponse response)  throws  IOException{     response.setContentType("text/html" );     PrintWriter  writer  =  response.getWriter();     writer         .println("<html><head><title>购物车</title>"  + tableStyle + "</head>" );     writer.println("<body><a href='products'>"  + "返回商品列表</a>" );     HttpSession  session  =  request.getSession();     @SuppressWarnings(          "unchecked"     )     List<ShoppingItem> cart = (List<ShoppingItem>) session         .getAttribute(CART_ATTRIBUTE);     if  (cart != null ) {         writer.println("<table>" );         writer.println("<tr><td style='width:150px'>数量"  + "</td>"              + "<td style='width:150px'>商品名称</td>"              + "<td style='width:150px'>单品价格</td>"  + "<td>合计</td></tr>" );                  double  total  =  0.0 ;                  for  (ShoppingItem shoppingItem : cart) {                          Product  product  =  shoppingItem.getProduct();                          int  quantity  =  shoppingItem.getQuantity();             if  (quantity != 0 ) {                 float  price  =  product.getPrice();                 writer.println("<tr>" );                 writer.println("<td>"  + quantity + "</td>" );                 writer.println("<td>"  + product.getName() + "</td>" );                 writer.println(                     "<td>"  + currencyFormat.format(price) + "</td>" );                 double  subtotal  =  price * quantity;                 writer.println(                     "<td>"  + currencyFormat.format(subtotal) + "</td>" );                 total += subtotal;                 writer.println("</tr>" );             }         }         writer.println("<tr><td colspan='4' "  + "style='text-align:right'>"              + "总价格:"  + currencyFormat.format(total) + "</td></tr>" );         writer.println("</table>" );     }     writer.println("</table></body></html>" ); }