「最近瀏覽」功能能顯著提升電商轉化率。本文展示基於 Cookie 的輕量級實現:無需數據庫、無需登錄、瀏覽器端持久化,適合匿名用戶行為追蹤。
public class Book implements Serializable {
private String id, name, price, auth, publish, description;
// 構造器、Getter/Setter 省略
}
public class BookDao {
private static Map<String, Book> bookMap = new LinkedHashMap<>();
static {
bookMap.put("1", new Book("1", "Java核心技術", "99.0", "Cay Horstmann", "機械工業出版社", "經典入門"));
bookMap.put("2", new Book("2", "Effective Java", "89.0", "Joshua Bloch", "Addison-Wesley", "進階必讀"));
bookMap.put("3", new Book("3", "Java併發編程實戰", "109.0", "Brian Goetz", "Addison-Wesley", "併發聖經"));
}
public static Map<String, Book> getBooks() { return bookMap; }
public static Book getBook(String id) { return bookMap.get(id); }
}
@WebServlet("/bookList")
public class BookListServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
// 1. 顯示所有書籍鏈接
for (Map.Entry<String, Book> entry : BookDao.getBooks().entrySet()) {
Book book = entry.getValue();
out.write("<a href='" + req.getContextPath() + "/bookDetail?id=" + book.getId() + "'>"
+ book.getName() + "</a><br>");
}
out.write("<hr>");
// 2. 讀取 Cookie 顯示最近瀏覽
Cookie[] cookies = req.getCookies();
Cookie historyCookie = null;
if (cookies != null) {
for (Cookie c : cookies) if ("recentBooks".equals(c.getName())) historyCookie = c;
}
if (historyCookie == null) {
out.write("暫無瀏覽記錄!");
} else {
out.write("您最近瀏覽過的書籍:<br>");
String[] ids = historyCookie.getValue().split(",");
for (String id : ids) {
Book book = BookDao.getBook(id);
if (book != null) out.write(book.getName() + "<br>");
}
}
}
}
@WebServlet("/bookDetail")
public class BookDetailServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
String id = req.getParameter("id");
Book book = BookDao.getBook(id);
if (book == null) {
resp.getWriter().write("書籍不存在!");
return;
}
// 顯示詳情
PrintWriter out = resp.getWriter();
out.write("<h1>" + book.getName() + "</h1>");
out.write("<p>作者:" + book.getAuth() + "</p>");
out.write("<p>價格:" + book.getPrice() + "</p>");
out.write("<p>出版社:" + book.getPublish() + "</p>");
out.write("<p>描述:" + book.getDescription() + "</p>");
// 更新最近瀏覽 Cookie(最多保留 3 條,新訪問置頂,去重)
String newHistory = book.getId();
Cookie[] cookies = req.getCookies();
Cookie historyCookie = null;
if (cookies != null) {
for (Cookie c : cookies) if ("recentBooks".equals(c.getName())) historyCookie = c;
}
if (historyCookie != null) {
String[] oldIds = historyCookie.getValue().split(",");
StringBuilder sb = new StringBuilder();
sb.append(book.getId()).append(",");
for (String oldId : oldIds) {
if (!oldId.equals(book.getId()) && sb.toString().split(",").length < 3) {
sb.append(oldId).append(",");
}
}
newHistory = sb.substring(0, sb.length() - 1); // 移除尾部逗號
}
Cookie newCookie = new Cookie("recentBooks", newHistory);
newCookie.setMaxAge(3600 * 24 * 30); // 30 天
newCookie.setPath(req.getContextPath());
resp.addCookie(newCookie);
}
}
recentBooks 存儲書籍 ID 列表,逗號分隔。setMaxAge(30*24*3600) 實現 30 天持久化。setPath(contextPath) 限制在當前應用下發送。| 局限 | 改進方案 |
|---|---|
| Cookie 大小限制(4KB),不可存大量數據 | 改用 Server-side Session + Redis,Cookie 僅存 SessionID |
| 用戶清除 Cookie 即丟失歷史 | 登錄用戶將歷史同步至數據庫,多端同步 |
| 不同瀏覽器/設備數據不互通 | 用戶體系統一標識後合併歷史 |
| 敏感信息洩露風險 | 僅存非敏感 ID,詳情由服務端查詢 |
基於 Cookie 的最近瀏覽實現簡單、無狀態、零後端存儲成本,適合中小型項目快速上線。隨著業務增長,建議遷移至服務端 Session/Redis 方案,實現多端同步與個性化推薦。