- cookie&session
6.1 会话
用户打开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程成为会话
6.2 Cookie&Session
session和cookie的主要区别在于:
1.cookie是把用户的数据写给用户浏览器
2.session是把用户的数据写到用户独占的session中去(服务端)
session对象由服务器创建,开发人员可以调用request对象的getSession方法得到session对象。
Session 与 cookie的对比:
Cookie : 由于 cookie是客户端浏览器, 所以 数据 不是很安全… 但是减轻了服务器的压力.
Session: 由于数据是存在 服务器端的, 所以 数据会 比较安全, 但是 加重了服务器的压力.
6.3 Cookie
Cookie
- 1.一个cookie只能标识一种信息,至少含有一个标识该信息的名称和值
- 2.一个web站点可以给一个浏览器发送多个cookie,一个浏览器可以存储多个web站点发送的cookie
- 3.浏览器一般只允许存放300条cookie,每个站点至多存放20条cookie,每个cookie大小为4kb
- 4.如果创建了一个cookie,发送至浏览器,默认它是会话级别的,当用户退出浏览器后被删除,若想永久的存储在磁盘上,需要设置maxAge,以秒为单位。
注意:一个cookie 持久化保存到硬盘上之后, 实际上你也还是可以通知浏览器 删除 这个cookie 的, 就是将 setMaxAge设置为 0 , 设置 为0 , 就表示 不保存 cookie 信息了. 但是特别要注意, 删除 cookie的时候, 这个cookie名称和有效路径必须 一致 , 否则不会删除.
response接口中定义了一个addCookie()方法,用于在其响应头增加一个Set-Cookie头字段,同样request接口中定义了一个getCookies()方法,用于获取客户端提交的Cookie。
Cookie类的方法有:
Public Cookie(String name,String value)
setValue与getValue
setMaxAge与getMaxAge
setPath与getPath
getName
案例1:利用cookie,显示用户上次访问网站时间
//获得用户请求的时候,封装在request中的cookie信息
Cookie[] cookies=request.getCookies();
response.setContentType("text/html;charset=UTF-8");
//遍历这个cookie数组时,找到目标cookie对象,每个cookie都有一个唯一的名字标识一个cookie对象
Cookie targetcookie=findTargetCookie(cookies,"lastvisit");
if(targetcookie==null) {
//没有目标cookie,说明是第一次访问
response.getWriter().println("第一次访问网站!");
}else {
//说明之前访问过
String value=targetcookie.getValue();
long time=Long.parseLong(value);
response.getWriter().println("上次访问时间是:"+new Date(time).toLocaleString());
}
//把当前时间写回Cookie
Cookie cookie=new Cookie("lastvisit",System.currentTimeMillis()+"");
cookie.setPath("/");//这里“/”代表当前主机localhost
//http://www.baidu.com/123 这里/代表www.baidu.com
cookie.setMaxAge(60*60*24*7);//从当前时间开始保存cookie一个周,以秒为单位
response.addCookie(cookie);//把cookie写回当前的浏览器
private Cookie findTargetCookie(Cookie[] cookies, String name) {
// TODO Auto-generated method stub
if(cookies==null) {
//说明没有带任何的cookie过来,直接返回null
return null;
}
//如果走到这里,说明带了cookie过来,遍历cookies数组,找到目标cookie对象
for(Cookie cookie:cookies) {
if(cookie.getName().equals(name)) {
//说明当前的cookie就是目标cookie,返回cookie对象
return cookie;
}
}
return null;
}
问题:
1.浏览器关闭之后再次打开去访问,发现 又变成了第一次访问了
注意: 默认的情况下, 一个cookie 的有效期是 浏览器进程, 那么在浏览器关闭之后,浏览器 进程没了, 那么相应的 cookie 信息也就没有。
如何 实现在浏览器关闭之后 ,再次打开,仍然可以 显示上次的访问时间呢?
可以自己手动的去设置 cookie 的有效期 就好了,设置 cookie 的有效期之后, 只要是在有效期内, 那么 cookie 就会一直 保留在浏览器的缓存中,以文件的形式存在.
cookie.setMaxAge(60*60*24*7);//从当前时间开始,保存cookie一个周,以秒为单位
2.如何给cookie设置有效路径?
如果给某个cookie 设置有效路径, 那么就表示 ,当 再次使用浏览器去访问某个 目标资源的时候,如果要访问的目标的路径与 cookie 所包含的有效路径不匹配, 那么 cookie 不会在访问的时候 带过去给 服务器, 如果匹配, 才会带过去.
//http://localhost:8080/day11/access
cookie.setPath("/");//设置有效路径,这里“/”表示当前主机名localhost,那么就表示只有访问当前主机名localhost下的资源文件时,cookie才会带过去
一般开发过程中, 设置 成什么样 路径 最多 ?
setPath(“/”) , 写成 / 并不是最好的, 但是 却是 使用最多的. 的确是最简单的一种方式.
案例2:显示用户上次浏览过的商品
products.jsp
<%@page import="com.lln.cookie.util.CookieUtil"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>商品列表</h3>
智能时代<a href="/day11/showinfo?id=1">查看</a><br>
浪潮之巅<a href="/day11/showinfo?id=2">查看</a><br>
自制操作系统<a href="/day11/showinfo?id=3">查看</a><br>
Linux命令行与shell脚本编程大全<a href="/day11/showinfo?id=4">查看</a><br>
Linux私房菜-服务器架设篇<a href="/day11/showinfo?id=5">查看</a><br>
计算机算法基础<a href="/day11/showinfo?id=6">查看</a><br>
<hr>
<br>
<a href="/day11/clearrecords">清空浏览记录</a>
<br>
<br>
<%
Cookie[] cookies=request.getCookies();
Cookie targetcookie=CookieUtil.findTargetCookie(cookies, "history");
//
if(targetcookie==null){
//没有任何浏览记录
out.println("还没有浏览过商品。。。。。<a href='/day11/products.jsp'>去浏览</a>");
}else{
//说明浏览过商品,取出商品,显示一下
String value=targetcookie.getValue();
String[] records=value.split("-");
String[] booknames={"智能时代","浪潮之巅","自制操作系统","Linux命令行与shell脚本编程大全","Linux私房菜-服务器架设篇","计算机算法基础"};
out.println("浏览过的商品有:"+"<br/>");
for(String record:records){
out.println("书名:"+booknames[Integer.parseInt(record)-1]+"<br>");
}
}
%>
</body>
</html>
ShowInfo.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//获取查看的书的id
String id = request.getParameter("id");
//h获得带过来的cookie数组,查看有没有目标cookie
Cookie[] cookies=request.getCookies();
Cookie targetcookie=CookieUtil.findTargetCookie(cookies,"history");
if(targetcookie==null) {
//说明没有浏览记录,把当前书的id存入cookie
Cookie cookie=new Cookie("history",id);
cookie.setMaxAge(60*60*24);
cookie.setPath("/");
response.addCookie(cookie);
}else {
//说明之前有浏览记录
//如果没有,就将此次的浏览id加进去,如果浏览过就什么也不做
String value=targetcookie.getValue();
String[] records=value.split("-");//1-2-5
if(!checkExistId(records,id)) {
//需要将当前的id拼接上去
Cookie cookie=new Cookie("history",value+"-"+id);//1-2-5-4
cookie.setMaxAge(60*60*24);
cookie.setPath("/");
response.addCookie(cookie);
}
}
response.setContentType("text/html;charset=UTF-8");
response.getWriter().println("浏览商品成功。。。。<a href='/day11/products.jsp'>继续浏览</a>");
}
//判断是否包含当前点击的书的id
private boolean checkExistId(String[] records, String id) {
// TODO Auto-generated method stub
for(String record:records) {
if(record.equals(id)) {
//如果进来则说明找到了当前点击的书
return true;
}
}
return false;
}
CookieUtil.java
public class CookieUtil {
public static Cookie findTargetCookie(Cookie[] cookies, String name) {
// TODO Auto-generated method stub
if(cookies==null) {
return null;}
for(Cookie cookie:cookies) {
if(cookie.getName().equals(name)) {
//如果进来则说明找到了cookie对象,返回
return cookie;
}
}
return null;
}
}
案例3:清空浏览记录
ClearRecords.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
Cookie cookie=new Cookie("history","");//1-2-5-4
cookie.setMaxAge(0);
cookie.setPath("/");
response.addCookie(cookie);
// response.sendRedirect("/day11/products.jsp");
response.sendRedirect(request.getContextPath()+"/products.jsp");
}
6.4 Session
6.4.1 session原理
Session的实现原理是基于cookie的,是在访问服务器的时候给浏览器回写一个JSESSIONID的cookie,这个cookie的值是session的id号,那么这个浏览器收到了,在后续访问服务器的时候会带着这个cookie过去,从而服务器就解析出来了,解析到session的id后,通过这个id号找到了服务器端对应的session对象,从而取出数据为用户服务。
默认情况下,一个session对象创建后,就一直驻留在内存中,如果一个session对象连续半个小时没有被访问,那么就会被销毁。
6.4.2 session 实现数据共享
session1.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//实现session保存数据,实现数据共享
//注意:session对象的创建不是你自己new出来的
//内部原理是,你来访问的时候,如果没有为你的浏览器创建过对象,那么就会新创建,如果已创建过,那么就拿已创建的session对象为你服务
HttpSession session=request.getSession();
session.setAttribute("name", "张三");
//回写同名的cookie
//通过session.getId()获得具体的id号
Cookie cookie=new Cookie("JESSIONID",session.getId());//1-2-5-4
cookie.setMaxAge(60*60*24);
cookie.setPath("/");
response.addCookie(cookie);
}
session2.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//获得session对象的引用
HttpSession session=request.getSession();
//获得session中保存的数据
String name = (String) session.getAttribute("name");
response.setContentType("text/html;charset=UTF-8");
response.getWriter().println("name:"+name);
}
问题1:关闭浏览器后,再次直接去打开session2,看不到数据。
因为session是基于cookie的,默认情况下cookie有效期是浏览器进程,浏览器一关闭,cookie就没了,从而下次再打开的时候,就找不到服务器端的session对象。
如何实现在关闭浏览器之后仍然可以 找到之前的数据呢?
按照 同样的方式, 在 浏览器访问 服务器端的servlet的时候, 回写一个同名的cookie , 并且设置一个 有效期 … 这样cookie 就会持久化保存到硬盘上, 从而实现下次打开浏览器 仍然可以找到 之前的 数据.
//回写同名的cookie
//通过session.getId()获得具体的id号
Cookie cookie=new Cookie("JESSIONID",session.getId());//1-2-5-4
cookie.setMaxAge(60*60*24);
cookie.setPath("/");
response.addCookie(cookie);
问题2:如果浏览器禁用了cookie 会怎么样呢?
-
那么禁用了cookie 之后, 还能服务器端 使用 session 保存的 用户的商品信息吗 ?
肯定是找不到了, 因为 session 是基于cookie 的, cookie 禁用了, 所以 对应 的session的信息 也就没了 .
-
浏览器禁用了cookie后,的确就找不到 服务器的session 对象了, 那 服务器端的session 对象还在吗 ?
在的, session 对象的存在与否 与浏览器是否禁用 cookie 没有 任何的 关系. -
服务端的session ,它的生命 周期 又是怎样的呢?
默认的情况下, 一个session 创建后 就一直 驻留在内存中, 如果一个session 对象 连续 半个小时没有被访问过, 那么就会被销毁…
实际上你是可以 自己去修改这个值的.
在tomcat服务器的conf目录下的web.xml(是被所有的web应用都共享的 ) 文件中 有配置
你可以 进入到自己的web工程下 web.xml 文件中更改
设置session的有效期有多种方式:
方式一: 在web.xml文件中配置
方式二: 使用代码 去 设置
要的是 秒
方式三: 手动的立马销毁session 对象
问题3:浏览器禁用cookie后,如何实现session的追踪(了解)?
可以使用url 重写 的方式去实现 … ,实际开发过程中,这个技术 没有人会去用.
案例一:使用Session完成简单的购物车功能
处理用户请求的购买的Servlet程序
- 1.获得购买的商品的信息
- 2.获得session中的购物车,判断购物车中是否有当前点击的商品
- 有:将原有的数量取出来+1,再放进去
- 没有:就将现有商品存进去,数量设置为1
- 3.需要将购物车存到session中去
- 4.给用户提示,添加商品到购物车成功
清空购物车,将购物车中的商品给移除 - 两种方式:
- 1.由于购物车是存在session中的,可以手动的将session销毁
- session.invalidate()
- 2.将购物车从session中移除
- session.removeAttribute(“cart”);
product.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>出售商品如下:</h3>
智能时代<a href="/day11/buy?id=1">购买</a><br>
浪潮之巅<a href="/day11/buy?id=2">购买</a><br>
自制操作系统<a href="/day11/buy?id=3">购买</a><br>
Linux命令行与shell脚本编程大全<a href="/day11/buy?id=4">购买</a><br>
Linux私房菜-服务器架设篇<a href="/day11/buy?id=5">购买</a><br>
计算机算法基础<a href="/day11/buy?id=6">购买</a><br>
<hr>
<a href="/day11/cart.jsp">查看购物车</a>
<hr>
<br>
<a href="/day11/clearcart">清空购物车</a>
</body>
</html>
cart.jsp
<%@page import="java.util.Set"%>
<%@page import="java.util.Map"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="/day11/clearcart">清空购物车</a><br>
<%
Map <String,Integer> cart=(Map<String, Integer>) request.getSession().getAttribute("cart");
if(cart==null){
//还没有购买过商品
out.println("还没有购买过商品。。。。<a href='/day11/product.jsp'>去购买</a>");
}else{
//遍历购物车,取出商品
Set<String> keys=cart.keySet();
out.println("购买的商品有:");
for(String key:keys){
Integer count=cart.get(key);
out.println("商品名称:"+key+" 数量:"+count);
}
}
%>
</body>
</html>
BuyServlet.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
String id=request.getParameter("id");
String[] booknames={"智能时代","浪潮之巅","自制操作系统","Linux命令行与shell脚本编程大全","Linux私房菜-服务器架设篇","计算机算法基础"};
//获得书名
String bookname=booknames[Integer.parseInt(id)-1];
//获得购物车
Map <String,Integer> cart=(Map<String, Integer>) request.getSession().getAttribute("cart");
if(cart==null) {
//如果进来,说明之前没有购买过商品,则新建一个购物车出来
cart=new HashMap<String,Integer>();
}
if(cart.containsKey(bookname)) {
//则说明之前购买过这本书,获得原有数量+1,再进去
Integer count=cart.get(bookname);
cart.put(bookname, count+1);
}else {
//没有购买过,直接put进去
cart.put(bookname, 1);
}
//需要将购物车存到session中去
request.getSession().setAttribute("cart", cart);
//给用户提示,添加商品到购物车成功
response.setContentType("text/html;charset=UTF-8");
response.getWriter().println("添加商品到购物车成功。。。。<a href='/day11/product.jsp'>继续购买</a>");
}
ClearCart.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
// request.getSession().invalidate();
request.getSession().removeAttribute("cart");
//重定向回购物车页面
response.sendRedirect(request.getContextPath()+"/cart.jsp");
}
案例二:利用Session实现一次性验证码用户登陆
login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
function checkimage(){
document.getElementById("myimage").src="/day11/checkimage?"+new Date().getTime();
}
</script>
</head>
<body>
<h3>登录页面</h3>
<font color="red" size="5">${message} </font>
<form action="/day11/login" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="text" name="password"><br>
验证码:<input type=" text" name="checkcode">
<img src="/day11/checkimage" style="cursor:pointer" onclick="checkimage();" id="myimage" ><br>
<input type="submit" value="登录">
</form>
</body>
</html>
CheckImage.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//首先需要在内存中构建一张图片出来
BufferedImage bf=new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics=(Graphics2D) bf.getGraphics();
Color color=new Color(203,232,225);
//设置背景杨色
graphics.setColor(color);
graphics.fillRect(0, 0, WIDTH, HEIGHT);
String base="ABCDEFGHIJKLMN";
Random random=new Random();
//状态机:如果之前设置过相应属性,下次没有调用相应API时,其状态不会发生改变
graphics.setColor(Color.RED);
graphics.setFont(new Font("楷体",Font.BOLD,18));
int m=13;
StringBuilder sb=new StringBuilder();
for(int i=0;i<4;i++) {
int index=random.nextInt(base.length());
char charAt=base.charAt(index);
//-30-------30
int jiaodu=random.nextInt(60)-30;
double theta=jiaodu*Math.PI/180;
graphics.drawString(charAt+"", m, 15);
graphics.rotate(theta, m, 15);
sb.append(charAt);
m+=20;
}
//将sb存到session域对象中去
request.getSession().setAttribute("checkcode_session", sb.toString());
System.out.println("checkcode_session:"+request.getSession().getAttribute("checkcode_session"));
for(int i=0;i<4;i++) {
int x1=random.nextInt(WIDTH);
int y1=random.nextInt(HEIGHT);
int x2=random.nextInt(WIDTH);
int y2=random.nextInt(HEIGHT);
graphics.drawLine(x1, y1, x2, y2);
}
ImageIO.write(bf,"png",response.getOutputStream());
}
Login.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//解决乱码问题
request.setCharacterEncoding("UTF-8");
//获取用户名、密码、验证码
String username = request.getParameter("username");
String password = request.getParameter("password");
String checkcode = request.getParameter("checkcode");
System.out.println("checkcode:"+checkcode);
//校验验证码
String checkcode_session=(String) request.getSession().getAttribute("checkcode_session");
System.out.println("login:"+checkcode_session);
if(checkcode==null||!checkcode.equalsIgnoreCase(checkcode_session)) {
//如果进来,说明验证码不正确
request.setAttribute("message", "对不起,您输入的验证码不正确。。。。");
//请求转发到登录页面
request.getRequestDispatcher("/login.jsp").forward(request, response);
return ;
}
//如果走到这里说明验证码正确,
//做用户名和密码的校验
if("admin".equals(username)&&"admin".equals(password)) {
//将登录的用户存到域对象中去
request.getSession().setAttribute("loginUser", "admin");
//说明用户名和密码正确,重定向到网站的首页
response.sendRedirect(request.getContextPath()+"/index.jsp");
}else {
//说明用户名和密码不正确,请求转发到登录页面
request.setAttribute("message", "对不起,您的用户名或密码不正确。。。。");
request.getRequestDispatcher("/login.jsp").forward(request, response);
}
}