一、Cookie
1、Cookie是Web服务器保存在客户端的一系列文本信息。
2、Cookie的工作原理。
客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站 时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
查看某个网站颁发的Cookie很简单。在浏览器地址栏输入javascript:alert (document. cookie)就可以了(必须有网才能查看)。
JavaScript脚本会弹出一个对话框显示本网站颁发的所有Cookie的内容,如图1.1所示。
3、Cookie的作用
a) 对特定对象的追踪
b) 统计网页浏览次数
c) 简化登录
4、安全性能
容易信息泄露
5、Cookie常用的方法
6、 Cookie的有效期
Cookie的maxAge决定着Cookie的有效期,单位为秒(Second)。
Cookie中通过getMaxAge()方法与setMaxAge(int maxAge)方法来读写maxAge属性。
(1) 如果maxAge为正数,则表示该Cookie会在maxAge秒之后自动失效。浏览器会将maxAge为正数的Cookie持久化,即写到对应的Cookie文件中。无论客户关闭了浏览器还是电脑,只要还在maxAge秒之前,登录网站时该Cookie仍然有效。下面代码中的Cookie信息将永远有效。
Cookie cookie = new Cookie("username","boy"); // 新建Cookie
cookie.setMaxAge(Integer.MAX_VALUE); // 设置生命周期为MAX_VALUE
response.addCookie(cookie); // 输出到客户端
(2)如果maxAge为负数,则表示该Cookie仅在本浏览器窗口以及本窗口打开的子窗口内有效,关闭窗口后该Cookie即失效。maxAge为负数的Cookie,为临时性Cookie,不会被持久化,不会被写到Cookie文件中。Cookie信息保存在浏览器内存中,因此关闭浏览器该Cookie就消失了。Cookie默认的maxAge值为–1。
Cookie cookie = new Cookie("username","boy"); // 新建Cookie
response.addCookie(cookie); // 输出到客户端
(3)如果maxAge为0,则表示删除该Cookie。Cookie机制没有提供删除Cookie的方法,因此通过设置该Cookie即时失效实现删除Cookie的效果。失效的Cookie会被浏览器从Cookie文件或者内存中删除,
Cookie cookie = new Cookie("username","boy"); // 新建Cookie
cookie.setMaxAge(0); // 设置生命周期为0,不能为负数
response.addCookie(cookie); // 必须执行这一句
注意:从客户端读取Cookie时,包括maxAge在内的其他属性都是不可读的,也不会被提交。浏览器提交Cookie时只会提交name与value属性。maxAge属性只被浏览器用来判断Cookie是否过期。
7、Cookie的修改、删除
Cookie并不提供修改、删除操作。
修改某个Cookie,只需要新建一个同名的Cookie,添加到response中覆盖原来的Cookie。
删除某个Cookie,只需要新建一个同名的Cookie,并将maxAge设置为0,并添加到response中覆盖原来的Cookie。
8、永久性的登录
最直接的是把用户名与密码都保持到Cookie中,下次访问时检查Cookie中的用户名与密码,与数据库比较。这是一种比较危险的选择,一般不把密码等重要信息保存到Cookie中。
在登录时查询一次数据库,以后访问验证登录信息时不再查询数据库。实现方式是把账号按照一定的规则加密后,连同账号一块保存到Cookie中。下次访问时只需要判断账号的加密规则是否正确即可!
账号保存到名为account的Cookie中,把账号连同密钥用MD5算法加密后保存到名为ssid的Cookie中。 验证时验证Cookie中的账号与密钥加密后是否与Cookie中的ssid相等
<%@page import="java.security.MessageDigest"%>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" isErrorPage="false" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'login.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<%!//常量
private static final String KEY = ":cookie@myback.com";
// 密钥
public final static String calcMD5(String ss) { // MD5 加密算法
String s = ss == null ? "" : ss; // 若为null返回空
char hexDigits[] = { '0', '1', '2', '3', '4', '1', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f' }; // 字典
try {
byte[] strTemp = s.getBytes(); // 获取字节
MessageDigest mdTemp = MessageDigest.getInstance("MD5"); // 获取MD1
mdTemp.update(strTemp); // 更新数据
byte[] md = mdTemp.digest(); // 加密
int j = md.length; // 加密后的长度
char str[] = new char[j * 2]; // 新字符串数组
int k = 0; // 计数器k
for (int i = 0; i < j; i++) { // 循环输出
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str); // 加密后字符串
} catch (Exception e) {
return null;
}
}
%>
<%
//处理中文乱码
request.setCharacterEncoding("UTF-8");
String action = request.getParameter("action"); // 获取action参数
//判断登录
if ("login".equals(action)) { //login
//获得账号
String account = request.getParameter("account");
//获得密码
String pwd = request.getParameter("pwd");
//获得时间
int timeout = Integer.parseInt(request.getParameter("timeout"));
//out.println("timeout="+timeout);
if ("sa".equals(account.trim()) && "123".equals(pwd.trim())) {
//把账号、密钥使用MD1加密后保存
String ssid = calcMD5(account + KEY);
out.println("ssid="+ssid);
// 1)新建Cookie account
Cookie accountCookie = new Cookie("account", account);
// 设置有效期
accountCookie.setMaxAge(timeout);
// 2)新建Cookie ssid
Cookie ssidCookie = new Cookie("ssid", ssid);
// 设置有效期
ssidCookie.setMaxAge(timeout);
// 输出到客户端
response.addCookie(accountCookie);
response.addCookie(ssidCookie);
//重新请求本页面,参数中带有时间戳,禁止浏览器缓存页面内容
response.sendRedirect(request.getRequestURI() + "?"
+ System.currentTimeMillis());
}
} else if ("logout".equals(action)) { //logout
// 新建Cookie,内容为空
Cookie accountCookie = new Cookie("account", "");
// 设置有效期为0,删除
accountCookie.setMaxAge(0);
// 新建Cookie,内容为空
Cookie ssidCookie = new Cookie("ssid", "");
ssidCookie.setMaxAge(0); // 设置有效期为0,删除
// 输出到客户端
response.addCookie(accountCookie);
response.addCookie(ssidCookie);
//重新请求本页面,参数中带有时间戳,禁止浏览器缓存页面内容
response.sendRedirect(request.getRequestURI() + "?"
+ System.currentTimeMillis());
}
%>
<%
boolean login = false; // 是否登录
String account = null; // 账号
String ssid = null; // SSID标识
if (request.getCookies() != null) { // 如果Cookie不为空
for (Cookie cookie : request.getCookies()) { // 遍历Cookie
if (cookie.getName().equals("account")) // 如果Cookie名为
account = cookie.getValue(); // 保存account内容
if (cookie.getName().equals("ssid")) // 如果为SSID
ssid = cookie.getValue(); // 保存SSID内容
}
}
if (account != null && ssid != null) { // 如果account、SSID都不为空
login = ssid.equals(calcMD5(account + KEY));
// 如果加密规则正确, 则视为已经登录
}
%>
<body>
<fieldset><legend>当前有效 Cookie</legend>
<%
if (request.getCookies() != null) { // 如果Cookie不为空
for (Cookie cookie : request.getCookies()) { // 遍历Cookie
out.println("<span style='margin-left:60px; display:block;color:blue;'>"+cookie.getName()+":"+cookie.getValue()+"</span>");
}
}
%>
</fieldset>
<br/>
<fieldset><legend><%=login ? "欢迎您回来" : "请先登录"%></legend>
<%
if (login) {
%>
欢迎您, <span style="color:green;font-size:28px;">${ cookie.account.value }</span>
<a href="${ pageContext.request.requestURI }?action=logout"> 注销</a>
<%
} else {
%>
<form action="${pageContext.request.requestURI }?action=login"
method="post">
<table border="0">
<tr>
<td>账号:</td>
<td><input type="text" name="account"
style="width:
200px; ">
</td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="pwd"></td>
</tr>
<tr>
<td>有效期:</td>
<td><input type="radio" name="timeout" value="-1" checked>
关闭浏览器即失效 <br /> <input type="radio" name="timeout"
value="<%=30 * 24 * 60 * 60%>"> 30天 内有效 <br /> <input
type="radio" name="timeout" value="<%=Integer.MAX_VALUE%>">
永久有效 <br /></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value=" 登 录 " class="button">
</td>
</tr>
</table>
</form><fieldset>
<%
}
%>
</body>
</html>
如图所示:
二、session
1、Session机制
除了使用Cookie,Web应用程序中还经常使用Session来记录客户端状态。Session是服务器端使用的一种记录客户端状态的机制,使用上比Cookie简单一些,相应的也增加了服务器的存储压力。
2、什么是Session
Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。
3、Session的生命周期
Session保存在服务器端。为了获得更高的存取速度,服务器一般把Session放在内存里。每个用户都会有一个独立的Session。
如果Session内容过于复杂,当大量客户访问服务器时可能会导致内存溢出。因此,Session里的信息应该尽量精简。
Session在用户第一次访问服务器的时候自动创建。需要注意只有访问JSP、Servlet等程序时才会创建Session,只访问HTML、IMAGE等静态资源并不会创建Session。如果尚未生成Session,也可以使用request.getSession(true)强制生成Session。
Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,并维护该Session。用户每访问服务器一次,无论是否读写Session,服务器都认为该用户的Session“活跃(active)”了一次。
4、Session的有效期
由于会有越来越多的用户访问服务器,因此Session也会越来越多。为防止内存溢出,服务器会把长时间内没有活跃的Session从内存删除。这个时间就是Session的超时时间。如果超过了超时时间没访问过服务器,Session就自动失效了。 Session有效期默认值是1800秒
5、 Session的常用方法
6、 Session对浏览器的要求
HTTP协议是无状态的,Session不能依据HTTP连接来判断是否为同一客户,因此服务器向客户端浏览器发送一个名为JSESSIONID的Cookie,它的值为该Session的id(也就是HttpSession.getId()的返回值)。Session依据该Cookie来识别是否为同一用户。
该Cookie为服务器自动生成的,它的maxAge属性一般为–1,表示仅当前浏览器内有效,并且各浏览器窗口间不共享,关闭浏览器就会失效。
因此同一机器的两个浏览器窗口访问服务器时,会生成两个不同的Session。但是由浏览器窗口内的链接、脚本等打开的新窗口(也就是说不是双击桌面浏览器图标等打开的窗口)除外。这类子窗口会共享父窗口的Cookie,因此会共享一个Session。
package com.hlx.entity;
import java.util.Date;
/**
* 学生类
* @author Administrator
*
*/
public class Student {
private String name; //姓名
private String pwd; //密码
private int age; //年龄
private Date birthday; //生日
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Student(String name, String pwd, int age, Date birthday) {
super();
this.name = name;
this.pwd = pwd;
this.age = age;
this.birthday = birthday;
}
public Student() {
super();
}
}
(2)login.jsp页面
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>登录</title>
</head>
<body>
<fieldset>
<legend>用户登录</legend>
<form method="post" action="doLogin.jsp" name="frm">
<table border="0" width="298" height="133" align="center">
<tbody>
<tr>
<td> 用户名:</td>
<td> <input type="text" name="uname"></td>
</tr>
<tr>
<td> 密码:</td>
<td> <input type="password" name="upwd"></td>
</tr>
<tr>
<td> </td>
<td> <input type="reset" value="重置" name="button4"><input
type="submit" value="登录" name="button3"></td>
</tr>
</tbody>
</table>
</form>
</fieldset>
</body>
</html>
(3)doLogin.jsp处理页面
<%@page import="java.text.SimpleDateFormat"%>
<%@page import="java.text.DateFormat"%>
<%@page import="com.hlx.entity.Student"%>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%!DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); // 日期格式化器%>
<%
//动态数组对象
List<Student> students = new ArrayList<Student>();
//添加学生对象
students.add(new Student("张三", "123456", 22, dateFormat
.parse("1993-01-01")));
students.add(new Student("刘芳", "654321", 18, dateFormat
.parse("1997-01-01")));
students.add(new Student("光头强", "098765", 20, dateFormat
.parse("1995-01-01")));
//处理中文
request.setCharacterEncoding("UTF-8");
//获得值
String name = request.getParameter("uname");
String pwd = request.getParameter("upwd");
//遍历数据
for (Student stu : students) {
//判断
if (stu.getName().equals(name.trim()) && stu.getPwd().equals(pwd.trim())) {
// 登录成功,设置将用户的信息以及登录时间保存到Session
// 保存登录的Student
session.setAttribute("stu", stu);
// 保存登录的时间
session.setAttribute("loginTime", new Date());
//跳转
response.sendRedirect("welcome.jsp");
} else {
out.println("<script>alert('用户名或密码错误!');window.location.href='login.jsp';</script>");
}
}
%>
(4)welcome.jsp欢迎页面
<%@page import="com.hlx.entity.Student"%>
<%@page import="com.sun.xml.internal.ws.client.Stub"%>
<%@page import="java.text.SimpleDateFormat"%>
<%@page import="java.text.DateFormat"%>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>欢迎页面</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<a href="javascript:history.go(-1)">返回</a><p/>
<%!DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); // 日期格式化器
DateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); // 日期格式化器
%>
<%
Student student = (Student) session.getAttribute("stu"); // 获取登录的student
Date loginTime = (Date) session.getAttribute("loginTime"); // 获取登录时间
%>
<fieldset>
<legend>用户登录</legend>
<table style="margin-left: 80px; font-size:14px;line-height: 25px; color: blue">
<tr>
<td>您的姓名:</td>
<td><%=student.getName()%></td>
</tr>
<tr>
<td>登录时间:</td>
<td><%=dateFormat2.format(loginTime)%></td>
</tr>
<tr>
<td>您的年龄:</td>
<td><%=student.getAge()%></td>
</tr>
<tr>
<td>您的生日:</td>
<td><%=dateFormat.format(student.getBirthday())%></td>
</tr>
</table></fieldset>
</body>
</html>
如图所示:
注意程序中Session中直接保存了Student类对象与Date类对象,使用起来要比Cookie方便。
当多个客户端执行程序时,服务器会保存多个客户端的Session。获取Session的时候也不需要声明获取谁的Session。Session机制决定了当前客户只会获取到自己的Session,而不会获取到别人的Session。各客户的Session也彼此独立,互不可见。
提示:Session的使用比Cookie方便,但是过多的Session存储在服务器内存中,会对服务器造成压力。
三、cookie 和session 的区别:
1、session是在服务器端保存用户信息,Cookie是在客户端保存用户信息2、session中保存的是对象,Cookie保存的是字符串
3、session随会话结束而关闭,Cookie可以长期保存在客户端
4、Cookie通常用于保存不重要的用户信息,重要的信息使用session保存