在WEB開(kāi)發(fā)中蹲盘,服務(wù)器可以為每個(gè)用戶瀏覽器創(chuàng)建一個(gè)會(huì)話對(duì)象(session對(duì)象)珊随,注意:一個(gè)瀏覽器獨(dú)占一個(gè)session對(duì)象(默認(rèn)情況下)。因此找岖,在需要保存用戶數(shù)據(jù)時(shí),服務(wù)器程序可以把用戶數(shù)據(jù)寫到用戶瀏覽器獨(dú)占的session中敛滋,當(dāng)用戶使用瀏覽器訪問(wèn)其它程序時(shí)许布,其它程序可以從用戶的session中取出該用戶的數(shù)據(jù),為用戶服務(wù)绎晃。
一蜜唾、Session簡(jiǎn)單介紹
在WEB開(kāi)發(fā)中杂曲,服務(wù)器可以為每個(gè)用戶瀏覽器創(chuàng)建一個(gè)會(huì)話對(duì)象(session對(duì)象),注意:一個(gè)瀏覽器獨(dú)占一個(gè)session對(duì)象(默認(rèn)情況下)袁余。因此擎勘,在需要保存用戶數(shù)據(jù)時(shí),服務(wù)器程序可以把用戶數(shù)據(jù)寫到用戶瀏覽器獨(dú)占的session中颖榜,當(dāng)用戶使用瀏覽器訪問(wèn)其它程序時(shí)棚饵,其它程序可以從用戶的session中取出該用戶的數(shù)據(jù),為用戶服務(wù)掩完。
二噪漾、Session和Cookie的主要區(qū)別
Cookie是把用戶的數(shù)據(jù)寫給用戶的瀏覽器。
Session技術(shù)把用戶的數(shù)據(jù)寫到用戶獨(dú)占的session中且蓬。
Session對(duì)象由服務(wù)器創(chuàng)建欣硼,開(kāi)發(fā)人員可以調(diào)用request對(duì)象的getSession方法得到session對(duì)象。
三缅疟、session實(shí)現(xiàn)原理
3.1分别、服務(wù)器是如何實(shí)現(xiàn)一個(gè)session為一個(gè)用戶瀏覽器服務(wù)的?
服務(wù)器創(chuàng)建session出來(lái)后存淫,會(huì)把session的id號(hào)耘斩,以cookie的形式回寫給客戶機(jī),這樣桅咆,只要客戶機(jī)的瀏覽器不關(guān)括授,再去訪問(wèn)服務(wù)器時(shí),都會(huì)帶著session的id號(hào)去岩饼,服務(wù)器發(fā)現(xiàn)客戶機(jī)瀏覽器帶session id過(guò)來(lái)了荚虚,就會(huì)使用內(nèi)存中與之對(duì)應(yīng)的session為之服務(wù)。
可以用如下的代碼證明:
第一次訪問(wèn)時(shí)籍茧,服務(wù)器會(huì)創(chuàng)建一個(gè)新的sesion版述,并且把session的Id以cookie的形式發(fā)送給客戶端瀏覽器,點(diǎn)擊刷新按鈕寞冯,再次請(qǐng)求服務(wù)器渴析,此時(shí)就可以看到瀏覽器再請(qǐng)求服務(wù)器時(shí),會(huì)把存儲(chǔ)到cookie中的session的Id一起傳遞到服務(wù)器端了
request.getSession()方法內(nèi)部新創(chuàng)建了Session之后一定是做了如下的處理:
//獲取session的Id
String sessionId = session.getId();
//將session的Id存儲(chǔ)到名字為JSESSIONID的cookie中
Cookie cookie = new Cookie("JSESSIONID", sessionId);
//設(shè)置cookie的有效路徑
cookie.setPath(request.getContextPath());
response.addCookie(cookie);
四吮龄、瀏覽器禁用Cookie后的session處理
4.1俭茧、解決方案:URL重寫
response.encodeRedirectURL(java.lang.String url) 用于對(duì)sendRedirect方法后的url地址進(jìn)行重寫。
response.encodeURL(java.lang.String url)用于對(duì)表單action和超鏈接的url地址進(jìn)行重寫
4.2漓帚、范例:禁用Cookie后servlet共享Session中的數(shù)據(jù)
IndexServlet:
package xdp.gacl.session;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//首頁(yè):列出所有書
public class IndexServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
//創(chuàng)建Session
request.getSession();
out.write("本網(wǎng)站有如下書:<br/>");
Set<Map.Entry<String,Book>> set = DB.getAll().entrySet();
for(Map.Entry<String,Book> me : set){
Book book = me.getValue();
String url =request.getContextPath()+ "/servlet/BuyServlet?id=" + book.getId();
//response. encodeURL(java.lang.String url)用于對(duì)表單action和超鏈接的url地址進(jìn)行重寫
url = response.encodeURL(url);//將超鏈接的url地址進(jìn)行重寫
out.println(book.getName() + " <a href='"+url+"'>購(gòu)買</a><br/>");
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
/**
* @author gacl
* 模擬數(shù)據(jù)庫(kù)
*/
class DB{
private static Map<String,Book> map = new LinkedHashMap<String,Book>();
static{
map.put("1", new Book("1","javaweb開(kāi)發(fā)"));
map.put("2", new Book("2","spring開(kāi)發(fā)"));
map.put("3", new Book("3","hibernate開(kāi)發(fā)"));
map.put("4", new Book("4","struts開(kāi)發(fā)"));
map.put("5", new Book("5","ajax開(kāi)發(fā)"));
}
public static Map<String,Book> getAll(){
return map;
}
}
class Book{
private String id;
private String name;
public Book() {
super();
}
public Book(String id, String name) {
super();
this.id = id;
this.name = name;
}
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;
}
}
BuyServlet:
package xdp.gacl.session;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class BuyServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String id = request.getParameter("id");
Book book = DB.getAll().get(id); //得到用戶想買的書
HttpSession session = request.getSession();
List<Book> list = (List) session.getAttribute("list"); //得到用戶用于保存所有書的容器
if(list==null){
list = new ArrayList<Book>();
session.setAttribute("list", list);
}
list.add(book);
//response. encodeRedirectURL(java.lang.String url)用于對(duì)sendRedirect方法后的url地址進(jìn)行重寫
String url = response.encodeRedirectURL(request.getContextPath()+"/servlet/ListCartServlet");
System.out.println(url);
response.sendRedirect(url);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
ListCartServlet:
package xdp.gacl.session;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class ListCartServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
HttpSession session = request.getSession();
List<Book> list = (List) session.getAttribute("list");
if(list==null || list.size()==0){
out.write("對(duì)不起母债,您還沒(méi)有購(gòu)買任何商品!!");
return;
}
//顯示用戶買過(guò)的商品
out.write("您買過(guò)如下商品:<br>");
for(Book book : list){
out.write(book.getName() + "<br/>");
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
當(dāng)瀏覽器禁用了cookie后,就可以用URL重寫這種解決方案解決Session數(shù)據(jù)共享問(wèn)題。而且response. encodeRedirectURL(java.lang.String url) 和response. encodeURL(java.lang.String url)是兩個(gè)非常智能的方法毡们,當(dāng)檢測(cè)到瀏覽器沒(méi)有禁用cookie時(shí)迅皇,那么就不進(jìn)行URL重寫了。
五衙熔、session對(duì)象的創(chuàng)建和銷毀時(shí)機(jī)
5.1喧半、session對(duì)象的創(chuàng)建時(shí)機(jī)
在程序中第一次調(diào)用request.getSession()方法時(shí)就會(huì)創(chuàng)建一個(gè)新的Session,可以用isNew()方法來(lái)判斷Session是不是新創(chuàng)建的
范例:創(chuàng)建session
//使用request對(duì)象的getSession()獲取session青责,如果session不存在則創(chuàng)建一個(gè)
HttpSession session = request.getSession();
//獲取session的Id
String sessionId = session.getId();
//判斷session是不是新創(chuàng)建的
if (session.isNew()) {
response.getWriter().print("session創(chuàng)建成功,session的id是:"+sessionId);
}else {
response.getWriter().print("服務(wù)器已經(jīng)存在session取具,session的id是:"+sessionId);
}
5.2脖隶、session對(duì)象的銷毀時(shí)機(jī)
session對(duì)象默認(rèn)30分鐘沒(méi)有使用,則服務(wù)器會(huì)自動(dòng)銷毀session暇检,在web.xml文件中可以手工配置session的失效時(shí)間产阱,例如:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name></display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- 設(shè)置Session的有效時(shí)間:以分鐘為單位-->
<session-config>
<session-timeout>15</session-timeout>
</session-config>
</web-app>
5.3手動(dòng)銷毀session
當(dāng)需要在程序中手動(dòng)設(shè)置Session失效時(shí),可以手工調(diào)用session.invalidate方法块仆,摧毀session构蹬。
HttpSession session = request.getSession();
//手工調(diào)用session.invalidate方法,摧毀session
session.invalidate();