Web的状态管理——Cookie和session技术的使用

一、状态管理

1.1 为什么需要状态管理

HTTP协议是无状态的,不能保存每次提交的信息,即当服务器返回与请求相对应的应答之后,这次事务的所有信息就丢掉了。
如果用户发来一个新的请求,服务器无法知道它是否与上次的请求有联系。
对于那些需要多次提交数据才能完成的Web操作,比如登录来说,就成问题了。

1.2 什么是状态管理

WEB应用中的会话是指一个客户端浏览器与WEB服务器之间连续发生的一系列请求和响应过程。
WEB应用的会话状态是指WEB服务器与浏览器在会话过程中产生的状态信息,借助会话状态,WEB服务器能够把属于同一会话中的一系列的请求和响应过程关联起来。

1.3 状态管理的两种常见模式

  1. 客户端状态管理技术:将状态保存在客户端。代表性的是Cookie技术。
  2. 服务器状态管理技术:将状态保存在服务器端。代表性的是session技术(服务器传递sessionID时需要使用Cookie的方式)和application

1.4 两者的关系图

在这里插入图片描述

二、Cookie应用

2.1 什么是Cookie

Cookie是在浏览器访问WEB服务器的某个资源时,由WEB服务器在HTTP响应消息头中附带传送给浏览器的一小段数据,WEB服务器传送给各个客户端浏览器的数据是可以各不相同的。

一旦WEB浏览器保存了某个Cookie,那么它在以后每次访问该WEB服务器时,都应在HTTP请求头中将这个Cookie回传给WEB服务器。

WEB服务器通过在HTTP响应消息中增加Set-Cookie响应头字段将Cookie信息发送给浏览器,浏览器则通过在HTTP请求消息中增加Cookie请求头字段将Cookie回传给WEB服务器。

一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置(VALUE)。

一个WEB站点可以给一个WEB浏览器发送多个Cookie,一个WEB浏览器也可以存储多个WEB站点提供的Cookie。

浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB

2.2 Cookie常用方法

基本步骤:

  1. 创建Cookie对象
  2. 设置有效期
  3. 设置有效路径
  4. 设置协议读取
  5. 把cookie放入response响应中,给浏览器
@WebServlet(name = "CookieServlet",value = "/cookieservlet")
public class CookieServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //cookie本质就是键值对,而且只能是字符串类型,这里中文需要转码,但是不同浏览器情况不同,根据情况进行处理
        Cookie cookie = new Cookie("username", URLEncoder.encode("张三", "utf-8"));
        //设置属性
        //1.设置有效期,单位说秒,正数表示过多少秒过期,存储在硬盘和内存,负数表示不存储,只保存在内存中,浏览器退出删除,0表示立即删除
        cookie.setMaxAge(60*60*24);
        //2.设置有效路径,给浏览器用,单独斜杠表示localhost:8080
        cookie.setPath("/");
        //3.设置只有Http协议读取
        cookie.setHttpOnly(true);
        //4.把cookie放入response响应中,给浏览器
        response.addCookie(cookie);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

读取Cookie

cookie.getName()方法获取键值
cookie.getValue()方法获取值

@WebServlet(name = "ReadCookieServlet", value = "/readcookie")
public class ReadCookieServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //读取浏览器回传过来的cookie
        Cookie[] cookies = request.getCookies();
        if (null != cookies) {
            for (Cookie cookie : cookies) {
                //如果设置了编码,则读取的时候需要解码
                System.out.println(cookie.getName() + "....." + URLDecoder.decode(cookie.getValue(), "utf-8"));
            }
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

更新Cookie

注意:如果键相同,即name,有效路径相同,就是同一个cookie,会覆盖浏览器的cookie

@WebServlet(name = "UpdateServlet", value = "/updatecookie")
public class UpdateServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //更新cookie
        //如果名字相同name,有效路径相同,就是同一个cookie,会覆盖浏览器的cookie
        Cookie cookie = new Cookie("username", URLEncoder.encode("李四", "utf-8"));
        cookie.setMaxAge(60*60);
        cookie.setPath("/");
        cookie.setHttpOnly(true);
        response.addCookie(cookie);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

三、状态管理-Session

3.1 什么是Session

Session用于跟踪客户的状态。Session指的是在一段时间内,单个客户与Web服务器的一连串相关的交互过程。

在一个Session中,客户可能会多次请求访问同一个网页,也有可能请求访问各种不同的服务器资源。

每个Session都存储有一个id号,第一次响应的时候反馈给浏览器。

3.2 Session工作原理

session被用于表示一个持续的连接状态,在网站访问中一般指代客户端浏览器的进程从开启到结束的过程。session其实就是网站分析的访问(visits)度量,表示一个访问的过程。

session的常见实现形式是cookie(session cookie),即未设置过期时间的cookie,这个cookie的默认生命周期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。实现机制是当用户发起一个请求的时候,服务器会检查该请求中是否包含sessionid,如果未包含,则系统会创造一个名为JSESSIONID的输出 cookie返回给浏览器(只放入内存,并不存在硬盘中),并将其以HashTable的形式写到服务器的内存里面;当已经包含sessionid时,服务端会检查找到与该session相匹配的信息,如果存在则直接使用该sessionid,若不存在则重新生成新的 session。这里需要注意的是session始终是有服务端创建的,并非浏览器自己生成的。

3.3 常用方法

Session可以作为一个容器进行存储数据使用,并在各个servlet中通过新建Session都可以进行获取,不像request,数据传输不依赖重定向或者转发。

@WebServlet(name = "SessionServlet", value = "/sessionservlet")
public class SessionServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.获取Session对象,相当于一个集合,可以存储东西
        HttpSession session = request.getSession();
        //2.获取session信息
        String id = session.getId();
        System.out.println("session的ID: " + id);
        //3.获取创建时间
        long time = session.getCreationTime();
        System.out.println("创建时间:" + new Date(time));
        //4.获取最后访问时间
        long lastAccessedTime = session.getLastAccessedTime();
        System.out.println("最后一次访问时间:" + new Date(lastAccessedTime));
        //5. 存储数据
        session.setAttribute("username", "张三");
        //6. 读取session中的数据,一经存储,只要网页不关闭,其他servlet类也可以get获取
        String username = (String) session.getAttribute("username");
        System.out.println(username);
        //7.设置有效期,默认是1800秒,还可以在web.xml里配置
        session.setMaxInactiveInterval(20 * 60);
        //8. 获取session的有效期,单位是秒,从最后一次访问起计时
        System.out.println("session的有效期:" + session.getMaxInactiveInterval());
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}
//打印结果
session的ID: 3083F11A52BEA23152E6270377CDD01B
创建时间:Mon Sep 02 19:34:12 CST 2019
最后一次访问时间:Mon Sep 02 19:34:12 CST 2019
张三
session的有效期:1200

通过配置web.xml文件设置session有效期

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <session-config>
        <!--单位是分钟-->
        <session-timeout>10</session-timeout>
    </session-config>
</web-app>

删除Session需要手动处理,因为即使关闭了网页,Session依然在服务器中,毕竟是由服务器创建的
失效的几种情况:
(1)超过了设置的超时时间
(2)主动调用了invalidate方法
(3)服务器主动或异常关闭,浏览器关闭并不会让Session失效

@WebServlet(name = "InvalidateSessionServlet",value = "/invalidatesessionservlet")
public class InvalidateSessionServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //手动使session失效,因为即使关闭网页,服务器中还是存在
        HttpSession session = request.getSession();
        session.removeAttribute("username"); //首先要将所存储的属性一个个清理掉
        session.invalidate();
        System.out.println(session.getId() + "失效了");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

浏览器禁用Cookie的解决方案
一般用户都不会禁用Cookie,但是如果有人禁用了Cookie,则有部分网站无法登陆,而且Session也无法使用,服务器在默认情况下,会使用Cookie的方式将sessionID发送给浏览器,如果用户禁止Cookie,则sessionID不会被浏览器保存,此时,服务器可以使用如URL重写这样的方式来发送sessionID。

实现方法:

//如果是链接地址和表单提交,使用
response.encodeURL(String url)生成重写后的URL
//如果是重定向,使用
response.encodeRedirectURL(String url)生成重写的URL

案例:验证码登录

前端登录界面,参考《servlet的使用——response和request》案例二

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户登录</title>
</head>
<body>
    <h1>用户登录</h1>
    <form action="loginservlet" method="post" enctype="application/x-www-form-urlencoded">
        用户名:<input type="text" name="username"/><br/>
        密码:<input type="password" name="password"/><br/>
        验证码:<input type="text" name="validcode" />
        <!--vs是验证码servlet,提供的图片-->
        <img id="coding" src="/0902web1/vs" onclick="change()">
        <a href="" onclick="return change()">看不清</a><br/>
        <input type="submit" value="登录"/>
    </form>
    <script type="text/javascript">
        function change() {
            var coding = document.getElementById("coding");
            coding.src = "/0902web1/vs?n=" + Math.random();
            return false;
        }
    </script>
</body>
</html>

验证码servlet,用session存储验证码信息,方便在loginservlet中进行验证比对

@WebServlet(name = "ValidateCodeServlet" , value = "/vs")
public class ValidateCodeServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ValidateCode validateCode = new ValidateCode(120, 30, 4, 20);
        //将验证码存储
        String code = validateCode.getCode();
        HttpSession session = request.getSession();  //创建session,将验证码的字符串存入
        //把验证码放入session
        session.setAttribute("vCode", code);
        validateCode.write(response.getOutputStream()); //图片需要二进制流输出
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

登录servlet,用来进行比对验证

@WebServlet(name = "LoginServlet",value = "/loginservlet")
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String validcode = request.getParameter("validcode");//获取验证码

        HttpSession session = request.getSession();
        PrintWriter writer = response.getWriter();

        //判断验证码
        String vCode = (String) session.getAttribute("vCode");
        if (!validcode.equalsIgnoreCase(vCode)) {
            writer.println("验证码输入有误");
            return;
        }

        if (username.equals("admin") && password.equals("123")) {
            //登录成功,将信息放入session
            session.setAttribute("username", username);
            writer.println("<h1>登录成功</h1>");
        } else {
            writer.println("<h1>登录失败</h1>");
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值