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。

posted @ 2020-10-20 16:45  ALiWang1123  阅读(99)  评论(0编辑  收藏  举报