15.Cookie&Session
15.1.会话技术
- 会话:一次会话中包含多次请求和响应。
- 一次会话:浏览器第一次给服务器资源发送请求,会话建立,直到有一方断开为止
- 功能:在一次会话的范围内的多次请求间,共享数据
- 方式:
- 客户端会话技术:Cookie
- 服务器端会话技术:Session
- 原因:因为Html的无状态无标记性,浏览器无法识别当前HTTP报文是哪一个客户端发送过来的,引入会话技术解决浏览器存储数据问题
15.2.Cookie
- 概念:客户端会话技术,将数据保存到客户端
- 使用步骤:
- public Cookie(String name, String value):构造方法,创建Cookie对象,绑定数据
- response.addCookie(Cookie cookie) : 发送Cookie对象
- Cookie[] request.getCookies() : 获取Cookie,拿到数据
- 实现原理
- 基于响应头set-cookie和请求头cookie实现
- cookie的细节
- 一次可以发送多个cookie
- 可以创建多个Cookie对象,使用response调用多次addCookie方法发送cookie即可。
- cookie在浏览器中保存时间
- 默认情况下,当浏览器关闭后,Cookie数据被销毁
- 持久化存储:setMaxAge(int seconds)
- 正整数:将Cookie数据写到硬盘的文件中。持久化存储。并指定cookie存活时间,时间到后,cookie文件自动失效
- 负整数:默认值
- 零:删除cookie信息,删除之前,一定要setPath相同的路径,浏览器要比对是否一致
@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 { //通过访问该servlet,将cookie信息删除 Cookie[] cookies = request.getCookies(); if(cookies != null){ for (Cookie cookie : cookies) { if("username".equals(cookie.getName())){ cookie.setMaxAge(0); //需要把这个告诉给浏览器 response.addCookie(cookie); } } } } }
- cookie存储中文
- 在tomcat 8 之前 cookie中不能直接存储中文数据。
- 需要将中文数据转码—一般采用URL编码(%E3)
- 在tomcat 8 之后,cookie支持中文数据。特殊字符还是不支持,建议使用URL编码存储,URL解码解析
- 在tomcat 8 之前 cookie中不能直接存储中文数据。
- cookie共享问题
- 假设在一个tomcat服务器中,部署了多个web项目,那么在这些web项目中cookie能不能共享?
- 默认情况下cookie不能共享
- setPath(String path) : 设置cookie的获取范围。默认情况下,设置当前的虚拟目录
- 不可以设置一个和当前域名无关的cookie信息,如当前localhost,设置一个baidu.com域名的cookie是不成功的,原因是出于安全性考虑。
- 如果要共享,则可以将path设置为”/”
- 删除cookie时,如果当前cookie没有设置path,那么直接设置MaxAge=0即可删除cookie
- 但是如果cookie设置了path,那么删除cookie的时候,一定要再把path写一遍。
cookie.setMaxAge(0); cookie.setPath(request.getContextPath() + "/info"); response.addCookie(cookie);
- 假设在一个tomcat服务器中,部署了多个web项目,那么在这些web项目中cookie能不能共享?
- 不同的tomcat服务器间cookie共享问题
- setDomain(String path):如果设置一级域名相同,那么多个服务器之间cookie可以共享
- setDomain(“.baidu.com”),那么tieba.baidu.com和news.baidu.com中cookie可以共享
- Cookie的特点和作用
- cookie存储数据在客户端浏览器
- 浏览器对于单个cookie 的大小有限制(4kb) ,浏览器的cookie总数一般限制300个,对同一个域名下的总cookie数量也有限制(20-50个)
- 作用:
- cookie一般用于存出少量的不太敏感的数据,且只能存储字符串
- 在不登录的情况下,完成服务器对客户端的身份识别
- 案例:记住上一次访问时间
- 需求:
- 访问一个Servlet,如果是第一次访问,则提示:您好,欢迎您首次访问。
- 如果不是第一次访问,则提示:欢迎回来,您上次访问时间为:显示时间字符串
- 分析:
- 可以采用Cookie来完成
- 在服务器中的Servlet判断是否有一个名为lastTime的cookie
- 有:不是第一次访问
- 响应数据:欢迎回来,您上次访问时间为:2018年6月10日11:50:20
- 写回Cookie:lastTime=2018年6月10日11:50:01
- 没有:是第一次访问
- 响应数据:您好,欢迎您首次访问
- 写回Cookie:lastTime=2018年6月10日11:50:01
@WebServlet("/cookieTest")
public class CookieTest extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//设置响应的消息体的数据格式以及编码
response.setContentType("text/html;charset=utf-8");
//1.获取所有Cookie
Cookie[] cookies = request.getCookies();
boolean flag = false;//没有cookie为lastTime
//2.遍历cookie数组
if(cookies != null && cookies.length > 0){
for (Cookie cookie : cookies) {
//3.获取cookie的名称
String name = cookie.getName();
//4.判断名称是否是:lastTime
if("lastTime".equals(name)){
//有该Cookie,不是第一次访问
flag = true;//有lastTime的cookie
//设置Cookie的value
//获取当前时间的字符串,重新设置Cookie的值,重新发送cookie
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String str_date = sdf.format(date);
System.out.println("编码前:"+str_date);
//URL编码
str_date = URLEncoder.encode(str_date,"utf-8");
System.out.println("编码后:"+str_date);
cookie.setValue(str_date);
//设置cookie的存活时间
cookie.setMaxAge(60 * 60 * 24 * 30);//一个月
response.addCookie(cookie);//响应数据
//获取Cookie的value,时间
String value = cookie.getValue();
System.out.println("解码前:"+value);
//URL解码:
value = URLDecoder.decode(value,"utf-8");
System.out.println("解码后:"+value);
response.getWriter().write("<h1>欢迎回来,您上次访问时间为:"+value+"</h1>");
break;
}
}
}
if(cookies == null || cookies.length == 0 || flag == false){
//没有,第一次访问
//设置Cookie的value
//获取当前时间的字符串,重新设置Cookie的值,重新发送cookie
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String str_date = sdf.format(date);
System.out.println("编码前:"+str_date);
//URL编码
str_date = URLEncoder.encode(str_date,"utf-8");
System.out.println("编码后:"+str_date);
Cookie cookie = new Cookie("lastTime",str_date);
//设置cookie的存活时间
cookie.setMaxAge(60 * 60 * 24 * 30);//一个月
response.addCookie(cookie);
response.getWriter().write("<h1>您好,欢迎您首次访问</h1>");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
15.3.Session
15.3.1.概念
- 服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务器端的对象中。HttpSession是一个接口,所以不能直接new
- 获取HttpSession对象:
- HttpSession session = request.getSession()
- 如果有HttpSession对象,那么返回已有的HttpSession对象
- 如果浏览器不存在HttpSession对象,那么创建一个,
- HttpSession session = request.getSession(boolean creat):
- 如果有HttpSession对象,那么返回已有的HttpSession对象,与creat无关
- 如果没有HttpSession对象
- 如果creat参数为true,返回null
- 如果creat参数为false,创建一个新的
- HttpSession session = request.getSession()
15.3.2.session域
- 作用域介于request域和context域之间,每个客户端的浏览器访问会生成一个session域
- Object getAttribute(String name)
- void setAttribute(String name, Object value)
- void removeAttribute(String name)
- 对于一个商城类网站来说
- Session域可以用来存储和用户相关的数据,比如用户的用户名、用户的信息、购物车等
- Context域可以用来存储和用户无关的数据,比如当前商城的商品分类,数码、服装、食品
@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");
String password = request.getParameter("password");
//不做任何校验,只要输入就当作登录成功
request.getSession().setAttribute("username", username);
response.getWriter().println("登录成功,即将跳转至个人主页....");
response.setHeader("refresh", "2;url=" + request.getContextPath() + "/info");
//Context域不可以
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
@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 {
//
String username = (String) request.getSession().getAttribute("username");
if(username == null){
username = "";
}
response.setContentType("text/html;charset=utf-8");
response.getWriter().println("<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
"<head>\n" +
" <meta charset=\"UTF-8\">\n" +
" <title>Title</title>\n" +
"</head>\n" +
"<body>");
response.getWriter().println("欢迎您," + username);
response.getWriter().println("</body>\n" +
"</html>");
}
}
15.3.3.原理
- Session的实现是依赖于Cookie的。
- request.getSession()方法会判断当前请求种是否含有一个有效的cookie:JSESSIONID=xxxx
- 如果有的话,则根据这个id找到对应的session对象;
- 如果没有的话,或者说是一个无效的id,那么这个时候给它创建一个新的session对象。
- 本质上就是利用set-Cookie:JSESSIONID=xxxx
15.3.4.细节
- 当浏览器关闭后,服务器不关闭,两次获取session是否为同一个?
- 默认情况下。不是。此时session对象处于一个不可达的状态,即无法访问到
- Session丢失的根本原因是Cookie消失,因为Session是依赖于Cookie存在的,关闭浏览器Cookie会销毁
- 如果需要相同,则可以创建Cookie,键为JSESSIONID,设置最大存活时间,让cookie持久化保存。
Cookie c = new Cookie("JSESSIONID",session.getId()); c.setMaxAge(60*60); response.addCookie(c);
- 浏览器不关闭,服务器关闭后,两次获取的session是同一个吗?
- 不是同一个,因为Session对象的地址变了,但是要确保数据不丢失。tomcat自动完成以下工作
- session的钝化:
- 在服务器正常关闭之前,将session对象将ID和数据内容序列化到硬盘上
- session的活化:
- 在服务器启动后,将session文件转化为内存中的session对象即可。
可以理解为JSESSIONID及其数据内容是灵魂,寄居在一个新的对象上(全新的内存地址)
- session的钝化:
- 不是同一个,因为Session对象的地址变了,但是要确保数据不丢失。tomcat自动完成以下工作
- session销毁时间
- 服务器关闭
- session对象调用invalidate() 。
- session默认失效时间 30分钟
- 选择性配置修改
<session-config> <session-timeout>30</session-timeout> </session-config>
我们通过一个管理系统来验证应用的卸载。
-
本地安装的tomcat的webapps有manager应用
-
本地安装的tomcat的conf/tomcat-users.xml文件配置如下
> 3. 访问http:localhost:8080/app/manager,输入用户名和密码,可以进入管理界面 4. session的特点 – session用于存储一次会话的多次请求的数据,存在服务器端 – session可以存储任意类型,任意大小的数据 5. 生命周期: – 创建:在用户访问第一次访问服务器时创建 – 需要注意只有访问JSP、Servlet等程序时才会创建Session,只访问HTML、IMAGE等静态资源并不会创建Session – 可调用request.getSession(true)强制生成Session。 – 销毁: 1. 服务器会把长时间没有活动的Session从服务器内存中清除,此时Session便失效。Tomcat中Session的默认失效时间为30分钟。 2. 调用Session的invalidate方法。 > session的过期时间是从什么时候开始计算的?是从一登录就开始计算还是说从停止活动开始计算? > > – 从session不活动的时候开始计算,如果session一直活动,session就总不会过期。 > – 从该Session未被访问,开始计时; 一旦Session被访问,计时清0; 3. 作用域:在一次会话范围内容有效
15.3.5.session与Cookie的区别
- session存储数据在服务器端,Cookie在客户端
- session没有数据大小限制,Cookie有
- session数据安全,Cookie相对于不安全
15.3.6.Cookie被禁用
- session依赖于cookie,那么如果cookie被禁用了,可以使用URL进行重写
- JSESSIONID会附着在地址栏的url后面
15.4.简单的商城案例
- 实现如下简单功能:
- 查看购物车
- 添加购物车
- 查看商品详情
//商品类
public class Product {
private String id;
private String name;
private Double price;
private String description;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
public Product(String id, String name, Double price, String description) {
this.id = id;
this.name = name;
this.price = price;
this.description = description;
}
@Override
public String toString() {
return "Product{" +
"id=" + id +
", name='" + name + '\'' +
", price=" + price +
", description='" + description + '\'' +
'}';
}
}
//网站首页
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;
import java.util.ArrayList;
import java.util.List;
@WebServlet(value = "/index",loadOnStartup = 1)
public class IndexServlet extends HttpServlet {
@Override
public void init() throws ServletException {
List<Product> products = new ArrayList<>();
Product model3 = new Product("1", "Tesla Model 3", 240000.0, "国产Tesla model3");
Product nio = new Product("2", "Nio ES6", 450000.0, "国产电动车");
Product xpeng = new Product("3", "Xpeng P7", 230000.0, "国产电动");
Product li = new Product("4", "Li one", 250000.0, "国产电动三");
products.add(model3);
products.add(nio);
products.add(xpeng);
products.add(li);
getServletContext().setAttribute("products", products);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//显示出来
List<Product> products = (List<Product>) getServletContext().getAttribute("products");
response.getWriter().println("<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
"<head>\n" +
" <meta charset=\"UTF-8\">\n" +
" <title>Title</title>\n" +
"</head>\n" +
"<body>");
for (Product product : products) {
String detail = response.encodeURL(request.getContextPath() + "/detail?id=" + product.getId());
response.getWriter().println("<div><a href='" + detail + "'>" + product.getName() + "</a></div>");
}
response.getWriter().println("\n" +
"</body>\n" +
"</html>");
}
}
//商品详情
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;
import java.util.List;
@WebServlet("/detail")
public class DetailServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
String id = request.getParameter("id");
//判断是否为空
List<Product> products = (List<Product>) getServletContext().getAttribute("products");
for (Product product : products) {
if(product.getId().equals(id)){
response.getWriter().println(product);
}
}
String index = response.encodeURL(request.getContextPath() + "/index");
String addCart = response.encodeURL(request.getContextPath() + "/addCart?id=" + id);
String viewCart = response.encodeURL(request.getContextPath() + "/viewCart");
response.getWriter().println("<a href='" + index + "'>返回首页</a>");
response.getWriter().println("<a href='" + addCart + "'>加入购物车</a>");
response.getWriter().println("<a href='" + viewCart + "'>查看购物车</a>");
}
}
//添加购物车
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 javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@WebServlet("/addCart")
public class AddCartServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
String id = request.getParameter("id");
HttpSession session = request.getSession();
//判断是否为空 学有余力的同学可以晚上加上数量
// list
//要先取出来,再塞进去
List<String> cart = (List<String>) session.getAttribute("cart");
if(cart == null){
cart = new ArrayList<>();
session.setAttribute("cart", cart);
}
cart.add(id);
response.getWriter().println("加入购物车成功,即将跳转回首页");
String index = response.encodeURL(request.getContextPath() + "/index");
response.setHeader("refresh", "2;url=" + index );
}
}
//查看购物车
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 javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;
@WebServlet("/viewCart")
public class ViewCartServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
HttpSession session = request.getSession();
List<String> cart = (List<String>) session.getAttribute("cart");
if(cart == null){
response.getWriter().println("购物车为空");
return;
}
List<Product> products = (List<Product>) getServletContext().getAttribute("products");
for (Product product : products) {
for (String id : cart) {
if(id.equals(product.getId())){
response.getWriter().println(product);
}
}
}
String index = response.encodeURL(request.getContextPath() + "/index");
response.getWriter().println("<a href='" + index + "'>返回首页</a>");
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/181052.html