《Servlet、JSP和Spring MVC初學指南》——2.4 HttpSession對象
本節書摘來自異步社區《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?'>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訪問應用的主界麵:
https://localhost:8080/app02a/products
該URL會展示商品列表,如圖2.9所示。
單擊Details(詳細)鏈接,Servlet會顯示所選產品的詳細信息,如圖2.10所示。請注意頁麵上的輸入框和Buy按鈕,輸入一個數字並單擊Buy按鈕,就可以添加該產品到購物車中。
提交購物表單,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();
…
最後更新:2017-05-27 18:31:10