Web开发会话技术(Cookie,Session)

  • Cookie是服务器在客户端保存用户的信息,比如登录名,浏览历史等,就可以以cookie方式保存.

  • Cookie信息就像是小甜饼(cookie中文)一样,数据量并不大,服务器端在需要的时候可以从客户端/浏览器读取(http协议)

  • JSESSIONID是用来标识每一次会话的,是不同会话的唯一标识

  • 创建Cookie对象,发送到浏览器

    • 先创建一个Cookie对象
    • 再将Cookie对象加入的http的响应对象resp中
package com.hspedu.cookie_session;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @Projectname: servlet
 * @Filename: CreateCookie
 * @Author: 杨逸
 * @Data:2023/4/8 11:01
 * @Description: TODO
 */
public class CreateCookie extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //创建一个Cookie
        /**
         * cookieName是该Cookie对象的名称,是唯一的,不能重复,重复会覆盖上一个
         * cookieValue是该Cookie的值
         * 可以同时创建多个Cookie
         */
        Cookie cookie = new Cookie("cookieName", "cookieValue");
        resp.setContentType("text/html;charset=utf-8");
        //将Cookie放入http响应发送给浏览器
        resp.addCookie(cookie);
        PrintWriter writer = resp.getWriter();
        writer.print("<h1>创建Cookie成功</h1>");
        writer.flush();
        writer.close();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}
  • 读取浏览器发送的Cookie
    • 先从http的请求对象中获得存放所有的Cookie的数组
    • 再遍历存放Cookie的数组得到Cookie
package com.hspedu.cookie_session;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @Projectname: servlet
 * @Filename: ReadCookie
 * @Author: 杨逸
 * @Data:2023/4/8 11:19
 * @Description: TODO
 */
public class ReadCookie extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //读取http请求发送过来的Cookie
        //获得http发送的所有Cookie
        Cookie[] cookies = req.getCookies();
        //判断,遍历
        if (cookies != null && cookies.length != 0){
            for (Cookie cookie :cookies) {
                System.out.println("Cookie的名字" + cookie.getName() + "Cookie的值" + cookie.getValue());
            }
        }

        resp.setContentType("text/html;charset=utf-8");
        PrintWriter writer = resp.getWriter();
        writer.print("<h1>Cookie读取成功</h1>");
        writer.flush();
        writer.close();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}
  • Cookie的修改
package com.hspedu.cookie_session;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @Projectname: servlet
 * @Filename: UpdateCookie
 * @Author: 杨逸
 * @Data:2023/4/8 11:49
 * @Description: TODO
 */
public class UpdateCookie extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //修改Cookie的值
        //获得存放Cookie的数组
        Cookie[] cookies = req.getCookies();
        //获得指定名称的Cookie
        Cookie cookieName = CookieUtils.getCookieByName("cookieName", cookies);
        if (cookieName != null){
            //如果找到指定的Cookie就修改
            cookieName.setValue("updateCookieOfValue");
            //修改后在加入到http响应对象resp中
            resp.addCookie(cookieName);
        }else {
            //如果没找到指定的Cookie,就打印没有找到
            System.out.println("没有指定的Cookie");
        }

        resp.setContentType("text/html;charset=utf-8");
        PrintWriter writer = resp.getWriter();
        writer.print("<h1>Cookie修改</h1>");
        writer.flush();
        writer.close();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}
  • Cookie的生命周期
{
 //创建一个Cookie,使用setMaxAge()方法设置生命周期
        //默认是-1,即浏览器退出后该Cookie就不生效
        //0表示浏览器接收到该Cookie后,马上就失效了
        //设置具体的数字n,表示浏览器接收到该Cookie后n秒后,该Cookie才失效
        Cookie cookie = new Cookie("job", "java");
    	//设置该Cookie60秒后过期
        cookie.setMaxAge(60);
}
  • Cookie的有效路径
    • Cookie的path属性可以有效的过滤哪些Cookie可以发送给服务器。哪些不发。path属性是通过请求的地址
      来进行有效的过滤
    • 规则如下:
    • Cookie的默认有效路径是项目的工程路径
    • 通过控制Cookie的有效路径,可以控制浏览器在访问哪些资源时可以发送服务器需要的Cookie
//设置Cookie的路径
        Cookie cookie = new Cookie("name1", "value1");
        Cookie cookie1 = new Cookie("name2", "value2");
        //开始设置不同的有效路径
        cookie.setPath(getServletContext().getContextPath());
        cookie1.setPath(getServletContext().getContextPath() + "/aaa");
  • 使用Cookie实现自动填用户信息
    1. 使用两个Servlet,一个用于展示页面,一个用于处理登陆请求
    2. 展示页面Servlet通过获得Cookie信息决定页面然后展示
    3. 登陆处理Servlet通过表单提交的信息设置Cookie信息
//用于展示页面的Servlet
package com.hspedu.cookie_session;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @Projectname: servlet
 * @Filename: HomeworkCookie
 * @Author: 杨逸
 * @Data:2023/4/8 15:24
 * @Description: Cookie的作业
 * 使用Cookie实现自动填写用户名
 */
public class HomeworkCookie extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //先获得Cookie
        Cookie[] cookies = req.getCookies();
        //获得标记自动填写用户名的Cookie
        Cookie keepCookie = CookieUtils.getCookieByName("KeepLogin", cookies);
        //设置返回的格式和编码
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter writer = resp.getWriter();
        //判断是否要自动填写
        if (keepCookie != null && "1".equals(keepCookie.getValue())){
            //自动填写用户名
            Cookie username = CookieUtils.getCookieByName("username",cookies);
            if (username != null){
                //用于登陆的html
                String meg = "<!DOCTYPE html>\n" +
                        "<html lang=\"en\">\n" +
                        "<head>\n" +
                        "    <meta charset=\"UTF-8\">\n" +
                        "    <base href=\"/servlet/\">\n" +
                        "    <title>登陆</title>\n" +
                        "</head>\n" +
                        "<body>\n" +
                        "<form action=\"login\" method=\"post\">\n" +
                        "    用户名<input type=\"text\" name=\"username\" value=\""+username.getValue()+"\"><br>\n" +
                        "    密    码<input type=\"password\" name=\"password\"><br>\n" +
                        "    <input type=\"submit\" value=\"提交\">\n" +
                        "</form>\n" +
                        "</body>\n" +
                        "</html>";
                writer.print(meg);

            }
        }else {
            String meg = "<!DOCTYPE html>\n" +
                    "<html lang=\"en\">\n" +
                    "<head>\n" +
                    "    <meta charset=\"UTF-8\">\n" +
                    "    <base href=\"/servlet/\">\n" +
                    "    <title>登陆</title>\n" +
                    "</head>\n" +
                    "<body>\n" +
                    "<form action=\"login\" method=\"post\">\n" +
                    "    用户名<input type=\"text\" name=\"username\"><br>\n" +
                    "    密    码<input type=\"password\" name=\"password\"><br>\n" +
                    "    <input type=\"submit\" value=\"提交\">\n" +
                    "</form>\n" +
                    "</body>\n" +
                    "</html>";
            writer.print(meg);
        }
        writer.flush();
        writer.close();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}


//用于处理登陆的Servlet
package com.hspedu.cookie_session;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @Projectname: servlet
 * @Filename: LoginServlet
 * @Author: 杨逸
 * @Data:2023/4/8 15:31
 * @Description: 登陆的servlet
 */
public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获得登陆表单提交的信息
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        //创建一个保存用户名的Cookie
        Cookie cookie1 = new Cookie("username", username);
        resp.addCookie(cookie1);
        //判断密码是否正确
        if ("123456".equals(password)){
            //如果正确就创建一个标记自动填写用户名的Cookie返回
            Cookie cookie = new Cookie("KeepLogin", "1");
            resp.addCookie(cookie);
            resp.setContentType("text/html;charset=utf-8");
            PrintWriter writer = resp.getWriter();
            writer.print("<h1>登陆成功!</h1>");
        }else {
            resp.setContentType("text/html;charset=utf-8");
            PrintWriter writer = resp.getWriter();
            writer.print("<h1>密码或用户名错误,登陆成功失败!</h1>");
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}
  • Cookie注意事项和细节
  1. 一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置值(
    VALUE)。

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

  3. Cookie的总数量没有限制,但是每个域名的COOKIE数量和每个COOKIE的大小是有限制的
    (不同的浏览器限制不同,知道即可),Cookie不适合存放数据量大的信息。

  4. 注意,删除Cookie时,path必须一致,否则不会删除

  5. Java servlet中Cookie中文乱码解决

    • Cookie中使用中文默认是会报错的

    • 可以使用URl编码后再存放

    • 读取是先对数据进URl解码,就是正常的中文

      //使用URLEncoder类对中文进行编码
      String s = URLEncoder.encode("中文", "utf-8");
      //编码后再放入到Cookie中就不会报错
      //使用RULDecoder类对编码后的字符串进行解码
      String decode = URLDecoder.decode(s, "utf-8");
      //解码后就是正常的内容了
      

Session

  • Session是服务器端技术,服务器在运行时为每一个用户的浏览器创建一个其独享的session对象/集合
  • 由于session为各个用户浏览器独享,所以用户在访问服务器的不同页面时,可以从各自的session中读取/添
    加数据,从而完成相应任务
  • 创建Session对象是通过HttpServletRequest对象的getSession()方法获得的
    • 当Cookie中存在JSESSIONID时,查看Tomcat容器中是否存在该ID的Session对象
    • 如果有就直接返回,如果没有就创建再返回
    • 当Cookie中没有JSESSIONID时,就先获得JSESSIONID,返回给浏览器,然后再创建Session对象
  • Session对象的常用方法
    1. 设置Session的属性,属性的名称是字符串类型,属性的值是Object对象类型,setAttribute("SessionName","SessionValue");
    2. 获得Session的属性,getAttribute("SessionName")
    3. 删除Session的属性,removeAttribute("SessionName")
    4. 获得Session的JSESSIONID(就是用户的唯一标识),getId()
    5. 设置Session的生命周期,单位秒(s),setMaxInactiveInterval(60)
      • 没有参数,就是Tomcat中的配置的生命周期,默认是30分钟
      • 参数是负数时,表示永不过期
      • 参数为零时,表示马上过期
      • 参数为正数时,表示过期时间的倒计时
    6. 获得Session的过期时间,getMaxInactiveInterval()
    7. 调用方法使当前Session立即无效,invalidate()
  • Session的生命周期指的是:客户端两次请求最大间隔时长,而不是累积时长。即当客户端访问了自己的
    session,session的生命周期将从0开始重新计算。(指的是同一个会话两次请求之间的间隔时间)
    • 底层:Tomcat用一个线程来轮询会话状态,如果某个会话的空闲时间超过设定的最大值,则将该会话销毁
package com.hspedu.cookie_session;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

/**
 * @Projectname: servlet
 * @Filename: GetSession
 * @Author: 杨逸
 * @Data:2023/4/8 18:08
 * @Description: 获得session对象
 */
public class GetSession extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获得Session对象,通过HttpServletRequest对象创建(获得)Session对象
        //当Cookie中存在JSESSIONID时,查看Tomcat容器中是否存在该ID的Session对象,
        // 如果有就直接返回,如果没有就创建再返回
        //当Cookie中没有JSESSIONID时,就先获得JSESSIONID,返回给浏览器,然后再创建Session对象
        HttpSession session = req.getSession();
        //设置Session的属性
        //属性的名称是字符串类型,属性的值是Object对象类型
        session.setAttribute("SessionName","SessionValue");
        //获得Session的属性
        Object name = session.getAttribute("SessionName");
        System.out.println("session的值" + name);
        //删除Session的属性
        session.removeAttribute("SessionName");
        //设置Session的生命周期,单位秒(s)
        session.setMaxInactiveInterval(60);
         //获得Session的过期时间
        int maxInactiveInterval = session.getMaxInactiveInterval();
        //调用方法使当前Session立即无效
        session.invalidate();
        //获得Session的JSESSIONID(就是用户的唯一标识)
        String id = session.getId();
        System.out.println("session的JSESSIONID=" + id );

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

  • 使用Session实现管理页面访问控制(Session作业)
  • 没有登陆成功时,直接访问管理页面会跳转到登陆失败页面
  • 只有登陆成功时访问管理页面,管理页面的Servlet才会返回信息
  • 使用两个Servlet实现,一个检查表单提交的参数,一个检查当前访问是否成功登陆
  • 检查表单的Servlet
//检查表单的Servlet
package com.hspedu.cookie_session;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

/**
 * @Projectname: servlet
 * @Filename: LoginCheckServlet
 * @Author: 杨逸
 * @Data:2023/4/8 18:57
 * @Description: Session的登陆检查Servlet
 */
public class LoginCheckServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获得表单提交的数据
        String password = req.getParameter("password");
        //判断
        if ("666666".equals(password)){
            //如果密码通过,就创建一个Session
            HttpSession session = req.getSession();
            //给Session设置,允许访问登陆成功页面
            session.setAttribute("login","1");
            //然后转发到登陆成功管理Servlet
            resp.sendRedirect("sessionManageLogin");
            System.out.println("转发到登陆管理Servlet");
        }else {
            //如果密码没有通过,就转发到登陆失败页面
            resp.sendRedirect("html/sessionLoginError.html");
            System.out.println("转发到登陆失败页面");
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

  • 控制页面访问的Servlet
//控制页面访问的Servlet
package com.hspedu.cookie_session;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @Projectname: servlet
 * @Filename: SessionManageLogin
 * @Author: 杨逸
 * @Data:2023/4/8 19:11
 * @Description: Session登陆成功页面的管理Servlet
 */
public class SessionManageLogin  extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获得请求的Session对象
        HttpSession session = req.getSession();
        //获得允许访问的属性
        Object login = session.getAttribute("login");
        //判断是否能访问该页面
        if ("1".equals(login)){
            //能访问,返回登陆成功页面
            resp.setContentType("text/html;charset=utf-8");
            PrintWriter writer = resp.getWriter();
            String meg = "<!DOCTYPE html>\n" +
                    "<html lang=\"en\">\n" +
                    "<head>\n" +
                    "    <meta charset=\"UTF-8\">\n" +
                    "    <base href=\"/servlet/\">\n" +
                    "    <title>session登陆成功页面</title>\n" +
                    "</head>\n" +
                    "<body>\n" +
                    "<h1>session登陆成功页面</h1>\n" +
                    "</body>\n" +
                    "</html>";
            writer.print(meg);
            writer.flush();
            writer.close();
            System.out.println("登陆成功");
        }else {
            //不能访问,转发到登陆失败页面
            resp.sendRedirect("html/sessionLoginError.html");
            System.out.println("登陆失败");
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

  • 登陆表单html和登陆失败的页面
//登陆表单html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <base href="/servlet/">
    <title>sessionLogin</title>
</head>
<body>
<form action="loginCheckServlet" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="提交">
</form>

</body>
</html>

//登陆失败的页面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <base href="/servlet/">
    <title>session登陆失败页面</title>
</head>
<body>
<h1>登陆失败</h1>
<a href="html/sessionLogin.html">重新登录</a>
</body>
</html>