`Cookie`和`Session`

CookieSession

会话技术:

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

**功能:**在一次会话的范围内的多次请求间,共享数据

方式:

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

概念:客户端会话技术,将数据保存到客户端

快速入门
  1. 创建Cookie对象,绑定数据

    new Cookie(String name,String value);

  2. 发送Cookie对象

    response.addCookie(Cookie cookie);

  3. 获取Cookie,拿到数据

    Cookie[] request.getCookies();

@WebServlet(urlPatterns = {"/cookie1"})
public class Cookie1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String value = "hello Cookie";
        // 由于Cookie不能存储特殊的字符如:空格$#等,需要转编码
        // 调用
        String encode = URLEncoder.encode(value, "utf-8");
        // 创建Cookie对象,并且存储数据
        Cookie cookie = new Cookie("message", encode);

        // 发送Cookie,由于响应是Response对象的
        resp.addCookie(cookie);

        System.out.println("发送");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req,resp);
    }
}
@WebServlet(urlPatterns = {"/cookie2"})
public class Cookie2 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req,resp);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取出Cookie的值,获取需要使用Request对象
        Cookie[] cookies = req.getCookies();
        // 遍历Cookie
        if (cookies!=null&&cookies.length!=0){
            for (Cookie cookie:cookies) {
                String name = cookie.getName();
                String value = cookie.getValue();
                // 由于发送Cookie时,数据封装数据时,使用编码的方式
                // 需要解码
                String decode = URLDecoder.decode(value,"utf-8");
                System.out.println(name+" : "+decode);
            }
        }
    }
}
Cookie实现原理

基于响应头set-cookie和请求头cookie之间的通信

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hzvz56y2-1651883084510)(D:\typora笔记\javaweb\img\Cookie原理.bmp)]

Cookie的实现步骤

  1. 当浏览器第一次访问服务器端时,服务器会创建一个Cookie对象用于封装数据
  2. 服务器会发送一个set-cookie的一个头信息给浏览器
  3. 当浏览器接收到一个set-cookie头信息时,会自动将set-cookie的信息保存到浏览器中
  4. 当浏览器下一次访问服务器时,会自动的携带着一个为cookie的头信息去访问服务器
  5. 服务器可以获取cookie头信息
可以一次发送多个Cookie?
可以
可以创建多个`Cookie`对象,使用`respone`调用多次
`addCookie`方法发送`Cookie`即可
/**
 * 演示Cookie一次性发送多个
 */
@WebServlet(urlPatterns = {"/cookie3"})
public class Cookie3 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req,resp);
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 由于在服务器中不支持特殊字符所以需要将发送的信息进行编码,防止报错
        String message = "hello Cookie";
        String message_enc = URLEncoder.encode(message, "utf-8");
        String username = "海康";//在tomcat8之前不支持中文,在tomcat8之后,解决中文问题,但是还是不支持特殊字符如:空格@#¥等
        String username_enc = URLEncoder.encode(username,"utf-8");
        // 创建多个Cookie
        Cookie cookie1 = new Cookie("username", username_enc);
        Cookie cookie2 = new Cookie("message", message_enc);
        // 调用Response对象发送Cookie
        resp.addCookie(cookie1);
        resp.addCookie(cookie2);
        System.out.println("Cookie发送完毕。。。");
    }
}
Cookie在浏览器中保存多长时间?
1.默认情况下,当浏览器关闭后,`Cookie`数据被销毁
2.持久化存储
	调用`Cookie`中的`setMaxAge(int seconds)`方法,设置`Cookie`在浏览器中的存活时间
	取值:
		1.正数:将`Cookie`数据写到硬盘文件中。持久化存储,并指定`Cookie`的存活时间,时间到后,`Cookie`文件自动失效
		
		2.负数:默认值,浏览器关闭就失效,如果服务器关闭,如果该Cookie还存活着,等服务器启动后访问还能在服务器中获取到该Cookie的值,但是会话结束了
		
		3.零  :删除`Cookie`信息

1.注意是:将Cookie的存活时间持久化到硬盘中,就是浏览器没有关闭,持久化到硬盘中的Cookie如果存活时间到,访问服务器也不会获取到该Cookie的值,因为被删除了**

2.如果服务器关闭,如果该Cookie还存活着,等服务器启动后访问还能在服务器中获取到该Cookie的值,但是会话结束了

/**
 * 演示Cookie的存活时间
 */
@WebServlet(urlPatterns = {"/cookie4"})
public class Cookie4 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        /**
         * 1.正数:将`Cookie`数据写到硬盘文件中。持久化存储,并指定`Cookie`的存活时间,时间到后,`Cookie`文件自动失效
         * 2.负数:默认值
         * 3.零  :删除`Cookie`信息
         */
        // 创建Cookie
        Cookie cookie = new Cookie("message", "hello");
        // 设置Cookie的存活时间
        cookie.setMaxAge(-1);//默认值就是负数,表示浏览器关闭Cookie值就失效,服务器关闭不会影响保存在浏览器中的Cookie,但是会话结束了
//        cookie.setMaxAge(0);//表示删除所有Cookie的值
//         cookie.setMaxAge(100);//表示将Cookie持久化到硬盘中100秒后,自动删除
        // 发送Cookie
        resp.addCookie(cookie);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req,resp);
    }
}
Cookie能否存储中文
在`tomcat8`之前`Cookie`不能保存中文,需要将中文数据转码
	一般采用`URL`编码方式
	编码调用的是`URLEncoder`类中的`encode("编码字符串", "字符集[一般是utf-8]");`
	
	解码调用的是`URLDecoder`类中的`decode("解码字符串","字符集[需要与编码字符集一致]");`//如编码是`utf-8`,解码就得是`utf-8`
编码
String username = "海康";//在tomcat8之前不支持中文,在tomcat8之后,解决中文问题,但是还是不支持特殊字符如:空格@#¥等
        String username_enc = URLEncoder.encode(username,"utf-8");
        // 创建多个Cookie
        Cookie cookie1 = new Cookie("username", username_enc);
        
        
 解码       
String name = cookie.getName();
                String value = cookie.getValue();
                // 由于发送Cookie时,数据封装数据时,使用编码的方式
                // 需要解码
                String decode = URLDecoder.decode(value,"utf-8");
                System.out.println(name+" : "+decode);
Cookie数据共享问题?

同一个服务器下部署不能项目的共享问题

1.假设在一个`tomcat`服务器中,部署多个web项目,那么在这些web项目中`cookie`能不能共享数据?
	默认情况下是不能的,原因是在没有设置`Cookie`对象的中`path`属性值,默认值是该项目的`虚拟目录`,所以是不能共享数据的
	
	如果需要`Cookie`在不同项目下共享数据,需要调用`Cookie`中的`void setPath(String path)`方法,可以将`path`设置为服务器的根目录`/`

方法:

 // 设置路径
    public void setPath(String uri) {
        this.path = uri;
    }

默认情况下是不能的,原因是在没有设置Cookie对象的中path属性值,默认值是该项目的虚拟目录,所以是不能共享数据的

如果需要Cookie在不同项目下共享数据,需要调用Cookie中的void setPath(String path)方法,可以将path设置为服务器的根目录/

不能服务器下部署不同项目共享数据问题

不同的`tomcat`服务器间`Cookie`共享问题?
	需要调用`Cookie`对象中的`setDomain(String path);`方法,需要设置一级域名相同,达到多个服务器间的`Cookie`共享数据问题

方法:

// 设置Cookie在浏览器中存活时间
    public void setMaxAge(int expiry) {
        this.maxAge = expiry;
    }
Cookie的特点和作用

特点:

1.`Cookie`存储数据在客户端浏览器中

2.浏览器对于单个`Cookie`的大小有限制`(4kb)`以及对同一个域名下的总`Cookie`数量也有限制`(20个)`[浏览器不同也有差别]

作用:

1.`Cookie`一般用于存储少量的不太敏感的数据
2.在不登录的情况下,完成服务器对象客户端的身份识别
综合案例
案例需求:
	1. 访问一个Servlet,如果是第一次访问,则提示:您好,欢迎您首次访问。
	2. 如果不是第一次访问,则提示:欢迎回来,您上次访问时间为:显示时间字符串
Cookie源码区
public class Cookie implements Cloneable, Serializable {
    private static final long serialVersionUID = -6454587001725327448L;
    private static final String TSPECIALS;
    private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings";
    private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.http.LocalStrings");
    private String name;
    private String value;
    private String comment;
    private String domain;//一级域【一般用于在不同服务器中部署的不同项目之间的数据共享】
    private int maxAge = -1;//默认值,设置Cookie在浏览器中的存活时间
    private String path;//路径[一般用于设置在一个服务器上部署的多个项目之间共享数据]
    private boolean secure;
    private int version = 0;
    private boolean isHttpOnly = false;

    public Cookie(String name, String value) {
        if (name != null && name.length() != 0) {
            if (this.isToken(name) && !name.equalsIgnoreCase("Comment") && !name.equalsIgnoreCase("Discard") && !name.equalsIgnoreCase("Domain") && !name.equalsIgnoreCase("Expires") && !name.equalsIgnoreCase("Max-Age") && !name.equalsIgnoreCase("Path") && !name.equalsIgnoreCase("Secure") && !name.equalsIgnoreCase("Version") && !name.startsWith("$")) {
                this.name = name;
                this.value = value;
            } else {
                String errMsg = lStrings.getString("err.cookie_name_is_token");
                Object[] errArgs = new Object[]{name};
                errMsg = MessageFormat.format(errMsg, errArgs);
                throw new IllegalArgumentException(errMsg);
            }
        } else {
            throw new IllegalArgumentException(lStrings.getString("err.cookie_name_blank"));
        }
    }

     //设置注释
    public void setComment(String purpose) {
        this.comment = purpose;
    }

    //获取注释
    public String getComment() {
        return this.comment;
    }

    //设置一级域名,用于在不同服务器中部署的不同项目之间共享数据
    public void setDomain(String domain) {
        this.domain = domain.toLowerCase(Locale.ENGLISH);
    }

    //获取一级域名
    public String getDomain() {
        return this.domain;
    }

    // 设置Cookie在浏览器中存活时间
    public void setMaxAge(int expiry) {
        this.maxAge = expiry;
    }

    // 获取Cookie的存活时间
    public int getMaxAge() {
        return this.maxAge;
    }

    // 设置路径
    public void setPath(String uri) {
        this.path = uri;
    }

    // 获取路径
    public String getPath() {
        return this.path;
    }

    public void setSecure(boolean flag) {
        this.secure = flag;
    }

    public boolean getSecure() {
        return this.secure;
    }

    // 获取Cookie的名称
    public String getName() {
        return this.name;
    }

    // 设置Cookie中的值
    public void setValue(String newValue) {
        this.value = newValue;
    }

    // 获取Cookie中的值
    public String getValue() {
        return this.value;
    }

    // 获取版本号
    public int getVersion() {
        return this.version;
    }
    
    // 设置版本号
    public void setVersion(int v) {
        this.version = v;
    }

    private boolean isToken(String value) {
        int len = value.length();

        for(int i = 0; i < len; ++i) {
            char c = value.charAt(i);
            if (c < ' ' || c >= 127 || TSPECIALS.indexOf(c) != -1) {
                return false;
            }
        }

        return true;
    }

    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException var2) {
            throw new RuntimeException(var2.getMessage());
        }
    }

    public void setHttpOnly(boolean isHttpOnly) {
        this.isHttpOnly = isHttpOnly;
    }

    public boolean isHttpOnly() {
        return this.isHttpOnly;
    }

    static {
        if (Boolean.valueOf(System.getProperty("org.glassfish.web.rfc2109_cookie_names_enforced", "true"))) {
            TSPECIALS = "/()<>@,;:\\\"[]?={} \t";
        } else {
            TSPECIALS = ",; ";
        }

    }
}

Session重点

概念:服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务器端的对象中

快速入门

1.获取HttpSession对象

调用`Request`对象中的`getSession()`方法获取一个`HttpSession`对象

2.使用HttpSession对象共享数据常用方法

获取共享的数据
Object getAttribute(String name)  

设置共享的数据
void setAttribute(String name, Object value)

删除共享的数据
void removeAttribute(String name)  

这三个方法与Request对象和ServletContext对象中的三个方法一样,只是操作的对象不同,这三个对象都是用于共享数据的,只是作用域不同

案例:

/**
 * @Author 海康
 * @Version 1.0
 *
 * Session的快速入门
 * 说明Session是在一次会话之中共享数据的
 */
@WebServlet(urlPatterns = {"/session1"})
public class Session1 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req,resp);
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1.获取 HttpSession 对象
        HttpSession session = req.getSession();
        // 2.存储数据
        session.setAttribute("message","用Session在一次会话中共享数据");
        System.out.println("存储数据完毕!");
    }
}



@WebServlet(urlPatterns = {"/session2"})
public class Session2 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req,resp);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取在一次会话中Session共享的数据
        //先获取HttpSession对象
        HttpSession session = req.getSession();
        // 获取Session共享,根据键名获取
        String message = (String) session.getAttribute("message");
        System.out.println(message);
    }
}
Session原理【重之重】

Session的实现是依赖于Cookie

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2ReVk9QM-1651883084511)(D:\typora笔记\javaweb\img\Session原理.bmp)]

Session的原理

  1. 当浏览器访问服务器时,服务器第一次获取Session对象,在Cookie中没有JSESSIONID的值【也有可能此时没有Cookie头,会在内存中创建一个Session对象,并将对象Session对应的JSESSIONID封装到Cookie中响应给浏览器】
  2. 服务器会在内存中创建一个Session对象,并且在内存中生成一个JSESSIONID用于唯一标识Session对象,并且将Session中的值封装到一个set-cookie头中,响应给浏览器
  3. 浏览器接收到一个set-cookie头后,将值保存在浏览器中
  4. 浏览器下次访问服务器地,携带着JSESSIONID去访问服务器,服务器根据JSESSIONID在服务器获取对象的Session对象
  5. 所以在一次会话中获取的HttpSession对象都是同一个
Session细节
1.当客户端关闭后,服务器不关闭,两次获取Session是否为同一个?
默认情况下,不是同一个`Session`对象,因为保存在客户端浏览器中的`JSESSIONID`已经被销毁了



修改`Cookie`的存活时间,如果需要相同,则可以创建一个`Cookie`,设置Cookie的键是`JSESSION`,设置最大的存活时间,让Cookie持久保存到硬盘中

代码区:
HttpSession session = req.getSession();
Cookie cookie = new Cookie("JSESSION",session.getID());
cookie.setMaxAget(60*60*24);//比如设置一天
response.addCookie(cookie);

案例:

@WebServlet(urlPatterns = {"/servlet"})
public class SessionMaxAge extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req,resp);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取一个Session对象
        HttpSession session = req.getSession();
        // 创建一个Cookie对象,用于封装数据,使用浏览器关闭后,再次请求服务器时,获取到Session还是同一个
        Cookie cookie = new Cookie("JSESSIONID", session.getId());
        cookie.setMaxAge(60*60*24);//设置存活时间是 24 小时
        // 发送Cookie
        resp.addCookie(cookie);
        System.out.println(session);//打印Session地址值
    }
}
2.客户端不关闭,服务器关闭后,再次获取的Session是同一个吗?
在默认情况下,不是同一个

但是要确保数据不丢失,需要对`Session`钝化【就是序列化】和`Session`活化【就是反序列化】
`Session`的钝化:
		在服务器正常关闭之前,将`session`对象系列化到硬盘上
		
`Session`的活化
		在服务器启动后,将`session`文件转化为内存中的`session`对象即可

上述的钝化和活化tomcat自动完成了以下的工作了

Seesion什么时候被销毁,有三种情况
情况一:
服务器关闭时,服务器关闭后,保存在内存中的`Session`会被销毁

情况二:
可以调用`Session`中的`invalidate()`,将服务器端`Session`销毁掉

情况三:可以在`web.xml`文件中配置`Session`的销毁时间
<session-config>
	<session-timeout>30</session-timeout>//默认情况下是30分钟,可以修改该值
</session-config>
Session的特点
  1. Session用于存储一次会话的多次请求的数据,存在服务器端
  2. Session可以存储任意类型,任意大小的数据
SessionCookie的区别
  1. Session存储数据在服务器,Cookie在客户端
  2. Session没有数据大小的限制,Cookie有大小限制【4kb
  3. Session数据安全【在服务器端防护相对高】,Cookie相对是不安全的
Session源码
public interface HttpSession {
    long getCreationTime();//获取创建时间

    String getId();//获取Session的ID

    long getLastAccessedTime();

    ServletContext getServletContext();//获取ServletContext对象

    void setMaxInactiveInterval(int var1);

    int getMaxInactiveInterval();

    /** @deprecated */
    @Deprecated
    HttpSessionContext getSessionContext();

    Object getAttribute(String var1);

    /** @deprecated */
    @Deprecated
    Object getValue(String var1);

    Enumeration<String> getAttributeNames();

    /** @deprecated */
    @Deprecated
    String[] getValueNames();

    void setAttribute(String var1, Object var2);

    /** @deprecated */
    @Deprecated
    void putValue(String var1, Object var2);

    void removeAttribute(String var1);

    /** @deprecated */
    @Deprecated
    void removeValue(String var1);

    void invalidate();//销毁Session对象方法,谁调用销毁谁

    boolean isNew();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值