servlet之session&cookie

会话技术

可以简单理解为:浏览器打开到关闭就是一次会话

session和cookie可以实现会话跟踪技术,功能有重叠一般结合使用

session和cookie结合使用的例子:用户访问浏览器,服务器生成JESSIONID,JESSIONID是一个cookie,每次http请求会携带此cookie,用来让服务器知道选择哪个session,即JESSIONID相当于session的id。(因为服务器中存这好多用户的会话session),这个过程由服务器自动完成。

会话技术可以:记住浏览的商品,可以识别用户,可以实现会话时间内免登录

Cookie

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sDgXvuCk-1607248393480)(C:\Users\hello\AppData\Roaming\Typora\typora-user-images\image-20201106203324859.png)]

简单使用:


        //设置response的编码
        response.setContentType("text/html;charset=UTF-8");

        //创建Cookie对象,指定名称和值
        Cookie cookie = new Cookie("username", "zhongfucheng");
        
        //向浏览器给一个Cookie
        response.addCookie(cookie);

        response.getWriter().write("我已经向浏览器发送了一个Cookie");

cookie存储中文

  • 中文属于Unicode字符,英文数据ASCII字符,中文占4个字符或者3个字符,英文占2个字符。
  • 解决:Cookie使用Unicode字符时需要对Unicode字符进行编码负责出现异常
    response.setContentType("text/html;charset=UTF-8");
        PrintWriter printWriter = response.getWriter();

        String name = "中国";
              //对Unicode字符进行编码
        Cookie cookie = new Cookie("country", URLEncoder.encode(name, "UTF-8"));
        cookie.setMaxAge(2000);//存在了硬盘上
        response.addCookie(cookie);

        printWriter.write("我颁发了一个Cookie,值保存的是中文数据");

取出时进行解码:

   Cookie[] cookies = request.getCookies();
        for (int i = 0; cookies != null && i < cookies.length; i++) {
            String name = cookies[i].getName();

            //经过URLEncoding就要URLDecoding
            String value = URLDecoder.decode(cookies[i].getValue(), "UTF-8");

            printWriter.write(name + "------" + value);
        }

cookie有效期

Cookie的有效期是通过setMaxAge()来设置的

  • 如果MaxAge为正数浏览器会把Cookie写到硬盘中,只要还在MaxAge秒之前,登陆网站时该Cookie就有效【不论关闭了浏览器还是电脑】
  • 如果MaxAge为负数Cookie是临时性的,仅在本浏览器内有效,关闭浏览器Cookie就失效了,Cookie不会写到硬盘中。Cookie默认值就是-1。这也就为什么在我第一个例子中,如果我没设置Cookie的有效期,在硬盘中就找不到对应的文件。
  • 如果MaxAge为0,则表示删除该Cookie。Cookie机制没有提供删除Cookie对应的方法,把MaxAge设置为0等同于删除Cookie

cookie的删除和修改

我们已经知道了Cookie机制没有提供删除Cookie的方法。其实细心点我们可以发现,Cookie机制也没有提供修改Cookie的方法。那么我们怎么修改Cookie的值呢

Cookie存储的方式类似于Map集合

修改:

Cookie的名称相同,通过response添加到浏览器中,会覆盖原来的Cookie

删除:

除了名称相同外,设置setMaxAge(0)为零

        String name = "看完博客就点赞";

        //对Unicode字符进行编码
        Cookie cookie = new Cookie("country", URLEncoder.encode(name, "UTF-8"));

        //一定不要忘记添加到浏览器中
        cookie.setMaxAge(0);
        response.addCookie(cookie);

        printWriter.write("我删除了该Cookie");
  • 注意:删除,修改Cookie时,新建的Cookie除了value、maxAge之外的所有属性都要与原Cookie相同。否则浏览器将视为不同的Cookie,不予覆盖,导致删除修改失败

Cookie的domain

  • Cookie的隐私安全机制决定Cookie是不可跨域名的。也就是说www.baidu.comwww.google.com之间的Cookie是互不交接的。即使是同一级域名,不同二级域名也不能交接,也就是说:www.goole.comwww.image.goole.com的Cookie也不能访问
  • 现在我希望一级域名相同的网页Cookie之间可以相互访问。也就是说www.image.zhongfucheng.com可以获取到www.zhongfucheng.com的Cookie就需要使用到domain方法。
        Cookie cookie = new Cookie("name", "ouzicheng");
        cookie.setMaxAge(1000);
        cookie.setDomain(".zhongfucheng.com");
        response.addCookie(cookie);

        printWriter.write("使用www.zhongfucheng.com域名添加了一个Cookie,只要一级是zhongfucheng

Cookie的path

  • 一般地,Cookie发布出来,整个网页的资源都可以使用。现在我只想Servlet1可以获取到Cookie,其他的资源不能获取
  • 使用Servlet2颁发一个Cookie给浏览器,设置路径为"/Servlet1"。
        Cookie cookie = new Cookie("username", "java");
        cookie.setPath("/Servlet1");
        cookie.setMaxAge(1000);
        response.addCookie(cookie);

        printWriter.write("该Cookie只有Servlet1获取得到");

cookie应用

详情查看3y的github

1. 记录上次访问时间

先检查(遍历)所有Cookie有没有我要的,如果得不到我想要的Cookie,Cookie的值是null,那么就是第一次登陆

   SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter printWriter = response.getWriter();



        //获取网页上所有的Cookie
        Cookie[] cookies = request.getCookies();

        //判断Cookie的值是否为空
        String cookieValue = null;
        for (int i = 0; cookies != null && i < cookies.length; i++) {

            //获取到以time为名的Cookie
            if (cookies[i].getName().equals("time")) {
                printWriter.write("您上次登陆的时间是:");
                cookieValue = cookies[i].getValue();
                printWriter.write(cookieValue);

                cookies[i].setValue(simpleDateFormat.format(new Date()));
                response.addCookie(cookies[i]);
                
                //既然已经找到了就可以break循环了
                break;
            }
        }

        //如果Cookie的值是空的,那么就是第一次访问
        if (cookieValue == null) {
            //创建一个Cookie对象,日期为当前时间
            Cookie cookie = new Cookie("time", simpleDateFormat.format(new Date()));

            //设置Cookie的生命期
            cookie.setMaxAge(20000);

            //response对象回送Cookie给浏览器
            response.addCookie(cookie);

            printWriter.write("您是第一次登陆啊!");
        }
2. 记录浏览的商品

session

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qZEftCpM-1607248393483)(C:\Users\hello\AppData\Roaming\Typora\typora-user-images\image-20201106220950034.png)]

如果说Cookie是检查用户身上的”通行证“来确认用户的身份,那么Session就是通过检查服务器上的”客户明细表“来确认用户的身份的。Session相当于在服务器中建立了一份“客户明细表”

session使用

存:

 //得到Session对象
        HttpSession httpSession = request.getSession();
        
        //设置Session属性
        httpSession.setAttribute("name", "看完博客就要点赞!!");

取:

     //获取到从Servlet4的Session存进去的值
        HttpSession httpSession = request.getSession();
        String value = (String) httpSession.getAttribute("name");
        System.out.println(value);

session 生命周期和有效期

  • 一个session存在于浏览器打开到关闭的时间内,且session还有setMaxInactiveInterval来设置其存活时间。如果关闭浏览器,或者新打开其他浏览器,原来的session都会失效,因为session通过jESESSIONID来区分session,而Jessionid的MaxAge为负数,即浏览器关闭就失效。

    现在问题来了:服务器是如何实现一个session为一个用户浏览器服务的?换个说法:为什么服务器能够为不同的用户浏览器提供不同session?
        
    HTTP协议是无状态的,Session不能依据HTTP连接来判断是否为同一个用户。于是乎:服务器向用户浏览器发送了一个名为JESSIONID的Cookie,它的值是Session的id值。其实Session依据Cookie来识别是否是同一个用户。
        
    简单来说:Session 之所以可以识别不同的用户,依靠的就是Cookie
        
    该Cookie是服务器自动颁发给浏览器的,不用我们手工创建的。该Cookie的maxAge值默认是-1,也就是说仅当前浏览器使用,不将该Cookie存在硬盘中
    

设置session超时时间的三种方式

方式一:tomcat/conf/web.xml修改

所有的WEB应用都有效

 <session-config>
                <session-timeout>20</session-timeout>
 </session-config>  

方式二:单个的web.xml文件中设置

对单个web应用有效如果有冲突,以自己的web应用为准

  <session-config>
                <session-timeout>20</session-timeout>
</session-config>

方式三:通过setMaxInactiveInterval()方法设置


        //设置Session最长超时时间为60秒,这里的单位是秒
        httpSession.setMaxInactiveInterval(60);

        System.out.println(httpSession.getMaxInactiveInterval());

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q6fRPCRD-1607248393486)(C:\Users\hello\AppData\Roaming\Typora\typora-user-images\image-20201106222218876.png)]

session应用

1.购物
  • 将已经购买的商品添加到,session中,添加多个session开销大,直接添加一个List为session,因为session不仅可以存字符串也可以存对象。
  • 详细过程见3yhttps://segmentfault.com/a/1190000013130309
禁用cookie,session可使用吗?

我们知道Session 之所以可以识别不同的用户,依靠的就是Cookie(jessionid)

肯定不能正常使用了,但是有解决方法嘛?

有!URL地址重写

HttpServletResponse类提供了两个URL地址重写的方法:

  • encodeURL(String url)
  • encodeRedirectURL(String url)

URL地址重写的原理:将Session的id信息重写到URL地址中服务器解析重写后URL,获取Session的id。这样一来,即使浏览器禁用掉了Cookie,但Session的id通过服务器端传递,还是可以使用Session来记录用户的状态。

String url="/kan";
        resp.sendRedirect(resp.encodeURL(url));
2.session 防止表单重复提交
  • 前端设置标志位,可以防止表单重复点击提交

  • 刷新和后退再提交,无法通过前端防止,应该通过session

  • (没看太懂)

    html>
    
      <head>
        <meta content="text/html" charset="UTF-8" />
        <title>$Title$</title>
      </head>
      <body>
      <form action="/tt">
        姓名: <input type="text" name="name">
    
        <input type="hidden"  name="token" value="${token}">
        <input value="提交" type="submit">
      </form>
      </body>
    </html>
    
     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                TokenProcessor tokenProcessor=TokenProcessor.getInstance();
                String token=tokenProcessor.makeToken();
                req.getSession().setAttribute("token",token);
                //resp.sendRedirect("/index.jsp");
            req.getRequestDispatcher("/index.jsp").forward(req,resp);
        }
    
    import sun.misc.BASE64Encoder;
    
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.util.Random;
    
    public class TokenProcessor {
        private final static TokenProcessor tokenProcessor =new TokenProcessor();
    
        public  static TokenProcessor getInstance(){
            return  tokenProcessor;
        }
        public String makeToken(){
            String token=String.valueOf(System.currentTimeMillis()+new Random().nextInt(9999));
    
            MessageDigest messageDigest= null;
            try {
                messageDigest = MessageDigest.getInstance("md5");
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
            byte[] md5 = messageDigest.digest(token.getBytes());
            //如果我们直接 return  new String(md5)出去,得到的随机数会乱码。
            //因为随机数是任意的01010101010,在转换成字符串的时候,会查gb2312的码表,gb2312码表不一定支持该二进制数据,得到的就是乱码
            //于是乎经过base64编码成了明文的数据
            BASE64Encoder base64Encoder = new BASE64Encoder();
            return base64Encoder.encode(md5);
        }
    }
    
    
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String serverValue = (String) req.getSession().getAttribute("token");
            String clientValue = req.getParameter("token");
    
            if (serverValue != null && clientValue != null && serverValue.equals(clientValue)) {
    
                System.out.println("处理请求");
    
                //清除Session域对象数据
                req.getSession().removeAttribute("token");
    
            }else {
    
                System.out.println("请不要重复提交数据!");
            }
    
        }
    
3.一次性校验
  • 一次性校验码其实就是为了防止暴力猜测密码
  • 思路:生成验证码后,把验证码的数据存进Session域对象中,判断用户输入验证码是否和Session域对象的数据一致

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z8UYdcQu-1607248393492)(C:\Users\hello\AppData\Roaming\Typora\typora-user-images\image-20201106224558060.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Iq8UqE6g-1607248393495)(C:\Users\hello\AppData\Roaming\Typora\typora-user-images\image-20201106224736291.png)]

  • 只需要在处理购买页面上创建Cookie,Cookie的值是Session的id返回给浏览器即可
        Cookie cookie = new Cookie("JSESSIONID",session.getId());
        cookie.setMaxAge(30*60);
        cookie.setPath("/ouzicheng/");
        response.addCookie(cookie);
止暴力猜测密码**
- 思路:**生成验证码后,把验证码的数据存进Session域对象中,判断用户输入验证码是否和Session域对象的数据一致**

[外链图片转存中...(img-Z8UYdcQu-1607248393492)]

[外链图片转存中...(img-Iq8UqE6g-1607248393495)]

- 只需要在处理购买页面上创建Cookie,Cookie的值是Session的id返回给浏览器即可

    Cookie cookie = new Cookie("JSESSIONID",session.getId());
    cookie.setMaxAge(30*60);
    cookie.setPath("/ouzicheng/");
    response.addCookie(cookie);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值