JavaWeb学习笔记——会话管理(Cookie 和 Session)

目录

会话管理

Web 应用程序是使用 Http 协议传输数据的,Http 协议是无状态的协议,一旦数据交换完毕,则连接就会自动关闭,再次交换数据需要建立新的连接,这就意味着服务器无法从连接上跟踪会话。会话跟踪是 Web 程序中常用的技术,用来跟踪用户整个会话,通常的会话跟踪技术是 Cookie 和 Session 技术。 Cookie 通过在客户端记录信息确定用户身份, Session 通过在服务器端记录用户信息。

Cookie 实际上是一小段的文本信息,客户端请求服务器,如果服务器需要记录该用户的状态,就使用 response 向客户端发送一个 Cookie。客户端会将 cookie 保存起来,当浏览器再次访问该网站是,浏览器把请求的网址连同该 cookie 一同提交给服务器,服务器检查该 cookie,以此来辨认用户状态,此外,服务器还可以根据需要来修改 cookie 的内容。

Java 中把 Cookie 封装成为 javax.servlet.http.Cookie 类,每个 Cookie 都是该类的对象。通过 request.getCookies() 方法获取客户端提交的所有 cookie,通过 response.addCookie(Cookie cookie) 向客户端发送 Cookie。Cookie 对象使用 key-value 键值对的形式来保存用户的状态,一个 Cookie 对象保存一个属性对。

属性名 描述
String name 该 cookie 的名称,cookie 一旦创建,名称便不可更改
String value 该 cookie 的属性值
String path 该 cookie 的使用路径,路径最后必须以\结尾
int maxAge 该 cookie 的有效时间,以秒为单位,如果为0,则表示删除该 cookie
String domain 可以访问该 cookie 的域名,第一个字符必须以.开头

Cookie 的 maxAge 属性决定着 cookie 的有效期,通过 int getMaxAge()void setMaxAge() 来获取和设置 cookie 的有效期。

  • 有效期为正数:持久化 cookie,只要在 maxAge 属性之前,cookie 都有效;
  • 有效期为负数:cookie 在本浏览器窗口以及子窗口中有效,关闭浏览器则失效,默认值为 -1
  • 有效期为 0 :表示删除该 cookie;

Cookie 并不提供删除和修改操作,如果要修改 Cookie,只需要新建一个同名的 Cookie,并添加到 response 中覆盖原来的 Cookie;

如果需要删除 Cookie,需要新建一个同名的 Cookie,并且将其的 maxAge 属性设置为 0 ,并添加到 response 中覆盖原来的 Cookie;

2. 案列

2.1 显示用户上次浏览时间

浏览器首次访问该 Servlet 并未携带任何的 cookie ,然后在 servlet 中创建 lastAccessTimeCookie cookie 用来保存当前用户访问该页面时的时间。随后用户再次访问该 Servlet 时候,就会读取lastAccessTimeCookie 并显示出上次访问该页面的时间。

package com.cookie.lastAccessTime;

import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/LastAccessTime")
public class LastAccessTime extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        
        
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (int i=0; i<cookies.length; i++) {
                Cookie cookie = cookies[i];
                if (cookie.getName().equals("lastAccessTime")) {
                    long time = Long.valueOf(cookie.getValue());
                    out.println("<h3>上次访问时间为:"+new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒").format(new Date(time))+"</h3>");
                } 
                    
            }
        }
        
        Cookie lastAccessTimeCookie = new Cookie("lastAccessTime",String.valueOf(System.currentTimeMillis()));
        response.addCookie(lastAccessTimeCookie);
    }

}

2.2 记录用户访问次数

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page errorPage="login.jsp" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>显示用户访问次数</title>
</head>
<body>

<%
    // 定义用户名
    String username = "";
    // 记录访问次数,初始化为 0 
    int visitTimes = 0;
    // 获取 cookie
    Cookie[] cookies = request.getCookies();
    
    if (cookies != null) {
        for (int i=0; i<cookies.length; i++) {
            //  判断是否有 username cookie,如果有,将 cookie 的值赋值给 username
            if (cookies[i].getName().equals("username")) {
                username = cookies[i].getValue();
            // 判断是否有 visitTimes cookie,如果有,将 cookie 的值赋值给 visitTimes
            } else if (cookies[i].getName().equals("visitTimes")) {
                visitTimes = Integer.valueOf(cookies[i].getValue());
            }
        }
    }
    /*
        判断 username 是否为 null 或者是否为"";
        1. true : 进入下一步
        2. false : 抛出异常,跳转到 errorPage 页面
    */
    if (username.trim().length() == 0 || username == null) {
        throw new Exception();
    }
    
    // 向浏览器中添加 visitTimesCookie
    Cookie visitTimesCookie = new Cookie("visitTimes",String.valueOf(++visitTimes));
    response.addCookie(visitTimesCookie);
%>
    <fieldset>
        <legend>用户登录情况</legend>
        <form action="">
            <table>
                <tr>
                    <td>用户名:</td>
                    <td><%=username %></td>
                </tr>
                <tr>
                    <td>浏览次数:</td>
                    <td><%=visitTimes %></td>
                </tr>
            </table>
        </form>
    </fieldset>
</body>
</html>

程序使用 cookie 记录用户的访问次数,如果用户没有登录,则显示登录页面。工作原理是程序先检查 cookie 中是否包含 username 属性的 cookie ,如果没有,则抛出异常,跳转到 errorPage 进行登录。登录后再次重定向到页面。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<%
// 判断表单的提交方法,如果是 post 则执行内部代码
if (request.getMethod().equalsIgnoreCase("post")) {
    // 获取表单的提交数据
    String username = request.getParameter("username");
    // 将表单提交的数据存入usernameCookie中,并发送给浏览器
    Cookie usernameCookie = new Cookie("username",username);
    response.addCookie(usernameCookie);
    // 重定向到index.jsp页面
    response.sendRedirect("/visitTimes/index.jsp");
    return;
}
%>
<fieldset>
    <legend>登录页面</legend>
    <form action="login.jsp" method="post">
        <table>
            <tr>
                <td>帐号:</td>
                <td><input type="text" name="username" /></td>
            </tr>
            <tr>
                <td>密码:</td>
                <td><input type="password" name="password" /></td>
            </tr>
        </table>
        <input type="submit" value="提交登录信息" />
    </form>
</fieldset>
</body>
</html>

中文字符与英文字符不同,中文属于 Unicode 编码字符,在内存中占4个字符,而英文字符属于ASCII字符,在内存中占2个字符。Cookie 中使用 Unicode 字符时,需要对 Unicode 字符进行编码,否则会出现乱码。

  • 编码使用 java.net.URLEncoder 类的 encode(String str, String encoding) 方法;
  • 解码使用 java.net.URLDecoder 类的 decode(String str, String encoding) 方法;
package com.cookie.CN;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLDecoder;
import java.net.URLEncoder;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/encode")
public class EncodingServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        
        PrintWriter out = response.getWriter();

        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (int i = 0; i < cookies.length; i++) {
                if (cookies[i].getName().equals(URLEncoder.encode("姓名:", "UTF-8"))) {
                    out.println(URLDecoder.decode(cookies[i].getName(), "UTF-8") + " " + URLDecoder.decode(cookies[i].getValue(), "UTF-8"));
                }
            }
        }

        Cookie encodeCookie = new Cookie(URLEncoder.encode("姓名:", "UTF-8"), URLEncoder.encode("Java 路上的小蚂蚁", "UTF-8"));
        response.addCookie(encodeCookie);
    }

}

2.4 实现浏览历史商品

实现原理:创建ListItemServlet 做为首页,显示所有的商品。通过点击商品跳转到单个商品全部信息的页面,该页面设置一个记录每次浏览商品 id 号的 Cookie,每次访问后,在原有 cookie 值后面添加 _id 作为新的 cookie 值。

所用类及 Servlet:

  1. Book类: 简单 Java 类,提供 id,title,price 等属性;
  2. DB类:模拟数据库,类中使用 Map<String, Book> 键值形式保存数据,并且提供一个返回保存所有书的 map 集合;
  3. ListItem Servlet : 显示所有商品的列表;
  4. BuyServlet Servlet : 用来处理 Cookie;

Cookie 显示浏览过的历史记录

2.4.1 Book 类的搭建
package com.cookie.history.item;

public class Book {
    
    private int id;
    private String title;
    private double price;
    
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public double getPrice() {
        return price;
    }
    public void setPrice(double price) {
        this.price = price;
    }
    
    public Book() {}
    public Book(int id, String title, double price) {
        super();
        this.id = id;
        this.title = title;
        this.price = price;
    }
    
}
2.4.2 DB类,模拟数据库
package com.cookie.history.item;

import java.util.HashMap;
import java.util.Map;

public class DB {

    private static Map<String, Book> map = new HashMap<String,Book>();
    // 向 Map 集合中保存所有书籍
    static {
        map.put("1", new Book(1001,"Head First Java",89.5));
        map.put("2", new Book(1002,"Head First PHP",80.5));
        map.put("3", new Book(1003,"Head First Phoyne",75.5));
        map.put("4", new Book(1004,"Head First C++",105.0));
        map.put("5", new Book(1005,"Head First Servlet & JSP",69.5));
    }
    
    static Map<String,Book> getAll() {
        return map;
    }
}
2.4.3 ListItem 显示所有商品信息
package com.cookie.history.item;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/listItem")
public class ListItem extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        PrintWriter out = response.getWriter();
        // 获取所有书
        Map<String,Book> map = DB.getAll();
        out.println("<h2>本站有如下书籍在销:</h2>");
        
        Set<Entry<String, Book>> set = map.entrySet();
        Iterator<Entry<String,Book>> it = set.iterator();
        out.println("<ul>");
        while (it.hasNext()) {
            Entry<String,Book> entry = it.next();
            // 遍历所有商品
            out.println("<li><a href='buyServlet?id="+entry.getKey()+"'/>"+entry.getValue().getTitle()+"</a></li>");
        }
        out.println("</ul>");
        
        
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            out.println("<br/><br/><br/><h2>您在本站买过如下书籍:</h2>");
            out.println("<ul>");
            for (int i=0; i<cookies.length; i++) {
                if (cookies[i].getName().equals("bookHistoryIds")) {
                    Cookie bookIdsCookie = cookies[i];
                    // 拆分 cookie 值,去掉每个 ID 之间的"_" 
                    String[] bookIds = bookIdsCookie.getValue().split("\\_");
                    for (int j=0; j<bookIds.length; j++) {
                        out.println("<li>"+map.get(bookIds[j]).getTitle()+"</li>");
                    }
                }
            }
            out.println("<ul>");
        }
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

}
package com.cookie.history.item;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/buyServlet")
public class BuyServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        PrintWriter out = response.getWriter();
        
        Map<String,Book> map = DB.getAll();
        String id = request.getParameter("id");
        // 通过提交过来的 ID 获取指定的书
        Book book = map.get(id);
    
        out.println("<h2>你所查看的书籍信息如下:</h2>");
        out.println("编号:" + book.getId()+"<br/>");
        out.println("书名:" + book.getTitle()+"<br/>");
        out.println("价格:" + book.getPrice()+"<br/>");
        
        out.print("<a href='listItem'>返回首页</a>");
        
        // 将所有浏览过书籍的 ID 信息保存在 cookie 中
        Cookie bookHistoryIdsCookie = new Cookie("bookHistoryIds",makeHistoryIds(request,id));
        bookHistoryIdsCookie.setMaxAge(Integer.MAX_VALUE);
//      bookHistoryIdsCookie.setMaxAge(0);
        response.addCookie(bookHistoryIdsCookie);
        
    }

    private String makeHistoryIds(HttpServletRequest request, String id) {
        
        String lastTimeId = "";
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (int i=0; i<cookies.length; i++) {
                if (cookies[i].getName().equals("bookHistoryIds")) {
                    lastTimeId = cookies[i].getValue();
                }
            }
        }
        
        // 如果是第一次访问,则将 get 方法中的 id 返回给 cookie
        if (lastTimeId == null || lastTimeId.trim().length() == 0) {
            return id;
        } else {
            LinkedList<String> idsList = new LinkedList<String>();
            // 将 cookie 中的值以数组的形式保存在 ids 中
            String[] ids = lastTimeId.split("\\_");
            List<String> list = Arrays.asList(ids);
            idsList.addAll(list);
            /*
             *  判断 cookie 中的 id 个数是否超过 3个
             *      
             *      如果是3个:
             *          其中是否有刚提交过来的id
             *          如果有 : 删掉其中的 id,并将 id 添加在第一位置;
             *          如果没有:删掉集合中最后一个 id,并将刚提交过来的 id 放在第一位置;
             *  如果小于3:
             *          其中是否有刚提交过来的id
             *          如果有 : 删掉其中的 id,并将 id 添加在第一位置;
             *          如果没有:将刚提交过来的 id 放在第一位置;
             */
            if (idsList.size()<3) {
                if (idsList.contains(id)) {
                    idsList.remove(id);
                    idsList.addFirst(id);
                } else {
                    idsList.addFirst(id);
                } 
            } else {
                if (idsList.contains(id)) {
                    idsList.remove(id);
                    idsList.addFirst(id);
                } else {
                    idsList.removeLast();
                    idsList.addFirst(id);
                } 
            }
            
            StringBuffer buffer = new StringBuffer();
            for (int i=0; i<idsList.size(); i++) {
                buffer.append(idsList.get(i)).append("_");
            }
            // 将新的 ids 保存到 cookie 中
            return buffer.deleteCharAt(buffer.length() - 1).toString();
        }
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

}

二、 Session

在 Web 应用中,也经常使用 Session 来记录客户端状态,Session 是服务器端使用的一种记录客户端状态的机制,但是过多的 Session 相应的会增加服务器的存储压力。

Session 是保存在服务器上的,客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上,这就是 Session 。客户端浏览器再次访问是只需要从该 Session 中查找到该客户的状态就可以了。

Session 对应的类为 javax.servlet.http.HttpSession 。每个来访者对应一个 Session 对象,所有该客户的状态信息都保存在 Session 对象中,Session 对象是用户第一次访问服务器getSession()时候的时候创建的。 Session 也是一种键值对的属性,通过getAttribute(String key)setAttribute(String key , Object value) 方法读写客户端状态信息,通过 request.getSession() 方法获取该客户的 Session。

1. Session 的生命周期

Session 保存在服务器中,为了获得更高的存取速度,一帮都是把 Session 放在内存中,每个用户都会拥有一个独立的 Session,因此 Seesion 的信息应该尽量精简,一般 Session 都是存放 JavaBean 类型;

当用户第一次访问服务器getSession()时候,服务器就会自动为该用户创建一个 Session,Session 生成后,只要用户继续访问,服务器就会更新 Session 的最后访问时间,并且维护该 Session;

Session 的超时时间为 maxInactiveInterval 属性,通过对应的 settergetter 方法可以对 Session 的超时时间进行修改,此外, Session 超时时间也可以在 web.xml 中进行和使用 Session 的invalidate() 进行修改。

<session-config>
    <!-- 单位:分钟 -->
    <session-timeout>60</session-timeout>
</session-config>

2. Session 常用方法

方法名 描述
void setAttribute(String attribute, Object value) 设置 Session 属性值,可以为任何Java Object 类型,常为JavaBean;
String getAttribute(String attribute) 返回 Session 的属性值;
Enumeration getAttributes() 返回 Session 中存在的属性名;
void removeAttribute(String attribute) 移除 Session 属性;
String getId() 返回 Session 的 id,id 由服务器自动创建,并且保证唯一性;
long getCreationTime() 返回 Session 的创建时间;
long getLastAccessdTime() 返回 Session 的最后活跃时间;
int getMaxInactiveInterval() 返回 Session 的超时时间,单位为秒;
void setMaxInactiveInterval(int second) 设置 Session 超时时间,单位为秒;
boolean isNew() 返回该 Session 是否为新建 Session;
void invalidate() 使该 Session 失效;
package com.session.demo;

import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.sun.org.apache.bcel.internal.generic.NEW;

import sun.security.action.PutAllAction;

@WebServlet("/demo01")
public class SessionDemo01 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        
        PrintWriter out = response.getWriter();
        
        // 创建 Session 对象
        HttpSession session = request.getSession();
        // 设置 session 属性名和属性值
        session.setAttribute("product", "Lenovo Computer");
        // 判断 session 是否为新建 session
        out.println("是否为新建 session :"+session.isNew()+"<br/>");
        // 得到 session 的创建时间
        out.println("session 的创建时间为:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(session.getCreationTime()))+"<br/>");
        // 设置 session 的有效时间,单位为秒
        session.setMaxInactiveInterval(60 * 30);
        // 获取 session 的超时时间
        out.println("session 的有效时间为:"+session.getMaxInactiveInterval()+"秒<br/>");
        // 获取 session 的 ID
        out.println("session 的 ID :"+session.getId()+"<br/>");
        
    
    }

}

3. Session 原理和持久化

虽然 session 是保存在服务器中,但是对客户端是透明的,session 的正常运行需要使用 cookie 作为识别标志。HTTP 协议是无状态的,session 无法依据 HTTP状态来判断是否为同一客户。session 机制为了能够正常运行,需要向客户端浏览器发送一个名为 JSESSIONID 的 cookie,它的值是 session 的 id (session.getId() 的返回值),session 依据 cookie 来识别是否为同一客户。

该 cookie 为服务器自动生成,maxAge 属性值一般为-1,表示仅当当前浏览器内有效,并且个浏览器窗口间不共享,关闭浏览器就会失效。 如果需要在关闭浏览器之后继续使用之前 session,需要将 名为 JSESSIONID 的 cookie 进行持久化。

模拟购物案列,实现关闭浏览器之后能继续查看之前购买商品的案列:

  1. index.html:两个超链接,购买链接跳转到 BuySessionServlet;结帐链接跳转到 PaySessionServlet
  2. BuySessionServlet:生成 Session,并持久化 JSESSIONID 的 cookie;
  3. PaySessionServlet:获取BuySessionServlet中的 session 值;

index.html:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>首页</title>
    </head>
    <body>
        <a href="/session/BuySession">购买</a>
        &nbsp;&nbsp;&nbsp;&nbsp;
        <a href="/session/PaySession">结帐</a>
    </body>
</html>

BuySessionServlet:

package com.session.demo;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@WebServlet("/BuySession")
public class BuySession extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        
        PrintWriter out = response.getWriter();
        
        out.println("<html><head>"
                + "<meta charset='UTF-8'/>"
                + "<title>BuySession</title>"
                + "<head>"
                + "<body>");
        HttpSession session = request.getSession();
        session.setAttribute("product", "Compter");
        
        // Session 依靠 cookie 而存在,如果此时浏览器关闭,则再次访问结帐页面时后,将显示null
        // 实现浏览器关闭后还能获取 Session 中的值,则需要将一个名为JSESSIONID的cookie回写给客户端,并持久化该 cookie
        
        Cookie cookie = new Cookie("JSESSIONID", session.getId());
        cookie.setPath("/session");
        cookie.setMaxAge(60 * 30);
        response.addCookie(cookie);
        
        out.println("<a href='/session/index.html'>返回首页</a></body></html>");

    }

}

PaySessionServlet:

package com.session.demo;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.websocket.Session;

@WebServlet("/PaySession")
public class PaySession extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        
        PrintWriter out = response.getWriter();
        
        out.println("<html><head>"
                + "<meta charset='UTF-8'/>"
                + "<title>PaySession</title>"
                + "<head>"
                + "<body>");
        
        // 此时不需要创建新的session,只需要得到session,所以在创建session对象时候传入 false;
        HttpSession session = request.getSession();
        request.getSession(false);
        String product = (String) session.getAttribute("product");
        out.println("你购买的商品是:" + product);
        
        out.println("<a href='/session/index.html'>返回首页</a></body></html>");
    }

}

URL 地址重写是对客户端不支持 Cookie 的解决方案,URL 地址重写的原理是将该用户的 session 的 id 信息重写到 URL 地址中,服务器能够解析重写后的 URL 获取 session 的 id。这样即使客户端不支持 cookie,也可以使用 session 来记录用户状态。

URL 地址重写会自动判断客户端是否支持 Cookie,如果支持 Cookie,会将 URL 原封不动显示出来;如果不支持 Cookie ,则会将用户 session 的 id 重写到 URL 中。

URL 重写的两种方式:

  1. URL 重写:response.encodeURL(String url)
  2. 重定向 URL 地址的重写:response.encodeRedirectURL(String url)
模拟 URL 地址重写
  1. JavaBean : Book
  2. ListItem(Servlet) : 网站首页,显示网站所有的在售书籍;
  3. CartServlet : 购物车功能,显示用户查看过的所有书籍;
  4. PayServlet : 付款结帐功能,该页面显示用户所看过书籍的总价格;

JavaBean —— Book

package com.session.shopping;

public class Book {
    
    private int id;
    private String title;
    private double price;
    
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public double getPrice() {
        return price;
    }
    public void setPrice(double price) {
        this.price = price;
    }
    
    public Book() {}
    public Book(int id, String title, double price) {
        super();
        this.id = id;
        this.title = title;
        this.price = price;
    }
    
}

ListItem(Servlet) : 网站首页,显示网站所有的在售书籍

package com.session.shopping;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/listItem")
public class ListItem extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        PrintWriter out = response.getWriter();
        // 获取所有书
        Map<String,Book> map = DB.getAll();
        out.println("<h2>本站有如下书籍在销:</h2>");
        
        Set<Entry<String, Book>> set = map.entrySet();
        Iterator<Entry<String,Book>> it = set.iterator();
        out.println("<ul>");
        while (it.hasNext()) {
            Entry<String,Book> entry = it.next();
            // 遍历所有商品
            String url = response.encodeURL("cartServlet?id="+entry.getKey());
            // 注意此处,因为 cookie 被禁用,如果想要使用 session ,超链接的地址也需要进行 URL 重写
            out.println("<li>"+entry.getValue().getTitle()+"&nbsp;&nbsp;<a href='"+url+"'/>添加到购物车</a></li>");
        }
        out.println("</ul>");
        
    }

}

CartServlet : 购物车功能,显示用户查看过的所有书籍

package com.session.shopping;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.jasper.tagplugins.jstl.core.Out;

import com.sun.xml.internal.bind.v2.model.core.ID;

@WebServlet("/cartServlet")
public class CartServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        PrintWriter out = response.getWriter();

        Book book = DB.getAll().get(request.getParameter("id"));

        HttpSession session = request.getSession();
        List<Book> list = (List<Book>) session.getAttribute("bookList");
        if (list == null) {
            list = new ArrayList<Book>();
            session.setAttribute("bookList", list);
        }

        list.add(book);
        out.println("<h1>您浏览过的书籍信息如下:</h1>");
        for (int i = 0; i < list.size(); i++) {
            out.print("书籍名称:" + list.get(i).getTitle());
            out.println("<br/>");
            out.println("销售价格:" + list.get(i).getPrice());
            out.println("<br/>");
            out.println("<br/>");
        }

        out.println("<br/>");
        out.println("<br/>");

        out.println("<br/>");
        out.println("<br/>");
        out.println("<br/>");

        // 注意此处,因为 cookie 被禁用,如果想要使用 session ,超链接的地址也需要进行 URL 重写
        out.println("<a href='"+response.encodeURL("/session/listItem")+"'>返回首页</a>");
        out.println("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
        out.println("<a href='"+response.encodeURL("/session/payServlet")+"'>提交结帐</a>");

    }

}

PayServlet : 付款结帐功能,该页面显示用户所看过书籍的总价格

package com.session.shopping;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@WebServlet("/payServlet")
public class PayServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        
        response.setContentType("text/html;charset=UTF-8");
        request.setCharacterEncoding("UTF-8");

        double totalPrice = 0.0;
        
        PrintWriter out = response.getWriter();
        
        HttpSession session = request.getSession();
        // 只获取,不创建新的 session
        request.getSession(false);
        List<Book> list = (List<Book>) session.getAttribute("bookList");
        
        if (list != null && list.size() != 0) {
            out.println("你一共添加过:<br/>");
            for (int i=0; i<list.size();i++) {
                totalPrice += list.get(i).getPrice();
                out.println(list.get(i).getTitle()+"<br/>");
            }
        }
        
        out.println("总共需要支付:" +totalPrice+ "元");
        
    }

}

猜你喜欢

转载自www.cnblogs.com/martin0319/p/9383667.html