• Servlet API Cookie和Session


    在这里插入图片描述

    请添加图片描述

    ⭐️前言⭐️

    我们在前文【和面试官畅谈「HTTP协议」 3.3.6】中已经提及了Servlet在会话管理操作中的Cookie与Session,但在上篇文章中有些过于理论化,在这篇文章中,我们结合具体的API和综合案例来更深刻的理解Cookie和Session。

    🍉博客主页: 🍁【如风暖阳】🍁
    🍉精品Java专栏【JavaSE】【备战蓝桥】、【JavaEE初阶】【MySQL】【数据结构】
    🍉欢迎点赞 👍 收藏留言评论 📝私信必回哟😁

    🍉本文由 【如风暖阳】 原创,首发于 CSDN🙉

    🍉博主将持续更新学习记录收获,友友们有任何问题可以在评论区留言

    🍉博客中涉及源码及博主日常练习代码均已上传码云(gitee)GitHub


    请添加图片描述

    请添加图片描述

    🍅1.回顾Cookie与Session

    在我们浏览一些网页,比如b站或者码云时,需要进行用户登录的操作,这个操作只有在首次访问时才会有,如果之前已经进行过了,浏览器就会保存下来用户信息,下次再访问该页面时直接登录即可,不必再进行输入。

    每位用户在首次进行登陆时,都会在服务器端创建一个Session会话,在Session中存储了对应用户的一些属性,而且每个Session都有唯一身份标识sessionID;服务器存储管理着很多Session会话

    在客户端的Cookie中,就存储着sessionID,在客户端进行登录后发送给服务器的请求中有该sessionID,服务器在存储的所有Session会话中,根据sessionID进行查找,如果找到了就返回给客户端对应的Session会话响应。

    类似于我们去医院时,用到的就诊卡,就诊卡就相当于Cookie,包含了当前患者的关键信息,我们刷卡后就能查到自己过往病历的具体情况,每位患者的情况就是一个Session会话,存储在医院的服务器上。

    🍅2.核心方法

    2.1 HttpServletRequest类中的相关方法

    方法描述
    HttpSession getSession()在服务器中获取会话。参数如果为true,则当不存在会话时新建会话;参数如果为false,则当不存在会话时返回null
    Cookie[] getCookies()返回一个数组,包含客户端发送该请求的所有的Cookie对象。会自动把Cookie中的格式解析成键值对。

    getSession方法,既能用于获取到服务器上的会话,也能用于创建会话;在调用getSession时,具体要做的事情是:

    1.创建会话
    首先先获取到请求中cookie里面的sessionID字段(相当于会话的身份标识),判断这个sessionID是否在当前的服务器上存在;
    如果不存在,则进入创建会话逻辑。

    创建会话,会创建一个HttpSession对象,并且生成一个sessionID(通常是16进制表示的很长的数字,能够保证唯一性),接下来就会把这个sessionID作为key,把这个HttpSession对象作为value,把这个键值对保存到服务器内存中,一个类似“哈希表”的结构。

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

    2.获取会话
    首先先获取到请求中cookie里面的sessionID字段(相当于会话的身份标识),判断这个sessionID是否在当前的服务器上存在;
    如果存在,就直接查询出这个HttpSession对象,并且通过返回值返回回去。

    2.2 HttpServletResponse 类中的相关方法

    方法描述
    void addCookie(Cookie cookie)把指定的cookie添加到响应中

    该方法添加进来的键值对,会作为HTTP响应中的Set-Cookie字段来表示

    2.3 HttpSession 类中的相关方法

    一个HttpSession对象里面包含多个键值对,我们可以往HttpSession中存任何我们需要的信息(Key必须是String,value是一个Object)。

    方法描述
    Object getAttribute(String name)该方法返回在该session会话中具有指定名称的对象,如果没有指定名称的对象,则返回null (取键值对)
    void setAttribute(String name,Object value)该方法使用指定的名称绑定一个对象到该session会话(存键值对)
    boolean isNew()判定当前是否是新创建出的会话

    下图展示在服务器中HttpSession的存储。
    在这里插入图片描述

    2.4 Cookie 类中的相关方法

    每个Cookie对象也是一个键值对,这些键值对的格式,使用来分割多个键值对,使用=来分割键和值,这些键值对都会在请求中,通过Cookie字段传给服务器,服务器收到请求之后,就会进行解析,解析成Cookie[]这样的形式。

    方法描述
    String getName()该方法返回Cookie的名称。名称在创建后不能改变(这个值是Set-Cookie字段设置给浏览器的)
    String getValue()该方法获取与cookie关联的值
    void setValue(String newValue)该方法设置与cookie关联的值

    Cookie中,可以保存任意自定制的键值对,如果是一般的键值对,直接通过HttpServletRequest类中的getCookies方法来获取,如果是特殊的键值对(表示sessionID的键值对),不需要使用getCookies,直接用HttpServletRequest类中的getSession就可以帮我们自动从Cookie中获取sessionID了。

    🍅3.综合案例

    3.1 实现用户登录

    首先我们来梳理实现网页用户登录的逻辑
    在这里插入图片描述
    下边就是具体的开发流程:

    一:前后端约定接口(确定交互的数据格式类型)
    该次开发共需要实现两个接口,一个接口负责登录,另一个接口负责获取主页
    在这里插入图片描述
    在这里插入图片描述
    二:编写前端交互页面(基于form表单构造POST请求)

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Documenttitle>
    head>
    <body>
        <form action="login" method="post">
            <input type="text" name="username">
            <input type="text" name="password">
            <input type="submit" value="登录">
        form>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    界面预览:
    在这里插入图片描述
    三:编写处理登录请求的后端Servlet代码
    此处的验证登录逻辑,应该与数据库进行交互,为了简便,就不再与数据库进行交互了。

    处理思路:

    • 从请求中获取用户名和密码
    • 验证用户名和密码
    • 如果验证通过,则创建会话,并把username
      等属性加入会话中,创建好会话后,响应重定向到主页index
    • 如果验证不通过,告知验证失败即可
    public class LoginServlet extends HttpServlet {
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            req.setCharacterEncoding("utf8");
            resp.setCharacterEncoding("utf8");
            //获取用户用户名
            String username=req.getParameter("username");
            String password=req.getParameter("password");
            //验证用户
            if("lisi".equals(username)&&"123".equals(password)) {
                //登录成功
                //创建会话,为后续登录的页面做准备
                HttpSession httpSession= req.getSession(true);
                httpSession.setAttribute("username",username);
                //初始情况下设置登录次数
                httpSession.setAttribute("count",0);
                resp.sendRedirect("index");
            } else {
                resp.getWriter().write("登录失败!");
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    四:编写获取主页请求的后端Servlet代码
    处理思路:

    • 获取会话
    • 取出会话信息,将主页返回次数加一并写回到会话信息中
    • 返回一个简单的页面
    @WebServlet("/index")
    public class IndexServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //获取会话,参数需要是false
            HttpSession httpSession=req.getSession(false);
            //取出会话信息
            String username=(String)httpSession.getAttribute("username");
            Integer count=(Integer)httpSession.getAttribute("count");
    
            //访问次数加1
            count++;
            //写回到会话中
            httpSession.setAttribute("count",count);
    
            //构造页面
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("

    hello!"+username+"

    这个主页已经被访问了"+count+"次

    "
    ); } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    运行测试:
    请添加图片描述


    在整个过程中共有三次交互过程

    一:再搜索栏输入URL,相当于是浏览器给服务器发送了GET请求,服务器返回前端登录页面
    在这里插入图片描述
    二:输入用户名、密码后点击登录,浏览器给服务发送了请求登录的POST请求,服务器在验证请求中的用户名、密码正确后,返回给浏览器跳转到登陆后个人页面的重定向302响应.
    在这里插入图片描述
    三:在浏览器接收到服务器传来的重定向响应后,又重新向服务器发送重定向响应中指定跳转路径GET请求,服务器在接收到该请求后返回登录后的个人前端页面
    在这里插入图片描述

    3.2 文件上传

    文件上传,也是我们日常Servlet开发经常会涉及到的操作。
    其具体操作流程是,前端通过form-data类型的form表单,来构造HTTP请求,服务器通过getPart方法,来取到Part对象,再通过该对象就能获取到文件信息了。

    核心方法
    HttpServletRequest类方法

    方法描述
    Part getPart(String name)获取请求中给定name的文件
    Collection getParts()获取所有的文件

    Part类方法

    方法描述
    String getSubmittedFileName()获取提交的文件名
    String getContentType()获取提交的文件类型
    long getSize()获取文件的大小
    void write(String path)把提交的文件数据写入磁盘文件

    代码示例:文件上传到服务器

    前端交互
    注意在form标签中加入:enctype="multipart/form-data"

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Documenttitle>
    head>
    <body>
        <form action="upload" method="post" enctype="multipart/form-data">
            <input type="file" name="myfile">
            <input type="submit" value="提交">
        form>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    后端处理代码
    实现思路:

    • 从请求中获取Port对象
    • 调用Port对象的方法(例如写入磁盘)
    • 返回响应
    • 注意加上@MultipartConfig注解
    
    
    • 1

    效果预览:
    1.在这里插入图片描述
    2.
    在这里插入图片描述
    3.
    在这里插入图片描述
    4.
    在这里插入图片描述


    ⭐️最后的话⭐️
    总结不易,希望uu们不要吝啬你们的👍哟(^U^)ノ~YO!!如有问题,欢迎评论区批评指正😁

    请添加图片描述

  • 相关阅读:
    Java运算符
    OpenStack学习笔记之-Nova组件深入了解
    看界面控件DevExpress WinForms如何创建一个虚拟键盘
    shiro反序列化漏洞(CVE-2016-4437)
    C语言校园家教管理系统
    【无标题】LeetCode题解:19. 删除链表的倒数第 N 个结点,JavaScript,详细注释
    收藏这些素材网站,不再担心没有剪辑素材
    My Ninety-seventh Page - 不同的子序列 - By Nicolas
    MyBatis-Plus(详解)
    Dubbo启动报错
  • 原文地址:https://blog.csdn.net/qq_60856948/article/details/127696301