会话技术 Cookie和Session

长平狐 发布于 2012/09/03 12:30
阅读 1K+
收藏 2

 

一、获取ReqeustDispatcher的方式
1、ServletContext getRequestDispatcher(String path)
2、ServletRequest getRequestDispatcher(String path)
共同点:起到的作用是一样的
不同点:在于方法的参数path的写法上
1、path:必须是一个绝对路径。也就是说必须以“/”开头
2、path:既可以是绝对路径,又可以是相对路径。不以"/"开头就是相对路径(路径必须正确)
二、转发和重定向的细节
1、转发:只能转发到本应用的其他资源
2、请求重定向:可以转发到任何地址。
三、绝对路径的写法(都以/开头)
如果是给客户端用的,要加项目名称,否则(给服务器用的),不加项目名称

转发:getRequestDispatcher(String path)     不需要加项目名称 /servlet/Demo2
重定向:sendRedirect(String path)  需要加项目名称 /day06/servlet/Demo2
Refresh=2;URL=path   需要加项目名称 /day06/servlet/Demo2
form表单的action     需要加项目名称 /day06/servlet/Demo2
a的href:      需要加项目名称 /day06/servlet/Demo2
包含:include(String path)  不需要加项目名称 /servlet/Demo2 

四、什么是会话,如同打电话
会话过程中要解决的问题:用户数据的保存问题。保存在ServletContext和ServletRequest的域对象中是不可取的。
解决方案:
1、Cookie
 是客户端技术,程序把每个用户的数据以cookie的形式写给用户各自的浏览器
 响应消息头Set-Cookie:key=value
 请求消息头cookie:key=value
 一个cookie必须有name和value,还有以下可选属性
 comment:
 path:默认路径就是访问写写domain:
   名为abc的cookie的path:www.sina.com/mail
     http://localhost:8080/day06 能不能得到abc这个cookie。不能
     www.sina.com/mail 能不能得到abc这个cookie。能
     www.sina.com/mail/abc/a.jsp  能不能得到abc这个cookie。能

   如果把cookie的路径设置为:localhost/day06 说明day06下面的所有资源都可以访问这个cookie
   
 age:设置cookie的缓存时间。默认的时间是一个负数(浏览器关闭时删除)。如果是0,则是删除该cookie。正整数才是存活的时间。
 version:
 
 如何向客户端写一个cookie:
  HttpServletResponse.addCookie(javax.servlet.http.Cookie)
 注:每个服务器只能存放20 cookie (稀有)
 浏览器端最多能存放300cookie
 每个cookie的大小不能超过4Kb
 
 服务器如何获取客户端带来的cookie:
  HttpServletRequest.getCookies()
 注:不同网站向同一个客户端写的cookie的名称一致,可以通过cookie的path属性进行区分
 
 cookie的默认存活时间是会话范围。
 

2、HttpSession
 是服务器端技术,利用这个技术,服务器在运行时可以为每一个用户的浏览器创建一个其独享的session对象
 如何得到HttpSession对象:
  HttpServletRequest  getSession()
 其实session技术利用了cookie技术:
  向客户端写了一个名字为JSESSIONID的cookie
  value:session对象的id
  path:/day06 request.getContextPath()
  age:负数
特别注意:
 关闭浏览器是结束一次会话。但是对于服务器来讲,并不会立刻销毁内存中的session对象。默认的session的存活时间是30分钟。
 getSession():如果内存中有对应的session,它是获取方法。如果没有,则创建新的session。
 getSession(true)功能同没有参数的
 getSession(false):如果内存中有对应的session,它是获取方法。如果没有,返回null  

Cookie案例:
eg1:记录用户最近一次的访问时间
  每次访问页面的时候将系统时间记录下来
   Cookie c = new Cookie("lastAccessTime",System.currentTimeMillis()+"");
      
        //设置Cookie有限期
        c.setMaxAge(Integer.MAX_VALUE);
        c.setPath(request.getContextPath());
        //写回Cookie
  response.addCookie(c);
  
  清除上一次访问的时间
    
   //得到所有的Cookies  //day06/servlet路径下
   Cookie cookies[]= request.getCookies(); 
   //进行遍历查找对应的 Cookie ,并对其进行设置
   for(int i =0 ;cookies!=null&&i<cookies.length;i++ ){
    if("lastAccessTime".equals(cookies[i].getName())){
     Cookie c = cookies[i];
     //对其进行设置
     c.setMaxAge(0);//存活时间为零
     c.setPath(request.getContextPath());//path必须相同,以Cookiename相同时,用path进行区别
     //写回Cookie/也可理解为覆盖
     response.addCookie(c);
    }
   } 
  
eg2:记住用户名
  常量接口设计模式
  a)使用场景:在程序设计中,我们可以把所用要用到的常量设计为一个独立的类,使得对常量的管理有效清晰。
        eg:
  public interface MyConstant {
     //接口常量,这样可以避免拼写错误
        String USERNAME = "username";
        }
  CookieDemo1中:
  //让用户名默认为空,记录用户名被checked时才根据Cookie显示
  String username = "";
  String checked = "";
  //根据Cookie决定是否显示用户名
  Cookie cookies[] = request.getCookies();
  for(int i = 0;cookies!=null&&i<cookies.length;i++){
   if(MyConstant.USERNAME.equals(cookies[i].getName())){
    username = cookies[i].getValue();
    checked = "checked='checked'";
    break;
   }
  }
        //生成登录页面 
    response.setContentType("text/html;charset=UTF-8");
    PrintWriter out = response.getWriter();
    out.print("<html><head>用户登录</head><body>");
    out.print("<form action='"+request.getContextPath()+"/servlet/CookiesDemo4' method='post'>");
    out.print("用户名:<input type='text' name='username' value='"+username+"'><br/>");
    out.print("密码:<input type='password' name='password'><br/>");
    out.print("<input type='submit' value='登录'><br/>");
    out.print("记住用户名<input type='checkbox' name='remeber' "+checked+">");
    out.print("</form></body></html>");
  
    CookieDemo2中;
       // 获取表单中的信息,进行验证
  String username = request.getParameter("username");
  String remeber = request.getParameter("remeber");
  if (remeber == null) {// 不需要记住 ,需要清空Cookie
   Cookie cookies[] = request.getCookies();
            for(int i =0;cookies!=null&&i<cookies.length;i++){
             Cookie c = cookies[i];
             if(MyConstant.USERNAME.equals(username)){
              //清空Cookie
              c.setMaxAge(0);
              c.setPath(request.getServletPath());
              
              break;
             }
            }
  } else {
             //需要记录该 Cookie
    Cookie cookie = new Cookie(MyConstant.USERNAME, username);
    cookie.setMaxAge(Integer.MAX_VALUE);
    cookie.setPath(request.getContextPath());
       //写回cookie
    response.addCookie(cookie);
  }   
  
eg3:购物网站中的应用,记住用户最近浏览的商品记录
   ShowAllBookServlet;
        //列出所有的书籍
  response.setContentType("text/html;charset=UTF-8");
  PrintWriter out = response.getWriter();
  Map<String,Book> books = BookDb.getBooks();
  for(Map.Entry<String, Book> me:books.entrySet()){
   out.print("<a href='"+request.getContextPath()+"/servlet/ShowDetailsServlet?id="+me.getKey()+"' target='_blank'>"+me.getValue().getName()+"</a><br/>");
  }
  
  //显示最近浏览的商品列表,最多三件
  out.print("<hr/>");
  out.print("最近浏览过的商品:<br/>");
  
  //根据Cookie中保存的信息进行显示
  Cookie cookies[] = request.getCookies();
  for(int i=0;cookies!=null&&i<cookies.length;i++){
   Cookie cookie = cookies[i];
   if(MyConstant.BOOK_HISTORY.equals(cookie.getName())){
    String value = cookie.getValue();//1-2-3
    String ids[] = value.split("\\-");
    for(String id:ids){
     //显示书的名称
     out.print(BookDb.findBookById(id).getName()+"<br/>");
    }
    break;
   }
  }  
  ShowDetailsServlet:
       doGet():
   
       PrintWriter  out = response.getWriter();
       out.print("书的详细信息如下<br/>");;
       String id = request.getParameter("id");
       Book book = BookDb.findBookById(id);
       out.print("名称:"+book.getName()+"<br/>");
       out.print("作者:"+book.getAuthor()+"<br/>");
       out.print("价格:"+book.getPrice()+"<br/>");
       out.print("评价:"+book.getDescription()+"<br/>");
      
       //将书的id保存到Cookie中
       String value = makeId(id,request);
       Cookie cookie = new Cookie(MyConstant.BOOK_HISTORY, value);
       //设置Cookie属性
       cookie.setMaxAge(Integer.MAX_VALUE);
       cookie.setPath(request.getContextPath());
       //写回Cookie
       response.addCookie(cookie);
  /*
  **进行字符串拼接,根据用户当前浏览的书id 拼出浏览信息,如 1-2-3
  */
  private String makeId(String id, HttpServletRequest request) {
  
  Cookie cookies[] = request.getCookies();
  //cookies为空,为第一次访问书籍
  if(cookies==null)
   return id;
  
  
  Cookie cookie = null;//记录book_history
  for(Cookie c : cookies){
      //若存在name为BOOK_HISTORY的Cookie ,用cookie记录
   if(MyConstant.BOOK_HISTORY.equals(c.getName())){
    cookie = c;
    break;
   }
  }
  
  if(cookie==null)//有cookie但没有name为book_history的cookie
   return id;
  
  String value = cookie.getValue();
  String ids[] = value.split("\\-");
  
  LinkedList<String> list = new LinkedList<String>(Arrays.asList(ids));
  
  if(list.size()<3){//浏览商品少于三件
   if(list.contains(id)){
       //浏览过,从原来记录中删除,然后将其添加到第一位
    list.remove(id);
    list.addFirst(id);
   }else{
          //没有浏览过,直接添加到第一位
    list.addFirst(id);
   }
  }else{//浏览商品正好三件
   if(list.contains(id)){
   //浏览过,从原来记录中删除,然后将其添加到第一位
    list.remove(id);
    list.addFirst(id);
   }else{
   //没有浏览过,先移除最末一位.然后将当前浏览商品添加到第一位
    list.removeLast();
    list.addFirst(id);
   }   
  }
  
  StringBuffer sb = new StringBuffer();
  for(int i=0;i<list.size();i++){
   if(i>0){//从第一个id后添加-
    sb.append("-");
   }
   sb.append(list.get(i));
  }
  
  return sb.toString();
 }

Session 案例

eg1:简单的购物车

ShowAllProductsServlet 显示所有的商品,提供购买的超链接

//列出所有的书籍
  response.setContentType("text/html;charset=UTF-8");
  PrintWriter out = response.getWriter();
  out.print("本站有以下书籍<br/>");
  Map<String,Book> books = BookDb.getBooks();
  for(Map.Entry<String, Book> me:books.entrySet()){
   out.print(me.getValue().getName()+"<a href='"+request.getContextPath()+"/servlet/BuyServlet?id="+me.getKey()+"'>购买</a><br/>");
  }
  
BuyServlet 将当前购买的商品添加到购物车中
 String id = request.getParameter("id");
     Book book = BookDb.findBookById(id);
    
     HttpSession session = request.getSession();
     List<Book> carts  = (List<Book>) session.getAttribute("carts");
     if(carts==null){
      carts = new ArrayList<Book>();
      carts.add(book);
      session.setAttribute("carts", carts);
     }else{//若已经存在session则直接添加
      carts.add(book);
     }
     
     response.setContentType("text/html;charset=UTF-8");
     PrintWriter out = response.getWriter();
     out.print("<a href='/day06/servlet/ShowAllProductsServlet'>继续购物</a><br/><a href='/day06/servlet/ShowCartServlet'>去结算</a>");
 
ShowCartServlet 显示购物车中的商品 
      response.setContentType("text/html;charset=UTF-8");
      PrintWriter out =response.getWriter();
      HttpSession session = request.getSession();
      List<Book> carts = (List<Book>) session.getAttribute("carts");
      out.print("购物车中的商品:");
      for(Book book:carts){
       out.print(book.getName()+"<br/>");
      }
      out.print("去付款");
BookDb 模拟数据库信息
public class BookDb {
 // key->id value->book
 public static Map<String, Book> books = new HashMap<String, Book>();
    /*
     * 初始化时添加五本书
     */
 static{
     books.put("1", new Book("1","JAVA疯狂讲义","李刚","58.00","非常好的入门书"));
     books.put("2", new Book("2","java入门详解","张孝祥","99.00","好得不行了"));
     books.put("3", new Book("3","javascript","毕向东","55.00","经典初级入门"));
     books.put("4", new Book("4","web深入开发","方立勋","89.00","不错哦"));
     books.put("5", new Book("5","安卓深入浅出","老田","110.00","深入浅出经典之作"));
    }
 public static Map<String, Book> getBooks() {
  return books;
 }
    //通过id找到对应的书
 public static Book findBookById(String id){
  return books.get(id);
 }
}


eg2:简单的用户登录
 LoginServlet:
       request.setCharacterEncoding("UTF-8");
       response.setContentType("text/html;charset=UTF-8");
      
       String username = request.getParameter("username");
       String password = request.getParameter("password");
      
       PrintWriter out = response.getWriter();
       User user = new User();
       user.setUsername(username);
       user.setPassword(password);
      
       HttpSession session = request.getSession();
       session.setAttribute("user", user);
       out.print("登录成功,两秒后进行跳转");
       //登录成功,两秒后进行跳转
       response.setHeader("Refresh", "2;url=/day06/servlet/IndexServlet");
IndexServlet
     response.setContentType("text/html;charset=UTF-8");
     PrintWriter out = response.getWriter();
    
     HttpSession session = request.getSession();
     User user = (User) session.getAttribute("user");
    
     out.print("欢迎"+user.getUsername()+"登录<br/>");
     out.print("这里是主页");  
  
eg3:登录时进行验证码校验

    ImageServlet生成验证码时中记录下来,先进行加密,然后放到session中
  StringBuffer sb = new StringBuffer();
  
  for(int i = 0;i<4;i++){
   int num = r.nextInt(10);
   g.drawString(num+"", x, 15);
   x+=20;
   sb.append(num);
  }
   //得到生成的验证码
  String code = sb.toString();
  
  //用md5算法对验证码进行加密
  code = Md5Util.encode(code);
  
  HttpSession session = request.getSession();
  session.setAttribute("code", code);   
  
 在LoginServlet中将页面用户输入的验证码和生成的验证码进行对比
        String code = request.getParameter("code");
        PrintWriter out = response.getWriter();
     
        HttpSession session = request.getSession();
        //code2是正确的验证码,与用户填入的进行对比
        String code2 = (String) session.getAttribute("code");
        if(!code2.equals(Md5Util.encode(code))){
         out.print("对不起,验证码输入失败");
      //跳转回登录页面
         response.setHeader("Refresh", "2;url=/day06/Login2.html");
         return;
        }
    加密类Md5Util
 public class Md5Util {

 public static String encode(String code) {
  try{
     //得到md5算法的数据摘要
  MessageDigest md = MessageDigest.getInstance("md5");
  //根据MD5算法得到的数据指纹
  byte[] b = md.digest(code.getBytes());
  //用base64编码,将没有对应字符的二进制转为可见的字符
  BASE64Encoder base64 = new BASE64Encoder();
  
  return base64.encode(b);
  
  }catch(Exception e){
   throw new RuntimeException(e);
  }
 
 }
  
}

 
eg4:防止表单的重复提交
   javascript在点击提交按钮后,将其设置为disabled
   function toSubmit(btnObj){
     var formObj = document.getElementById("f1");
     btnObj.disabled=true;
     formObj.submit();
    }
 但用户刷新后仍可以重复提交,不能根本解决问题
 
   解决方案:
   生成一个UUid (随即且唯一) ,保存在session中,然后同页面中hidden的输入框中的id进行比较
   public class UUidUtil {
 public static String getId() {
  return UUID.randomUUID().toString();
 } 
}
  
   ServletDemo0:
    //生成登录页面
       response.setContentType("text/html;charset=UTF-8");
       PrintWriter out = response.getWriter();
       //随机生成一个唯一的码
       String id = UUidUtil.getId();
       out.print("<form id='f1' action='/day06/servlet/ServletDemo1' method='post'>"+
               "姓名:<input type='text' name='username'/><br/>"+
               "<input type='hidden' name='token' value='"+id+"'>"+
     "<input type='submit' value='提交'>");
      
       HttpSession session = request.getSession();
       session.setAttribute("id", id);
   
   ServletDemo1:
      request.setCharacterEncoding("UTF-8");
      response.setContentType("text/html;charset=UTF-8");
   String username = request.getParameter("username");
   String ctoken = request.getParameter("token");
  
   HttpSession session =request.getSession();
   String stoken = (String) session.getAttribute("id");
  
   PrintWriter out = response.getWriter();
   if(ctoken.equals(stoken)){//不一致 进行提交,然后移除session 里的id,让用户可以进行新的提交
    System.out.println(username); 
   session.removeAttribute("id");
   }else{//一致,说明是重复提交
   
    out.print("表单不能重复提交");
    return;
   } 


原文链接:http://blog.csdn.net/t12x3456/article/details/7583582
加载中
返回顶部
顶部