Javaweb (二) | Cookie、Session
7.Cookie、Session
新建项目 session-cookie,修改 web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaeehttp://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"metadata-complete="true"></web-app>
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"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>session-cookie</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging></project>
将 Servlet 和 JSP 的 API 放入到 pom.xml 中
<dependencies><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version></dependency><dependency><groupId>javax.servlet.jsp</groupId><artifactId>javax.servlet.jsp-api</artifactId><version>2.3.3</version></dependency></dependencies>
下面这里可以看到是否成功导入
7.1、会话
会话: 用户打开一个浏览器,点击了很多超链接,访问多个web资源,关闭浏览器,这个过程可以称之为会话;
有状态会话: 一个同学来过教室,下次再来教室,我们会知道这个同学,曾经来过,称之为有状态会话;
你怎么证明你是学校的学生?
- 发票, 学校给你发票(报名的发票)
- 学校登记, 学校标记你来过了
一个网站,怎么证明你来过?
客户端, 服务端
- 服务端给客户端一个 信件,客户端下次访问服务端带上信件就可以了; cookie
- 服务器登记你来过了,下次你来的时候我来匹配你; seesion
7.2、保存会话的两种技术
cookie
- 客户端技术 (服务器通过 响应 发送 cookie 给客户端,客户端通过 请求 带到服务器上),服务器不需要管什么。
session
- 服务器技术,利用这个技术,可以保存用户的会话信息? 我们可以把信息或者数据放在Session中!
常见:网站登录之后,你下次不用再登录了,第二次访问直接就上去了!
常见场景:网站登录之后,下次不用再登录了,第二次访问直接就上去了!
7.3、Cookie
实现保存用户上一次访问的时间(按照之前学得,可以用 IO 实现,即先保存到本地,然后再读,方法很 low)
服务器告诉你来的时间,把这个时间封装成一个信件(Cookie),下次你来的时候带上,就知道你来了
新建一个 CookieDemo01 类,在 doGet 中写入相关逻辑
// 保存用户上一次访问的时间
public class CookieDemo01 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 服务器告诉你来的时间,把这个时间封装成一个信件(Cookie),下次你来的时候带上,就知道你来了//解决中文乱码问题req.setCharacterEncoding("utf-8");resp.setCharacterEncoding("utf-8");resp.setContentType("text/html;charset=UTF-8");PrintWriter out = resp.getWriter();//cookie服务器从客户端获取Cookie[] cookies = req.getCookies();//这里返回数组说明cookie可能存在多个//判断cookie是否存在if (cookies!=null){//如果存在怎么办out.print("你上一次来的时间是:");for (Cookie cookie : cookies) {//获取cookie 的名字if (cookie.getName().equals("lastTime")){//获取cookie中的值Long l = Long.parseLong(cookie.getValue());Date date = new Date(l);out.write(date.toLocaleString());}}}else {out.print("第一次来");}// 服务器给客户端响应一个cookie,放在客户端Cookie cookie = new Cookie("lastTime", System.currentTimeMillis() + "");resp.addCookie(cookie); // 这里服务器到时候就会响应这个 cookie 给客户端}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doPost(req, resp);}
}
注册 servlet
<servlet><servlet-name>CookieDemo01</servlet-name><servlet-class>com.uestc.servlet.CookieDemo01</servlet-class></servlet><servlet-mapping><servlet-name>CookieDemo01</servlet-name><url-pattern>/c1</url-pattern></servlet-mapping>
配置 tomcat
启动 tomcat,请求 c1,但是没有输出代码逻辑中的 “第一次来”,说明 Cookie 中有东西
那这个东西到底在哪里呢? 查看网页的检查/审查元素等,可能不同浏览器称呼不同
我们再次请求 c1,这里就看到时间了
现在我们进入检查,把 lastTime 删除掉,服务器就需要再一次返回一个新的,请求 c1,成功,时间没有了
为什么能够拿到这个时间? 进入检查的网络(Network),看看响应:可以看到 c1 这个请求下,执行了 Set-Cookie
来看请求头,可以看到我们设置的 lastTime
然后我们关闭浏览器,重新打开,又没有了,因为浏览器关闭了,会话就结束了
Cookie 类中一个方法 cookie.setMaxAge,可以设置 Cookie 有效期,比如设置为一天就是 cookie.setMaxAge(24*60*60);
,按 s 开始的,加入到 doGet 添加 Cookie 的步骤中
此时重启 tomcat,关闭浏览器再打开,请求,依然可以拿到
但是浏览器都关闭了,Cookie 还存在,不安全!
总结
- 从请求中拿到cookie信息(客户端发送过来的)
- 服务器响应给客户端cookie
Cookie[] cookies = req.getCookies(); //获得Cookie(获得的是下面最后一行代码最后一次响应给客户端的,第一次没有)
cookie.getName(); //获得cookie中的key
cookie.getValue(); //获得cookie中的vlaue
new Cookie("lastLoginTime", System.currentTimeMillis()+""); //新建一个cookie
cookie.setMaxAge(24*60*60); //设置cookie的有效期
resp.addCookie(cookie); //响应给客户端一个cookie,也可以响应多个
浏览各种网站后的 cookie:一般会保存在本地的 用户目录下 AppData;
一个网站cookie是否存在上限!聊聊细节问题(比如学生证,一个人能给他发一万个学生证吗?肯定不能这样)
- 一个 Cookie 只能保存一个信息;new Cookie 的时候产生
- 一个 web 站点可以给浏览器发送多个 cookie,最多存放 20 个 cookie;
- Cookie 大小有限制4kb;
- 300 个 cookie 浏览器上限
删除 Cookie
- 不设置有效期,关闭浏览器,自动失效;
- 设置有效期时间为 0 ;
删除 Cookie 示例,新建一个 CookieDemo02
public class CookieDemo02 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 创建一个 cookie,名字必须要和要鹏除的名字一致Cookie cookie = new Cookie("lastTime", System.currentTimeMillis() + "");// 将 cookie 的有效期设置为 0,立马过期cookie.setMaxAge(0);resp.addCookie(cookie); // 这里服务器到时候就会响应这个 cookie 给客户端}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doPost(req, resp);}
}
注册 Servlet
<servlet><servlet-name>CookieDemo02</servlet-name><servlet-class>com.uestc.servlet.CookieDemo02</servlet-class></servlet><servlet-mapping><servlet-name>CookieDemo02</servlet-name><url-pattern>/c2</url-pattern></servlet-mapping>
访问 c1 有时间,访问 c2,c1 的 cookie 就被删除了!
中文数据传递
// 中文数据传递
public class CookieDemo03 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//解决中文乱码问题req.setCharacterEncoding("utf-8");resp.setCharacterEncoding("utf-8");resp.setContentType("text/html;charset=UTF-8"); // 一定要加上这行,负责后网页乱码//cookie服务器从客户端获取Cookie[] cookies = req.getCookies();//这里返回数组说明cookie可能存在多个PrintWriter out = resp.getWriter();//判断cookie是否存在if (cookies!=null){//如果存在怎么办out.print("你上一次来的时间是:");for (Cookie cookie : cookies) {//获取 cookie 的名字if (cookie.getName().equals("name")){//获取cookie中的值System.out.println(cookie.getValue()); // 输出编码的内容out.write(URLDecoder.decode(cookie.getValue(),"utf-8")); // 解码输出到网页}}}else {out.print("第一次来");}// 创建一个 cookie,名字必须要和要鹏除的名字一致Cookie cookie = new Cookie("name", URLEncoder.encode("青年有志", "utf-8")); // 一定要进行上面的解码操作resp.addCookie(cookie); // 这里服务器到时候就会响应这个 cookie 给客户端}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doPost(req, resp);}
}
注册Servlet
<servlet><servlet-name>CookieDemo03</servlet-name><servlet-class>com.uestc.servlet.CookieDemo03</servlet-class></servlet><servlet-mapping><servlet-name>CookieDemo03</servlet-name><url-pattern>/c3</url-pattern></servlet-mapping>
启动 Tomcat ,网页上就可以成功啦!
后台输出了编码后未解码的情况
注意: 编码解码,快速解决中文乱码问题
URLEncoder.encode("秦疆","utf-8")
URLDecoder.decode(cookie.getValue(),"UTF-8")
7.4、Session(重点)
什么是Session:
- 服务器会给每一个用户(浏览器)创建一个Session对象;
- 一个Session独占一个浏览器,只要浏览器没有关闭,这个Session就存在;
- 用户登录之后,整个网站它都可以访问! → \to → 保存用户的信息;保存购物车的信息……(比如进入B站,点击所有跳转,仍处于登录状态,进入淘宝等也是如此)
进入 HttpSession 类查看
创建 SessionDemo01 类
public class SessionDemo01 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//解决乱码问题req.setCharacterEncoding("UTF-8");resp.setCharacterEncoding("UTF-8");resp.setContentType("text/html;charset=utf-8");//得到SessionHttpSession session = req.getSession();//给Session中存东西session.setAttribute("name", "青年有志");//获取Session的IDString sessionId = session.getId();//判断Session是不是新创建if (session.isNew()){resp.getWriter().write("session创建成功,ID:"+sessionId);}else {resp.getWriter().write("session以及在服务器中存在了,ID:"+sessionId);}//Session创建的时候做了什么事情;会将上面的 session.getId() 放入到cookie中
// Cookie cookie = new Cookie("JSESSIONID",sessionId);
// resp.addCookie(cookie);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}
}
注册 Servlet
<servlet><servlet-name>SessionDemo01</servlet-name><servlet-class>com.uestc.servlet.SessionDemo01</servlet-class></servlet><servlet-mapping><servlet-name>SessionDemo01</servlet-name><url-pattern>/s1</url-pattern></servlet-mapping>
启动 tomcat,请求 s1
可以看到,只要打开了浏览器就有这个
同时 cookie 里面也可以看到
Session 创建的时候做了什么事情?实际上会将上面的 sessionId 放入到 cookie 中
下面我们去另外一个 servlet 中取出上面存的 session
创建类 SessionDemo02,
public class SessionDemo02 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//解决乱码问题req.setCharacterEncoding("UTF-8");resp.setCharacterEncoding("UTF-8");resp.setContentType("text/html;charset=utf-8");//得到SessionHttpSession session = req.getSession();String name = (String) session.getAttribute("name");// 打印 nameSystem.out.println(name);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}
}
注册 Servlet
<servlet><servlet-name>SessionDemo02</servlet-name><servlet-class>com.uestc.servlet.SessionDemo02</servlet-class></servlet><servlet-mapping><servlet-name>SessionDemo02</servlet-name><url-pattern>/s2</url-pattern></servlet-mapping>
启动 tomcat,第一次请求 s2,后台打印 null
然后通过 s1,向 session 内存入数据
然后再次请求 s2,获取到了内容!
下面再创建一个 Person 类
public class Person {private String name;private int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}
}
修改 SessionDemo01 类,设置为类对象
public class SessionDemo01 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//解决乱码问题req.setCharacterEncoding("UTF-8");resp.setCharacterEncoding("UTF-8");resp.setContentType("text/html;charset=utf-8");//得到SessionHttpSession session = req.getSession();//给Session中存东西session.setAttribute("name", new Person("青年有志", 18));//获取Session的IDString sessionId = session.getId();//判断Session是不是新创建if (session.isNew()){resp.getWriter().write("session创建成功,ID:"+sessionId);}else {resp.getWriter().write("session以及在服务器中存在了,ID:"+sessionId);}//Session创建的时候做了什么事情;会将上面的 session.getId() 放入到cookie中
// Cookie cookie = new Cookie("JSESSIONID",sessionId);
// resp.addCookie(cookie);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}
}
此时修改 SessionDemo02,获取到的不再是 String,而是一个 Person 对象
public class SessionDemo02 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//解决乱码问题req.setCharacterEncoding("UTF-8");resp.setCharacterEncoding("UTF-8");resp.setContentType("text/html;charset=utf-8");//得到SessionHttpSession session = req.getSession();Person person = (Person) session.getAttribute("name");// 打印 nameSystem.out.println(person.toString());}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}
}
重启 Tomcat,请求 s1,然后请求 s2,可以看到结果,因此 session 不只是可以存字符串,还可以存用户信息,同时跨 Servlet!。后续还会有更多 session 强大的部分
上面我们讲过将数据保存到 ServletContext 中,不建议,数据多了服务器会炸的!这里给出了多的一个选择,保存到 session 中。
同时可以注销 Session,我们新建一个 SessionDemo03
注册 Servlet
<servlet><servlet-name>SessionDemo03</servlet-name><servlet-class>com.uestc.servlet.SessionDemo03</servlet-class></servlet><servlet-mapping><servlet-name>SessionDemo03</servlet-name><url-pattern>/s3</url-pattern></servlet-mapping>
重启 tomcat,然后通过火狐和 Edge 浏览器(不同的浏览器),获取到了不同的 session。相同的浏览器无论开多少个窗口,session 都相同,不会变
然后我们先请求 s3 注销掉 session,再请求 s2,获取 session 就报错如下了,因为已经没有 session 了!
然后再请求 s1,获得了一个新的 session,因为一旦注销后,就会获取一个新的 session
Cookie 我们设置了一个时间,Session 同样可以设置一个超时时间,会话自动过期:web.xml 配置如下:
<!--设置Session默认的失效时间-->
<session-config><!--15分钟后Session自动失效,以分钟为单位--><session-timeout>15</session-timeout>
</session-config>
上面这个设置后,在 15 分钟后,session 就会变,打印 sessionID 可以观察到
Session 和 cookie 的区别:
- Cookie是把用户的数据写给用户的浏览器,浏览器保存 (可以保存多个)
- Session把用户的数据写到用户独占Session中,服务器端保存 (保存重要的信息,减少服务器资源的浪费)
- Session对象由服务创建;
使用场景:
- 保存一个登录用户的信息;
- 购物车信息;
- 在整个网站中经常会使用的数据,我们将它保存在 Session 中;(因为每次不需要 new 新的了,直接去取即可)
得到Session
//得到Session
HttpSession session = req.getSession();Person person = (Person) session.getAttribute("name");System.out.println(person.toString());HttpSession session = req.getSession();
session.removeAttribute("name");
//手动注销Session
session.invalidate();
,
s1 s2 s3 … 表示不同的 Servlet 请求,请求需要浏览器 URL 输入操作请求才能访问,即客户端,请求最终是交给服务器访问。服务器如何证明你来过?第一种方案:第一次来,给客户端发送一个 Cookie,客户端在每次请求的时候携带 Cookie,这样就知道啦!第二种方案:客户端发送请求,服务器会登记一个唯一的 Session ID,每个用户都有一个 Session ID,用户拿到这个 Session ID 自己也保存了一份,Session 所有数据都保存到服务器,当客户端来请求时,客户端的这个 Session ID 与服务器的 Session ID 一致,就会拿到自己对应的那份数据,就好比淘宝,每个人登录进入后信息是不同的,而 Cookie 的数据是保存到客户端。 而ServletContext保存数据的形式,如同多加了一个中间商,所有不同的 s1 s2 s3 … 都可以去拿到 ServletContext 的内容
Cookie 原理如下:
Session 原理如下:
ServletContext 原理如下: