六、Session和Cookie

JavaWeb會話技術(shù)

HTTP通信協(xié)議的特點(diǎn):

1.應(yīng)答式的協(xié)議古劲,只能是客戶端先發(fā)送請求然后服務(wù)器作出響應(yīng)斥赋。

2.明文傳輸,傳輸?shù)臄?shù)據(jù)是明文,沒有做加密之類處理

3.簡單快速产艾。HTTP協(xié)議相對簡單疤剑,所以傳輸較快。

4.無狀態(tài)闷堡,HTTP通信骚露,不會記錄客戶端的請求信息。默認(rèn)通信完成缚窿,傳輸斷開棘幸。

基于無狀態(tài)這點(diǎn),如果客戶端和服務(wù)器需要進(jìn)行二次會話倦零,且可能需要之前會話的數(shù)據(jù)這樣的需求場景误续。

所以,WEB技術(shù)中扫茅,提供了2種解決方案蹋嵌,這兩種解決方案就被稱之為會話技術(shù)。分別是:Session和Cookie葫隙。

1.如果一方需要之前溝通的記錄栽烂,在生活中是怎么處理的?

方案一: 將數(shù)據(jù)存儲起來,需要時進(jìn)行查看。Session

方案二:重新將之前的記錄發(fā)送一次腺办。Cookie

2.WEB中的Session技術(shù)

WEB中的Session技術(shù)焰手,是在服務(wù)器創(chuàng)建一個Session容器,可以將數(shù)據(jù)存儲在這個容器怀喉,然后將查找到這個容器key,給客戶端书妻,那么每次客戶端來請求服務(wù)器時,可以將這個key帶給服務(wù)器躬拢,服務(wù)器就可以根據(jù)這個key躲履,找到客戶端寄存在服務(wù)器的Session(數(shù)據(jù)容器),然后從session中獲取存儲的數(shù)據(jù)聊闯。

例如: 在超市里工猜,將物品進(jìn)行寄存,有一個寄存的號碼牌菱蔬,需要時篷帅,可以根據(jù)號碼牌,拿到寄存的物品汗销。

注意:

1.session是在服務(wù)器的內(nèi)存中犹褒,開辟了一存儲空間抵窒,默認(rèn)是有效時間是30分鐘弛针,若沒有主動釋放,則30分鐘會釋放內(nèi)存李皇。

2.session容器是一個map結(jié)構(gòu)的容器削茁,根據(jù)key查找對應(yīng)的session,若key不對掉房,那么session將找不到(找不到不代表它消失了)茧跋。一般關(guān)閉瀏覽器,或者使用新的瀏覽器卓囚,服務(wù)器會分配一個新的key給瀏覽器瘾杭,此時就找不到之前的那個session了,但是之前的session是在內(nèi)存中的哪亿。

3.客戶端從存儲session對應(yīng)的key是使用cookie技術(shù)存儲的粥烁,所以session技術(shù)也是依賴cookie技術(shù)。

2.1.session使用

session作為一個會話對象蝇棉,其中可以存儲多次請求需要共享的數(shù)據(jù)讨阻。例如:驗(yàn)證碼,當(dāng)前登錄用戶都可以存在session篡殷。所以首先要有session容器钝吮。

在調(diào)試時發(fā)現(xiàn),當(dāng)?shù)谝淮卧L問jsp頁面時,會有Cookie奇瘦,且Cookie中存在JSESSIONID的值棘催,但是訪問servlet的時候沒有,因?yàn)镴SP默認(rèn)會創(chuàng)建session對象(session是JSP的內(nèi)置對象之一)链患,但是session是不會主動創(chuàng)建session對象的巧鸭。所以在servlet中使用session,首先要創(chuàng)建一個session對象麻捻,而session與客戶端的請求關(guān)聯(lián)的纲仍,因?yàn)閟ession表示會話,會話包含多個請求贸毕,所以需要根據(jù)請求對象郑叠,找到關(guān)聯(lián)的session對象。


session示例.png
session示例2.png

以上圖片明棍,瀏覽器中Cookie中JSESSIONID對應(yīng)的值乡革,與服務(wù)器中產(chǎn)生的sesion對象的ID值一致,說明服務(wù)器將自己創(chuàng)建的session對象的ID值給了瀏覽器摊腋。且使用的是Cookie沸版。所以session是依賴Cookie,因?yàn)樾枰褂肅ookie存儲自己的唯一標(biāo)識兴蒸,便于瀏覽器找到對應(yīng)的Session.

package com.sxt.controller;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
 * @ClassName: SessionController 
 * @Description: 演示session的API
 * @author: Mr.T
 * @date: 2020年2月14日 上午11:36:30
 */
public class SessionController extends HttpServlet {

    private static final long serialVersionUID = -6539113475281947079L;

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("service方法執(zhí)行了");
        // getSession() : 返回與當(dāng)前請求關(guān)聯(lián)的session 如果沒有則創(chuàng)建一個新的session
        // getSession(create) : 返回當(dāng)前關(guān)聯(lián)的session對象, 如果create 為true,當(dāng)前session不存在時創(chuàng)建一個视粮,為false則返回null
        //一般都是使用  getSession() 
        HttpSession session = req.getSession();
        System.out.println("session的ID:"+session.getId());
        //resp.getWriter().println("Hello Session");
        //session中核心方法
        //session 作為作用域  其核心作用是數(shù)據(jù)管理
        //setAttribute(name, value) :向session 作用域中存儲數(shù)據(jù)
        //getAttribute(name) : 從session作用域中獲取數(shù)據(jù)
        //getAttributeNames() : 從session作用域中獲取所有存儲數(shù)據(jù)的name值
        //session生命周期方法
        //setMaxInactiveInterval(long) : 設(shè)置session 有效時間  單位是秒  
        //如果設(shè)置為0  或者 負(fù)數(shù),那么session 將永遠(yuǎn)不會失效  不建議  因?yàn)閟ession占服務(wù)器內(nèi)存
        // tomcat 服務(wù)器 默認(rèn)是 30分鐘
        //session.setMaxInactiveInterval(interval);
        //invalidate() : 是這個session不關(guān)聯(lián)任何對象,即取消session和request的關(guān)聯(lián)
        //這樣當(dāng)前request 就無法找到這個session
        //session.invalidate();
        
    }   
    
}

2.2session目前的不足

session是存儲在服務(wù)器的內(nèi)存中,所以session只支持單應(yīng)用橙凳,而不支持負(fù)載形式的應(yīng)用架構(gòu)蕾殴。

所以session只支持單應(yīng)用的架構(gòu),只支持只有一臺服務(wù)器的架構(gòu)岛啸。

session的不足.png

2.3.使用session記錄當(dāng)前用戶

一般在開發(fā)中钓觉,會將當(dāng)前登錄用戶,存儲在內(nèi)存中坚踩,便于其他地方使用荡灾。而在web程序,會將當(dāng)前的登錄用戶瞬铸,存儲在session中批幌。然后,在其他頁面或者servlet中赴捞,若要使用當(dāng)前用戶信息逼裆,則可以直接從session中獲取,不必根據(jù)用戶名和密碼重新查詢赦政,只需要登錄一次即可胜宇。

代碼:

package com.sxt.controller;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.sxt.pojo.User;
/**
 * @ClassName: UserController 
 * @Description: 用戶控制類
 * @author: Mr.T
 * @date: 2020年2月14日 下午2:40:11
 */
public class UserController extends HttpServlet {
    
    private static final long serialVersionUID = 7723086583204133716L;

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String userName = req.getParameter("userName");
        String password = req.getParameter("password");
        //根據(jù)用戶名和密碼查詢用戶
        //假設(shè)  用戶名和密碼 值都是 admin 當(dāng)做登錄成功
        if("admin".equals(userName) && "admin".equals(password)) {
            //將用戶信息存在session中
            User user = new User(1, "admin", "password","韓梅梅");
            //放入session  便于在當(dāng)前會話中  任何頁面或者servlet 都可以直接拿到當(dāng)前登錄用戶信息
            req.getSession().setAttribute("user", user);
        }
        //去登錄成功頁面
        resp.sendRedirect("success.jsp");
    }       
}

package com.sxt.controller;

import java.io.IOException;

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 com.sxt.pojo.User;
/**
 * @ClassName: TestController 
 * @Description: 用于測試 可以從session中獲取當(dāng)前登錄用戶
 * @author: Mr.T
 * @date: 2020年2月14日 下午2:47:58
 */
public class TestController extends HttpServlet {

    private static final long serialVersionUID = -5123674255870472885L;

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession session = req.getSession();
        User user = (User) session.getAttribute("user");
        System.out.println("當(dāng)前登錄的用戶是:"+user.getRealName());
    }
    

}

package com.sxt.pojo;

public class User {
    
    private Integer userId;
    
    private String userName;
    
    private String password;
    
    private String realName;
    
    
    public User() {}

    public User(Integer userId, String userName, String password, String realName) {
        super();
        this.userId = userId;
        this.userName = userName;
        this.password = password;
        this.realName = realName;
    }

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getRealName() {
        return realName;
    }

    public void setRealName(String realName) {
        this.realName = realName;
    }
    
    
    

}

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登錄頁面</title>
</head>
<body>
<form action="user.do">
    <p>用戶名:<input type="text" name="userName"  /></p>
    <p>用戶名:<input type="password" name="password"  /></p>
    <input  type="submit" value="登錄"/>
</form>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- 從session 獲取當(dāng)前登錄用戶的真實(shí)姓名 -->
歡迎:${user.realName}
</body>
</html>

2.4.使用session存儲驗(yàn)證碼

一般在web網(wǎng)頁上看到的圖片耀怜,其實(shí)是服務(wù)器將圖片數(shù)據(jù)使用字節(jié)流,輸出給瀏覽器桐愉,然后瀏覽器拿到數(shù)據(jù)后财破,將數(shù)據(jù)解析成圖片,渲染在頁面从诲。

那么左痢,在頁面上看到的驗(yàn)證碼圖片,其實(shí)就是服務(wù)器生成的一張圖片系洛,然后將圖片使用字節(jié)流發(fā)送給了俊性,瀏覽器。然后瀏覽器解析描扯。并且定页,在處理登錄請求的servlet時,拿到用戶輸入的驗(yàn)證碼和之前產(chǎn)生的驗(yàn)證碼要進(jìn)行比對绽诚。

那么此時典徊,就是在登錄的servlet,要使用造驗(yàn)證碼的servlet產(chǎn)生的數(shù)據(jù)恩够,但是造驗(yàn)證碼servlet程序已經(jīng)執(zhí)行完成了卒落,內(nèi)存已經(jīng)釋放了。之前造的驗(yàn)證碼字符串已經(jīng)消失了蜂桶,無法進(jìn)行比對儡毕。基于這樣的情況屎飘,所以一般是將產(chǎn)生驗(yàn)證碼的字符串妥曲,存儲在session中贾费,這樣在登錄請求的servlet中钦购,也可以拿到之前產(chǎn)生的驗(yàn)證碼,從而進(jìn)行比對褂萧。

產(chǎn)生驗(yàn)證碼

package com.sxt.controller;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
 * @ClassName: CheckCodeController 
 * @Description: 產(chǎn)生驗(yàn)證碼的servlet
 * @author: Mr.T
 * @date: 2020年2月14日 下午3:27:44
 */
public class CheckCodeController  extends HttpServlet {

    private static final long serialVersionUID = -1597171426922505140L;
    /**
     * 驗(yàn)證碼池  
     */
    static String[] codes = {"0","1","2","3","4","5","6","7","8","9","a","b","c","d"};
    
    
    /**
     * 驗(yàn)證碼的本質(zhì) 其實(shí)就是 一個有隨機(jī)字符串的圖片
     * 服務(wù)器押桃,將圖片轉(zhuǎn)化為字節(jié)流輸出給瀏覽器
     * 瀏覽器解析流數(shù)據(jù),將圖片渲染在頁面
     */
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //要使用Java程序  造一個含有隨機(jī)字符串的圖片
        //1. 創(chuàng)建一個背景圖  畫布
        BufferedImage image =  new BufferedImage(200, 100, BufferedImage.TYPE_INT_RGB);
        //2. 獲取一個跟畫布關(guān)聯(lián)的畫筆
        Graphics graphics = image.getGraphics();
        //3.使用畫筆繪制信息
        //為畫筆設(shè)置顏色
        graphics.setColor(Color.WHITE);
        //繪制一個填充的矩形  將默認(rèn)黑色的畫布 涂成白色
        graphics.fillRect(0, 0, 200, 100);
        //1. 獲取驗(yàn)證碼字符串   4個字符長度的驗(yàn)證碼
        String code = getCode(4);
        //將驗(yàn)證碼 放入session 便于在其他地方使用
        req.getSession().setAttribute("code", code);
        // 設(shè)置畫筆的字體 宋體 加粗 傾斜 35磅值
        Font font = new Font("宋體", Font.BOLD | Font.ITALIC, 60);
        graphics.setFont(font);
        //2.根據(jù)循環(huán)將字符 繪制到圖片上
        for (int i = 0; i < code.length(); i++) {
            //隨機(jī)改變畫筆顏色
            Color c = getColor();
            graphics.setColor(c);
            //獲取具體的字符
            String str = code.charAt(i)+"";
            //讓文字的橫坐標(biāo)值變大,從而向右側(cè)移動
            int x = 20 + i*40;
            graphics.drawString(str, x,65);
        }
        
        
        
        ImageIO.write(image, "jpg", resp.getOutputStream());
    }
    
    
    /**
     * @Title: getColor
     * @author: Mr.T   
     * @date: 2020年2月14日 下午3:54:56 
     * @Description: 隨機(jī)產(chǎn)生顏色
     * @return
     * @return: Color
     */
    private Color getColor() {
        //因?yàn)镽GB顏色 是由  0-255,0-255,0-255 的數(shù)值組成
        Random random = new Random();
        int r = random.nextInt(255);
        int g = random.nextInt(255);
        int b = random.nextInt(255);
        return new Color(r, g, b);
    }
    /**
     * @Title: getCode
     * @author: Mr.T   
     * @date: 2020年2月14日 下午3:57:55 
     * @Description: 產(chǎn)生隨機(jī)字符串
     * @param count 驗(yàn)證碼的個數(shù)
     * @return
     * @return: String
     */
    private String getCode(int count) {
        String code = "";
        Random random = new Random();
        for (int i = 0; i < count; i++) {
            int index = random.nextInt(codes.length);
            code = code + codes[index];
        }
        return code;
    }
    
    /**
     * @Title: method
     * @author: Mr.T   
     * @date: 2020年2月14日 下午4:03:38 
     * @Description: 繪制驗(yàn)證碼相關(guān)API的演示
     * @return: void
     */
    private void method(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 要使用Java程序 造一個含有隨機(jī)字符串的圖片
        // 1. 創(chuàng)建一個背景圖 畫布
        BufferedImage image = new BufferedImage(200, 100, BufferedImage.TYPE_INT_RGB);
        // 2. 獲取一個跟畫布關(guān)聯(lián)的畫筆
        Graphics graphics = image.getGraphics();
        // 3.使用畫筆繪制信息
        // 為畫筆設(shè)置顏色
        graphics.setColor(Color.WHITE);
        // 繪制一個填充的矩形 將默認(rèn)黑色的畫布 涂成白色
        graphics.fillRect(0, 0, 200, 100);
        // 可以在白色畫布上繪制文字 注意 此時畫筆是白色 繪制信息也是白色 所以需要改變畫筆的顏色
        // 畫筆設(shè)置為紅色
        graphics.setColor(Color.RED);
        // 設(shè)置畫筆的字體 宋體 加粗 傾斜 35磅值
        Font font = new Font("宋體", Font.BOLD | Font.ITALIC, 30);
        graphics.setFont(font);
        graphics.drawString("情人節(jié)快樂", 10, 55);
        // 繪制干擾線 2點(diǎn) 連起來 就是一條線
        graphics.drawLine(0, 0, 200, 100);
        // 使用輸出流 將圖片數(shù)據(jù)輸出給瀏覽器
        ImageIO.write(image, "jpg", resp.getOutputStream());
    }
    
}

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登錄頁面</title>
</head>
<body>
<form action="user.do">
    <p>用戶名:<input type="text" name="userName"  /></p>
    <p>用戶名:<input type="password" name="password"  /></p>
    <p>用戶名:<input type="password" name="checkCode" style="width: 50px"  />
        <img onclick="refreshCode()" src="checkCode.do" style="height: 50px" id="checkCodeImg" />
    </p>
    <input  type="submit" value="登錄"/>
</form>
</body>
<script type="text/javascript">
    //刷新驗(yàn)證碼
    function refreshCode(){
        console.log("點(diǎn)擊了");
        //設(shè)置 src的值  值一旦發(fā)生改變  瀏覽器 會重新請求這個url地址
        //瀏覽器存在緩存策略,當(dāng)src 后面值一樣,瀏覽器是不會重新請求
        //那么servlet就不會產(chǎn)生新的驗(yàn)證碼  所以驗(yàn)證碼沒有發(fā)生改變
        //基于這樣的情況  一般會在src 后面的url 拼接一個不可重復(fù)的字符 ,一般使用隨機(jī)數(shù) 或者 時間戳
        document.getElementById("checkCodeImg").src = "checkCode.do?"+new Date();
    }
</script>
</html>

使用Hutool生成驗(yàn)證碼:

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        /**
         *  width  : 圖片的寬度
         *  height : 圖片高度
         * codeCount : 驗(yàn)證碼的個數(shù)
         * circleCount : 干擾元素個數(shù)
         */
        LineCaptcha checkObj = CaptchaUtil.createLineCaptcha(200, 100, 4, 100);
        //獲取具體的驗(yàn)證碼字符串
        String code = checkObj.getCode();
        //將生成的驗(yàn)證碼 放入session
        req.getSession().setAttribute("code", code);
        //將驗(yàn)證碼輸出到頁面
        checkObj.write(resp.getOutputStream());
    }

校驗(yàn)驗(yàn)證碼:

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //獲取用戶輸入的驗(yàn)證碼
        String checkCode = req.getParameter("checkCode");
        //從session中獲取產(chǎn)生時存儲的驗(yàn)證碼
        Object code = req.getSession().getAttribute("code") ;
        //對驗(yàn)證碼進(jìn)行對比
        if(checkCode == null || !checkCode.equals(code.toString())) {
            System.out.println("驗(yàn)證碼錯誤!");
            resp.sendRedirect("login.jsp");
            return;
        }
        String userName = req.getParameter("userName");
        String password = req.getParameter("password");
        //根據(jù)用戶名和密碼查詢用戶
        //假設(shè)  用戶名和密碼 值都是 admin 當(dāng)做登錄成功
        if("admin".equals(userName) && "admin".equals(password)) {
            //將用戶信息存在session中
            User user = new User(1, "admin", "password","韓梅梅");
            //放入session  便于在當(dāng)前會話中  任何頁面或者servlet 都可以直接拿到當(dāng)前登錄用戶信息
            req.getSession().setAttribute("user", user);
        }
        //去登錄成功頁面
        resp.sendRedirect("success.jsp");
    }

3.WEB中的Cookie技術(shù)

在WEB中导犹,Cookie技術(shù)是將需要的數(shù)據(jù)唱凯,由服務(wù)器寫入(響應(yīng))到瀏覽器中(內(nèi)存中,一個文件中)谎痢,然后磕昼,瀏覽器接下來的請求,都會將這些數(shù)據(jù)通過請求頭节猿,帶給服務(wù)器票从。服務(wù)器可以通過解析請求頭漫雕,從而解析這些數(shù)據(jù)。這種技術(shù)方案就被稱之為Cookie.

注意:

  1. Cookie的存儲2種方式峰鄙,一種是內(nèi)存中一種磁盤文件中浸间,這兩種方式是Cookie生命周期的體現(xiàn)。默認(rèn)Cookie的生命周期吟榴,是在內(nèi)存中魁蒜,基本是一次會話。
  2. Cookie是由服務(wù)器吩翻,通過響應(yīng)對象兜看,將數(shù)據(jù)通知給客戶端,讓客戶端在本地進(jìn)行一定的存儲狭瞎,且下次來請求帶過來铣减。

3.1.Cookie的使用

  1. 創(chuàng)建Cookie

    Cookie cookie1 = new Cookie("name","value"); // cookie是map結(jié)構(gòu)

  2. 通過response對象,將創(chuàng)建的cookie給瀏覽器

    resp.addCookie(cookie1); //通過響應(yīng)對象脚作,設(shè)置set-cookie的響應(yīng)頭葫哗,瀏覽器拿到這個響應(yīng)頭后 ,會將響應(yīng)頭找中的數(shù)據(jù)保存到瀏覽器的內(nèi)存中或者本地

  3. 以后的請求球涛,瀏覽器會將cookie信息帶給服務(wù)器劣针,服務(wù)器可以從請求頭中,解析cookie信息亿扁。

代碼示例:

/**
 * @ClassName: CookieController 
 * @Description: 用于演示Cookie相關(guān)的API
 * @author: Mr.T
 * @date: 2020年2月16日 上午10:47:39
 */
public class CookieController extends HttpServlet {

    private static final long serialVersionUID = 2285648241402004645L;

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //cookie是由服務(wù)器  告訴客戶端 要存儲哪些數(shù)據(jù) 
        //cookie是由服務(wù)器創(chuàng)建  然后 服務(wù)器將這個cookie 給客戶端   客戶端將cookie數(shù)據(jù)進(jìn)行存儲
        //之后的請求,都會將cookie數(shù)據(jù)帶給服務(wù)器
        //1. 創(chuàng)建Cookie --- cookie數(shù)據(jù)結(jié)構(gòu)  map接口
        Cookie cookie1 = new Cookie("cookieName", "cookieValue");
        //設(shè)置cookie的有效期 單位是秒   如果設(shè)置為 0 則表示要刪除這個cookie
        //如果設(shè)置了有效期,瀏覽器會將cookie存儲在自己本地的文件中,如果不清除,且沒有過有效期,那么cookie就有效
        //之后請求,會將數(shù)據(jù)帶給服務(wù)器
        cookie1.setMaxAge(60*2);//2分鐘
        //設(shè)置cookie是否允許瀏覽器進(jìn)行操作   由于cookie是存在瀏覽器中,瀏覽器可以通過js對cookie進(jìn)行數(shù)據(jù)操作
        //servlet 3.0 后   setHttpOnly(true) : 只有HTTP可以操作Cookie 瀏覽器無法操作Cookie
        cookie1.setHttpOnly(true);
        //注意捺典,cookie 默認(rèn)只對當(dāng)前項(xiàng)目生效   有效路徑  當(dāng)前項(xiàng)目   域名  項(xiàng)目名
        //但是實(shí)際中,存在子域名,當(dāng)需要多個子域名cookie也生效,則需要設(shè)置這個屬性 
        //cookie1.setDomain(pattern);
        //注意,默認(rèn)只對項(xiàng)目及項(xiàng)目的子目錄生效。限制生效的URI,通過setPath進(jìn)行設(shè)置 
        //cookie1.setPath(uri);
        
        //2. 通過響應(yīng)對象  將cookie 給客戶端
        resp.addCookie(cookie1);
        resp.getWriter().print("Hello  Cookie");
    }
}
@Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //cookie數(shù)據(jù) 是瀏覽器 通過請求頭的信息  將數(shù)據(jù)傳給服務(wù)器的,所以解析cookie 要從請求對象中解析
        // 獲取所有的cookie
        Cookie[] cookies = req.getCookies();
        //判斷cookie是否存在
        if(cookies != null) {
            //只能通過遍歷的方式進(jìn)行判斷   遍歷所有cookie 獲取每個cookie的name值   對比name 從而拿到自己需要的cookie對象
            for (Cookie cookie : cookies) {
                //獲取cookie的name
                String name = cookie.getName();
                //獲取cookie的Value值
                String value = cookie.getValue();
                if(name.equals("cookieName")) {
                    System.out.println("cookieName 對應(yīng)的值:"+value);
                }
            }
        }
    }

cookie01.png
cookie02.png

3.2.Cookie的不足

Cookie是將數(shù)據(jù)存儲在瀏覽器从祝,然后每次瀏覽器自動會將Cookie數(shù)據(jù)放在請求頭中襟己,傳遞給無服務(wù)器。

1.安全性相對較差,可以在傳輸?shù)倪^程中牍陌,修改Cookie中數(shù)據(jù)擎浴。

2.無法與其它終端共享數(shù)據(jù)。例如:用戶在PC端進(jìn)行了操作毒涧,數(shù)據(jù)存在Cookie中贮预,用戶在移動端是看不到用戶在PC端的操作的。

3.Cookie中存儲的數(shù)據(jù)有限.

3.3.Cookie的場景

1.早期時契讲,使用Cookie做購物車仿吞。將用戶的購買的商品放入Cookie中。但是在現(xiàn)在捡偏,使用Cookie作為購物車唤冈,無法滿足需求,因?yàn)闆]有辦法在其它終端共享數(shù)據(jù)银伟。所以你虹,為了共享數(shù)據(jù)凉当,會將數(shù)據(jù)存在服務(wù)器數(shù)據(jù)庫中,便于在任何平臺都能看到用戶的購物車售葡,前提是用戶登錄了看杭。所以,如果用戶沒有登陸挟伙,會將用戶購物車數(shù)據(jù)存儲在Cookie中楼雹,但是,當(dāng)用戶登錄后尖阔,將Cookie中的數(shù)據(jù)保存到數(shù)據(jù)庫中贮缅。

2.用戶的瀏覽記錄。一般會將用戶的瀏覽記錄放入Cookie介却。例如: 瀏覽器的訪問記錄.

3.使用Cookie記錄用戶的登錄憑證谴供,讓用戶免密登錄。記住密碼齿坷。

3.5.使用Cookie記住密碼

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登錄頁面</title>
</head>
<body>
<!-- 用戶登錄表單 -->
<form action="user.do" method="post">
    <!-- 從cookie中 獲取 對應(yīng)的值 -->
    <p>用戶名<input type="text" name="userName" value="${cookie.userName.value}" /></p>
    <p>密碼:<input type="text" name="password" value="${cookie.password.value}" /></p>
    <p>記住密碼:<input type="checkbox" name="remeber"  value="1"/></p>
    <p><input type="submit" value="登錄" /></p>
</form>
</body>
</html>
package com.sxt.controller;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * @ClassName: UserController 
 * @Description: @WebServlet 就是代替 web.xml中的servlet 配置
 *              "/user.do"  就是xml中 url-pattern的值
 * @author: Mr.T
 * @date: 2020年2月16日 下午2:34:42
 */
@WebServlet("/user.do")
public class UserController extends HttpServlet {

    /**
     * @fieldName: serialVersionUID
     * @fieldType: long
     * @Description: TODO
     */
    private static final long serialVersionUID = 7723086583204133716L;

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //獲取用戶名
        String userName = req.getParameter("userName");
        //獲取密碼
        String password = req.getParameter("password");
        //是否記住密碼
        String remeber = req.getParameter("remeber");
        /**
         * 如果記住密碼  可以將賬號密碼信息放入cookie  下次登錄 直接從cookie中取  不用再輸入賬號面
         * 
         */
        if("1".equals(remeber)) {//表示記住密碼
            //將賬號放入cookie
            Cookie userNameCookie = new Cookie("userName", userName);
            //由于 cookie 默認(rèn)是瀏覽器關(guān)閉就會消失,設(shè)置cookie的有效期
            userNameCookie.setMaxAge(60*60*24*7);//1個星期
            //通過resp 將cookie給瀏覽器
            resp.addCookie(userNameCookie);
            
            //將密碼 放入cookie
            Cookie passwordCookie = new Cookie("password", password);
            //由于 cookie 默認(rèn)是瀏覽器關(guān)閉就會消失,設(shè)置cookie的有效期
            passwordCookie.setMaxAge(60*60*24*7);//1個星期
            //通過resp 將cookie給瀏覽器
            resp.addCookie(passwordCookie);
        }
        resp.getWriter().print("登錄成功"); 
    }
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末桂肌,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子永淌,更是在濱河造成了極大的恐慌崎场,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件遂蛀,死亡現(xiàn)場離奇詭異谭跨,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)李滴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門螃宙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人所坯,你說我怎么就攤上這事谆扎。” “怎么了包竹?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵燕酷,是天一觀的道長籍凝。 經(jīng)常有香客問我周瞎,道長,這世上最難降的妖魔是什么饵蒂? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任声诸,我火速辦了婚禮,結(jié)果婚禮上退盯,老公的妹妹穿的比我還像新娘彼乌。我一直安慰自己泻肯,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布慰照。 她就那樣靜靜地躺著灶挟,像睡著了一般。 火紅的嫁衣襯著肌膚如雪毒租。 梳的紋絲不亂的頭發(fā)上稚铣,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天,我揣著相機(jī)與錄音墅垮,去河邊找鬼惕医。 笑死,一個胖子當(dāng)著我的面吹牛算色,可吹牛的內(nèi)容都是我干的抬伺。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼灾梦,長吁一口氣:“原來是場噩夢啊……” “哼峡钓!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起若河,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤椒楣,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后牡肉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捧灰,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年统锤,在試婚紗的時候發(fā)現(xiàn)自己被綠了毛俏。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡饲窿,死狀恐怖煌寇,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情逾雄,我是刑警寧澤阀溶,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站鸦泳,受9級特大地震影響银锻,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜做鹰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一击纬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧钾麸,春花似錦更振、人聲如沸炕桨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽献宫。三九已至,卻和暖如春实撒,著一層夾襖步出監(jiān)牢的瞬間遵蚜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工奈惑, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留吭净,地道東北人。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓肴甸,卻偏偏與公主長得像寂殉,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子原在,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容