Cookie 和 Session

前言

在 Servlet 中,对于 Cookie 和 Session 有很好的支持!
所以,我们就可以基于 Servlet 里面提供的 Cookie 和 Session 的 API,来进行会话管理类似的操作。

一、Cookie 和 Session 介绍

Cookie 的几个问题
1.Cookie 是个啥?
        浏览器提供的持久化存储数据的机制~~
2.Cookie 从哪里来?   
        Cookie 从服务器返回给浏览器的。服务器代码中由程序猿决定要把啥样的信息保存到客户端这边~~通过 HTTP 响应的 Set-Cookie 字段, 把键值对写回去即可~~
3.Cookie 到哪里去?
        Cookie 会在后续浏览器访问服务器的时候带到请求的 header 中发给服务器~~
        (为啥要这么折腾?? 服务器不是只给一个客户端提供服务,同一时刻要处理多个客户端的请求~~此时服务器就可以通过 cookie 中的值,来识别当前客户端是谁,当前客户端的服务提供到哪个环节了.(客户端借助 cookie 自报家门))
4.Cookie 存储在哪里?
        存储在浏览器(客户端)所在主机的硬盘中
        浏览器会根据 域名 来分别存储~~

回忆之前的例子:

  1. 到了医院先挂号. 挂号时候需要提供身份证, 同时得到了一张 “就诊卡”, 这个就诊卡就相当于患者的 “令牌”(相当于是 cookie,里面存储这用户的详细信息).
  2. 后续去各个科室进行检查, 诊断, 开药等操作, 都不必再出示身份证了, 只要凭就诊卡即可识别出当前患者的身份.
  3. 看完病了之后, 不想要就诊卡了, 就可以注销这个卡. 此时患者的身份和就诊卡的关联就销毁了. (类似于网站的注销操作)
  4. 又来看病, 可以办一张新的就诊卡, 此时就得到了一个新的 “令牌”

Cookie 和 Session_第1张图片

但其实在实际情况中,使用的是一个 session 的方式来保存的。

毕竟一个人,他可能不止一张卡,而且卡可能会丢。
因此将身份信息全部存储到卡上并不安全,所以,卡上只需要存储一个会话窗口编号sessionId

通过这个会话窗口编号,就可以打开对应的窗口,调取对应的信息。
也就是说:
每一张卡 相当于 开启了 一个会话窗口,都可以通过这个会话窗口来获取自身的详细信息。


1.2 Cookie 和 Session 的区别:

另外,这里我们补充一点:
Cookie 和 Session 的区别:

  • Cookie 是客户端的存储机制. Session 是服务器端的存储机制.
  • Cookie 里面可以存各种键值对(还可以存别的)Session 则专门用来保存用户的身份信息
  • Cookie 完全可以单独使用,不搭配 session (实现非 登陆 场景下)Session 也可以不搭配 Cookie 使用.(手机 app 登陆服务器,服务器也需要 Session,此时就没有Cookie 的概念)
  • Cookie 跟浏览器强相关的,Cookie 是属于 HTTP 协议中的一个部分。Session 则可以和 HTTP 无关(TCP, websocket ... 也可以用 session)

二、核心方法

2.1 HttpServletRequest 类中的相关方法

2.1.1 getSession 方法

getSession 方法,既能用于获取到服务器上的会话,也能用于创建会话。

它的具体行为,取决于参数:

  • 如果参数为 true,会话不存在,则创建一个会话
  • 如果参数为false,会话不存在,则返回一个null 

(拿着请求中 cookie 里的 sessionld 查一下哈希表)

这就好比:我们去医院看病。
但是这个医院,我们是第一次来。
肯定是要先挂个号,那么人家会问你有没有就诊卡?
如果你有,人家就不用给你办卡了。反之,人家就会根据你的身份信息,给你办一张就诊卡。

大家要明确:
在办卡之后,你拿到的不光是一张卡,还在该医院的服务器上存了一份档案。
这份档案就相当于是一个会话,卡上存储的就是 这个会话窗口的id号(sessionId)。

在实际情况中,调用 getSession 的时候具体做什么?
1、创建会话(买一张就诊卡)

首先先获取到请求中 cookie 里面的 sessionId 字段。
sessionId 就相当于是会话的身份标识。
然后我们去判定这个sessionId 是否在当前服务器上存在。
如果不存在,则进入创建会话 逻辑 / 操作。


创建会话:会创建一个 HttpSession 对象,并且生成一个 sessionId。
sessionId 是一个很长的数字,通常是用 十六进制来表示的。
这个数字能够保证唯一性:它这里面有一些列相关的算法,能够生成一个唯一的sessionId,然后这个Id 就作为我们当前会话的身份标识。

接下来,就把 sessionId 作为 key,把这个 HttpSession 对象,作为 value。
把这个键值对,给保存到 服务器内存 的一个“哈希表” 这样的结构中。
这里的“哈希表”:只是表示一个类似 哈希表的数据结构。
也就是说,一定是一个键值对结构,但是 是不是 哈希表 就不能保证了。

再然后,服务器就会返回一个 HTTP 响应,把 sessionId 通过 Set-Cookie 字段 返回给浏览器。
然后,浏览器就可以保存这个 sessionId 到 cookie中了。

Cookie 和 Session_第2张图片

2、获取会话

先获取到请求中的 cookie 里面的 sessionId 字段,也就是会话的身份标识。
判断这个 sessionId 是否在当前服务器上存在,也就是遍历“哈希表”中key,来判断这个 sessionId 是否包含在其中。
如果有,就直接调出 sessionId 对应的 HttpSession对象,并且通过返回值返回去。
会话,我们搞清楚了。
我们再来谈谈 HttpSession是什么?
HttpSession,其实就是 创建会话的时候,需要生成的一个关键对象。
这个对象本质上也是一个“键值对”的json结构。
注意! 由于 HttpSession 对象是一个键值对结构,所以允许程序员 对 HttpSession 对象进行套娃操作!
这和我前面讲的 表白墙 中获取所有信息记录的响应格式json是一样的。
一个 json 对象 可以让 另一个json 对象,作为自己keys中的一个value值。
HttpSession 也是如此,可以让另一个 HttpSession 对象作为 自己keys中的一个value值。
HttpSession键值对结构中,key必须是字符串类型,value 是一个 Object类型。 

Cookie 和 Session_第3张图片

getCookies()方法

        getCookies()方法会返回一个数组,包含客户端发送该请求的所有的 Cookie 对象.会自动把Cookie 中的格式解析成键值对 

Cookie 和 Session_第4张图片

 2.2 Cookie 类中的相关方法 

Cookie 和 Session_第5张图片

2.3 HttpServletResponse 类中的相关方法 

响应中就可以根据 addCookie 这个方法,来添加一个 Cookie 信息(键值对)到 响应报文中 ,

这里添加进来的键值对,就会作为 HTTP 响应中的 Set-Cookie 字段来表示。

换个说法:把一个cookie键值对 转换成 字符串 格式,通过 Set-Cookie 来返回到 客户端(浏览器)这里。 

 2.4 HttpSession 类中的相关方法

一个 HttpSession 对象里面包含多个键值对. 我们可以往 HttpSession 中存任何我们需要的信息

Cookie 和 Session_第6张图片


 三、实战案例:网页登录 

3.1 理解例子逻辑

Cookie 和 Session_第7张图片

在编写案例代码之前,我们需要先约定前后端交互接口。
根据上面的逻辑图,一共有两组交互:
        1、登录页面
        2、主页面

要明白:针对前后端交互接口,这里有很多种约定方式。这么多约定方式,使用哪种都可以!一定要确定出一种约定方式,然后前后端代码的编写,就需要围绕着这一种约定的方式进行编写。如果如果不按照这种方式去写,代码会出现很多问题!
比如:请求是GET,但是服务器中处理请求的方法是POST,那么就会触发405 

Cookie 和 Session_第8张图片

 3.2 正式编写代码

 首先我们来写一个简易风格的登录页面

Cookie 和 Session_第9张图片

Cookie 和 Session_第10张图片接下来,就是编写一个服务器程序,用于处理登录页面发送的请求。 

Cookie 和 Session_第11张图片

Cookie 和 Session_第12张图片

Cookie 和 Session_第13张图片  编写服务器返回主页的逻辑 

Cookie 和 Session_第14张图片

 

Cookie 和 Session_第15张图片

效果展示

先来看一下,登录成功的效果。

 Cookie 和 Session_第16张图片

Cookie 和 Session_第17张图片

Cookie 和 Session_第18张图片

登录失败的效果:Cookie 和 Session_第19张图片

代码

loginServlet

@WebServlet("/login")
public class loginServlet extends HelloServlet{
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        1、处理用户请求
        String username = req.getParameter("username");
        String password = req.getParameter("password");
//        2、判断用户名 密码是否正确
//        正常来说是要放到数据库里进行存取的
//        注册的时候会把用户名和密码写入数据库
//        后续登录的时候,根据用户名看密码是否正确
//        这里为了简单就把密码写死
//        假设用户名为:zhangsan 密码为:123
        if("zhangsan".equals(username) && "123".equals(password)){
            //为了避免 username 和 password为空,而造成空指针异常,把写死的密码作
            // 登录成功
            //创建会话,并保存的身份信息
            HttpSession httpSession = req.getSession(true);
//            往会话中存储键值对(关键信息),必要的身份信息
            httpSession.setAttribute("username",username);

            resp.sendRedirect("index");
        }else {
            resp.getWriter().write("login error!");
        }
    }
}

indexservlet

@WebServlet("/index")
public class indexServlet extends HelloServlet{
//    doGet 要做的事情: 这回主页,主页就是简单的html
//    返回页面的前提,需要获得 用户名
//    也就是需要从 Httpsession 中拿到。
//    因为在上个服务器代码中,我们把用户名写作会话的属性,存入到会话中了。
//    此处的 getSession 的参数 必须为false!因为前面在登录过程中,已经创建过会话了
//    此处是要直接获取之前的会话。
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession httpSession = req.getSession(false);
        String username = (String)httpSession.getAttribute("username");
        resp.setContentType("text/html;charset=utf8");
        resp.getWriter().write("

欢迎"+username+"

"); } }

 login.html




  
  
  
  登录页面


  

你可能感兴趣的:(servlet,java,前端)