《Servlet、JSP和Spring MVC初学指南》——2.4 HttpSession对象

简介: 没有参数的getSession方法会返回当前的HttpSession,若当前没有,则创建一个返回。getSession(false)返回当前HttpSession,如当前存在,则返回null。getSession(true)返回当前HttpSession,若当前没有,则创建一个getSession(true)同getSession()一致。

本节书摘来自异步社区《Servlet、JSP和Spring MVC初学指南》一书中的第2章,第2.4节,作者:【加】Budi Kurniawan(克尼亚万) , 【美】Paul Deck著,更多章节内容可以访问云栖社区“异步社区”公众号查看

2.4 HttpSession对象

在所有的会话跟踪技术中,HttpSession 对象是最强大和最通用的。一个用户可以有且最多有一个HttpSession,并且不会被其他用户访问到。

HttpSession对象在用户第一次访问网站的时候自动被创建,你可以通过调用HttpServletRequest的getSession方法获取该对象。getSession有两个重载方法:

HttpSession getSession()

HttpSession getSession(boolean create)

没有参数的getSession方法会返回当前的HttpSession,若当前没有,则创建一个返回。getSession(false)返回当前HttpSession,如当前存在,则返回null。getSession(true)返回当前HttpSession,若当前没有,则创建一个getSession(true)同getSession()一致。

可以通过HttpSession的setAttribute方法将值放入HttpSession,该方法签字如下:

void setAttribute(java.lang.String name, java.lang.Object value)
请注意,不同于URL重新、隐藏域或cookie,放入到HttpSession 的值,是存储在内存中的,因此,不要往HttpSession放入太多对象或大对象。尽管现代的Servlet容器在内存不够用的时候会将保存在HttpSessions的对象转储到二级存储上,但这样有性能问题,因此小心存储。

此外,放到HttpSession的值不限于String类型,可以是任意实现java.io.Serializable的java对象,因为Servlet容器认为必要时会将这些对象放入文件或数据库中,尤其在内存不够用的时候,当然你也可以将不支持序列化的对象放入HttpSession,只是这样,当Servlet容器视图序列化的时候会失败并报错。

调用setAttribute方法时,若传入的name参数此前已经使用过,则会用新值覆盖旧值。
通过调用HttpSession的getAttribute方法可以取回之前放入的对象,该方法的签名如下:

java.lang.Object getAttribute(java.lang.String name)
HttpSession 还有一个非常有用的方法,名为getAttributeNames,该方法会返回一个Enumeration 对象来迭代访问保存在HttpSession中的所有值:

java.util.Enumeration<java.lang.String> getAttributeNames()
注意,所有保存在HttpSession的数据不会被发送到客户端,不同于其他会话管理技术,Servlet容器为每个HttpSession 生成唯一的标识,并将该标识发送给浏览器,或创建一个名为JSESSIONID的cookie,或者在URL后附加一个名为jsessionid 的参数。在后续的请求中,浏览器会将标识提交给服务端,这样服务器就可以识别该请求是由哪个用户发起的。Servlet容器会自动选择一种方式传递会话标识,无须开发人员介入。

可以通过调用 HttpSession的getId方法来读取该标识:

java.lang.String getId()
此外,HttpSession.还定义了一个名为invalidate 的方法。该方法强制会话过期,并清空其保存的对象。默认情况下,HttpSession 会在用户不活动一段时间后自动过期,该时间可以通过部署描述符的 session-timeout 元素配置,若设置为30,则会话对象会在用户最后一次访问30分钟后过期,如果部署描述符没有配置,则该值取决于Servlet容器的设定。

大部分情况下,你应该主动销毁无用的HttpSession,以便释放相应的内存。

可以通过调用HttpSession 的getMaxInactiveInterval 方法来查看会话多久会过期。该方法返回一个数字类型,单位为秒。调用setMaxInactiveInterval 方法来单独对某个HttpSession 设定其超时时间:

void setMaxInactiveInterval(int seconds)
若设置为0,则该HttpSession 永不过期。通常这不是一个好的设计,因此该 HttpSession 所占用的堆内存将永不释放,直到应用重加载或Servlet容器关闭。

清单2.9 ShoppingCartServlet 为一个小的有4个商品的在线商城,用户可以将商品添加到购物车中,并可以查看购物车内容,所用到的Product类可见清单2.7,ShoppingItem 类可见清单2.8,Product类定义了4个属性(id、name、description和price),ShoppingItem 有两个属性,即quantity和Product。
清单2.7 Product类

package app02a.httpsession;
public class Product {
    private int id;
    private String name;
    private String description;
    private float price;

    public Product(int id, String name, String description, float price)
       {
        this.id = id;
        this.name = name;
        this.description = description;
        this.price = price;
    }

    // get and set methods not shown to save space
}

清单2.8 ShoppingItem类

package app02a.httpsession;
public class ShoppingItem {
    private Product product;
    private int quantity;

    public ShoppingItem(Product product, int quantity) {
        this.product = product;
        this.quantity = quantity;
    }

    // get and set methods not shown to save space
}

清单2.9 ShoppingCartServlet类

package app02a.httpsession;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

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(name = "ShoppingCartServlet", urlPatterns = {
        "/products", "/viewProductDetails",
        "/addToCart", "/viewCart" })
public class ShoppingCartServlet extends HttpServlet {
    private static final long serialVersionUID = -20L;
    private static final String CART_ATTRIBUTE = "cart";

    private List<Product> products = new ArrayList<Product>();
    private NumberFormat currencyFormat = NumberFormat
            .getCurrencyInstance(Locale.US);

    @Override
    public void init() throws ServletException {
        products.add(new Product(1, "Bravo 32' HDTV",
                "Low-cost HDTV from renowned TV manufacturer",
                159.95F));
        products.add(new Product(2, "Bravo BluRay Player",
                "High quality stylish BluRay player", 99.95F));
        products.add(new Product(3, "Bravo Stereo System",
                "5 speaker hifi system with iPod player",
                129.95F));
        products.add(new Product(4, "Bravo iPod player",
                "An iPod plug-in that can play multiple formats",
                39.95F));
    }

    @Override
    public void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException,
            IOException {
        String uri = request.getRequestURI();
        if (uri.endsWith("/products")) {
            sendProductList(response);
        } else if (uri.endsWith("/viewProductDetails")) {
            sendProductDetails(request, response);
        } else if (uri.endsWith("viewCart")) {
            showCart(request, response);
        }
    }

    @Override
    public void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException,
            IOException {
        // add to cart
        int productId = 0;
        int quantity = 0;
        try {
            productId = Integer.parseInt(
                    request.getParameter("id"));
            quantity = Integer.parseInt(request
                    .getParameter("quantity"));
        } catch (NumberFormatException e) {
        }

        Product product = getProduct(productId);
        if (product != null && quantity >= 0) {

            ShoppingItem shoppingItem = new ShoppingItem(product,
                    quantity);
            HttpSession session = request.getSession();
            List<ShoppingItem> cart = (List<ShoppingItem>) session
                    .getAttribute(CART_ATTRIBUTE);
            if (cart == null) {
                cart = new ArrayList<ShoppingItem>();
                session.setAttribute(CART_ATTRIBUTE, cart);
            }
            cart.add(shoppingItem);
        }
        sendProductList(response);
    }

    private void sendProductList(HttpServletResponse response)
            throws IOException {
        response.setContentType("text/html");
        PrintWriter writer = response.getWriter();
        writer.println("<html><head><title>Products</title>" +
                    "</head><body><h2>Products</h2>");
        writer.println("<ul>");
        for (Product product : products) {
            writer.println("<li>" + product.getName() + "("
                    + currencyFormat.format(product.getPrice())
                    + ") (" + "<a href='viewProductDetails?id="
                    + product.getId() + "'>Details</a>)");
        }
        writer.println("</ul>");
        writer.println("<a href='viewCart'>View Cart</a>");
        writer.println("</body></html>");
    }

    private Product getProduct(int productId) {
        for (Product product : products) {
            if (product.getId() == productId) {
                return product;
            }
        }
        return null;
    }

    private void sendProductDetails(HttpServletRequest request,
            HttpServletResponse response) throws IOException {
        response.setContentType("text/html");
        PrintWriter writer = response.getWriter();
        int productId = 0;
        try {
            productId = Integer.parseInt(
                    request.getParameter("id"));
        } catch (NumberFormatException e) {
        }
        Product product = getProduct(productId);
        if (product != null) {
            writer.println("<html><head>"
                    + "<title>Product Details</title></head>"
                    + "<body><h2>Product Details</h2>"
                    + "<form method='post' action='addToCart'>");
            writer.println("<input type='hidden' name='id' "
                    + "value='" + productId + "'/>");
            writer.println("<table>");
            writer.println("<tr><td>Name:</td><td>"
                    + product.getName() + "</td></tr>");
            writer.println("<tr><td>Description:</td><td>"
                    + product.getDescription() + "</td></tr>");
            writer.println("<tr>" + "<tr>"
                    + "<td><input name='quantity'/></td>"
                    + "<td><input type='submit' value='Buy'/>"
                    + "</td>"
                    + "</tr>");
            writer.println("<tr><td colspan='2'>"
                    + "<a href='products'>Product List</a>"
                    + "</td></tr>");
            writer.println("</table>");
            writer.println("</form></body>");
        } else {
            writer.println("No product found");
        }

    }

    private void showCart(HttpServletRequest request,
            HttpServletResponse response) throws IOException {
        response.setContentType("text/html");
        PrintWriter writer = response.getWriter();
        writer.println("<html><head><title>Shopping Cart</title>"
                    + "</head>");
        writer.println("<body><a href='products'>" +
                    "Product List</a>");
        HttpSession session = request.getSession();
        List<ShoppingItem> cart = (List<ShoppingItem>) session
                .getAttribute(CART_ATTRIBUTE);
        if (cart != null) {
            writer.println("<table>");
            writer.println("<tr><td style='width:150px'>Quantity"
                    + "</td>"
                    + "<td style='width:150px'>Product</td>"
                    + "<td style='width:150px'>Price</td>"
                    + "<td>Amount</td></tr>");
            double total = 0.0;
            for (ShoppingItem shoppingItem : cart) {
                Product product = shoppingItem.getProduct();
                int quantity = shoppingItem.getQuantity();
                if (quantity != 0) {
                    float price = product.getPrice();
                    writer.println("<tr>");
                    writer.println("<td>" + quantity + "</td>");
                    writer.println("<td>" + product.getName()
                            + "</td>");
                    writer.println("<td>"
                            + currencyFormat.format(price)
                            + "</td>");
                    double subtotal = price * quantity;

                    writer.println("<td>"
                            + currencyFormat.format(subtotal)
                            + "</td>");
                    total += subtotal;
                    writer.println("</tr>");
                }
            }
            writer.println("<tr><td colspan='4' "
                    + "style='text-align:right'>"
                    + "Total:"
                    + currencyFormat.format(total)
                    + "</td></tr>");
            writer.println("</table>");
        }
        writer.println("</table></body></html>");

    }
}

ShoppingCartServlet 映射有如下URL:

/products:显示所有商品。
/viewProductDetails:展示一个商品的细节。
/addToCart:将一个商品添加到购物车中。
/viewCart:展示购物车的内容。
除/addToCart外,其他URL都会调用doGet方法。doGet 首先根据所请求的URL来生成相应内容:

String uri = request.getRequestURI();
        if (uri.endsWith("/products")) {
            sendProductList(response);
        } else if (uri.endsWith("/viewProductDetails")) {
            sendProductDetails(request, response);
        } else if (uri.endsWith("viewCart")) {
            showCart(request, response);
        }

如下URL访问应用的主界面:

http://localhost:8080/app02a/products
该URL会展示商品列表,如图2.9所示。
screenshot
单击Details(详细)链接,Servlet会显示所选产品的详细信息,如图2.10所示。请注意页面上的输入框和Buy按钮,输入一个数字并单击Buy按钮,就可以添加该产品到购物车中。
screenshot
提交购物表单,Web容器会调用ShoppingCartServlet的doPost方法,该方法将一个商品添加到该用户的HttpSession。

doPost方法首先构造一个ShoppingItem实例,传入用户所编辑的商品和数量:

        ShoppingItem shoppingItem = new ShoppingItem(product,
                quantity);

然后获取当前用户的HttpSession,并检查是否已经有一个名为“cart”的List对象:

        HttpSession session = request.getSession();
        List<ShoppingItem> cart = (List<ShoppingItem>) session
                .getAttribute(CART_ATTRIBUTE);

若不存在,则创建一个并添加到HttpSession中:

if (cart == null) {
                cart = new ArrayList<ShoppingItem>();
                session.setAttribute(CART_ATTRIBUTE, cart);
            }

最后,将所创建的ShoppingItem添加到该list中:

        cart.add(shoppingItem);

当用户单击View Cart(查看购物车)链接时,Web容器调用showCart方法,获取当前用户的HttpSession并调用其getAttribute方法来获取购物商品列表:

    HttpSession session = request.getSession();
    List<ShoppingItem> cart = (List<ShoppingItem>) session
            .getAttribute(CART_ATTRIBUTE);

然后迭代访问List对象,并将购物项发送给浏览器:

    if (cart != null) {
        for (ShoppingItem shoppingItem : cart) {
            Product product = shoppingItem.getProduct();
            int quantity = shoppingItem.getQuantity();
        …
相关文章
|
4天前
|
SQL Java 数据库连接
15:MyBatis对象关系与映射结构-Java Spring
15:MyBatis对象关系与映射结构-Java Spring
19 4
|
7天前
|
JSON Java 数据处理
Spring Boot与Jsonson对象:灵活的JSON操作实战
【4月更文挑战第28天】在现代Web应用开发中,JSON数据格式的处理至关重要。假设 "Jsonson" 代表一个类似于Jackson的库,这样的工具在Spring Boot中用于处理JSON。本篇博客将介绍Spring Boot中处理JSON数据的基本概念,并通过实际例子展示如何使用类似Jackson的工具进行数据处理。
18 0
|
9天前
|
XML Java 数据格式
手写spring第八章-定义标记类型Aware接口,实现感知容器对象
手写spring第八章-定义标记类型Aware接口,实现感知容器对象
6 0
|
9天前
|
XML Java 数据格式
手写spring第七章-完成便捷实现bean对象初始化和销毁方法
手写spring第七章-完成便捷实现bean对象初始化和销毁方法
7 0
|
9天前
|
前端开发 Java 应用服务中间件
Spring MVC常见面试题
Spring MVC常见面试题
6 0
|
11天前
|
Java Spring
Spring⼯⼚创建复杂对象
Spring⼯⼚创建复杂对象
31 11
|
12天前
|
设计模式 存储 前端开发
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式
|
23天前
|
数据采集 前端开发 Java
数据塑造:Spring MVC中@ModelAttribute的高级数据预处理技巧
数据塑造:Spring MVC中@ModelAttribute的高级数据预处理技巧
23 3
|
23天前
|
存储 前端开发 Java
会话锦囊:揭示Spring MVC如何巧妙使用@SessionAttributes
会话锦囊:揭示Spring MVC如何巧妙使用@SessionAttributes
14 1
|
23天前
|
前端开发 Java Spring
数据之桥:深入Spring MVC中传递数据给视图的实用指南
数据之桥:深入Spring MVC中传递数据给视图的实用指南
31 3