文章目录
1. 会话技术
- 基本概念
指⽤户开⼀个浏览器,访问⼀个⽹站,只要不关闭该浏览器,不管该⽤户点击多少个超链接,访问多少资源,直到⽤户关闭浏览器,整个这个过程我们称为⼀次会话。 - 应用场景:
1、在论坛登陆的时候,很多时候会有⼀个⼩框框问你是否要⾃动登陆,当你下次登陆的时候就不⽤输⼊密码了。
2、根据我以前浏览过的商品,猜我喜欢什么商品 - 会话跟踪技术有Cookie 和 Session
2. Cookie
2.1 什么是Cookie
- ⽹⻚之间的交互是通过HTTP协议传输数据的,⽽Http协议是⽆状态的协议。⽆状态的协议是什么意思呢?⼀旦数据提交完后,浏览器和服务器的连接就会关闭,再次交互的时候需要重新建⽴新的连接。
- 服务器⽆法确认⽤户的信息,于是乎,W3C就提出了:给每⼀个⽤户都发⼀个通⾏证,⽆论谁访问的时候都需要携带通⾏证,这样服务器就可以从通⾏证上确认⽤户的信息。通⾏证就是Cookie。
- Cookie的流程:浏览器访问服务器,如果服务器需要记录该⽤户的状态,就使⽤response向浏览器发送⼀个Cookie,浏览器会把Cookie保存起来。当浏览器再次访问服务器的时候,浏览器会把请求的⽹址连同Cookie⼀同交给服务器。
- Cookie 是服务器通知客户端保存键值对的一种技术,客户端有了Cookie之后,每次请求都发送给服务器。每个Cookie大小都不超过4kb。
2.2 Cookie API
- Cookie类⽤于创建⼀个Cookie对象
public Cookie(String name,String value)
- response接⼝中定义了⼀个
addCookie
⽅法,它⽤于在其响应头中增加⼀个相应的Set-Cookie头字段 - request接⼝中定义了⼀个
getCookies
⽅法,它⽤于获取客户端提交的Cookie。
2.3 Cookie 有效期
Cookie的有效期是通过setMaxAge()
来设置的。
- MaxAge为正数,浏览器会把Cookie写到硬盘中,只要还在MaxAge秒之前,登陆⽹站时该Cookie就有效【不论关闭了浏览器还是电脑】
- MaxAge为负数,Cookie是临时性的,仅在本浏览器内有效,关闭浏览器Cookie就失效了,Cookie不会写到硬盘中。Cookie默认值就是-1,意味着没设置Cookie的有效期,在硬盘中就找不到对应的⽂件。
- MaxAge为0,则表示删除该Cookie。Cookie机制没有提供删除Cookie的⽅法,把MaxAge设置为0等同于删除Cookie。
3. Cookie 基本操作
3.1 创建 Cookie
- Cookie保存英文
// 创建Cookie对象,指定 名称 和 值
Cookie cookie = new Cookie("username","zouxiaopang");
// 设置Cookie时间
cookie.setMaxAge(1000);
// 向浏览器传送一个Cookie
response.addCookie(cookie);
response.getWriter().write("我已经向浏览器发送了一个Cookie");
- cookie 保存中文
中⽂属于Unicode字符,英⽂数据ASCII字符,中⽂占4个字符或者3个字符,英⽂占2个字符。解决:
Cookie使⽤Unicode字符时需要对Unicode字符进⾏编码。
String pick = "小连";
Cookie cookie2 = new Cookie("pick", URLEncoder.encode(pick, "UTF-8"));
cookie2.setMaxAge(1000);
response.addCookie(cookie2);
response.getWriter().write("我已经向浏览器发送了一个Cookie");
3.2 获取Cookie
Cookie[] cookies = request.getCookies();
for (int i = 0; cookies != null && i < cookies.length; i++) {
String name = cookies[i].getName();
//经过URLEncoding就要URLDecoding
String value = URLDecoder.decode(cookies[i].getValue(), "UTF-8");
response.getWriter().write(name + "------" + value+"<br>");
}
3.3 Cookie的修改
Cookie存储的⽅式类似于Map集合,Cookie的名称相同,通过response添加到浏览器中,会覆盖原来的Cookie。
- 以pick为例,改变该属性的值。
– 原先 pick 值为 小连
– 后 pick 值为 小连、小天、小鬼
pick = "小连、小天、小鬼";
cookie2 = new Cookie("pick", URLEncoder.encode(pick, "UTF-8"));
response.addCookie(cookie2);
3.4 Cookie 删除
删除Cookie,需要将MaxAge
设置为0,并添加到浏览器中
String pick = "小连、小天、小鬼";
Cookie cookie = new Cookie("pick", URLEncoder.encode(pick,"UTF-8"));
cookie.setMaxAge(0);
response.addCookie(cookie);
response.getWriter().write("我删除了该cookie");
- 注:删除,修改Cookie时,新建的Cookie除了value、maxAge之外的所有属性都要与原Cookie相 同。否则浏览器将视为不同的Cookie,不予覆盖,导致删除修改失败!
3.5 Cookie的域名
- domain属性决定运⾏访问Cookie的域名。domain的值规定为
.域名
- Cookie的隐私安全机制决定Cookie是不可跨域名的。也就是说www.baidu.com和www.google.com之间的Cookie是互不交接的。即使是同⼀级域名,不同⼆级域名也不能交接,也就是说:www.goole.com和www.image.goole.com的Cookie也不能访问。
- 在本地配置两个虚拟主机,详见Tomcat 6.临时域名 。
<Engine name="Catalina" defaultHost="localhost">
<Host name="www.zouxiaopang.com" appBase="E:\SpringMvc\servlet">
<Context path="/" docBase="E:\SpringMvc\out\artifacts\servlet_war_exploded" />
</Host>
<Host name="www.lian.zouxiaopang.com" appBase="E:\SpringMvc\servlet">
<Context path="/" docBase="E:\SpringMvc\out\artifacts\servlet_war_exploded" />
</Host>
- 使用www.zouxiaopang.com域名发送了一个Cookie给浏览器
Cookie cookie = new Cookie("name","zouxiaopang");
cookie.setMaxAge(1000);
response.addCookie(cookie);
response.getWriter().write("使用www.zouxiaopang.com域名添加一个Cookie");
- 通过localhost:8080 和 www.lian.zouxiaopang.com是无法获取到www.zouxiaopang.com上传的Cookie。
- 要想⼀级域名相同的⽹⻚Cookie之间可以相互访问。也就是说www.lian.zouxiaopang.com可以获取到www.zouxiaopang.com的Cookie就需要使⽤到domain⽅法。
Cookie cookie = new Cookie("name","zouxiaopang");
cookie.setMaxAge(1000);
cookie.setDomain(".zouxiaopang.com");
response.addCookie(cookie);
response.getWriter().write("使用www.zouxiaopang.com域名添加一个Cookie,只要一级是zouxiaopang.com都可以访问");
4. Cookie 应用
4.1 获取上次访问的时间
- 每次登陆的时候,获取Cookie保存的值,在更新下Cookie的值。
- 访问Servlet有两种情况:
① 第一次访问
② 已经访问过
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM--dd HH:mm:ss");
response.setContentType("text/html;charset=UTF-8");
PrintWriter printWriter = response.getWriter();
//获取网页上所有的Cookie
Cookie[] cookies = request.getCookies();
//判断cookie的值是否为空
String cookieValue = null;
for(int i = 0; cookies != null && i < cookies.length; i++){
//获取到以time为名的Cookie
if(cookies[i].getName().equals("time")){
//获取上一次访问的时间
cookieValue = cookies[i].getValue();
printWriter.write("您上次访问的时间为:"+cookieValue);
//修改这次访问的time值
cookies[i].setValue(simpleDateFormat.format(new Date()));;
response.addCookie(cookies[i]);
break;
}
}
// 如果cookieValue的值是空的,那么就是第一次访问
if(cookieValue == null){
Cookie cookie = new Cookie("time",simpleDateFormat.format(new Date()));
cookie.setMaxAge(20000);
response.addCookie(cookie);
printWriter.write("您是第一次登陆!!!");
}
4.2 显示上次浏览过得商品
以查看书籍为例,所有 servlet 创建在 good 包中。
- 设计 book 对象 (建议设为Book对象,由于取名失误,后创建对象,取名及其奇怪!)
主要编写:属性,有参/无参构造器,各种get/set方法
package good;
public class book {
private String id;
private String name;
private String author;
public book() {
}
public book(String id, String name, String author) {
this.id = id;
this.name = name;
this.author = author;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
}
- 设计⼀个简单的数据库存储数据。就⽤LinkedHashMap集合【根据商品的id找书籍所以⽤Map,删改较多所以⽤Linked】
db.java
package good;
import java.util.LinkedHashMap;
public class db {
private static LinkedHashMap<String,book> linkedHashMap = new LinkedHashMap<>();
//简化开发复杂度,book的id和商品的id相同
static{
linkedHashMap.put("1", new book("1", "javaweb", "zou"));
linkedHashMap.put("2", new book("2", "java", "xiao"));
linkedHashMap.put("3", new book("3", "oracle", "pang"));
linkedHashMap.put("4", new book("4", "mysql", "xiao"));
linkedHashMap.put("5", new book("5", "ajax", "lian"));
}
//获取到所有书籍
public static LinkedHashMap getAll(){
return linkedHashMap;
}
}
- 显示⽹⻚上所有的书籍(
show.java
)
response.setContentType("text/html;charset=UTF-8");
PrintWriter printWriter = response.getWriter();
printWriter.write("所有书籍:<br/>");
//获取数据库所有的书
LinkedHashMap<String,book> linkedHashMap = db.getAll();
Set<Map.Entry<String,book>> entryset = linkedHashMap.entrySet();
//显示所有书到网页上
for(Map.Entry<String,book> entry : entryset){
book books = entry.getValue();
// 通过超链接的方式将书的id传递过去
printWriter.write("<a href='/details?id="+books.getId()+"'target='_blank'> " + books.getName() + "</a>");
printWriter.write("<br/>");
}
- 接收id,找到⽤户想要看哪⼀本书,输出该书的详细信息(
details.java
)
//由于book的id和商品的id是⼀致的。获取到⽤户点击的书
String id = request.getParameter("id");
book books = (book) db.getAll().get(id);
//输出书的详细信息
printWriter.write("编号:" + books.getId()+"<br/>");
printWriter.write("书名:" + books.getName()+"<br/>");
printWriter.write("作者:" + books.getAuthor()+"<br/>");
- 传送Cookie,由于访问的书比较多,定义只能显示最近浏览过得三本书籍。在
details.java
文件中创建protected String makeHistory(HttpServletRequest request, String id)
方法来获取Cookie内容。
- 步骤一: 先遍历下Cookie,看下有没有我们想要的Cookie。如果找到想要的Cookie,那就取出Cookie的值。
- 步骤二: 取出Cookie的值,有四种情况
a. Cookie的值为null【直接把传⼊进来的id当做是Cookie的值】
b. Cookie的值⻓度有3个了【把排在最后的id去掉,把传进来的id排在最前边】
c. Cookie的值已经包含有传递进来的id了【把已经包含的id先去掉,再把id排在最前⾯】
d. Cookie的值就只有1个或2个,直接把id排在最前边 - 步骤三: 是把集合中的值取出来,拼接成⼀个字符串
// 步骤一:
String bookHistory = null;
Cookie[] cookies = request.getCookies();
for (int i = 0; cookies != null && i < cookies.length; i++) {
if (cookies[i].getName().equals("bookHistory")) {
bookHistory = cookies[i].getValue();
}
}
// 步骤二: 情况a
if (bookHistory == null) {
return id;
}
// 步骤二: 情况bcd
//如果Cookie的值不是null的,那么就分解Cookie的得到之前的id。
String[] strings = bookHistory.split("\\_");
//为了增删容易并且还要判断id是否存在于该字符串内-----我们使⽤LinkedList集合装载分解出来id
List list = Arrays.asList(strings);
LinkedList<String> linkedList = new LinkedList<>();
linkedList.addAll(list);
if (linkedList.contains(id)) {
linkedList.remove(id);
linkedList.addFirst(id);
}else {
if (linkedList.size() >= 3) {
linkedList.removeLast();
linkedList.addFirst(id);
} else {
linkedList.addFirst(id);
}
}
// 步骤三:
StringBuffer stringBuffer = new StringBuffer();
//遍历LinkedList集合,添加个下划线“_”
for (String s : linkedList) {
stringBuffer.append(s + "_");
}
//最后⼀个元素后⾯就不需要下划线了
return stringBuffer.deleteCharAt(stringBuffer.length() - 1).toString();
- 设置Cookie的⽣命周期,回送给浏览器即可(
details.java
)
String bookHistory = makeHistory(request, id);
Cookie cookie = new Cookie("bookHistory", bookHistory);
cookie.setMaxAge(30000);
response.addCookie(cookie);
- 在show页面上获取Cookie的值,显示⽤户浏览过的商品
printWriter.write("您曾经浏览过的商品:<br/>");
//显示⽤户浏览过的商品
Cookie[] cookies = request.getCookies();
for (int i = 0; cookies != null && i < cookies.length; i++) {
if (cookies[i].getName().equals("bookHistory")) {
//获取到的bookHistory是2_3_1之类的
String bookHistory = cookies[i].getValue();
//拆解成每⼀个id值
String[] ids = bookHistory.split("\\_");
//得到每⼀个id值
for (String id: ids) {
//通过id找到每⼀本书
book books = linkedHashMap.get(id);
printWriter.write(books.getName());
printWriter.write("<br/>");
}
break;
}
}
没有访问过任何页面
访问javaweb,传cookie值为1
访问mysql书籍,返回cookie值为4_1