会话管理--cookie && session
会话:可以简单的理解为用户开一个浏览器,点击多个超链接,访问服务器的多个web资源,然后关闭浏览器,整个过程称之为一个会话。
会话管理:对一个会话过程中浏览器和服务器之间产生的会话数据进行管理。
常用的会员管理技术有两种:cookie 和 session。
Cookie
cookie是客户端技术,服务器把每个用户的数据以cookie的形式写给用户给的浏览器中。当用户使用浏览量再去访问服务器中的web资源时,就会带着各自的数据去,这样web资源处理的就是用户各自的数据了。
javax.servlet.http.Cookie类用于创建一个Cookie,response接口中也定义了一个addCookie的方法,它用于在其响应头中增加一个相应的Set-Cookie头字段。同样,request 接口中也定义了一个getCookies方法,它用于获取客户端提交的Cookie。
Cookie中常用的API
1、构造cookie对象
Cookie(java.lang.String name, java.lang.String value)
2、设置cookie
void setPath(java.lang.String uri) //设置cookie的有效访问路径 void setMaxAge(int expiry) //设置cookie的有效时间 void setValue(java.lang.String newValue) //设置cookie的值
注意:
(1)cookie有效期参数的类型决定者浏览器接受到该cookie中时,cookie存储的地方:
正整数:表示cookie数据保存浏览器的缓存目录(硬盘中),数值表示保存的时间。
负整数:表示cookie数据保存浏览器的内存中。浏览器关闭cookie就丢失了!!
零:表示删除同名的cookie数据。
(2)浏览器在cookie的有效路径下访问服务器时,请求头中才会携带该cookie,否则不带cookie信息。
3、发送cookie到浏览器端保存
void response.addCookie(Cookie cookie) //发送cookie
4、服务器接收cookie
Cookie[] cookies = request.getCookies(); //获取cookie //注意:判断null,否则空指针 if(cookies!=null){ //遍历 for(Cookie c:cookies){ String name = c.getName(); String value = c.getValue(); System.out.println(name+"="+value); } }else{ System.out.println("没有接收cookie数据"); }
cookie注意的细节:
1、一个cookie只能标识一种信息,它至少含有一个标识该信息的名称(name)和设置值(value),并且value的值类型只能是string类型,不支持中文。
2、一个web站点可以给一个web浏览器发送多个cookie,一个web浏览器页可以存储多个web站点提供的cookie。
3、浏览量一般只允许存放300个cookie,每个站点最多存放20个cookie,每个cookie的大小限制为4KB。
4、如果创建了一个cookie,并将它发送到浏览器,默认情况下是一个会话级别的cookie(即存储在浏览器的内存中)。
cookie使用案例
查看用户浏览过的商品:通过访问详情在列表页显示用于最近3次访问的商品。
1、程序模块按照模块来分为三个包:
ervlet包:网络服务操作类。
dao包:数据访问操作类。
entity包:实体类。
2、源码:
(1)实体类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class Product { 2 3 private String id; 4 private String proName; 5 private String proType; 6 private double price; 7 public String getId() { 8 return id; 9 } 10 public void setId(String id) { 11 this.id = id; 12 } 13 public String getProName() { 14 return proName; 15 } 16 public void setProName(String proName) { 17 this.proName = proName; 18 } 19 public String getProType() { 20 return proType; 21 } 22 public void setProType(String proType) { 23 this.proType = proType; 24 } 25 public double getPrice() { 26 return price; 27 } 28 public void setPrice(double price) { 29 this.price = price; 30 } 31 public Product(String id, String proName, String proType, double price) { 32 super(); 33 this.id = id; 34 this.proName = proName; 35 this.proType = proType; 36 this.price = price; 37 } 38 public Product() { 39 super(); 40 // TODO Auto-generated constructor stub 41 } 42 @Override 43 public String toString() { 44 return "Product [id=" + id + ", price=" + price + ", proName=" 45 + proName + ", proType=" + proType + "]"; 46 } 47 48 }
(2)servlet类
1)商品列表类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class ListServlet extends HttpServlet { 2 3 public void doGet(HttpServletRequest request, HttpServletResponse response) 4 throws ServletException, IOException { 5 response.setContentType("text/html;charset=utf-8"); 6 //1.读取数据库,查询商品列表 7 ProductDao dao = new ProductDao(); 8 List<Product> list = dao.findAll(); 9 10 11 //2.把商品显示到浏览器 12 PrintWriter writer = response.getWriter(); 13 String html = ""; 14 15 html += "<html>"; 16 html += "<head>"; 17 html += "<title>显示商品列表</title>"; 18 html += "</head>"; 19 html += "<body>"; 20 html += "<table border='1' align='center' width='600px'>"; 21 html += "<tr>"; 22 html += "<th>编号</th><th>商品名称</th><th>商品型号</th><th>商品价格</th>"; 23 html += "</tr>"; 24 //遍历商品 25 if(list!=null){ 26 for(Product p:list){ 27 html += "<tr>"; 28 // /day11_hist/DetailServlet?id=1 访问DetailSErvlet的servlet程序,同时传递 名为id,值为1 的参数 29 html += "<td>"+p.getId()+"</td><td><a href='"+request.getContextPath()+"/DetailServlet?id="+p.getId()+"'>"+p.getProName()+"</a></td><td>"+p.getProType()+"</td><td>"+p.getPrice()+"</td>"; 30 html += "<tr>"; 31 } 32 } 33 html += "</table>"; 34 35 /** 36 * 显示浏览过的商品 37 */ 38 html += "最近浏览过的商品:<br/>"; 39 //取出prodHist的cookie 40 Cookie[] cookies = request.getCookies(); 41 if(cookies!=null){ 42 for (Cookie cookie : cookies) { 43 if(cookie.getName().equals("prodHist")){ 44 String prodHist = cookie.getValue(); // 3,2,1 45 String[] ids = prodHist.split(","); 46 //遍历浏览过的商品id 47 for (String id : ids) { 48 //查询数据库,查询对应的商品 49 Product p = dao.findById(id); 50 //显示到浏览器 51 html += ""+p.getId()+" "+p.getProName()+" "+p.getPrice()+"<br/>"; 52 } 53 } 54 } 55 } 56 57 58 html += "</body>"; 59 html += "</html>"; 60 61 writer.write(html); 62 } 63 64 public void doPost(HttpServletRequest request, HttpServletResponse response) 65 throws ServletException, IOException { 66 doGet(request, response); 67 } 68 69 }
2)商品详情类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class DetailServlet extends HttpServlet { 2 3 public void doGet(HttpServletRequest request, HttpServletResponse response) 4 throws ServletException, IOException { 5 response.setContentType("text/html;charset=utf-8"); 6 //1.获取编号 7 String id = request.getParameter("id"); 8 9 //2.到数据库中查询对应编号的商品 10 ProductDao dao = new ProductDao(); 11 Product product = dao.findById(id); 12 13 //3.显示到浏览器 14 PrintWriter writer = response.getWriter(); 15 String html = ""; 16 17 html += "<html>"; 18 html += "<head>"; 19 html += "<title>显示商品详细</title>"; 20 html += "</head>"; 21 html += "<body>"; 22 html += "<table border='1' align='center' width='300px'>"; 23 if(product!=null){ 24 html += "<tr><th>编号:</th><td>"+product.getId()+"</td></tr>"; 25 html += "<tr><th>商品名称:</th><td>"+product.getProName()+"</td></tr>"; 26 html += "<tr><th>商品型号:</th><td>"+product.getProType()+"</td></tr>"; 27 html += "<tr><th>商品价格:</th><td>"+product.getPrice()+"</td></tr>"; 28 } 29 30 html += "</table>"; 31 html += "<center><a href='"+request.getContextPath()+"/ListServlet'>[返回列表]</a></center>"; 32 html += "</body>"; 33 html += "</html>"; 34 35 writer.write(html); 36 37 38 /** 39 * 创建cookie,并发送 40 */ 41 //1.创建cookie 42 Cookie cookie = new Cookie("prodHist",createValue(request,id)); 43 cookie.setMaxAge(1*30*24*60*60);//一个月 44 //2.发送cookie 45 response.addCookie(cookie); 46 } 47 48 /** 49 * 生成cookie的值 50 * 分析: 51 * 当前cookie值 传入商品id 最终cookie值 52 * null或没有prodHist 1 1 (算法: 直接返回传入的id ) 53 * 1 2 2,1 (没有重复且小于3个。算法:直接把传入的id放最前面 ) 54 * 2,1 1 1,2(有重复且小于3个。算法:去除重复id,把传入的id放最前面 ) 55 * 3,2,1 2 2,3,1(有重复且3个。算法:去除重复id,把传入的id放最前面) 56 * 3,2,1 4 4,3,2(没有重复且3个。算法:去最后的id,把传入的id放最前面) 57 * @return 58 */ 59 private String createValue(HttpServletRequest request,String id) { 60 61 Cookie[] cookies = request.getCookies(); 62 String prodHist = null; 63 if(cookies!=null){ 64 for (Cookie cookie : cookies) { 65 if(cookie.getName().equals("prodHist")){ 66 prodHist = cookie.getValue(); 67 break; 68 } 69 } 70 } 71 72 // null或没有prodHist 73 if(cookies==null || prodHist==null){ 74 //直接返回传入的id 75 return id; 76 } 77 78 // 3,21 2 79 //String -> String[] -> Collection :为了方便判断重复id 80 String[] ids = prodHist.split(","); 81 Collection colls = Arrays.asList(ids); //<3,21> 82 // LinkedList 方便地操作(增删改元素)集合 83 // Collection -> LinkedList 84 LinkedList list = new LinkedList(colls); 85 86 87 //不超过3个 88 if(list.size()<3){ 89 //id重复 90 if(list.contains(id)){ 91 //去除重复id,把传入的id放最前面 92 list.remove(id); 93 list.addFirst(id); 94 }else{ 95 //直接把传入的id放最前面 96 list.addFirst(id); 97 } 98 }else{ 99 //等于3个 100 //id重复 101 if(list.contains(id)){ 102 //去除重复id,把传入的id放最前面 103 list.remove(id); 104 list.addFirst(id); 105 }else{ 106 //去最后的id,把传入的id放最前面 107 list.removeLast(); 108 list.addFirst(id); 109 } 110 } 111 112 // LinedList -> String 113 StringBuffer sb = new StringBuffer(); 114 for (Object object : list) { 115 sb.append(object+","); 116 } 117 //去掉最后的逗号 118 String result = sb.toString(); 119 result = result.substring(0, result.length()-1); 120 return result; 121 } 122 123 public void doPost(HttpServletRequest request, HttpServletResponse response) 124 throws ServletException, IOException { 125 doGet(request, response); 126 } 127 128 }
(3)数据访问对象类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class ProductDao { 2 //模拟"数据库",存放所有商品数据 3 private static List<Product> data = new ArrayList<Product>(); 4 5 /** 6 * 初始化商品数据 7 */ 8 static{ 9 //只执行一次 10 for(int i=1;i<=10;i++){ 11 data.add(new Product(""+i,"笔记本"+i,"LN00"+i,34.0+i)); 12 } 13 } 14 15 16 17 /** 18 * 提供查询所有商品的方法 19 */ 20 public List<Product> findAll(){ 21 return data; 22 } 23 24 /** 25 * 提供根据编号查询商品的方法 26 */ 27 public Product findById(String id){ 28 for(Product p:data){ 29 if(p.getId().equals(id)){ 30 return p; 31 } 32 } 33 return null; 34 } 35 36 }
Session
session是服务器端的技术,利用这个技术,服务器在运行时可以为每一个用户的浏览器创建一个其共享的session对象,由于session为用户浏览器独享,所以用户在访问服务器web资源时,可以把各自的手放在各自的session中,当用户在去访问服务器中的其它web资源时,其它web资源再从用户各自的session中取出数据为用户服务。
session原理
当浏览器第一次访问web站点的时候创建session对象时,会给session对象分配一个唯一的ID,名字为JSESSIONID。然后把JSESSIONID作为cookie的值发送给浏览量器保存。浏览器第二次访问web站点的时候,会带着JSESSIONID的cookie访问服务器。服务器得到JSESSIONID后,在服务器的内存中搜索是否存放了对应的session对象,如果有则直接返回该对象,如果没有会根据创建session时方法的参数进行创建或者返回null。
session常用API
1、创建
request.getSession(true) / request.getSession() //创建或得到session对象。没有匹配的session编号,自动创建创对象。 request.getSession(false) //得到session对象。没有匹配的session编号,返回null
2、保存会话数据到session对象
void setAttribute(java.lang.String name, java.lang.Object value) //保存数据 java.lang.Object getAttribute(java.lang.String name) // 获取数据 void removeAttribute(java.lang.String name) // 清除数据
3、设置session对象
void setMaxInactiveInterval(int interval) //设置session的有效时间 void invalidate() //销毁session对象 java.lang.String getId() //得到session编号
注意:默认情况下30分钟服务器会自动回收session对象。
除了用上述API来修改session有效时间外,还可以在web.xml中配置全局变量来设置session的有效时间,配置代码如下
<!-- 修改session全局有效时间:分钟 --> <session-config> <session-timeout>1</session-timeout> </session-config>