zoukankan      html  css  js  c++  java
  • Cookie&Session

    Cookie&Session

    1.重定向和请求转发

    • 重定向

    之前的写法:

    //设置状态码,302表示临时重定向,常用于页面跳转
    resp.setStatus(302);
    //Location为固定写法,后面为要跳转的页面
    resp.setHeader("Location","login_success.html");
    

    重定向写法:

    resp.sendRedirect("login_success.html");
    
    1. 地址栏上显示的是最后的那个资源的路径地址;

    2. 请求次数最少有两次, 服务器在第一次请求后,会返回302 以及一个地址,浏览器在根据这个地址,执行第二次访问;

    3. 可以跳转到任意路径,不是自己的工程也可以跳;

    4. 效率稍低,因为执行两次请求;

    5. 后续的请求,不能使用上一次的request存储的数据,或者说不能使用上一次的request,因为是两次不同的请求。

    • 请求转发
    req.getRequestDispatcher("login_success.html").forward(req,resp);        
    
    1. 地址上显示的是请求servlet的地址,返回200 ok;

    2. 请求次数只有一次,因为是服务器内部帮客户端执行后续的工作;

    3. 只能跳转自己项目的资源路径;

    4. 效率稍高,因为只执行一次请求;

    5. 可以使用上一次的request对象。

    2.Cookie

    饼干,其实是一份小数据,是服务器给客户端,并且存储在客户端上的一份小数据。

    应用场景:自动登录、浏览记录、购物车。

    Cookie分类:

    • 会话Cookie

      默认情况下关闭浏览器Cookie就会消失。

    • 持久Cookie

      在一定时间内都有效,并会保存到客户端上。

      cookie.setMaxAge(60);//设置Cookie有效期60秒。

    2.1为什么要有Cookie

    http的请求是无状态。 客户端与服务器在通讯的时候,是无状态的,其实就是客户端在第二次来访的时候,服务器根本就不知道这个客户端以前有没有来访问过。 为了更好的用户体验,更好的交互(自动登录),其实从公司层面讲,就是为了更好的收集用户习惯(大数据)。

    2.2Cookie简单使用

    • 添加Cookie给客户端
    1. 在响应的时候添加Cookie
    Cookie cookie=new Cookie("aa","bb");
    resp.addCookie(cookie);
    
    1. 客户端收到的信息里面,响应头中多了一个字段 Set-Cookie

    • 获取客户端带过来的Cookie
    Cookie[] cookies = req.getCookies();
    for(Cookie c:cookies){
        System.out.println(c.getName()+c.getValue());
    }
    
    • 常用方法
    //设置cookie有效期为7天,有效期以秒计算
    cookie.setMaxAge(60*60*24*7);
    
    //给cookie赋新的值
    cookie.setValue("lisi");
    
    /*
    设置只有请求了指定域名时才带上cookie,即当访问.itheima.com或其子域名如map.itheima.com或再下一级域名的时候都会使用该cookie。
    注意:
    浏览器不会接收domain为com.cn的cookie,娜样互联网就乱套了;
    同一个域不能有同key的Cookie;
    只要是为cookie显式的声明domain,前面带不带"."没有区别。
    */
    cookie.setDomain(".itheima.com");
    
    //设置当访问该域名下的cookieDemo这个路径时才会携带cookie
    cookie.setPath("/CookieDemo");
    

    2.3例1:显示最近登录的时间

    @WebServlet("/CookieDemoServlet")
    //相当于web.xml里注册Servlet的那两段
    public class CookieDemoServlet extends HttpServlet {
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //避免响应中文时的乱码问题
            response.setContentType("text/html;charset=UTF-8");
            //1.判断账号密码是否正确
            String username = request.getParameter("username");
            String password = request.getParameter("password");
            Cookie loginTimeCookie=null;
            PrintWriter pw=response.getWriter();
            if(username.equals("abc")&&password.equals("123")){
                //2. 如果正确,则获取登录时间的cookie
                Cookie[] cookies = request.getCookies();
                if (cookies!=null){
                    for (Cookie c:cookies){
                        if(c.getName().equals("loginTime")){
                            System.out.println("1");
                            loginTimeCookie=c;
                            //3.如果找到的对象不为空, 表明不是第一次登录
                            pw.print("最近登录时间为:"+ URLDecoder.decode(loginTimeCookie.getValue(),"UTF-8"));
                            //更新最近登录时间
                            String loginTime=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
                            loginTime=URLEncoder.encode(loginTime,"UTF-8");
                            loginTimeCookie.setValue(loginTime);
                            //记得要重新添加回去
                            response.addCookie(loginTimeCookie);
                        }
                    }
                }else if(cookies==null||loginTimeCookie==null){
                    //4.如果cookies为空或者loginTimeCookie为空,表明是第一次登录,那么要添加cookie
                    System.out.println("2");
                    String loginTime=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
                    loginTime=URLEncoder.encode(loginTime,"UTF-8");
                    response.addCookie(new Cookie("loginTime",loginTime));
                }
            }else{
                pw.write("登录名或密码有误");
            }
        }
    
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doGet(request,response);
        }
    }
    

    注意:

    1. 设置loginTimeCookie的value时

    在设置loginTimeCookie的value时,如果直接:

    String loginTime=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
    loginTimeCookie.setValue(loginTime);
    

    会出现如下错误:

    java.lang.IllegalArgumentException: An invalid character [32] was present in the Cookie value

    原因是时间格式"yyyy-MM-dd HH:mm:ss"中有空格,所以会报错。可以直接删除或替换空格,或者也可以:

    String loginTime=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
    loginTime=URLEncoder.encode(loginTime,"UTF-8");
    loginTimeCookie.setValue(loginTime);
    
    1. 输出上次登录时间时

    输入上次登录时间时,如果直接:

    pw.print("最近登录时间为:"+ loginTimeCookie.getValue());
    

    会出现以下错误:

    浏览器上显示的为:最近登录时间为:2020-10-20+10%3A26%3A49

    解决方法:

    pw.print("最近登录时间为:"+ URLDecoder.decode(loginTimeCookie.getValue(),"UTF-8"));
    

    2.3例2:显示商品浏览记录

    2.3.1JSP

    jsp,即Java Server Pager,可以再jsp里面使用Java代码,最终会翻译成一个类,就是一个Servlet。

    • 定义局部变量
    <%! int a=99;%>
    
    • 定义全局变量
    <% int b = 999; %>
    //Java代码写在<%%>中
    
    • 在jsp页面显示a和b的值
    <% =a %> 
    <% =b %>
    

    2.3.2ProductInfoServlet

    @WebServlet("/ProductInfoServlet")
    public class ProductInfoServlet extends HttpServlet {
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            String id = request.getParameter("id");
            Cookie[] cookies = request.getCookies();
            Cookie historyCookie = CookieUtils.findCookie(cookies, "history");
            if(historyCookie==null){
                //证明是第一次来
                historyCookie=new Cookie("history",id);
            }else{
                //不是第一次来
                //不是第一次来,拼接以前的cookie
                String ago = historyCookie.getValue();
                historyCookie.setValue(id+"#"+ago);
            }
            historyCookie.setMaxAge(60*60*7*24);
            response.addCookie(historyCookie);
            System.out.println(historyCookie.getValue());
            response.sendRedirect("product_info.htm");
        }
    
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doGet(request,response);
        }
    }
    

    2.3.3Product_list.jsp展示浏览记录

    <ul style="list-style: none;">
                <%
                    Cookie[] cookies=request.getCookies();
                    Cookie historyCookie = CookieUtils.findCookie(cookies, "history");
                    if(historyCookie==null){
                %>
                        <h2>您暂未浏览任何商品</h2>
                <%
                    }else{
                        String[] ids = historyCookie.getValue().split("#");
                        for (String id:ids){
                %>
                            <img src="products/1/cs1000<%=id%>.jpg" width="130px" height="130px" />
    
                <%
                        }
                    }
                %>
     </ul>
    

    2.3.4清除浏览记录

    其实就是清除Cookie,删除cookie是没有什么delete方法的,只有设置maxAge为0。

    • ClearCookieServlet
    @WebServlet("/ClearCookieServlet")
    public class ClearCookieServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doGet(request,response);
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //新建一个同名但为空的Cookie覆盖之前的Cookie
            Cookie cookie = new Cookie("history","");
            //删除Cookie其实就是把生命周期设置为0
            cookie.setMaxAge(0);
            //记得再重新添加回去
            response.addCookie(cookie);
            response.sendRedirect("product_list.jsp");
        }
    }
    

    3.Session

    由于Cookie会保存在客户端上,所以有安全隐患问题。另外Cookie的大小和个数有限制。Session可有效解决这个问题。

    Session,即会话,是基于Cookie的一种会话机制。 Cookie是服务器返回一小份数据给客户端,并且存放在客户端上。Session是,数据存放在服务端。

    3.1Session创建与销毁,常见API

    • 创建

      当在Servlet里调用request.getSession()。

    • 销毁

      1. 关闭服务器;
      2. Session会话时间过期,默认是30分钟。
    • 常见API

      HttpSession session = request.getSession();
      //得到会话ID
      String id = session.getId();
      //存值
      session.setAttribute("name","zhangsan");
      //取值
      String name = (String) session.getAttribute("name");
      //移除值
      session.removeAttribute("name");
      //销毁Session
      session.invalidate();
      

    3.2例1:简单购物车

    • CartServlet
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //1.获取要添加的商品id
            Integer id = Integer.parseInt(request.getParameter("id"));
            String[] products={"小米8","魅族16th","华为P30"};
            String product=products[id];
            //2.存储到购物车
            HttpSession session = request.getSession();
            Map<String,Integer> cartMap = (Map<String,Integer>)session.getAttribute("cart");
            if(cartMap==null){
                //即没有名为cart的session
                session.setAttribute("cart",new HashMap<String,Integer>());
            }
            if(cartMap.containsKey(product)){
                //如果购物车中已有该商品
                cartMap.put(product,cartMap.get(product)+1);
               // session.setAttribute("cart",cartMap);
            }else {
                //如果购物车中没有该商品
                cartMap.put(product,1);
                //session.setAttribute("cart",cartMap);
            }
            //遍历输出session
            Set<Map.Entry<String, Integer>> entries = cartMap.entrySet();
            Iterator<Map.Entry<String, Integer>> iterator = entries.iterator();
            while(iterator.hasNext()){
                Map.Entry<String, Integer> next = iterator.next();
                System.out.println(next.getKey()+"="+next.getValue());
            }
        }
    

    这里有个疑问,为什么更新完session的值后,如需要重新赋值回去,session也会更新?

    如下:

    cartMap.put(product,cartMap.get(product)+1);
    // session.setAttribute("cart",cartMap);
    

    原因:

    当我们创建购物车时,内存当初就会开辟一块空间来存放数据,当我们把购物车放入session中后,有一个理解误区,那就是购物车并不是放入了session,还是把购物车的引用地址放入了session,以方便我们通过session快速的找到购物车的hashmap。当我们操作购物车时,是通过session里的引用地址找到了hashmap对象,然后操作它,但是这个对象没有变,session对它的引用地址也没有变,所以不需要再重新放入session。

  • 相关阅读:
    GET和POST区别
    es索引介绍
    前端 用法记录
    axios 使用
    react技巧 学习
    vuex 学习笔记
    fetch 学习笔记
    react-router 4.0 学习笔记
    react 学习笔记2
    react 学习笔记
  • 原文地址:https://www.cnblogs.com/ALiWang/p/13847397.html
Copyright © 2011-2022 走看看