C/C++教程

Cookie&Session

本文主要是介绍Cookie&Session,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

15.Cookie&Session

15.1.会话技术
  1. 会话:一次会话中包含多次请求和响应。
    • 一次会话:浏览器第一次给服务器资源发送请求,会话建立,直到有一方断开为止
  2. 功能:在一次会话的范围内的多次请求间,共享数据
  3. 方式:
    1. 客户端会话技术:Cookie
    2. 服务器端会话技术:Session
  4. 原因:因为Html的无状态无标记性,浏览器无法识别当前HTTP报文是哪一个客户端发送过来的,引入会话技术解决浏览器存储数据问题
15.2.Cookie
  1. 概念:客户端会话技术,将数据保存到客户端
  2. 使用步骤:
    • public Cookie(String name, String value):构造方法,创建Cookie对象,绑定数据
    • response.addCookie(Cookie cookie) : 发送Cookie对象
    • Cookie[] request.getCookies() : 获取Cookie,拿到数据
  3. 实现原理
    • 基于响应头set-cookie和请求头cookie实现
  4. cookie的细节
    • 一次可以发送多个cookie
    • 可以创建多个Cookie对象,使用response调用多次addCookie方法发送cookie即可。
    • cookie在浏览器中保存时间
      • 默认情况下,当浏览器关闭后,Cookie数据被销毁
      • 持久化存储:setMaxAge(int seconds)
        • 正整数:将Cookie数据写到硬盘的文件中。持久化存储。并指定cookie存活时间,时间到后,cookie文件自动失效
      • 负整数:默认值
        • 零:删除cookie信息,删除之前,一定要setPath相同的路径,浏览器要比对是否一致
        @WebServlet("/del")
        public class DelCookieServlet extends HttpServlet {
            protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        
            }
        
            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                //通过访问该servlet,将cookie信息删除
                Cookie[] cookies = request.getCookies();
                if(cookies != null){
                    for (Cookie cookie : cookies) {
                        if("username".equals(cookie.getName())){
                            cookie.setMaxAge(0);
                            //需要把这个告诉给浏览器
                            response.addCookie(cookie);
                        }
                    }
                }
            }
        }
        
    • cookie存储中文
      • 在tomcat 8 之前 cookie中不能直接存储中文数据。
        • 需要将中文数据转码—一般采用URL编码(%E3)
      • 在tomcat 8 之后,cookie支持中文数据。特殊字符还是不支持,建议使用URL编码存储,URL解码解析
    • cookie共享问题
      • 假设在一个tomcat服务器中,部署了多个web项目,那么在这些web项目中cookie能不能共享?
        • 默认情况下cookie不能共享
        • setPath(String path) : 设置cookie的获取范围。默认情况下,设置当前的虚拟目录
        • 不可以设置一个和当前域名无关的cookie信息,如当前localhost,设置一个baidu.com域名的cookie是不成功的,原因是出于安全性考虑。
        • 如果要共享,则可以将path设置为"/"
      • 删除cookie时,如果当前cookie没有设置path,那么直接设置MaxAge=0即可删除cookie
      • 但是如果cookie设置了path,那么删除cookie的时候,一定要再把path写一遍。
        cookie.setMaxAge(0);
        cookie.setPath(request.getContextPath() + "/info");
        response.addCookie(cookie);
        
    • 不同的tomcat服务器间cookie共享问题
      • setDomain(String path):如果设置一级域名相同,那么多个服务器之间cookie可以共享
      • setDomain(".baidu.com"),那么tieba.baidu.com和news.baidu.com中cookie可以共享
  5. Cookie的特点和作用
    1. cookie存储数据在客户端浏览器
    2. 浏览器对于单个cookie 的大小有限制(4kb) ,浏览器的cookie总数一般限制300个,对同一个域名下的总cookie数量也有限制(20-50个)
  6. 作用:
    • cookie一般用于存出少量的不太敏感的数据,且只能存储字符串
    • 在不登录的情况下,完成服务器对客户端的身份识别
  7. 案例:记住上一次访问时间
  8. 需求:
    1. 访问一个Servlet,如果是第一次访问,则提示:您好,欢迎您首次访问。
    2. 如果不是第一次访问,则提示:欢迎回来,您上次访问时间为:显示时间字符串
    3. 分析:
      1. 可以采用Cookie来完成
      2. 在服务器中的Servlet判断是否有一个名为lastTime的cookie
      3. 有:不是第一次访问
      • 响应数据:欢迎回来,您上次访问时间为:2018年6月10日11:50:20
      • 写回Cookie:lastTime=2018年6月10日11:50:01
      1. 没有:是第一次访问
        • 响应数据:您好,欢迎您首次访问
        • 写回Cookie:lastTime=2018年6月10日11:50:01
@WebServlet("/cookieTest")
	public class CookieTest extends HttpServlet {
	    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
	        //设置响应的消息体的数据格式以及编码
	        response.setContentType("text/html;charset=utf-8");
	
	        //1.获取所有Cookie
	        Cookie[] cookies = request.getCookies();
	        boolean flag = false;//没有cookie为lastTime
	        //2.遍历cookie数组
	        if(cookies != null && cookies.length > 0){
	            for (Cookie cookie : cookies) {
	                //3.获取cookie的名称
	                String name = cookie.getName();
	                //4.判断名称是否是:lastTime
	                if("lastTime".equals(name)){
	                    //有该Cookie,不是第一次访问
	
	                    flag = true;//有lastTime的cookie
	
	                    //设置Cookie的value
	                    //获取当前时间的字符串,重新设置Cookie的值,重新发送cookie
	                    Date date  = new Date();
	                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
	                    String str_date = sdf.format(date);
	                    System.out.println("编码前:"+str_date);
	                    //URL编码
	                    str_date = URLEncoder.encode(str_date,"utf-8");
	                    System.out.println("编码后:"+str_date);
	                    cookie.setValue(str_date);
	                    //设置cookie的存活时间
	                    cookie.setMaxAge(60 * 60 * 24 * 30);//一个月
	                    response.addCookie(cookie);//响应数据
	                    //获取Cookie的value,时间
	                    String value = cookie.getValue();
	                    System.out.println("解码前:"+value);
	                    //URL解码:
	                    value = URLDecoder.decode(value,"utf-8");
	                    System.out.println("解码后:"+value);
	                    response.getWriter().write("<h1>欢迎回来,您上次访问时间为:"+value+"</h1>");
	
	                    break;
	
	                }
	            }
	        }
            if(cookies == null || cookies.length == 0 || flag == false){
	            //没有,第一次访问
	
	            //设置Cookie的value
	            //获取当前时间的字符串,重新设置Cookie的值,重新发送cookie
	            Date date  = new Date();
	            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
	            String str_date = sdf.format(date);
	            System.out.println("编码前:"+str_date);
	            //URL编码
	            str_date = URLEncoder.encode(str_date,"utf-8");
	            System.out.println("编码后:"+str_date);
	
	            Cookie cookie = new Cookie("lastTime",str_date);
	            //设置cookie的存活时间
	            cookie.setMaxAge(60 * 60 * 24 * 30);//一个月
	            response.addCookie(cookie);
	
	            response.getWriter().write("<h1>您好,欢迎您首次访问</h1>");
	        }
        }
	
	    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	        this.doPost(request, response);
	    }
	}
15.3.Session
15.3.1.概念
  • 服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务器端的对象中。HttpSession是一个接口,所以不能直接new
  • 获取HttpSession对象:
    • HttpSession session = request.getSession()
      • 如果有HttpSession对象,那么返回已有的HttpSession对象
      • 如果浏览器不存在HttpSession对象,那么创建一个,
    • HttpSession session = request.getSession(boolean creat):
      • 如果有HttpSession对象,那么返回已有的HttpSession对象,与creat无关
      • 如果没有HttpSession对象
        • 如果creat参数为true,返回null
        • 如果creat参数为false,创建一个新的
15.3.2.session域
  • 作用域介于request域和context域之间,每个客户端的浏览器访问会生成一个session域
    • Object getAttribute(String name)
    • void setAttribute(String name, Object value)
    • void removeAttribute(String name)
  • 对于一个商城类网站来说
    • Session域可以用来存储和用户相关的数据,比如用户的用户名、用户的信息、购物车等
    • Context域可以用来存储和用户无关的数据,比如当前商城的商品分类,数码、服装、食品
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        //不做任何校验,只要输入就当作登录成功
        request.getSession().setAttribute("username", username);
        response.getWriter().println("登录成功,即将跳转至个人主页....");
        response.setHeader("refresh", "2;url=" + request.getContextPath() + "/info");
        //Context域不可以
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}



@WebServlet("/info")
public class InfoServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //
        String username = (String) request.getSession().getAttribute("username");
        if(username == null){
            username = "";
        }
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().println("<!DOCTYPE html>\n" +
                "<html lang=\"en\">\n" +
                "<head>\n" +
                "    <meta charset=\"UTF-8\">\n" +
                "    <title>Title</title>\n" +
                "</head>\n" +
                "<body>");

        response.getWriter().println("欢迎您," + username);

        response.getWriter().println("</body>\n" +
                "</html>");
    }
}
15.3.3.原理
  • Session的实现是依赖于Cookie的。
  • request.getSession()方法会判断当前请求种是否含有一个有效的cookie:JSESSIONID=xxxx
    • 如果有的话,则根据这个id找到对应的session对象;
    • 如果没有的话,或者说是一个无效的id,那么这个时候给它创建一个新的session对象。
      • 本质上就是利用set-Cookie:JSESSIONID=xxxx
15.3.4.细节
  1. 当浏览器关闭后,服务器不关闭,两次获取session是否为同一个?
    • 默认情况下。不是。此时session对象处于一个不可达的状态,即无法访问到
    • Session丢失的根本原因是Cookie消失,因为Session是依赖于Cookie存在的,关闭浏览器Cookie会销毁
    • 如果需要相同,则可以创建Cookie,键为JSESSIONID,设置最大存活时间,让cookie持久化保存。
      Cookie c = new Cookie("JSESSIONID",session.getId());
      c.setMaxAge(60*60);
      response.addCookie(c);
      
  2. 浏览器不关闭,服务器关闭后,两次获取的session是同一个吗?
    • 不是同一个,因为Session对象的地址变了,但是要确保数据不丢失。tomcat自动完成以下工作
      • session的钝化:
        • 在服务器正常关闭之前,将session对象将ID和数据内容序列化到硬盘上
      • session的活化:
        • 在服务器启动后,将session文件转化为内存中的session对象即可。

      可以理解为JSESSIONID及其数据内容是灵魂,寄居在一个新的对象上(全新的内存地址)

  3. session销毁时间
    1. 服务器关闭
    2. session对象调用invalidate() 。
    3. session默认失效时间 30分钟
      • 选择性配置修改
    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>
    

    我们通过一个管理系统来验证应用的卸载。

    1. 本地安装的tomcat的webapps有manager应用

    2. 本地安装的tomcat的conf/tomcat-users.xml文件配置如下

> 3. 访问http:localhost:8080/app/manager,输入用户名和密码,可以进入管理界面 4. session的特点 - session用于存储一次会话的多次请求的数据,存在服务器端 - session可以存储任意类型,任意大小的数据 5. 生命周期: - 创建:在用户访问第一次访问服务器时创建 - 需要注意只有访问JSP、Servlet等程序时才会创建Session,只访问HTML、IMAGE等静态资源并不会创建Session - 可调用request.getSession(true)强制生成Session。 - 销毁: 1. 服务器会把长时间没有活动的Session从服务器内存中清除,此时Session便失效。Tomcat中Session的默认失效时间为30分钟。 2. 调用Session的invalidate方法。 > session的过期时间是从什么时候开始计算的?是从一登录就开始计算还是说从停止活动开始计算? > > - 从session不活动的时候开始计算,如果session一直活动,session就总不会过期。 > - 从该Session未被访问,开始计时; 一旦Session被访问,计时清0; 3. 作用域:在一次会话范围内容有效
15.3.5.session与Cookie的区别
  1. session存储数据在服务器端,Cookie在客户端
  2. session没有数据大小限制,Cookie有
  3. session数据安全,Cookie相对于不安全
15.3.6.Cookie被禁用
  • session依赖于cookie,那么如果cookie被禁用了,可以使用URL进行重写
  • JSESSIONID会附着在地址栏的url后面
15.4.简单的商城案例
  • 实现如下简单功能:
    • 查看购物车
    • 添加购物车
    • 查看商品详情
//商品类
public class Product {

    private String id;

    private String name;

    private Double price;

    private String description;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getId() {
        return id;
    }

    public Product(String id, String name, Double price, String description) {
        this.id = id;
        this.name = name;
        this.price = price;
        this.description = description;
    }


    @Override
    public String toString() {
        return "Product{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", price=" + price +
                ", description='" + description + '\'' +
                '}';
    }
}



//网站首页
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 java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@WebServlet(value = "/index",loadOnStartup = 1)
public class IndexServlet extends HttpServlet {

    @Override
    public void init() throws ServletException {
        List<Product> products = new ArrayList<>();
        Product model3 = new Product("1", "Tesla Model 3", 240000.0, "国产Tesla model3");
        Product nio = new Product("2", "Nio ES6", 450000.0, "国产电动车");
        Product xpeng = new Product("3", "Xpeng P7", 230000.0, "国产电动");
        Product li = new Product("4", "Li one", 250000.0, "国产电动三");
        products.add(model3);
        products.add(nio);
        products.add(xpeng);
        products.add(li);
        getServletContext().setAttribute("products", products);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //显示出来
        List<Product> products = (List<Product>) getServletContext().getAttribute("products");
        response.getWriter().println("<!DOCTYPE html>\n" +
                "<html lang=\"en\">\n" +
                "<head>\n" +
                "    <meta charset=\"UTF-8\">\n" +
                "    <title>Title</title>\n" +
                "</head>\n" +
                "<body>");

        for (Product product : products) {
            String detail = response.encodeURL(request.getContextPath() + "/detail?id=" + product.getId());
            response.getWriter().println("<div><a href='" + detail + "'>" + product.getName() + "</a></div>");
        }
        response.getWriter().println("\n" +
                "</body>\n" +
                "</html>");
    }
}



//商品详情
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 java.io.IOException;
import java.util.List;

@WebServlet("/detail")
public class DetailServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        String id = request.getParameter("id");
        //判断是否为空
        List<Product> products = (List<Product>) getServletContext().getAttribute("products");
        for (Product product : products) {
            if(product.getId().equals(id)){
                response.getWriter().println(product);
            }
        }
        String index =      response.encodeURL(request.getContextPath() + "/index");
        String addCart =    response.encodeURL(request.getContextPath() + "/addCart?id=" + id);
        String viewCart =   response.encodeURL(request.getContextPath() + "/viewCart");
        response.getWriter().println("<a href='" + index + "'>返回首页</a>");
        response.getWriter().println("<a href='" + addCart + "'>加入购物车</a>");
        response.getWriter().println("<a href='" + viewCart + "'>查看购物车</a>");

    }
}


//添加购物车
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;
import java.util.ArrayList;
import java.util.List;

@WebServlet("/addCart")
public class AddCartServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        String id = request.getParameter("id");
        HttpSession session = request.getSession();
        //判断是否为空 学有余力的同学可以晚上加上数量
        // list
        //要先取出来,再塞进去
        List<String> cart = (List<String>) session.getAttribute("cart");
        if(cart == null){
            cart = new ArrayList<>();
            session.setAttribute("cart", cart);
        }
        cart.add(id);
        response.getWriter().println("加入购物车成功,即将跳转回首页");
        String index = response.encodeURL(request.getContextPath() + "/index");
        response.setHeader("refresh", "2;url=" + 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;
import java.util.List;

@WebServlet("/viewCart")
public class ViewCartServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        HttpSession session = request.getSession();
        List<String> cart = (List<String>) session.getAttribute("cart");
        if(cart == null){
            response.getWriter().println("购物车为空");
            return;
        }
        List<Product> products = (List<Product>) getServletContext().getAttribute("products");
        for (Product product : products) {
            for (String id : cart) {
                if(id.equals(product.getId())){
                    response.getWriter().println(product);
                }
            }
        }
        String index = response.encodeURL(request.getContextPath() + "/index");
        response.getWriter().println("<a href='" + index + "'>返回首页</a>");
    }
}
这篇关于Cookie&Session的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!