week12_day05_Fileupload02&&Cookie

微信头像有个功能是改国旗,为什么自己看有红旗,别人看没有?

一般不会将图片的二进制信息存在数据库中,只是把路径存进去。
缓存,缓存一部分数据,减轻某个系统的压力,在图中就是减轻访问数据库的压力。

NoSQL,非关系型数据库,Redis
缓存可以用Redis实现。

整个流程:用户上传一个头像,上传成功后,将头像地址保存到服务器的数据库里,同时用户客户端本地也会将新头像保存到本地缓存中,用户查看的时候就看的是自己本地缓存的图片。而对于其他用户而言,想要查看此用户的头像,就要去微信服务器缓存中查看,而由于访问量的暴增,服务器缓存的数据可能并没有及时和数据库中的数据保持同步。这就造成了用户查看到自己的头像和其朋友查看到的头像不一致的情况。
在这里插入图片描述


总结昨天的内容:

Fileupload的三个注意事项:

  1. form表单的method=“post”
  2.     <input type="file" name="image">
    
  3. enctype=“multipart/form-data”

昨天留了一个问题:比如,还是像之前获取form表单数据一样,接下来需要将这些数据封装到一个bean中,然后保存到数据库,怎么操作简便一些??????

1.4.2.保存数据到bean中

1.4.2.1.方式一 中规中矩的方式

将Fileupload01中的uploadServlet2进行改进:

  1. 将processFormField和processUploadedFile传入的参数改成两个,即加一个user参数。
    processUploadedFile(FileItem item, User user)、
    processFormField(FileItem item, User user)
    在这里插入图片描述
  2.      //对name和value进行判断
         if("username".equals(name)){
             user.setUsername(value);
         }else if("password".equals(name)){
             user.setUsername(value);
         }
    
  3. 在user当对象保存路径上传文件在服务器中的路径
    在这里插入图片描述
    uploadServlet:
package com.cskaoyan.upload;

import com.cskaoyan.bean.User;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import javax.servlet.ServletContext;
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.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.List;

@WebServlet("/upload")
public class uploadServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //因为提交的是multipart/form-data,所以响应正文的数据结构发生改变,无法通过以下代码解决乱码问题。
        //request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");
        //post里面写代码
        //返回的是true表示有Multipart
        boolean result = ServletFileUpload.isMultipartContent(request);
        if (!result) {
            response.getWriter().println("不包含上传的文件");
            return;
        }
        //result=true
        DiskFileItemFactory factory = new DiskFileItemFactory();
        ServletContext servletContext = getServletContext();
        File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
        factory.setRepository(repository);

        // Create a new file upload handler
        ServletFileUpload upload = new ServletFileUpload(factory);
        //如果上传的文件名中文乱码,可以这么解决
        //upload.setHeaderEncoding("utf-8");
        // 允许上传文件的最大大小为1024 bytes
        //upload.setFileSizeMax(1024);

        User user = new User();
        try {
            List<FileItem> items = upload.parseRequest(request);
            //对items进行迭代
            Iterator<FileItem> iterator = items.iterator();
            while (iterator.hasNext()) {
                //每一个item其实就是一个有name属性的input框的封装
                FileItem item = iterator.next();
                if (item.isFormField()) {
                    //当前是普通的form表单数据
                    processFormField(item, user);
                } else {
                    //当前是上传的文件
                    processUploadedFile(item, user);
                }
            }
            System.out.println(user);
        } catch (FileUploadException e) {
            e.printStackTrace();
        }
        //JDBC,将user保存到数据库等操纵
    }

    /**
     * 处理上传的文件逻辑
     *
     * @param item
     * @param user
     */
    private void processUploadedFile(FileItem item, User user) {
        String fieldName = item.getFieldName();
        String fileName = item.getName();
        System.out.println(fieldName + " === " + fileName);
        String UPLOAD_BASE = "upload/";
        UPLOAD_BASE = UPLOAD_BASE + fileName;
        String realPath = getServletContext().getRealPath(UPLOAD_BASE);
        File file = new File(realPath);
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        try {
            //保存文件到硬盘中
            item.write(file);
            //在user对象中保存文件路径,保存什么路径呢?相对路径
            //img src='/应用名/资源名'
            user.setImage(UPLOAD_BASE);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 处理普通的form表单数据
     * 只需要获取name和value值即可
     * 上传文件之后,不要再用getParameter去获取请求参数了
     * 有没有中文乱码问题呢?
     *
     * @param item
     * @param user
     */
    private void processFormField(FileItem item, User user) {
        String name = item.getFieldName();
        String value = null;
        try {
            //表示value用utf-8编码
            value = item.getString("utf-8");
            //对name和value进行判断
            if ("username".equals(name)) {
                user.setUsername(value);
            } else if ("password".equals(name)) {
                user.setPassword(value);
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        System.out.println(name + " = " + value);
    }

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

    }
}

中规中矩方式,但是实现起来很繁琐。必须要求掌握的。


1.4.2.2.方式二 优化版

上一块的代码逻辑只能用于处理user对象上,如果我想用于处理商品的发布等信息,还得改动,如何让一块代码能够完全复用呢?

  1. 将processFormField和processUploadedFile传入的user参数改成map
    processUploadedFile(FileItem item, Map map)、
    processFormField(FileItem item, Map map)
    在这里插入图片描述
  2. user.setName()、user.setPassword()、user.setImg(),将数据封装在user对象中这块改成将数据保存在map中:
    在这里插入图片描述
    在这里插入图片描述
  3. 同时,直接输出user也变成了将map中的数据封装到user对象中再输出user:
    在这里插入图片描述
    用debug模式,可以查看map中的key-value值:
    在这里插入图片描述
    uploadServlet02:
package com.cskaoyan.upload;

import com.cskaoyan.bean.User;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import javax.jws.soap.SOAPBinding;
import javax.servlet.ServletContext;
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.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

@WebServlet("/upload02")
public class uploadServlet02 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //因为提交的是multipart/form-data,所以响应正文的数据结构发生改变,无法通过以下代码解决乱码问题。
        //request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");
        //post里面写代码
        //返回的是true表示有Multipart
        boolean result = ServletFileUpload.isMultipartContent(request);
        if (!result) {
            response.getWriter().println("不包含上传的文件");
            return;
        }
        //result=true
        DiskFileItemFactory factory = new DiskFileItemFactory();
        ServletContext servletContext = getServletContext();
        File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
        factory.setRepository(repository);

        // Create a new file upload handler
        ServletFileUpload upload = new ServletFileUpload(factory);
        //如果上传的文件名中文乱码,可以这么解决
        //upload.setHeaderEncoding("utf-8");
        // 允许上传文件的最大大小为1024 bytes
        //upload.setFileSizeMax(1024);

        Map map = new HashMap();
        try {
            List<FileItem> items = upload.parseRequest(request);
            //对items进行迭代
            Iterator<FileItem> iterator = items.iterator();
            while (iterator.hasNext()) {
                //每一个item其实就是一个有name属性的input框的封装
                FileItem item = iterator.next();
                if (item.isFormField()) {
                    //当前是普通的form表单数据
                    processFormField(item, map);
                } else {
                    //当前是上传的文件
                    processUploadedFile(item, map);
                }
            }
        } catch (FileUploadException e) {
            e.printStackTrace();
        }
        //JDBC,将user保存到数据库等操作
        System.out.println(map);

        //接下来怎么做? 有一个map,然后需要将数据封装到对象中
        //如果你处理的是user对象,就封装到user对象中,如果是商品对象,就封装到商品对象中
        User user = new User();
        try {
            BeanUtils.populate(user,map);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        System.out.println(user);
    }

    /**
     * 处理上传的文件逻辑
     *
     * @param item
     * @param map
     */
    private void processUploadedFile(FileItem item, Map map) {
        String fieldName = item.getFieldName();
        String fileName = item.getName();
        System.out.println(fieldName + " === " + fileName);
        String UPLOAD_BASE = "upload/";
        UPLOAD_BASE = UPLOAD_BASE + fileName;
        String realPath = getServletContext().getRealPath(UPLOAD_BASE);
        File file = new File(realPath);
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        try {
            //保存文件到硬盘中
            item.write(file);
            //在user对象中保存文件路径,保存什么路径呢?相对路径
            //img src='/应用名/资源名'
            map.put(fieldName, UPLOAD_BASE);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 处理普通的form表单数据
     * 只需要获取name和value值即可
     * 上传文件之后,不要再用getParameter去获取请求参数了
     * 有没有中文乱码问题呢?
     *
     * @param item
     * @param map
     */
    private void processFormField(FileItem item, Map map) {
        String name = item.getFieldName();
        String value = null;
        try {
            //表示value用utf-8编码
            value = item.getString("utf-8");
            //如果传入进来的是checkbox,那么下面需要变更一下
            map.put(name, value);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        System.out.println(name + " = " + value);
    }

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

    }
}


写成这样还没罢休,应当再进行改进,将以上代码改成一个FileUploadUtils类:

FileUploadUtils类主要是把前端页面输入的所有数据整成了一个map(以name-value的形式存储)。
FileUploadUtils:

package com.cskaoyan.utils;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.*;

public class FileUploadUtils {

    public static Map parseRequest(HttpServletRequest request){
        DiskFileItemFactory factory = new DiskFileItemFactory();
        ServletContext servletContext = request.getServletContext();
        File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
        factory.setRepository(repository);

        // Create a new file upload handler
        ServletFileUpload upload = new ServletFileUpload(factory);
        //如果上传的文件名中文乱码,可以这么解决
        //upload.setHeaderEncoding("utf-8");
        // bytes  1024 bytes
        //upload.setFileSizeMax(1024);
        Map map = new HashMap();
        try {
            List<FileItem> items = upload.parseRequest(request);
            //对items进行迭代
            Iterator<FileItem> iterator = items.iterator();
            while (iterator.hasNext()){
                //每一个item其实就是一个input框的封装
                FileItem item = iterator.next();
                if(item.isFormField()){
                    //当前是普通的form表单数据
                    processFormField(item, map);
                }else{
                    //当前是上传的文件
                    processUploadedFile(item, map, request);
                }
            }

        } catch (FileUploadException e) {
            e.printStackTrace();
        }
        return map;
    }

    /**
     * 处理上传的文件逻辑
     * @param item
     * @param map
     * @param request
     */
    private static void processUploadedFile(FileItem item, Map map, HttpServletRequest request) {
        String fieldName = item.getFieldName();
        String fileName = item.getName();
        String UPLOAD_BASE = "upload";
        //解决文件重名问题
        fileName =  UUID.randomUUID().toString() + "-" + fileName;
        //解决目录内文件数过多的问题
        int hashCode = fileName.hashCode();
        String hexString = Integer.toHexString(hashCode);
        char[] chars = hexString.toCharArray();
        for (char aChar : chars) {
            UPLOAD_BASE = UPLOAD_BASE + "/" + aChar;
        }
        System.out.println(fieldName + " === " + fileName);
        UPLOAD_BASE = UPLOAD_BASE + "/" + fileName;
        String realPath = request.getServletContext().getRealPath(UPLOAD_BASE);
        File file = new File(realPath);
        if(!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        try {
            //保存文件到硬盘中
            item.write(file);
            //保存什么路径呢?
            //img src='/应用名/资源名'
            map.put(fieldName, UPLOAD_BASE);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 处理普通的form表单数据
     * 只需要获取name和value值即可
     * 上传文件之后,不要再用getParameter去获取请求参数了
     * 有没有中文乱码问题呢?
     * @param item
     * @param map
     */
    private static void processFormField(FileItem item, Map map) {
        String name = item.getFieldName();
        String value = null;
        try {
            value = item.getString("utf-8");
            //如果传入进来的是checkbox,那么下面需要变更一下
            map.put(name, value);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        System.out.println(name + " = " + value);
    }

}

uploadServlet03:

package com.cskaoyan.upload;

import com.cskaoyan.bean.User;
import com.cskaoyan.utils.FileUploadUtils;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import javax.servlet.ServletContext;
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.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

@WebServlet("/upload03")
public class uploadServlet03 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //因为提交的是multipart/form-data,所以响应正文的数据结构发生改变,无法通过以下代码解决乱码问题。
        //request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");
        //post里面写代码
        //返回的是true表示有Multipart
        boolean result = ServletFileUpload.isMultipartContent(request);
        if (!result) {
            response.getWriter().println("不包含上传的文件");
            return;
        }
        //通过FileUploadUtils获取map,map中存取的是name-value键值对
        Map map = FileUploadUtils.parseRequest(request);
        User user = new User();
        //将map中的数据封装成一个user对象
        try {
            BeanUtils.populate(user, map);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        System.out.println(user);
    }

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

    }
}


同时在FileUploadUtils解决了两个问题:

  1. 文件重名问题:
        //解决文件重名问题
        fileName =  UUID.randomUUID().toString() + "-" + fileName;
  1. 目录内文件数目过多问题:
        //解决目录内文件数过多的问题
		int hashCode = fileName.hashCode();
        String hexString = Integer.toHexString(hashCode);
        char[] chars = hexString.toCharArray();
        for (char aChar : chars) {
            UPLOAD_BASE = UPLOAD_BASE + "/" + aChar;
        }
        System.out.println(fieldName + " === " + fileName);
        UPLOAD_BASE = UPLOAD_BASE + "/" + fileName;

如果所有的文件全部放在upload目录中,假如里面有100w个文件,加载这些文件就非常耗费性能。
想让100w个文件尽量分散开。用Hash,散列。乘值最好为31,这样可以让存储的数据尽可能的散列。
取自String类中的hashCode方法:
在这里插入图片描述
Filename -----取哈希值 ----转化为16进制数字
目录形式:1/4 /a/ 5/ f/ 7/ 8/ f—文件


1.4.6.保存回显操作
注册(上传头像),封装到Bean中,将bean中的数据取出来,通过JDBC,保存到数据库。

回显:
到数据库里面去查询这条数据,然后封装到bean中,接下来,将它在页面显示出来。
注册成功之后,封装到bean,我们不去保存到数据库,而是通过转发交给另外一个servlet
,该servlet本页面中将之前选择的数据进行回显。

转发就涉及到user对象的共享,就涉及到request域。
在uploadServlet03中加这么一段代码:

        //转发给另一个Servlet,将其内容显示出来
        request.setAttribute("user", user);
        request.getRequestDispatcher("/view").forward(request, response);

viewServlet:

package com.cskaoyan.upload;

import com.cskaoyan.bean.User;

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;

/**
 * @author shihao
 * @create 2020-06-27 0:20
 */
@WebServlet("/view")
public class viewServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        User user = (User) request.getAttribute("user");
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().println("<div>用户名:" + user.getUsername() + "</div>");
        response.getWriter().println("<div>密码:" + user.getPassword() + "</div>");
        response.getWriter().println("<div>头像:<img src='" + request.getContextPath() + "/" + user.getImage() + "'></div>");
    }

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

    }
}

打断点后能显示头像,直接运行无法显示头像。
打断点注意:step out表示跳出方法体,step into表示进入 方法体

原因是FileUploadUtils中的代码:item.write(file);
文件可能还在传输的过程中,而此时viewServlet就调用

        response.getWriter().println("<div>头像:<img src='" + request.getContextPath() + "/" + user.getImage() + "'></div>");

这个问题可以忽略,之后从数据库中取数据然后再显示是不会出现这种问题的。


1.会话技术

日常生活中就是谈话。
A:你吃过了吗
B:我吃了
A:吃的什么
B:面
A:什么面,粗面还是细面

网络请求过程中,会话。客户端发起一个请求,到达服务器,接下来又发送了一个请求,又到达服务器,服务器是区分不了客户端的。在服务器眼里,客户端全部都是一样的。
为什么会出现这种情况呢?
因为http协议的无状态性。每次请求之间没有任何区别,服务器无法区分请求之间的区别。
最严重的后果就是购物车里面的数据有哪些、登录的是谁?
但是实际上这些情况并没有发生,原因就是在于存在会话技术,解决了这些问题。
会话技术存在两种
Cookie、session
http协议中有Set-Cookie响应头和Cookie请求头

1.1.Cookie
一小串数据。数据是由服务器生成的,然后在响应的过程中传给客户端(以set-Cookie响应头的形式发送给客户端),客户端及时保存下来,等到下次访问服务器的时候(以Cookie请求头的形式发回给服务端),就会把这个cookie给携带上。服务器通过解析请求报文就知道谁在访问。
你们去理发,给了你们一张不记名的卡片,下次去理发,带上该打卡即可。

构造方法:
Cookie(java.lang.String name, java.lang.String value)
Constructs a cookie with a specified name and value.

通过键值对的形式定义一个Cookie

ServletCookie:

package com.cskaoyan;

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;
import java.io.IOException;

/**
 * @author shihao
 * @create 2020-06-27 7:21
 */
@WebServlet(name = "ServletCookie")
public class ServletCookie extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //生成一个cookie
        Cookie cookie = new Cookie("name", "lisi");
        //响应给客户端,以set-Cookie响应头
        //自己完全可以构建一个set-Cookie响应头,但是实际上没有必要
        //因为response已经帮助我们封装好了
        //这行代码的含义其实就是帮助我们构建set-Cookie响应头
        response.addCookie(cookie);
    }

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

    }
}

在这里插入图片描述
在这里插入图片描述
1.1.1.案例1
简单的登录案例。用两个浏览器模拟两个用户。直接在浏览器的窗口将登录的用户名打印出来。
不用之前的转发技术,使用今天的cookie技术来实现。
loginServlet :

package com.cskaoyan.login;

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;
import java.io.IOException;

/**
 * @author shihao
 * @create 2020-06-27 7:36
 */
@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");
        Cookie cookie = new Cookie("username", username);
        response.addCookie(cookie);
        response.getWriter().println("登录成功,即将跳转至个人主页");
        //定时刷新
        response.setHeader("refresh", "2, url=" + request.getContextPath() + "/info");
    }

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

    }
}

Info servlet:

package com.cskaoyan.login;

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;
import java.io.IOException;

/**
 * @author shihao
 * @create 2020-06-27 7:47
 */
@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 {
        //应当从请求头中拿到cookie
        //getHeader去一点一点解析,但是也没有必要
        //因为request也帮助我们封装好了
        response.setContentType("text/html;charset=utf-8");
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if ("username".equals(cookie.getName())) {
                    response.getWriter().println("欢迎您," + cookie.getValue());
                }
            }
        }
    }
}

过程:
登录login.html,登录成功之后,写入cookie信息,返回给客户端保存,同时发起一个定时刷新,跳转至info页面,客户端就会把cookie请求头给带上,服务端取出key为username的cookie value值。

1.1.2.案例2
打印出上次访问该页面的时间。

ServletLastLogin :

package com.cskaoyan.login;

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;
import java.io.IOException;
import java.util.Date;

/**
 * @author shihao
 * @create 2020-06-27 11:11
 */
@WebServlet("/last")
public class ServletLastLogin extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //先接受cookie
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if ("lastLogin".equals(cookie.getName())) {
                    response.getWriter().println("last login:" + cookie.getValue());
//                    String value = cookie.getValue();
//                    Date date = new Date(Long.parseLong(value));
//                    response.getWriter().println("last login: " + date);
                }
            }
        }
        Cookie cookie = new Cookie("lastLogin", new Date().toString());
        //cookie的value值中不能有空格(但我的上句代码能正常执行)
        //Cookie cookie = new Cookie("lastLogin", System.currentTimeMillis() + "");
        response.addCookie(cookie);

    }
}

1.1.3.cookie的设置
为什么关闭浏览器之后,cookie就消失了呢?

1.1.3.1.设置MaxAge

默认情况下,没有设置的话,表示负数,含义表示仅存在于浏览器内存中;
设置一个正数,表示可以存活多少秒。这个时候,会存在于硬盘中持续一段时间。
如果设置0呢?表示的是删除cookie。

DelCookieServlet :

package com.cskaoyan.maxAge;

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;
import java.io.IOException;
import java.util.Date;

@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 {
        Cookie[] cookies = request.getCookies();
        if(cookies != null){
            for (Cookie cookie : cookies) {
                if("lastLogin".equals(cookie.getName())){
                    cookie.setMaxAge(0);
                }
            }
        }
    }
}

1.1.3.2.设置path
在这里插入图片描述
指定客户端应将cookie返回到的cookie的路径。

cookie对指定目录中的所有页以及该目录的子目录中的所有页都可见。cookie的路径必须包括设置cookie的servlet,例如/catalog,它使cookie对/catalog下服务器上的所有目录都可见。

默认情况下,如果没有设置path的话,则当访问当前域名下任意资源时,均会带上该cookie,如果想仅部分路径携带cookie,则可以通过设置path来实现。

PathServlet1 :

package com.cskaoyan.path;

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;
import java.io.IOException;

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

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Cookie cookie = new Cookie("name","path");
        cookie.setPath(request.getContextPath() + "/path2");
        response.addCookie(cookie);
    }
}

在这里插入图片描述
接着访问path2
在这里插入图片描述

这个时候,如果path2Servlet中没有设置path,那么删除cookie可以删除吗?
此时通过抓包发现,无法成功删除该cookie,原因
如果没有设置path,那么删除cookie时,直接设置maxAge=0即可,但是如果设置了path,那么删除cookie时,必须要和生成cookie时设置相同的path。
过程:
在path1里设置cookie,path是path2,第一次访问path2,理应会带上cookie,关键看第二次访问path2,还会不会带上

PathServlet2 :

package com.cskaoyan.path;

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;
import java.io.IOException;

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

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Cookie[] cookies = request.getCookies();
        if(cookies != null){
            for (Cookie cookie : cookies) {
                if("name1".equals(cookie.getName())){
/*                  此时通过抓包发现,无法成功删除该cookie,原因
                    如果没有设置path,那么删除cookie时,直接设置maxAge=0即可,
                    但是如果设置了path,那么删除cookie时,必须要和生成cookie时设置相同的path。*/
                    cookie.setPath(request.getContextPath() + "/path2");
                    cookie.setMaxAge(0);
                    response.addCookie(cookie);
                }
            }
        }
    }
}

在这里插入图片描述
第一次访问path2
在这里插入图片描述
第二次访问path2
在这里插入图片描述
设置path的意义:比如设置某些情况下不需要带cookie,比如请求一个静态资源文件,js、css文件。

1.1.3.3.设置domain

设置域名。浏览器有一个大的原则,你不能设置和当前应用无关的域名cookie。比如当前域名是localhost,然后你设置了一个cookie,域名是www.baidu.com。这个时候浏览器是不允许的。
父子域名的规则
Zsquirrel.com 127.0.0.1 ------父域名
Video.zsquirrel.com 127.0.0.1 -------一级子域名
Story.video.zsquirrel.com 127.0.0.1 ------二级子域名

如果你在父域名下,设置了一个cookie的domain是zsquirrel.com,那么接下来,下面所有的子域名均可以共享你的这个cookie。

在这里插入图片描述
指定应在其中显示此cookie的域。

域名的格式由RFC 2109指定。域名以点(.foo.com网站)并且意味着cookie对指定域名系统(DNS)区域中的服务器可见(例如,www.foo.com网站,但不是a.b.foo.com网站). 默认情况下,cookie只返回给发送它们的服务器。

DomainServlet :

package com.cskaoyan.domain;

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;
import java.io.IOException;

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

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Cookie cookie = new Cookie("key", "domain");
        //必须显式的去配置这一句代码才可以
        //指定在域名zsquirrel.com中显示此cookie,同样还会在其子域名中显示
        cookie.setDomain("zsquirrel.com");
        response.addCookie(cookie);
    }
}

在这里插入图片描述
设置域名
在这里插入图片描述
接下来,访问子域名的资源
在这里插入图片描述
进一步子域名
在这里插入图片描述
域名得配置,否则是不能演示的,老师的电脑中是这样配置的:
在这里插入图片描述
1.1.4.cookie细节
1.cookie的name和value值均是字符串类型
2.cookie它只能存储少量的数据,一般不超过4k
3.默认生成的cookie是会话级别的,仅存在于浏览器内存中,如果想要持久化保存,则需要设置一个MaxAge为正数的值,表示在硬盘存活多久;设置0表示删除cookie,但是需要注意的是,如果该cookie设置了path,那么删除时,必须也设置同样的path,否则无法删除

不同浏览器之间可以共享cookie吗???????
不可以。

如果有一些敏感数据,或者需要存储很大量的数据,这个时候,可以怎么办呢?
Session

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-玫瑰少年-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值