Cookie(保存在用户端)
什么是Cookie:
Cookie(s)实际上是一个小型文本文件,信息内容以key-value的形式存在.Cookie就像是商城的会员卡,当用户通过浏览器访问网站时,网站服务器可以将一些必要信息保存在cookie中,通过response对象返回给浏览器,浏览器会保存在本地,在下一次浏览改网站时,就会把这些cookie信息一同发送给该web服务器,web服务器就可以根据cookie中的信息来做出响应.(实现判断用户身份)
使用步骤:
1. 创建Cookie对象,绑定数据
* new Cookie(String name, String value)
2. 发送Cookie对象
* response.addCookie(Cookie cookie)
3. 获取Cookie,拿到数据
* Cookie[] request.getCookies()
cookie的机制:
当用户第一次访问并登陆一个网站的时候,cookie的设置以及发送会经历以下4个步骤:
客户端发送一个请求到服务器 -- 服务器发送一个HttpResponse响应到客户端,其中包含Set-Cookie的头部 -- 客户端保存cookie,之后向服务器发送请求时,HttpRequest请求中会包含一个Cookie的头部 -- 服务器返回响应数据
二.[案例]显示用户上次访问时间
1.通过cookie保存用户上次访问时间
package cn.itcast.chapter05.cookie.example;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
@WebServlet("/LastAccessServlet")
public class LastAccessServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// 指定服务器输出内容的编码方式UTF-8,防止发生乱码
response.setContentType("text/html;charset=utf-8");
String lastAccessTime = null;
// 获取所有的cookie,并将这些cookie存放在数组中
Cookie[] cookies = request.getCookies();
// 遍历cookies数组
for (int i = 0; cookies != null && i < cookies.length; i++) {
if ("lastAccess".equals(cookies[i].getName())) {
// 如果cookie的名称为lastAccess,则获取该cookie的值
lastAccessTime = cookies[i].getValue();
}
}
// 判断是否存在名称为lastAccess的cookie
if (lastAccessTime == null) {
response.getWriter().print("您是首次访问本站!!!");
} else {
response.getWriter().print("您上次的访问时间是: "
+ lastAccessTime);//把上次的时间显示到浏览完
}
// 创建cookie,将当前时间作为cookie的值发送给客户端
String time=String.format("%tF%<tF", new Date());
Cookie cookie = new Cookie("lastAccess",time);
Cookie cookie1 = new Cookie("dashujv","2004");
response.addCookie(cookie);
response.addCookie(cookie1);
}
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.doPost(req, resp);
}
}
查看运行的成果:
再次访问:
注意事项:没有显示访问时间,说明之前浏览器存放的Cookie信息被删除。是因为在默认情况下,Cookie对象的Max-Age属性的值是 -1(即浏览器关闭,删除这个cookie对象)
通过setMaxAge()方法进行设置让cookie对象在客户端有较长的存活时间,如设置有效时间为1小时
总结:
1.Cookie可创建多个Cookie对象,使用response调用多次addCookie方法发送cookie即可;
2.cookie在浏览器中的保存时间:
默认情况下,当浏览器关闭后,Cookie数据被销毁
持久化存储:* setMaxAge(int seconds)
正数:持久化存储。将Cookie数据写到硬盘的文件中。取决于时间设置
负数:默认值
零:删除cookie信息
3. Cookie的特点和作用
* 特点:
Cookie存储数据在客户端浏览器
浏览器对于单个Cookie的大小有限制(4kb)以及对
同一个域名下的总Cookie数量也有限制(20个)
* 作用:
Cookie一般用于存储少 的不太重要的数据(因为不安全)
. 在不登录的情况下,完成服务器对客户端的身份识别
4.cookie中文问题:
在tomcat 8 之前 cookie中不能直接存储中文数据。
需要将中文数据转码---一般采用URL编码(%E3)
在tomcat 8 之后,cookie支持中文数据。特殊字符不支持,建议使用URL编码存储,解码解析
5.cookie在web项目中共享问题
同一个tomcat服务器间多个web项目cookie共享问题
默认情况下cookie不能共享
setPath(String path):设置cookie的获取范围。
默认情况下,设置当前的虚拟目录
如果要共享,则可以将path设置为"/"
不同的tomcat服务器间多个web项目cookie共享问题
setDomain(String path):如果设置一级域名相同,那么多个服务器之间cookie可以共享
setDomain(".baidu.com"),那么tieba.baidu.com和news.baidu.com中cookie可以共享
Session保存在服务端
获取HttpSession对象:
HttpSession session = request.getSession();
session被称为"会话控制". 会话指的是从用户打开浏览器访问一个网站开始,无论在这个网站中访问了多少页面,点击了多少链接,都属于同一个会话。 直到该用户关闭浏览器为止,都属于同一个会话。session同样是用于保存信息,但是不同于cookie对用户可见及存储限制,session是保存在服务端,对用户不可见,但是同样可以实现在同一站点中共享信息的功能;
Session机制
用户访问服务器—>服务器判断是否是第一次连接—>第一次连接则创建一个新的session,期中包含一个唯一的ID值—>该ID值会以cookie信息的形式(key=jsessionid, value=ID)返回给用户端保存,用以下次辨别用户身份—>用户再次访问,服务器就可以判断用户已经访问过;
总结:
1.当客户端关闭后,服务器不关闭,两次获取的session在默认情况下不是同一个;
如果需要相同,则可以创建Cookie,键为JSESSIONID,设置最大存活时间,让cookie持久化保存。
Cookie c = new Cookie("JSESSIONID",session.getId());
c.setMaxAge(60*60);
response.addCookie(c);
2.客户端不关闭,服务器关闭后,两次获取的session不是同一个;
相同的话要必须确保数据不丢失。tomcat自动完成以下工作
session的钝化:序列化过程
在服务器正常关闭之前,将session对象系列化到硬盘上
session的活化:反序列化过程
在服务器启动后,将session文件转化为内存中的session对象即可。
3.session什么时候被销毁?
1. 服务器关闭
2. session对象调用invalidate() 。
3. session默认失效时间 30分钟
选择性配置修改
<session-config>
<session-timeout>30</session-timeout>
</session-config>
5. session的特点:
session用于存储一次会话的多次请求的数据,存在服务器端;
session可以存储任意类型,任意大小的数据;
实现列题购物车:
对ListBookServlet 类中 for 循环内的代码进行修改,将请求访问的路径改为URL重写
for(Book b:books) {
String name=b.getName();
String id=b.getId();
String url="<a href='purchares?id="+id+"'>购买记录</a>";
out.print("图书名称:"+name+" "+url+"<br/><br/>");
System.out.println("图书名称:"+name+" "+url+"<br/><br/>");
}
修改purchaservlet
String id=request.getParameter("id");
System.out.println("id : "+id);
if(id==null) {
response.sendRedirect("list");
return;
}
重启:
实现用户登录
网站首界面代码:
package cn.itcast.chapter05.session.example02;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.*;
public class IndexServlet extends HttpServlet {
public void doGet(HttpServletRequest request,HttpServletResponse response)
throws ServletException, IOException {
// 解决乱码问题
response.setContentType("text/html;charset=utf-8");
// 创建或者获取保存用户信息的Session对象
HttpSession session = request.getSession();
User user = (User) session.getAttribute("user");
if (user == null) {
response.getWriter().print(
"您还没有登录,请<a href='/chapter05/login.html'>登录</a>");
} else {
response.getWriter().print("您已登录,欢迎你," + user.getUsername() + "!");
response.getWriter().print(
"<a href='/chapter05/LogoutServlet'>退出</a>");
// 创建Cookie存放Session的标识号
Cookie cookie = new Cookie("JSESSIONID", session.getId());
cookie.setMaxAge(60 * 30);
cookie.setPath("/chapter05");
response.addCookie(cookie);
}
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
登录成功界面代码:
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
String username = request.getParameter("username");
String password = request.getParameter("password");
PrintWriter pw = response.getWriter();
//假设正确的用户名 是Lily 密码是123
if (("LiLy").equals(username) && ("123").equals(password)) {
User user = new User();
user.setUsername(username);
user.setPassword(password);
request.getSession().setAttribute("user", user);
response.sendRedirect("/chapter05/IndexServlet");
} else {
pw.write("用户名或密码错误,登录失败");
}
}
用户注销代码:
public class LogoutServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 将Session对象中的User对象移除
request.getSession().removeAttribute("user");
response.sendRedirect("/chapter05/IndexServlet");
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)throws ServletException, IOException {
doGet(request, response);
}
}
验证码设置:
public void doGet(HttpServletRequest request,HttpServletResponseresponse)throwsServletException, IOException {
response.setContentType("text/html;charset=utf-8");
String username = request.getParameter("username");
String password = request.getParameter("password");
String checkCode = request.getParameter("check_code");
String savedCode = (String) request.getSession().getAttribute(
"check_code");
PrintWriter pw = response.getWriter();
if (("Lily").equals(username) && ("123").equals(password)
&& checkCode.equals(savedCode)) {
User user = new User();
user.setUsername(username);
user.setPassword(password);
request.getSession().setAttribute("user", user);
response.sendRedirect("/chapter05/IndexServlet");
} else if (checkCode.equals(savedCode)) {
pw.write("用户名或密码错误,登录失败");
} else {
pw.write("验证码错误");
}
}
验证码图片:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.awt.*;
import java.awt.image.*;
import javax.imageio.ImageIO;
public class CheckServlet extends HttpServlet
{
private static int WIDTH = 60; //验证码图片宽度
private static int HEIGHT = 20; //验证码图片高度
public void doGet(HttpServletRequest request,HttpServletResponse response)
throws ServletException,IOException{
HttpSession session = request.getSession();
response.setContentType("image/jpeg");
ServletOutputStream sos = response.getOutputStream();
//设置浏览器不要缓存此图片
response.setHeader("Pragma","No-cache");
response.setHeader("Cache-Control","no-cache");
response.setDateHeader("Expires", 0);
//创建内存图象并获得其图形上下文
BufferedImage image =
new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
//产生随机的认证码
char [] rands = generateCheckCode();
//产生图像
drawBackground(g);
drawRands(g,rands);
//结束图像的绘制过程,完成图像
g.dispose();
//将图像输出到客户端
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ImageIO.write(image, "JPEG", bos);
byte [] buf = bos.toByteArray();
response.setContentLength(buf.length);
//下面的语句也可写成:bos.writeTo(sos);
sos.write(buf);
bos.close();
sos.close();
//将当前验证码存入到Session中
session.setAttribute("check_code",new String(rands));
//直接使用下面的代码将有问题,Session对象必须在提交响应前获得
//request.getSession().setAttribute("check_code",new String(rands));
}
//生成一个4字符的验证码
private char [] generateCheckCode()
{
//定义验证码的字符表
String chars = "0123456789abcdefghijklmnopqrstuvwxyz";
char [] rands = new char[4];
for(int i=0; i<4; i++)
{
int rand = (int)(Math.random() * 36);
rands[i] = chars.charAt(rand);
}
return rands;
}
private void drawRands(Graphics g , char [] rands)
{
g.setColor(Color.BLACK);
g.setFont(new Font(null,Font.ITALIC|Font.BOLD,18));
//在不同的高度上输出验证码的每个字符
g.drawString("" + rands[0],1,17);
g.drawString("" + rands[1],16,15);
g.drawString("" + rands[2],31,18);
g.drawString("" + rands[3],46,16);
System.out.println(rands);
}
private void drawBackground(Graphics g)
{
//画背景
g.setColor(new Color(0xDCDCDC));
g.fillRect(0, 0, WIDTH, HEIGHT);
//随机产生120个干扰点
for(int i=0; i<120; i++)
{
int x = (int)(Math.random() * WIDTH);
int y = (int)(Math.random() * HEIGHT);
int red = (int)(Math.random() * 255);
int green = (int)(Math.random() * 255);
int blue = (int)(Math.random() * 255);
g.setColor(new Color(red,green,blue));
g.drawOval(x,y,1,0);
}
}
}
Cookie与Session主要有如下区别:
Cookie和HttpSession是保存会话相关数据的技术,其中Cookie将信息存储在浏览器端,是客户端技术,Session将数据保存在服务器端,是服务器端技术;
Cookie是基于HTTP协议中的Set-Cookie响应头和Cookie请求头进行工作的;
默认情况下HttpSession是基于一个名称为JSESSIONID 的特殊Cookie工作的;
浏览器对Cookie具有严格的限制,一个网站能在浏览器中保存多少Cookie是有限制的;
HttpSession默认是基于Cookie运作的;