本篇继续来做一个cookie的经典练习场景,如何显示用户浏览器网站上的商品的历史纪录。这个功能很多购物网站上都有,我们来模拟这个场景的实现过程。例如一个卖书的网站,我们定义这个网站有4本书,然后我们历史纪录只显示用户最近浏览的三本书,当然也可能用户只浏览了一本,两本或者没有一本书,这些场景都需要考虑。
需求场景
上面就是用户第一次打开这个卖书网站,这个时候没有浏览任何一本书详情页,所以没有cookie也就没有历史纪录。下面点击四本书任何一本,跳转到详情页。
返回带主页
1.项目结构
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<servlet>
<servlet-name>showAllBooksServlet</servlet-name>
<servlet-class>com.anthony.history.ShowAllBooksServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>showAllBooksServlet</servlet-name>
<url-pattern>/cookie/showAllBook</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>showBookDetail</servlet-name>
<servlet-class>com.anthony.history.ShowBookDetail</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>showBookDetail</servlet-name>
<url-pattern>/cookie/showBookDetail</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
Book.java
package com.anthony.entity;
public class Book {
private String id;
private String name;
private double price;
private String author;
public Book(String id, String name, double price, String author) {
super();
this.id = id;
this.name = name;
this.price = price;
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 double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
@Override
public String toString() {
return "Book [id=" + id + ", name=" + name + ", price=" + price + ", author=" + author + "]";
}
}
DBUtil.java
package com.anthony.util;
import java.util.HashMap;
import java.util.Map;
import com.anthony.entity.Book;
public class DBUtil {
private static Map<String, Book> books = new HashMap<String, Book>();
//这里不走数据库查询,直接生成几本书来模拟下
static {
books.put("1", new Book("1", "西游记", 16.9, "吴承恩"));
books.put("2", new Book("2", "红楼梦", 37.3, "曹雪芹"));
books.put("3", new Book("3", "三国演义", 25.8, "罗贯中"));
books.put("4", new Book("4", "水浒传", 33.0, "施耐庵"));
}
//得到所有图书
public static Map<String, Book> findAllBooks() {
return books;
}
//根据id查找到书
public static Book findBookById(String id) {
return books.get(id);
}
}
com.anthony.history.ShowAllBooksServlet.java
package com.anthony.history;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.anthony.entity.Book;
import com.anthony.util.DBUtil;
public class ShowAllBooksServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
out.write("本网站有以下好书:<br/>");
Map<String, Book> books = DBUtil.findAllBooks();
for (Map.Entry<String, Book> b : books.entrySet()) {
out.write("<a href='"+req.getContextPath()+"/cookie/showBookDetail?id="+b.getKey()+" ' target='_blank'>"+b.getValue().getName()+"</a><br/>");
}
out.write("<hr/>你最近浏览过的书有:<br/>");
//拿到cookie
Cookie[] cookies = req.getCookies();
for (int i = 0; cookies != null && i < cookies.length; i++) {
if("bookHistoryId".equals(cookies[i].getName())) {
String value = cookies[i].getValue();
String[] ids = value.split("-"); //切割 然后遍历
for (int j = 0; j < ids.length; j++) {
//根据id查找书
Book book = DBUtil.findBookById(ids[j]);
//out.print(book.getName() + "<br/>");
out.write("<a href='"+req.getContextPath()+"/cookie/showBookDetail?id=" + book.getId()+" ' target='_blank'>" + book.getName()+"</a><br/>");
}
}
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
com.anthony.history.ShowBookDetail.java
package com.anthony.history;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.LinkedList;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.anthony.entity.Book;
import com.anthony.util.DBUtil;
public class ShowBookDetail extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
//显示图书的详细信息
//获得id
String id = req.getParameter("id");
Book book = DBUtil.findBookById(id);
out.print(book);
//把当前浏览过书的ID写到cookie(客户端)
String bookHistoryId = organizeId( id, req);
Cookie ck = new Cookie("bookHistoryId", bookHistoryId);
ck.setPath("/");
ck.setMaxAge(Integer.MAX_VALUE);// 一直保存
resp.addCookie(ck);
}
private String organizeId(String id, HttpServletRequest req) {
//拿到cookie
Cookie[] cookies = req.getCookies();
if(cookies == null) {
return id; //第一次请求时没有cookie
}
//判断cookie数组中有没有叫做historyBookId的cookie
Cookie historyBookId = null;
for (int i = 0; i < cookies.length; i++) {
if("bookHistoryId".equals(cookies[i].getName())) {
historyBookId = cookies[i];
}
}
//如果没有想要的cookie
if(historyBookId == null) {
return id;
}
String value = historyBookId.getValue(); //得到可能时 2-1-3这样字符串
String[] values = value.split("-"); //切割拿到全部id
LinkedList<String> list = new LinkedList<String>(Arrays.asList(values));
//这里我们模拟历史纪录只能存3本书的场景
if(list.size() < 3) { // 1-2
if(list.contains(id)) {
list.remove(id); // 如果 1-2 中包含2, 那么就删除2
}
}else { //三本数
if(list.contains(id)) {
list.remove(id);// 从3本书中删除id对应这本,后面还会添加回来
}else {
list.removeLast(); //删除最后一本,后面会添加id新纪录进去
}
}
list.addFirst(id); // 62行删除的id,这行会加回来,这样浏览先后顺序就对了
//从浏览先后顺序倒叙输出三本书ID
StringBuffer sb = new StringBuffer();
for (int i = 0; i < list.size(); i++) {
if( i > 0) {
sb.append("-"); // 1-2-3
}
sb.append(list.get(i));
}
return sb.toString();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
启动tomcat,部署代码,就可以看到需求描述的场景。