首先我们先创建一个Maven,然后补齐main里面的包,之后我们将web.xml里面的进行复制过来,之后将大项目里面的pom.xml里面复制过来。如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>untitled2</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Cookie</artifactId>
<packaging>war</packaging>
<dependencies>
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
我们将里面没有用的东西删除掉即可,相关详细步骤我们再之前的博客里面已经提过了。
我们进行刷新之后,发现全部导入进去了。
这就是我们准备工作完成了。
1.1会话
会话:用户打开一个浏览器,点击了很多超链接,访问多个web资源,关闭浏览器,这个过程可以称之为会话
有状态会话:一个同学来过教室,下次再来教室,我们会知道这个同学,曾经来过。称之为有状态会话。
你能怎么能证明自己是哪所大学的学生:
在你和你的大学之间作为两个对象:我们可以通过以下两种方法
1.交学费的发票凭证 你的大学给你发票
2.学校登记 你的大学标记你来过了
同样的,我们借此来思考一个网站怎么证明你来过:
客户端 服务端(怎么让服务端证明客户端已经来过呢):以下方法:
1.服务端给客户端一个信件,客户端下次访问服务端带上信件就可以了;(服务端给客户端发了一个Cookie)客户端访问的时候带的Cookie.
2.服务器登记你来过了,下次你来的时候我来匹配你;session(session就是在服务器端)
无状态会话:打开浏览器并关闭
1.2保存会话的两种技术
cookie:客户端技术(响应:服务器将Cookie发给客户端,请求:客户端将Cookie带到服务器)客户端携带的
session:服务器技术,利用这个技术可以保存用户的会话信息,我们可以把信息或者数据放在Session中!
我们之前学到的能把信息或者东西放到一个东西里面让别人去取是ServletContext。用了setAttribute。ServletContext详解_蕾峰的博客-CSDN博客
常见场景:网站登录之后,下次可以不用再登录了第二次访问直接就登录进去了。
比如我们再登录CSDN的时候,首次登录需要密码,当我们让网站记住密码,下次再次重新点开CSDN的界面的时候,我们发现直接登录上去了。
我们先要学习一个东西,要首先看他的源码。
我们创建一个新的类之后,写入Cookie,如下所示:
我们按住ctrl键,进入源码界面:
这个类可以被克隆(实现了可以克隆的接口):
public class Cookie implements Cloneable, Serializable {
我们点击进行下载它的源码:
我们来进行查看源码如下所示:
设置一些文件:
private static final String LSTRING_FILE =
设置一些键值对一样的东西:
private String name; // NAME= ... "$Name" style is reserved
private String value; // value of NAME
设置一些守护:(设置他的有效域)
private String domain; // ;Domain=VALUE ... domain that sees cookie
设置保存的时间(即为过期时间)
private int maxAge = -1; // ;Max-Age=VALUE ... cookies auto-expire
设置注册一些版本:
private int version = 0; // ;Version=1 ... means RFC 2109++ style
得到一些方法:
private String path; // ;Path=VALUE ... URLs that see the cookie
我们打开Structure可以发现在这些属性有对应的get和set方法。有了get和set方法可以对属性进行一些操作。说白了就是在操作Cookie这个类。
我们要实现保存用户上一次访问的时间,我们的思维逻辑如下所示:
首先我们先解决中文乱码问题:
req.setCharacterEncoding("utf-8");
//响应
resp.setCharacterEncoding("utf-8");
之后我们来设置获取输入与输出的信息:
//想要客户端返回一些字符串,需要返回一个输出对象。(响应)用Response.
PrintWriter out = resp.getWriter();
// 请求是客户端拿着cookie到服务器。服务器获取Cookie。
//Cookie,服务器给了客户端,客户端带来的时候是服务器端需要从客户端获取,是Request。
Cookie[] cookies = req.getCookies(); //这里返回数组,说明cookie可能存在多个(多个标志)。
之后我们利用if--else语句进行判断是否有Cookie:
/判断cookie是否存在
if (cookies!=null){ //不等于null,说明cookie有值
//如果存在cookie怎么办:
out.write("你上一次访问的时间是:");
//第一次访问一定是没有值的
}else{
out.write("这是您第一次访问本站");
}
当我们判断没有值的时候,我们需要传递一个Cookie,我们设置Cookie如下所示:
/客户端第一次访问服务器的时候,服务器需要给客户端发一个Cookie。
//服务器给客户端响应一个cookie:
Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis()+"");
resp.addCookie(cookie); //添加一个Cookie,他的参数是cookie这样子一个对象
}
我们查看Cookie里面发现如下所示:
Cookie只能存String,存在局限性,说明存的东西比较少
接下来我们进行设计如果Cookie存在的话代码如何设计:
if (cookies!=null){ //不等于null,说明cookie有值
//如果存在cookie怎么办
//如果存在我们要取出我们想取出的数据
out.write("你上一次访问的时间是:");
//进行遍历数据
//两种for循环:
//for(Cookie cookie:cookies){}
//我们更倾向于使用下一种for循环(更加的灵活)
for (int i=0;i<cookies.length;i++){
Cookie cookie=cookies[i];
//通过for循环进行遍历之后,我们拿到了每个cookie。
//获取Cookie的名字
//获取了cookie的名字之后,我们需要与服务器响应的Cookie进行对比。
if(cookie.getName().equals("lastLoginTime")){
//获取cookie中的值
cookie.getValue();
//我们获取了cookie的值之后,我们想要将他输出出去,以Date的形式进行输出。
//我们获取的cookie现在是一个字符串,我们需要将他进行解析,将他解析为长整型之类的在把他转化为字符串。
//把字符串变成时间戳了。
long lastLoginTime = Long.parseLong(cookie.getValue());
//把时间戳变成一个对象(new的Date为util包下的)
Date date = new Date(lastLoginTime);
//之后我们需要将date转换为String,有的方法过期了但是也可以用,我们采用格林威治时间(toLocaleString)
out.write(date.toLocaleString());
}
}
//第一次访问一定是没有值的
}else{
out.write("这是您第一次访问本站");
}
我们完成代码的设计之后,我们进行在web.xml里面进行注册:
<servlet>
<servlet-name>CookieDemo01</servlet-name>
<servlet-class>com.rgf.servlet.CookieDemo01</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CookieDemo01</servlet-name>
<url-pattern>/c1</url-pattern>
</servlet-mapping>
之后我们进行配置Tomcat:
配置完毕之后,点击OK。我们点击运行之后,发现出现如下所示:
出现了乱码问题,我们在进行UTF-8地方加入这行代码:
resp.setContentType("text/html");
我们重新运行之后如下所示:
我们发现成功运行出来了。
我们进入浏览器,点击开发者工具,点击Application,我们发现Cookies,进入之后,我们发现lastLoginTime,除了这个以外,我们还发现其他的cookie,
我们将cookie进行删除后,
重新进入页面如下所示:
我们再次刷新之后,我们发现如下所示:
服务器再次给客户端发送了一个新的cookie。
我们发现除了我们设置的Cookie之外,我们还有一个Cookie:
JSESSIONID,这是服务器端,只要一连上浏览器就会开启一次会话。我们将浏览器关了之后就没有啦。我们每次刷新都会出现一个不同的时间,都会发送一个新的Cookie。
我们为什么会获取这个时间,我们通过分析网站请求来看:
我们重新进入刷新,点开Network,点开Headers,我们发现 Response(响应)里面的:
Set-Cookie:lastLoginTime=1662384316731
Cookie是一个键值对的形式
我们来看Request里面:
我们发现这里面也有一个Cookie:
Cookie:JSESSIONID=837B90BDAA8682E02EB26870323F909A; lastLoginTime=1662366474311
我们发现这个Cookie里面有两组键值对。
其中Request里面的lastLoginTime=1662366474311是我们上一次登录的时间,而Response里面的lastLoginTime=1662384316731为响应回来的新的登录时间。
我们将浏览器关掉Cookie还会存在么:
我们进行访问发现出现如下所示:
发现Cookie不见了,这个会话就是浏览器关了,这个会话就结束了。
我们将浏览器里面的Cookie进行清除之后,才发现第一次进入了我们所编写的这是您第一次访问本站。而我们在第一次访问的时候出现的是你上一次访问的时间是:,原因是浏览器会默认在Cookie中存放一些数据,所以不可能判断Cookie为空,所以我们直接按存有东西进行响应。即会出现你上一次访问的时间是。
如何将Cookie进行多层会话呢?我们进入Cookie的源码界面进行查看:
我们发现Cookie里面的源码如下所示:
其中的代码:
可以设置存活的时间:setMaxAge(int expiry)。
expiry为有效期的意思
我们在设置Cookie里面的代码进行设计如下所示:
//服务器给客户端响应一个cookie:
Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis()+"");
//设置Cookie有效期为一天。
cookie.setMaxAge(24*60*60);
resp.addCookie(cookie); //添加一个Cookie,他的参数是cookie这样子一个对象
然后点击运行如下所示:
我们进行刷新发现出现如下所示:
我们发现此时Cookie为lastLogintime的值为:1662448381522
之后我们关闭浏览器,然后再重新打开浏览器。
我们发现浏览器关掉之后仍然能再次拿到Cookie,
我们点击Network进行查看:
我们发现Set-Cookie里面出现的时间cookie到2022年9月7日才结束。里面多了一个Max-Age(多了一个最大的时间)刚开始的时候,我们只有一个lastLoginTime。
我们在Request里面进行查看Cookie,发现他的值为:lastLoginTime=1662448267811
我们所编写的代码为获取上一次访问的时间,所以lastLoginTime一直在发生变化。
浏览器关闭之后Cookie仍然存在,这种行为是非常不安全的。
我们对实现上一次的访问时间的完整代码如下所示:
package com.rgf.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.crypto.Data;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
//保存用户上一次访问的时间(我们也可以使用IO进行实现,
// 就是他过来的时候你把东西保存在本地,写一个文件,下次过来的时候再去读他,把那个所写的文件带上,把里面的东西读出来,这种方法比较低级一点)
public class CookieDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//服务器告诉你你来的时间,把这个时间封装成为一个信件,然后给了你,你下次来的时候带来,服务器就知道你来了。
//首先解决中文乱码问题:
//请求
req.setCharacterEncoding("utf-8");
//响应
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html");
//想要客户端返回一些字符串,需要返回一个输出对象。(响应)用Response.
PrintWriter out = resp.getWriter();
// 请求是客户端拿着cookie到服务器。服务器获取Cookie。
//Cookie,服务器给了客户端,客户端带来的时候是服务器端需要从客户端获取,是Request。
Cookie[] cookies = req.getCookies(); //这里返回数组,说明cookie可能存在多个(多个标志)。
//我们为了要获取Cookie,首先要判断Cookie是否存在,这是一个正常的程序逻辑。
//判断cookie是否存在
if (cookies!=null){ //不等于null,说明cookie有值
//如果存在cookie怎么办
//如果存在我们要取出我们想取出的数据
out.write("你上一次访问的时间是:");
//进行遍历数据
//两种for循环:
//for(Cookie cookie:cookies){}
//我们更倾向于使用下一种for循环(更加的灵活)
for (int i=0;i<cookies.length;i++){
Cookie cookie=cookies[i];
//通过for循环进行遍历之后,我们拿到了每个cookie。
//获取Cookie的名字
//获取了cookie的名字之后,我们需要与服务器响应的Cookie进行对比。
if(cookie.getName().equals("lastLoginTime")){
//获取cookie中的值
cookie.getValue();
//我们获取了cookie的值之后,我们想要将他输出出去,以Date的形式进行输出。
//我们获取的cookie现在是一个字符串,我们需要将他进行解析,将他解析为长整型之类的在把他转化为字符串。
//把字符串变成时间戳了。
long lastLoginTime = Long.parseLong(cookie.getValue());
//把时间戳变成一个对象(new的Date为util包下的)
Date date = new Date(lastLoginTime);
//之后我们需要将date转换为String,有的方法过期了但是也可以用,我们采用格林威治时间(toLocaleString)
out.write(date.toLocaleString());
}
}
//第一次访问一定是没有值的
}else{
out.write("这是您第一次访问本站");
}
//客户端第一次访问服务器的时候,服务器需要给客户端发一个Cookie。
//服务器给客户端响应一个cookie:
Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis()+"");
//设置Cookie有效期为一天。
cookie.setMaxAge(24*60*60);
resp.addCookie(cookie); //添加一个Cookie,他的参数是cookie这样子一个对象
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
我们对Cookie的总结如下所示:
1.从请求中拿到Cookie信息
2.服务器响应给客户端Cookie。
我们所使用的方法有:
Cookie[] cookies = req.getCookies(); //获得Cookie
cookie.getName() //获得cookie中的key
cookie.getValue(); //获得cookie中的value
new Cookie("lastLoginTime", System.currentTimeMillis()+""); //新建一个cookie
cookie.setMaxAge(24*60*60) //设置cookie的有效期
resp.addCookie(cookie) //响应给客户端一个cookie
我们自身电脑也有好多cookie,我们可以打开C盘进行查看:
cookie:一般会保存在本地的用户目录下 Appdata文件夹里面
这是本机保存的部分Cookies。
cookie为什么会保存,就是因为cookie在本地中会有个缓存文件。
我们进行思考:一个网站cookie是否存在上限?我们进行查看细节问题:
(1)一个Cookie只能保存一个信息;
(2)一个web站点可以给浏览器发送多个cookie。浏览器上限大概为300个cookie,每个站点最多存放20个cookie。
(3)cookie有大小限制,限制为4KB.1KB=1024B,4KB=4096B。
删除cookie:
(1)不设置有效期,关闭浏览器,自动失效;
(2)设置有效期时间为0;
我们进行设置做到删除cookie的代码:
package com.rgf.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.crypto.Data;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
public class CookieDemo02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建一个Cookie,名字必须要和删除的名字一致
Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis()+"");
//将cookie有效期设置为0,立马过期
cookie.setMaxAge(0);
resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
之后我们进行编写web.xml。如下所示:
<servlet>
<servlet-name>CookieDemo02</servlet-name>
<servlet-class>com.rgf.servlet.CookieDemo02</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CookieDemo02</servlet-name>
<url-pattern>/c2</url-pattern>
</servlet-mapping>
我们进行运行之后如下所示:
我们打开Application进行查看如下:
我们发现Cookie没有了。这是因为此时的Cookie已经过时了。
我们再进行请求c1的时候,如下所示:
此时又有了cookie。
然后再请求c2的时候,cookie如下所示:
此时cookie已经又过期了。这就达到了删除cookie的目的。
我们该如何做到中文数据的传递:
我们设计的代码如下所示:
package com.rgf.servlet;
import javax.servlet.ServletException;
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.io.PrintWriter;
import java.util.Date;
import static java.lang.System.out;
//中文数据怎么传递
public class CookieDemo03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//首先解决中文乱码问题:
//请求
req.setCharacterEncoding("utf-8");
//响应
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html");
Cookie[] cookies = req.getCookies(); //这里返回数组,说明cookie可能存在多个(多个标志)。
PrintWriter out = resp.getWriter();
//我们为了要获取Cookie,首先要判断Cookie是否存在,这是一个正常的程序逻辑。
//判断cookie是否存在
if (cookies!=null){ //不等于null,说明cookie有值
//如果存在cookie怎么办
//如果存在我们要取出我们想取出的数据
out.write("你上一次访问的时间是:");
//进行遍历数据
//两种for循环:
//for(Cookie cookie:cookies){}
//我们更倾向于使用下一种for循环(更加的灵活)
for (int i=0;i<cookies.length;i++){
Cookie cookie=cookies[i];
//通过for循环进行遍历之后,我们拿到了每个cookie。
//获取Cookie的名字
//获取了cookie的名字之后,我们需要与服务器响应的Cookie进行对比。
if(cookie.getName().equals("name")){
out.println(cookie.getValue());
}
}
//第一次访问一定是没有值的
}else{
out.write("这是您第一次访问本站");
}
Cookie cookie = new Cookie("name","蕾峰编程");
resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
之后我们编辑web.xml的文件:
<servlet>
<servlet-name>CookieDemo03</servlet-name>
<servlet-class>com.rgf.servlet.CookieDemo03</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CookieDemo03</servlet-name>
<url-pattern>/c3</url-pattern>
</servlet-mapping>
我们运行之后如下所示:
Tomcat8之后cookie就可以存放中文啦
如果我们再编程中遇到无法去传送中文,我们可以利用:
编码解码进行解决:
编码:URLEncoder.encode("蕾峰编程","utf-8")
有编码,我们后台进行获取的时候就需要有解码:
URLDecoder.decode(cookie.getValue(),"UTF-8")。
代码如下所示:
package com.rgf.servlet;
import javax.servlet.ServletException;
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.io.PrintWriter;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Date;
import static java.lang.System.out;
//中文数据怎么传递
public class CookieDemo03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//首先解决中文乱码问题:
//请求
req.setCharacterEncoding("utf-8");
//响应
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html");
Cookie[] cookies = req.getCookies(); //这里返回数组,说明cookie可能存在多个(多个标志)。
PrintWriter out = resp.getWriter();
//我们为了要获取Cookie,首先要判断Cookie是否存在,这是一个正常的程序逻辑。
//判断cookie是否存在
if (cookies!=null){ //不等于null,说明cookie有值
//如果存在cookie怎么办
//如果存在我们要取出我们想取出的数据
out.write("你上一次访问的时间是:");
//进行遍历数据
//两种for循环:
//for(Cookie cookie:cookies){}
//我们更倾向于使用下一种for循环(更加的灵活)
for (int i=0;i<cookies.length;i++){
Cookie cookie=cookies[i];
//通过for循环进行遍历之后,我们拿到了每个cookie。
//获取Cookie的名字
//获取了cookie的名字之后,我们需要与服务器响应的Cookie进行对比。
if(cookie.getName().equals("name")){
URLDecoder.decode(cookie.getValue(),"UTF-8");
//解码
out.println(URLDecoder.decode(cookie.getValue(),"UTF-8"));
}
}
//第一次访问一定是没有值的
}else{
out.write("这是您第一次访问本站");
}
//编码,有编码就要有解码
Cookie cookie = new Cookie("name", URLEncoder.encode("蕾峰编程","utf-8"));
resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
我们运行之后如下所示:
发现成功进行了输出。