zoukankan      html  css  js  c++  java
  • Java EE入门(十三)——会话技术(Cookie&Session)基础

    Java EE入门(十三)——会话技术(Cookie&Session)基础
      iwehdio的博客园:https://www.cnblogs.com/iwehdio/

    导图

    1、 会话技术

    一次会话:浏览器第一次给服务器资源发送请求,会话建立;直到有一方断开为止。一次会话中包含多次请求和响应。

    • 会话的功能:在一次会话的范围内的多次请求间,共享资源。

    • 方式(数据存储在哪):

      1. 客户端会话技术:Cookie。
      2. 服务器端会话技术:Session。

    2、Cookie

    • Cookie 是客户端会话技术,将数据保存在客户端。服务器端创建 Cookie 并通过响应发送到客户端,客户端在下一次发送请求时同时发送 Cookie 。

    • 使用 Cookie 对象的步骤:

      1. 服务器端创建 Cookie 对象,绑定数据。
        • new Cookie(String name, String value)
      2. 服务器端发送 Cookie 对象。
        • response.addCookie(Cookie cookie)
      3. 服务器端获取 Cookie 对象。
        • Cookie[] request.getCookies()
      • 简单实现:

        @WebServlet("/Cookie1")
        public class Cookie1 extends HttpServlet {
            protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                //创建Cookie
                Cookie c = new Cookie("msg", "hello");
                //发送Cookie
                response.addCookie(c);
            }
            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                this.doPost(request, response);
            }
        }
        
        @WebServlet("/Cookie2")
        public class Cookie2 extends HttpServlet {
            protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                //获取Cookie并遍历
                Cookie[] cs = request.getCookies();
                if(cs != null){
                    for(Cookie cc : cs){
                        String name = cc.getName();
                        String value = cc.getValue();
                        System.out.println(name + "_" + value);
                    }
                }
            }
            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                this.doPost(request, response);
            }
        }
        
    • Cookie 原理分析:

      • 第一次响应,服务器端使用响应头中的 set-cookie 头发送 Cookie。
      • 第二次请求,浏览器使用请求头中的 cookie 头发送 Cookie。
    • Cookie 的相关问题:

      • 一次能否发送多个 Cookie ?
        • 一次可以发送多个 Cookie,只需创建多个对象。
        • 实质上的同一个响应头 / 请求头下用逗号分隔的多个键值对。
      • Cookie 在浏览器中保存多长时间。
        • 默认情况下,当浏览器关闭后,Cookie数据被销毁。
        • 也可以设置 Cookie 的生命周期,使其持久化存储。
        • setMaxAge(int seconds):传入正数表示将Cookie数据写到硬盘的文件中,数字表示cookie的存活时间;传入负数表示默认状态;传入零表示删除 Cookie 信息。
      • Cookie 能否存储中文数据?
        • 在 Tomcat8 之后才支持存储中文数据,但仍不支持特殊字符。
        • 如果在 Tomcat8 之前,需要将中文数据转码,一般使用 URL 编码。
        • URLEncoder.encode(String s, String charset)编码。
        • URLDecoder.decode(String s, String charset)解码。
      • Cookie 的共享:
        • 默认情况下,在 Tomcat 服务器中部署的多个项目之间,Cookie 不能共享。
        • setPath(String path):设置 Cookie 的获取范围,默认为当前的虚拟目录。设置为 "/" 表示设置为当前服务器的根目录,可以在同一个服务器下的多个项目间共享。
        • 不同的 Tomcat 服务器间,通过setDomain(String path)设置一级域名相同,那么多个服务器间 Cookie 可以共享。如传入 .baidu.com 那么 tieba.baidu.com 和 news.baidu.com 可以共享。
    • Cookie 的特点 :

      • Cookie 存储数据在客户端浏览器,安全性一般。
      • 浏览器对单个 Cookie 的大小(一般为4KB)和对同一个域名下的总 Cookie 数量也有限制(一般为20个)。
    • Cookie 的作用:

      • 一般用于存储少量的、不太注重安全性的数据。
      • 用于在不登录的情况下,完成服务器对客户端的身份识别。
    • 案例:记住上一次访问时间。

      • 步骤:

        1. 判断是否有 lasttime 的 Cookie ,根据结果进行响应。
        2. 更新时间写回 Cookie 。
      • 实现:

        @WebServlet("/CookieTest")
        public class CookieTest extends HttpServlet {
            protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                //设置编码
                response.setContentType(("text/html;charset=utf-8"));
                boolean flag = false;
                Cookie[] cs = request.getCookies();
                if(cs != null && cs.length > 0){
                    for(Cookie c : cs){
                        String name = c.getName();
                        if("lasttime".equals(name)){
                            //不是首次访问
                            flag = true;
                            //更新时间
                            Date date = new Date();
                            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
                            String str_date = sdf.format(date);
                            str_date = URLEncoder.encode(str_date, "utf-8");
                            c.setValue(str_date);
                            c.setMaxAge(60 * 60 * 24 * 30);
                            response.addCookie(c);
                            //显示上次访问
                            String value = c.getValue();
                            value = URLDecoder.decode(value, "utf-8");
                            response.getWriter().write("上次访问" + value);
                            break;
                        }
                    }
                }
                if(cs == null || cs.length == 0 || !flag) {
                    //首次访问
                    Date date = new Date();
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
                    String str_date = sdf.format(date);
                    str_date = URLEncoder.encode(str_date, "utf-8");
                    Cookie c = new Cookie("lasttime", str_date);
                    c.setMaxAge(60 * 60 * 24 * 30);
                    response.addCookie(c);
                    response.getWriter().write("首次访问");
                }
                System.out.println("3");
            }
            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                this.doPost(request, response);
            }
        }
        

    2、Session

    服务器端会话技术,将数据保存在服务器端对象中。

    • HttpSession 对象的方法:

      • Object getAttribute(String name):获取数据。
      • void setAttribute(String name, Object value):设置数据。
      • void removeAttribute(String name):移除数据。
    • 使用 HttpSession 对象的步骤:

      1. 在第一个 Servlet 中获取 Session 。
        • HttpSession session = request.getSession()
      2. 在第一个 Servlet 中存储数据。
        • session.setAttribute("name", "value")
      3. 在第二个 Servlet 中获取 Session 。
      4. 在第二个 Servlet 中获取数据。
        • session.getAttribute("name")
    • Session 原理:

      • 服务器确保在一次会话范围内,多次获取的 Session 是同一个。
      • Session 的实现实际上是依赖于 Cookie 的。
      • 第一次获取 Session 时,在内存中创建一个新的 Session 。创建后,服务器会向浏览器响应 Cookie ,内容为 Session 的 ID 即 JSESSIONID 。
      • 之后在同一次会话中,浏览器都会携带相同的 JSESSIONID 请求服务器,这样服务器每次都获取同一个 Session 。
    • Session 的相关问题:

      • 客户端关闭后,服务器不关闭,两次获取 Session 默认情况下不是同一个。

        • 如果要在客户端关闭后, 获取的 Session 也相同,可以手动创建 Cookie 。

        • 实现:

          //创建 Cookie ,内容为 Session 的 id
          Cookie c = new Cookie("JSESSIONID", session.getId);
          //设置 Cookie 的最大存活时间
          c.setMaxAge(60*60);
          //响应 Cookie
          response.addCookie(c);
          
      • 客户端不关闭,服务器关闭,两次获取 Session 默认情况下不是同一个。

        • 获取的不是一个对象,但要保证数据不丢失,即对应的 Session id 不变。
        • Session 的钝化:在服务器正常关闭直接,将 Session 对象系列化存储到硬盘上。
        • Session 的活化:在服务器启动后,将 Session 文件转化为内存中的 Session 对象。
        • 直接使用 Tomcat 部署,Session 存储在 项目的 work 目录下,再次启动时自动活化。IDEA 启动项目时会将 work 目录删除,因此无法完成活化。
      • Session 被销毁。

        • 服务器被关闭。
        • Session 对象调用 invalidate() 方法。
        • 默认失效时间30分钟。可以在 web.xml 下的 session-config 标签下配置。
    • Session 的特点:

      • 用于存储一次会话的多次请求的数据,存在服务器端。
      • 可以存储任意类型、任意大小的数据。
      • 相较于 Cookie 数据较为安全。
    • 案例:用户登录。

      • 步骤:

        1. 编写页面,生成验证码并存储到 Session。
        2. 提交表单,获取 request 和 Session 参数。
        3. 先比较验证码,再比较用户名密码。全部正确则重定向到登录成功。有一个不正确则转发到登录页面。
      • 实现:

        • login.jsp :

          <%@ page contentType="text/html;charset=UTF-8" language="java" %>
          <html>
          <head>
              <title>Login</title>
              <script>
                  //点击更换验证码
                  window.onload = function () {
                      document.getElementById("img").onclick = function () {
                          this.src="/Session/Check?time=" +  new Date().getDate();
                      }
                  }
              </script>
          </head>
          <body>
              <form action="/Session/Session1" method="post">
                  <table>
                      <tr>
                          <td>登录</td>
                          <td><input type="text" name="username" ></td>
                      </tr>
                      <tr>
                          <td>密码</td>
                          <td><input type="password" name="password" ></td>
                      </tr>
                      <tr>
                          <td>验证码</td>
                          <td><input type="text" name="checkcode" ></td>
                      </tr>
                      <tr>
                          <td colspan="2"><img src="/Session/Check" id="img" ></td>
                      </tr>
                      <tr>
                          <td colspan="2"><input type="submit" value="登录"></td>
                      </tr>
                  </table>
              </form>
              <div><%= request.getAttribute("login_error")==null? "" : request.getAttribute("login_error") %></div>
              <div><%= request.getAttribute("checkcode_error")==null? "" : request.getAttribute("checkcode_error") %></div>
          </body>
          </html>
          
        • Session.java :

          @WebServlet("/Session1")
          public class Session1 extends HttpServlet {
              protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                  //获取 request 参数 (多参数应使用 Map 获取)
                  request.setCharacterEncoding("utf-8");
                  String username = request.getParameter("username");
                  String password = request.getParameter("password");
                  String checkcode = request.getParameter("checkcode");
                  //获取 Session 并设置存储验证
                  HttpSession session = request.getSession();
                  String session_checkcode = (String) session.getAttribute("checkcode_session");
                  session.removeAttribute("checkcode_session");
                  //先比较验证码(不区分大小写)
                  if(session_checkcode!=null && session_checkcode.equalsIgnoreCase(checkcode)){
                      //如果验证码正确,比较用户名密码 (具体应使用数据库)
                      if("uadmin".equals(username) && "padmin".equals(password)){
                          //如果用户名密码正确,重定向到 success.jsp
                          session.setAttribute("username", username);
                          response.sendRedirect(request.getContextPath() + "/success.jsp");
                      } else {
                          //如果用户名密码错误,转发到 login.jsp
                          request.setAttribute("login_error", "用户名或密码错误");
                          request.getRequestDispatcher("/login.jsp").forward(request, response);
                      }
                  } else {
                      //如果验证码错误,转发到 login.jsp
                      request.setAttribute("checkcode_error", "验证码错误");
                      request.getRequestDispatcher("/login.jsp").forward(request, response);
                  }
              }
              protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                  this.doPost(request, response);
              }
          }
          
        • Check.java : 其他同 response 中的验证码,只添加存储到 Session 中。

          StringBuilder sb = new StringBuilder();
                  for (int i = 1; i <= 4; i++) {
                      int index = ran.nextInt(str.length());
                      //获取字符
                      char ch = str.charAt(index);//随机字符
                      sb.append(ch);
                      //写验证码
                      g.drawString(ch+"",width/5*i,height/2);
                  }
                  String check_code_session = sb.toString();
                  request.getSession().setAttribute("checkcode_session", check_code_session);
          
        • success.jsp :

          <%@ page contentType="text/html;charset=UTF-8" language="java" %>
          <html>
          <head>
              <title>success</title>
          </head>
          <body>
              <h1><%= request.getSession().getAttribute("username") %></h1>
          </body>
          </html>
          

    iwehdio的博客园:[https://www.cnblogs.com/iwehdio/](https://www.cnblogs.com/iwehdio/)
  • 相关阅读:
    w3c盒子模型与ie盒子模型
    前端入门
    连接数据库好用工具
    前端开发工具
    刚发现的取色工具
    使用val()另一个妙用------选中select/checkbox/radio的值
    z-index的妙用
    react生命周期函数
    react中虚拟dom的diff算法
    React中的虚拟DOM
  • 原文地址:https://www.cnblogs.com/iwehdio/p/12421173.html
Copyright © 2011-2022 走看看