目录

1、Cookie和Session

1.1、如何理解Cookie和Session

1.2、Servlet会话管理操作

1.3、实现登录

1.4、总结Cookie和Session的区别与联系

2、上传文件


1、Cookie和Session

1.1、如何理解Cookie和Session

无状态”协议,这里的“无状态”指的是默认情况下 HTTP 协议的客户端和服务器之间的当次通信, 和下次通信之间没有直接的联系,但是在实际开发中是需要建立起来联系的,比如一个网站的登录,在生活中,我们登录一次网站后,再退出网站后,再次登录网站,我们会发现并不需要再次输入账号密码登录,网站会自动地帮助我们登录。

在用户第一次输入账号密码登录的时候,服务器会创建一个Session会话来保存当前用户的数据和信息,和生成一个Cookie,Cookie里面含有该Session里面的一些关键身份信息,服务器会将这个Cookie作为响应给客户端,客户端或者说是浏览器就会将这个Cookie储存起来,当下一次登录时,浏览器发送请求的时候就会带上这个Cookie,服务器收到请求后会去获取请求中的Cookie列表,并去查询服务器中是否存在对应的Session,如果存在就会自动登录,不用用户输入账号与密码,否则需要用户输入账号密码进行登录。

Cookie与Session机制最主要的作用就是用来识别用户的身份信息。

1.2、Servlet会话管理操作

HttpServletRequest类中,可以使用getSession来获取或创建会话与getCookies可以获取请求中的Cookie列表。

前端能看到 session里的数据吗 前端操作session_服务器

        对于getCookies方法,由于Cookie能够任意自定义键值对,如果想要获取一般的键值对,可以使用该方法获取,但是如果想要获取特殊的键值对,如SessionId,可以通过getSession直接获取,没必要通过getCookies方法的途径来获取,因为getSession方法它自动帮助我们获取了SessionId。

调用getSession方法所做的事情:

创建会话

  • 第一步,获取cookie里面的sessionId字段,相当于会话标识。
  • 第二步,判断是否在服务器上存在。
  • 第三步,如果不存在,则创建一个新的HttpSession对象,并生成一个新的sessionId。
  • 第四步,接下来就会以新生成的sessionId作为key,生成的HttpSession对象作为value,以键值对形式储存到类似与哈希表的结构中。
  • 第五步,返回响应,将sessionId通过set-Cookie字段返回给浏览器,这样浏览器就得到了sessionId,浏览器就可以将SessionId保存到Cookie中了。

获取会话:

  • 第一步,获取cookie里面的sessionId字段,相当于会话标识。
  • 第二步,判断是否在服务器上存在。
  • 第三步,直接查询HttpServlet对象,找到直接作为响应返回给客户端。

关于HttpSession

        这个对象本质上也是一个键值对的形式,并且允许程序员在对象中储存任意的键值对数据,但是key必须是String, value随意。

        HttpSession里面的每一个键值对称为属性(Attribute),该类中提供了两个方法可以用来获取该对象中的属性和储存属性(键值对)。

前端能看到 session里的数据吗 前端操作session_servlet_02

Cookie类常用方法

        Cookie对象包含了两个属性,一个是name,另一个是value,而在请求中是以键值对的形式储存的,服务器收到请求后会将键值对形式的cookie转换为Cookie对象。

 

前端能看到 session里的数据吗 前端操作session_servlet_03

 在响应中添加Cookie

        我们可以通过HttpServletResponse类中的addCookie方法来在响应中添加Cookie,它会作为HTTP响应中set-Cookie字段来进行表示。

前端能看到 session里的数据吗 前端操作session_servlet_04

1.3、实现登录

第一步,约定前后端接口。
我们需要实现两套交互逻辑,一是登录跳转,二是获取主页。
登录跳转约定:
约定使用POST请求,响应采用302重定向。

前端能看到 session里的数据吗 前端操作session_java_05

 获取主页约定:

采用GET请求,响应返回一个页面。

前端能看到 session里的数据吗 前端操作session_前端能看到 session里的数据吗_06

 第二步,编写前端交互页面
        我们的重点是来学习登录的逻辑,因此登录的界面不需要很好看很复杂,只要能够有两个输入框和一个提交按钮让我们输入账号密码就行。目标页面如下:

前端能看到 session里的数据吗 前端操作session_servlet_07

         前面我们约定了登录的跳转采用post请求,由于场景很简单,我们直接使用form表单构造post请求就可以了。

<!DOCTYPE html>
<html lang="ch">
<head>
    <meta charset="UTF-8">
    <title>login</title>
</head>
<body>
    <form action="login" method="post">
        <input type="text" name="username">
        <input type="password" name="password">
        <input type="submit" value="登录">
    </form>
</body>
</html>

其中input标签的name属性就对应键值对的key,输入的内容就对应键值对的value

第三步,编写后端处理代码

对于登录跳转页面post请求处理思路如下:

  • 从请求中获取账号与密码。
  • 验证账号与密码。
  • 如果验证通过,创建会话,并将username数据加入到会话中,当然还可以加入其它的属性,比如主页被访问的次数,创建好会话后,重定向到主页index。
  • 如果验证不通过,告知登录失败即可。
     
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebServlet("/login")
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");
        //验证账户
        //验证按照正常流程应该从数据库读数据,但是为了便于演示登录的逻辑,我们直接将账号密码写死
        //假设正确的账号与密码是 zhangsan 123
        if ("zhangsan".equals(username) && "123".equals(password)) {
            //登录成功
            //创建会话,为后续需登录的页面做准备
            HttpSession httpSession = req.getSession(true);
            httpSession.setAttribute("username", username);
            //初始情况下设置登录次数
            httpSession.setAttribute("count", 0);
            //跳转到目标页面index
            resp.sendRedirect("index");
        } else {
            //登录失败
            resp.getWriter().write("登录失败!");
        }
    }
}

获取主页的get请求处理思路:

  • 获取会话。
  • 取出会话信息,将主页返回次数加1并写回到会话信息中。
  • 返回一个简单的页面。
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@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 cnt = (Integer) httpSession.getAttribute("count");
        //访问次数加1
        cnt++;
        //写回到会话中
        httpSession.setAttribute("count", cnt);

        //构造页面。我们简单构造一下就好
        resp.setContentType("text/html; charset=utf8");
        resp.getWriter().write("<h3>欢迎您!" + username + "</h3> <h4>这个主页已经被访问了" + cnt + "次</h4>");
    }
}

抓包结果:

前端能看到 session里的数据吗 前端操作session_java_08

  • 第一次交互,浏览器从服务器上拿到登录页面。
  • 第二次交互,浏览器给服务器一个登录请求,服务器返回响应,重定向页面。
  • 第三次交互,浏览器收到302重定向响应后,再次向服务器发起请求,访问主页。

效果演示:

前端能看到 session里的数据吗 前端操作session_java_09

前端能看到 session里的数据吗 前端操作session_服务器_10

1.4、总结Cookie和Session的区别与联系

  • 安全性:Session比Cookie安全,Session是存储在服务器端的,Cookie是存储在客户端的
  • 存取值的类型不同:Cookie只支持存字符串数据,想要设置其他类型的数据,需要将其转换成字符串,Session可以存任意数据类型
  • 有效期不同:Cookie可设置为长时间有效,比如我们会使用的默认登录功能,Session一般失效时间较短,客户端关闭(默认式)或者Session超时都会失效
  • 存储大小的不同:单个Cookie保存的数据不能超过3k,Session可存储数据远高于Cookie,但是当访问量过多,会占用过多的服务器资源

2、上传文件

        上传文件时,前端需要使用到form表单,表单中需要使用一种特殊的类型,叫做form-data类型。

        提交文件的时候,浏览器会把文件以form-data的格式构造到Http请求中,服务器可以通过getPart方法来取的Part对象(文件),再通过Part对象就能够获取到文件信息了。

前端能看到 session里的数据吗 前端操作session_服务器_11

 Part类常用方法:

前端能看到 session里的数据吗 前端操作session_java_12

        上传文件的请求采用post请求,使用form表单构造post请求,我们来实现将一个文件上传到本机的一个目录下。

前端交互页面:

前端能看到 session里的数据吗 前端操作session_键值对_13

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>file</title>
</head>
<body>
    <form action="upload" method="post" enctype="multipart/form-data">
        <input type="file" name="myfile">
        <input type="submit" value="提交">
    </form>

</body>
</html>

后端处理代码:

基本实现思路:

  • 从请求中获取Part对象。
  • 调用Part对象的一些方法,获取文件信息,在磁盘写文件等。
  • 返回响应。
  • 加上@MultipartConfig注解,不然会出错。
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.IOException;

@MultipartConfig
@WebServlet("/upload")
public class UploadServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取Part对象
        Part part = req.getPart("myfile");
        //输出文件信息
        //文件名
        System.out.println("文件名:" + part.getSubmittedFileName());
        //文件类型
        System.out.println("文件类型:" + part.getContentType());
        //文件大小
        System.out.println("文件大小:" + part.getSize());
        //将文件写入磁盘
        part.write("D:/ssbb.gif");
        //返回响应
        resp.setContentType("text/html; charset=utf8");
        resp.getWriter().write("上传成功!");
    }
}

效果演示:

前端能看到 session里的数据吗 前端操作session_键值对_14

前端能看到 session里的数据吗 前端操作session_servlet_15

提交后:

前端能看到 session里的数据吗 前端操作session_servlet_16

再去对应目录查看:

 

前端能看到 session里的数据吗 前端操作session_java_17

本期结束啦,下期见咯!