• Cookie与Session


    一、Cookie详解
        1、属性:
            name:(必须)
            value:(必须)不能是中文
            maxage:(可选)最长存活时间.默认是会话。单位是秒
            path:(可选)路径
                一个cookie的默认路径是:写cookie的那个servlet的访问路径。
                写cookie的servlet的路径是:String path = /day05_01_cookie/servlet/
                                如果访问的路径.startWith(path),浏览器就会把刚才写的cookie带给服务器。
            domain :(可选)域名
            comment:(可选)注释
            version:(可选)版本号
     
        2、服务器如何向客户端写Cookie:
            HttpServletResponse.addCookie(javax.servlet.http.Cookie)(实际上就是写了一个Set-Cookie的响应消息头)
            浏览器对于一个网站最多存20个cookie  (Cookie的个数是有限的)
            cookie总数不能超过300个。
            每个Cookie大小不能超过4KB。
        3、服务器如何取出客户端带来的cookie:HttpServletRequest.getCookies() (实际上就是获取 名字为cookie的请求消息头)
     
        4、如何唯一确定一个Cookie
            domain+path+name
            localhost/day05_01_cookie/servlet/   + lastAccessTime
    Cookie案例
    利用cookie技术记录用户最近一次访问的时间
     public   void  doGet(HttpServletRequest  request , HttpServletResponse response)
                 throws  ServletException, IOException {
            response.setContentType( "text/html;charset=UTF-8" );
            PrintWriter out = response.getWriter();
            out.write( "上次访问的时间是:" );
             //得到指定的cookie,该cookie中记录了上次访问的时间
            Cookie[] cs = request.getCookies();
             for ( int  i=0;cs!= null &&i<cs. length ;i++){
                Cookie c = cs[i];
                 if ( "lastTime" .equals(c.getName())){
                    String value = c.getValue();
                     //把cookie里面字符串转成long,再由Date转成可读格式
                     long  time = Long. parseLong (value);
                    String ti =  new  Date(time). toLocaleString() ;
                    out.write(ti);
                }
            }
             //清除cookie
            out.write( "<a href='/my_exericse_day05/servlet/MyCookieDemo2'>清除cookie</a>" );
             //把当前时间写入到cookie里面
            Cookie cookie =  new  Cookie( "lastTime" , System. currentTimeMillis ()+ "" );
             //设置cookie的存货时间,单位是秒.如果是Long单位多半是毫秒
            cookie.setMaxAge(1*30*24*60*60);
             //设置路径为当前应用的名称,意味着当前应用的任何资源都可以得到该cookie.
            cookie.setPath(request.getContextPath());
            response.addCookie(cookie);     }
    最近一次访问的时间

    删除指定的Cookie

     //删除指定的cookie
         public   void  doGet(HttpServletRequest request, HttpServletResponse response)
                 throws  ServletException, IOException {
            response.setContentType( "text/html;charset=UTF-8" );
            PrintWriter out = response.getWriter();
            Cookie c =  new  Cookie( "lastAccesTime" ,  "" ); //和上面的一样的
            c.setMaxAge(0);
            c.setPath(request.getContextPath());
            response.addCookie(c);
            
            out.write( "删除成功!" );     }

    提供选项让用户设置是否记录登录名

     //提供登陆界面
         //显示记住的用户名
         public   void  doGet(HttpServletRequest request, HttpServletResponse response)
                 throws  ServletException, IOException {
            response.setContentType( "text/html;charset=UTF-8" );
            PrintWriter out = response.getWriter();
             //显示记住的用户名
            String username =  "" ;
            String checked =  "" ;
             //找到指定的cookie
            Cookie cs[] = request.getCookies();
             for ( int  i=0;cs!= null &&i<cs. length ;i++){
                 if (CookieStatics. LOGIN_USERNAME .equals(cs[i].getName())){
                     //找到了
                    String value = cs[i].getValue();
                    username = value;
                    checked =  "checked='checked'" ;
                     break ; //不希望程序继续往下运行
                }
            }        
             //提供登陆界面
            out.write( "<form action='" +request.getContextPath()+ "/servlet/LoginServletDemo2' method='post'>" );
            out.write( "用户名:<input type='text' name='username' value='" +username+ "'/><br/>" );
            out.write( "密码:<input type='password' name='password'/><br/>" );
            out.write( "记住用户名:<input type='checkbox' name='remember' " +checked+ " /><br/>" );
            out.write( "<input type='submit' value='登陆'/>" );
            out.write( "</form>" );     }
    记住登录名-1
    //验证用户名或密码
         //根据用户是否需要记住用户名来处理cookie
         //是:添加cookie
         //否:删除cookie
         public   void  doGet(HttpServletRequest request, HttpServletResponse response)
                 throws  ServletException, IOException {
            response.setContentType( "text/html;charset=UTF-8" );
            PrintWriter out = response.getWriter();
             //验证用户名或密码
            String username = request.getParameter( "username" );
            String remember = request.getParameter( "remember" );
             //根据用户是否需要记住用户名来处理cookie
             //用一个借口,来定义一个常量。直接引用,不容易出错
            Cookie c =  new  Cookie(CookieStatics. LOGIN_USERNAME , username);
            c.setPath(request.getContextPath());
             if (remember== null ){
                 //否:删除cookie
                c.setMaxAge(0);
            } else {
                 //是:添加cookie的失效时间为最大
                c.setMaxAge(Integer. MAX_VALUE );
            }
            response.addCookie(c);
            out.write( "登陆成功!" );     }
    记住登陆名-2

    记录用户的浏览记录

    //显示所有的书籍,并提供查看详细的链接
    //显示用户最近的浏览记录:保留3
    public   void  doGet(HttpServletRequest request, HttpServletResponse response)
             throws  ServletException, IOException {
        response.setContentType( "text/html;charset=UTF-8" );
        PrintWriter out = response.getWriter();
         //显示所有的书籍,并提供查看详细的链接
        out.write( "本站有以下好书,欢迎选购:<br/>" );
        Map<String, Book> books = BookDB. findAllBooks ();
         for (Map.Entry<String, Book> me:books.entrySet()){
            out.write(me.getValue().getName()+ "  <a href='" +request.getContextPath()+ "/servlet/ShowBookDetailServlet?id=" +me.getValue().getId()+ "'>详情</a><br/>" );
        }
         //显示用户最近的浏览记录:保留3   bookHistory=3-2-1
        out.write( "<hr/>您最近的浏览记录:<br/>" );
        Cookie cs[] = request.getCookies();
         for ( int  i=0;cs!= null &&i<cs. length ;i++){
            Cookie c = cs[i];
             if ( "bookHistory" .equals(c.getName())){
                String bookIds = c.getValue(); //3-2-1
                String ids[] = bookIds.split( "\-" );
                 for (String id:ids){
                    Book book = BookDB. findBookById (id);
                    out.write(book.getName()+ "<br/>" );
                }
                 break ;
            }
        }      }
    显示所有的书
    //显示书籍的详细内容
    //向客户端写cookie记录浏览历史
    public   void  doGet(HttpServletRequest request, HttpServletResponse response)
             throws  ServletException, IOException {
        response.setContentType( "text/html;charset=UTF-8" );
        PrintWriter out = response.getWriter();
         //显示书籍的详细内容
        String bookId = request.getParameter( "id" );
        out.write( "详情:" +BookDB. findBookById (bookId).toString());
        out.write( "<br/><a href='" +request.getContextPath()+ "/servlet/ShowAllBooksServlet'>继续购物</a>" );
         //向客户端写cookie记录浏览历史
        String ids = makeIds(request,bookId); //用-分隔
        Cookie c =  new  Cookie( "bookHistory" , ids);
        c.setPath(request.getContextPath());
        c.setMaxAge(Integer. MAX_VALUE );
        response.addCookie(c);
    }
    //组织要写回的书的id
    //    当前情况                                    新看的书            应写回的id
    //    cookie一个都没有                                1                1
    //    cookie不为null,但没有bookHistory                1                1
    //    bookHistory=1                                2                2-1
    //    bookHistory=2-1                                1                1-2
    //    bookHistory=2-1                                3                3-2-1
    //    bookHistory=2-1-3                            3                3-2-1
    //    bookHistory=2-1-3                            4                4-2-1
    private  String makeIds(HttpServletRequest request, String bookId) {
    //        cookie一个都没有                                1                1
        Cookie cs[] = request.getCookies();
         if (cs== null ||cs. length ==0)
             return  bookId;     
    //        cookie不为null,但没有bookHistory                1                1
        Cookie bookHistoryCookie =  null ;
         for (Cookie c:cs){
             if ( "bookHistory" .equals(c.getName())){
                bookHistoryCookie = c;
                 break ;
            }
        }
         if (bookHistoryCookie== null ){
             return  bookId;
        }     
    //        bookHistory=1                                2                2-1
    //        bookHistory=2-1                                1                1-2
    //        bookHistory=2-1                                3                3-2-1     
        String id = bookHistoryCookie.getValue(); // 2-1     
        LinkedList<String> list =  new  LinkedList<String>(Arrays. asList (id.split( "\-" ))); // 2 1     
         if (list.size()<3){
             if (list.contains(bookId)){
                list.remove(bookId);
            }
            list.addFirst(bookId);
        } else {     
    //        bookHistory=2-1-3                            3                3-2-1
    //        bookHistory=2-1-3                            4                4-2-1
             if (list.contains(bookId)){
                list.remove(bookId);
            } else {
                list.removeLast();
            }
            list.addFirst(bookId);
        }
         //把list中的id组织成字符串
         //3 2 1---->3-2-1
        StringBuffer sb =  new  StringBuffer();
         for ( int  i=0;i<list.size();i++){
             if (i>0)
                sb.append( "-" );
            sb.append(list.get(i));
        }
         return  sb.toString(); }
    处理
    二、HttpSession原理详解
        HttpSession借助Cookie技术的。
     
        HttpSession getSession():服务器会根据用户带来的JSESSIONIDcookie的值,先查找。找到继续为你服务,没有找到,创建新的HttpSession对象。
        HttpSession getSession(boolean b):
                        b为true:效果同getSession()
                        b为false:只是查询。
     
    HttpSession原理详解
        HttpSession借助Cookie技术的。
        HttpSession getSession():服务器会根据用户带来的JSESSIONIDcookie的值,先查找。找到继续为你服务,没有找到,创建新的HttpSession对象。
        HttpSession getSession(boolean b):
                        b为true:效果同getSession()
                        b为false:只是查询。
     

    (依赖Cookie)  
       
    我们都知道HTTP是无状态协议,但是为什么session可以跟踪会话状态呢?没错,session依赖Cookie。

    银行卡你一定有吧,卡里有钱么?别误会,我问的是表示金额的这个数据是在卡里么?当然不是,卡上只有一个ID,其他什么都没有,表示金额的这个数据在银行的数据库里。那为什么在ATM上我们只需要把卡插入就可以看到卡上余额呢?原因是ATM获取卡上的ID,然后通过ID去银行数据库中查找对应的账户!每个账户都有一个ID属性,账户上可能还会有密码属性、余额属性等。每张卡上只有一个ID,再没有其他的东西了。但ATM可以读取卡上的ID,然后去银行数据库中查找对应的账户!所以你大可以放心,银行卡坏掉了没有关系,钱不会掉的,因为账户余额在银行的数据库中,你只需要重新去银行办一张卡,把你的卡号置入到新卡中就OK了。

    每个session对象都有一个id属性,session就相当于银行的账户。而sessionId就相当于卡!银行数据库就是Tomcat服务器,而手里只有卡的我们就是客户端浏览器。

    当你第一次去银行办理业务时,这需要办一张卡,然后你需要拿着卡回家,下一次再去银行办理业务时就不需要再办卡了,但你不要忘记带着卡去银行。

    当客户端第一次访问服务器时,服务器会为客户端创建一个session对象,然后把session对象放到session池中,在响应时把sessionId通过Cookie响应给客户端。注意,只有在第一次访问时,服务器才会创建session,给客户端响应sessionId。从此以后就不会了!

    当客户端再次访问服务器时,会在请求中带着sessionId给服务器,服务器通过sessionId到session池中找到session对象,这就可以完成会话跟踪了。也就是说,服务器端保存的是session对象,而客户端只有sessionId。每次访问都需要通过客户端的sessionId来匹配服务器端的session对象!这样用户在session中保存的数据就可以再次被使用了。

    sessionId是服务器通过Cookie发送给客户端浏览器的,这个Cookie的maxAge为-1,即只在浏览器内存中存在。如果你关闭所有浏览器窗口,那么这个Cookie就会消失了!

    session失效

    session失效有如下几个原因:

    l  客户端的请求中没有sessionId。可能是因为这是第一次请求(开始一个新的会话),也可能是服务器设置Cookie的maxAge为0导致的;(客户端没有银行卡)

    l  客户端请求中存在sessionId,但这个sessionId在session池中没有匹配的session对象。这可能是因为session太久没有使用,服务器把session从池中移除的原因;(银行卡没有对应的银行账户)

    l  客户端请求中存在sessionId,但匹配的session对象被标记为失效!这可能是因为服务器调用了session.invalidate()方法导致的。(银行账户找到了,但账户已被冻结)

    HttpSession的案例

        1、简单的不能再简单的购物车(先建立JavaBean,然后JavaBeanDB)
                浏览器关闭了,会话结束了。但是服务器端原来为您服务的HttpSession对象并没有消失(等待超时,默认30分钟)
    //显示所有的产品。提供购买和显示已买产品的链接
    public   void  doGet(HttpServletRequest request, HttpServletResponse response)
             throws  ServletException, IOException {
        response.setContentType( "text/html;charset=UTF-8" );
        PrintWriter out = response.getWriter();
        request.getSession();
        out.write( "本站有以下好书:<br/>" );
        Map<String, Book> books = BookDB. findAllBooks ();
         for (Map.Entry<String, Book> me:books.entrySet()){
            String url = request.getContextPath()+ "/servlet/BuyServlet?id=" +me.getKey();
            url = response.encodeURL(url);
            out.write(me.getValue().getName()+ "  <a href='" +url+ "'>购买</a><br/>" );
        }
        String url = request.getContextPath()+ "/servlet/ShowCartServlet" ;
        url = response.encodeURL(url);
        out.write( "<hr/><a href='" +url+ "'>显示已购买商品</a>" ); }
    显示
    //购买 Servlet :把购买的书籍放入购物车(容器)。提供继续购物的链接
    public   void  doGet(HttpServletRequest request, HttpServletResponse response)
             throws  ServletException, IOException {
        response.setContentType( "text/html;charset=UTF-8" );
        PrintWriter out = response.getWriter();
        String id = request.getParameter( "id" );
        Book book = BookDB. findBookById (id);
         //放入购物车:一个客户端只有一个购物车,且不能被替换
        HttpSession session = request.getSession();
        List<Book> cart =  (List<Book>) session.getAttribute( "cart" ) ;
         if (cart== null ){
            cart =  new  ArrayList<Book>();
            session.setAttribute( "cart" , cart);
        }
        cart.add(book);
        String url = request.getContextPath()+ "/servlet/ShowProductServlet" ;
        url = response.encodeURL(url);
        out.write(book.getName()+ "已放入您的购物车!<a href='" +url+ "'>继续购物</a>" ); }
    处理
    //显示购物车中的内容
    public   void  doGet(HttpServletRequest request, HttpServletResponse response)
             throws  ServletException, IOException {
        response.setContentType( "text/html;charset=UTF-8" );
        PrintWriter out = response.getWriter();
         //getSession()等于getSession(true),如果有Session,则返回,如果没有则创建.
         //getSession(false),如果有Session,则返回,如果没有Session,则返回null
        HttpSession session = request.getSession( false );
         if (session== null ){
            out.write( "哥们,你TMD真有才,什么都木有买就看看,SB" );
             return ;
        }
         //session肯定创建过了:需要进一步显示
        out.write( "您购买的商品如下:<br/>" );
        List<Book> cart =  (List<Book>) session.getAttribute( "cart" ) ;
         if (cart== null ){
            out.write( "您还没有购买任何商品" );
        } else
             for (Book b:cart){
                out.write(b.getName()+ "<br/>" );
            }
        String url = request.getContextPath()+ "/servlet/ShowProductServlet" ;
        url = response.encodeURL(url);
        out.write( "<a href='" +url+ "' target='_blank'>继续购物</a>" ); }
     
    显示购物车内容
    2、完成用户登陆和一次性的验证码验证
    建立一个JavaBean,存用户信息
    建立一个ImageServlet,验证图片
    建立登录HTML页面
      < form   action = "/day06_00_session/servlet/LoginServlet"   method = "post" >
            用户名: < input   type = "text"   name = "username" />< br />
            密码: < input   type = "password"   name = "password" />< br />
            验证码: < input   type = "text"   name = "code"   size = "4" />< img   id = "code"   src = "/day06_00_session/servlet/ImageServlet" />
             < a   href = "javascript:changeNum()" > 看不清 </ a >
             < br />
             < input   type = "submit"   value = "登陆" />
         </ form >
         < script   type = "text/javascript" >
            function  changeNum(){
                 //alert("haha");
                 //地址如果相同,浏览器不会发出请求
                document.getElementById( "code" ).src= "/day06_00_session/servlet/ImageServlet?" + new  Date().getTime();
            }      </ script >
    页面
    //用户登陆
    public   void  doGet(HttpServletRequest request, HttpServletResponse response)
             throws  ServletException, IOException {
        request.setCharacterEncoding( "UTF-8" );
        response. setContentType ( "text/html;charset=UTF-8" );
        PrintWriter out = response.getWriter();
         //验证“验证码”是否正确:从session中取出,与用户提交过来的参数进行对比
        HttpSession session = request.getSession();
        String sCode = (String) session.getAttribute( "code" );
        String pCode = request.getParameter( "code" );
         if (!pCode.equalsIgnoreCase(sCode)){
            response.setHeader( "Refresh" ,  "2;URL=" +request.getContextPath()+ "/login.html" );
            out.write( "验证码有误!2秒后自动转向登陆页面" );
             return ;
        }
         //验证用户名和密码
        User user =  new  User();
        user.setUsername(request.getParameter( "username" ));
        session.setAttribute( "user" , user);
        response.setHeader( "Refresh" ,  "2;URL=" +request.getContextPath()+ "/servlet/IndexServlet" );
        out.write( "登陆成功!2秒后转向主页" ); }
    用户登录
    //模拟默认主页
    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();
        User user = (User)session.getAttribute( "user" );
         if ( user == null ){
            out.write( "<a href='" +request.getContextPath()+ "/login.html'>登陆</a>" );
        } else {
            out.write( "欢迎您:" +user.getUsername()+ "  <a href='" +request.getContextPath()+ "/servlet/LogoutServlet'>注销</a>" );
        }
        out.write( "<hr/>这是主页内容" ); }
    主页
    //注销
    public   void  doGet(HttpServletRequest request, HttpServletResponse response)
             throws  ServletException, IOException {
        HttpSession session = request.getSession();
        session.invalidate(); //立即失效 }
    注销

       3、防止表单重复提交

    原理图:

       MD5加密

    public   static  String md5Encode(String str){
         try  {
             //返回实现指定摘要算法的 MessageDigest 对象
            MessageDigest md = MessageDigest. getInstance ( "md5" );
             //进行MD5编码
             byte  b[] = md.digest(str.getBytes()); //得到加密后的字节码
             //把b字节码转换成字符串
            BASE64Encoder base64 =  new  BASE64Encoder();
             return  base64.encode(b);
        }  catch  (NoSuchAlgorithmException e) {
             throw   new  RuntimeException(e);
        } }
    加密
    客户端禁用Cookie后的会话数据保存:URL重写
        解决办法:
        1、主页提示:为了更好的浏览本网站,请不要禁用您的cookie
        2、URL重写:很麻烦。必须对网站的所有地址都重写。
        重写后有以下效果:
            http://localhost:8080/day06_00_session/servlet/ShowCartServlet
            http://localhost:8080/day06_00_session/servlet/ShowCartServlet;JSESSIONID=sessionId
            用户禁用后,可以用一下方法重写地址。
            String response.encodeURL(String url); 自动判断用户有无禁用cookie,禁用了,重写。没有禁用,就不重写了。
     
     
    HttpSession对象的状态转换(要实现Serializable接口,以序列化.?)
    关闭session的两种方式:
    1,在web.XML中进行一下配置,更改session保持时间,到时间就会被干掉。
    <session-config>
          <session-timeout>1</session-timeout><!-- 1分钟,默认30分钟 -->
      </session-config>
    2,session.invalidate();语句
     
     
    IE浏览器何时才会开启一次新的会话
        1、IE8+:开启一个新的浏览器进程,都是一次会话。
        2、开启选项卡或者在新窗口中打开新页面都是同一此会话。
     
        3、开启新会话:“文件”-->"新建会话"
     
     
  • 相关阅读:
    dart中Map类型详解
    洛谷P1582 倒水(二进制)
    maven依赖 临时转阿里云镜像
    java jdbc 连接数据库
    java 常用类
    java 异常处理
    java 对象 this static 封装
    java 面对对象 内存分析
    团队开发 git
    java 代码块
  • 原文地址:https://www.cnblogs.com/lulu638/p/4242409.html
Copyright © 2020-2023  润新知