Session通常譯爲會話,是解決Http協議的無狀態問題的方案,能夠將一次會話中的數據存儲在服務器端的內存中,保證在下一次的會話中可使用。javascript
在客戶端瀏覽器第一次向服務器端發送請求時,服務器端會爲這個客戶端建立獨有的Session,並具備惟一的Session ID,存儲在服務器端的內存中。在客戶端第二次訪問服務器端時,會攜帶Session ID在請求中,服務器端會根據Session ID查找對應的Session信息,進行進一步地操做。html
在JavaEE中提供了javax.servlet.http.HttpSession接口,經過該接口能夠將共享的數據內容存儲在HttpSession對象中,從而解決Http協議的無狀態問題。java
Session直接翻譯成中文比較困難,通常都譯成時域。在計算機專業術語中,Session是指一個終端用戶與交互系統進行通訊的時間間隔,一般指從註冊進入系統到註銷退出系統之間所通過的時間。以及若是須要的話,可能還有必定的操做空間。web
具體到Web中的Session指的就是用戶在瀏覽某個網站時,從進入網站到關閉這個網站所通過的這段時間,也就是用戶瀏覽這個網站所花費的時間。所以從上述的定義中咱們能夠看到,Session其實是一個特定的時間概念。數據庫
須要注意的是,一個Session的概念須要包括特定的客戶端,特定的服務器端以及不中斷的操做時間。A用戶和C服務器創建鏈接時所處的Session同B用戶和C服務器創建鏈接時所處的Session是兩個不一樣的Session。apache
會話(session)是一種持久網絡協議,在用戶(或用戶代理)端和服務器端之間建立關聯,從而起到交換數據包的做用機制,session在網絡協議(例如telnet或FTP)中是很是重要的部分。編程
在不包含會話層(例如UDP)或者是沒法長時間駐留會話層(例如HTTP)的傳輸協議中,會話的維持須要依靠在傳輸數據中的高級別程序。例如,在瀏覽器和遠程主機之間的HTTP傳輸中,HTTP cookie就會被用來包含一些相關的信息,例如session ID,參數和權限信息等。設計模式
Session與Cookie都是解決Http協議的無狀態問題,可是二者之間仍是存在必定區別的:api
總的來講,Session與Cookie各有優點,不能簡單來講誰更優。具體用法要考慮具體案例狀況而定。瀏覽器
在JavaEE提供的javax.servlet.http.HttpSession接口,是Web應用程序開發使用Session的接口,該接口提供了不少API方法,而經常使用的方法有如下幾個:
Method Summary |
|
getAttribute(String name) |
|
getAttributeNames() |
|
void |
removeAttribute(String name) |
void |
setAttribute(String name, Object value) |
HttpSession session = request.getSession();
session.setAttribute("name", "longestory");
String name = (String)session.getAttribute("name");
掌握瞭如何獲取Session對象及向Session對象中設置及獲取共享數據內容,下面咱們就來利用HttpSession對象實現數據內容共享。
public class FirstServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(); session.setAttribute("name", "longestory"); System.out.println("已經成功向HttpSession對象中存儲了共享數據內容name=longestory..."); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
public class SecondServlet 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(); String name = (String)session.getAttribute("name"); out.println("<h1>你存儲的共享數據內容爲name="+name+"</h1>"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
<?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> <servlet> <servlet-name>FirstServlet</servlet-name> <servlet-class>app.java.session.FirstServlet</servlet-class> </servlet> <servlet> <servlet-name>SecondServlet</servlet-name> <servlet-class>app.java.session.SecondServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>FirstServlet</servlet-name> <url-pattern>/first</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>SecondServlet</servlet-name> <url-pattern>/second</url-pattern> </servlet-mapping> </web-app>
在JavaEE的javax.servlet.http.HttpSession接口提供了除經常使用方法外,還有不少其餘方法可供使用:
Method Summary |
|
long |
getCreationTime() |
getId() |
|
long |
getLastAccessedTime() |
int |
getMaxInactiveInterval() |
getServletContext() |
|
void |
invalidate() |
boolean |
isNew() |
void |
setMaxInactiveInterval(int interval) |
下面咱們經過一個Servlet將上述中的一些方法進行測試,這裏理解性記憶就好,後面案例中用到哪一個方式再具體掌握。
public class ThreeServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); Calendar calendar = Calendar.getInstance(); HttpSession session = request.getSession(); System.out.println("Session的ID爲"+session.getId()); calendar.setTimeInMillis(session.getCreationTime()); System.out.println("Session的建立時間爲"+formatter.format(calendar.getTime())); calendar.setTimeInMillis(session.getLastAccessedTime()); System.out.println("Session的最後活動時間爲"+formatter.format(calendar.getTime())); System.out.println("當前Session是否爲新的?"+session.isNew()); System.out.println("Session的默認活動時間爲"+session.getMaxInactiveInterval()/60+"分鐘"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
<?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> <servlet> <servlet-name>ThreeServlet</servlet-name> <servlet-class>app.java.session.ThreeServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>ThreeServlet</servlet-name> <url-pattern>/three</url-pattern> </servlet-mapping> </web-app>
如今掌握了HttpSession對象的基本使用方法,到目前爲止,Servlet的三大域對象都已經掌握。Servlet的三大域對象分別爲HttpServletRequest對象、ServletContext對象及HttpSession對象:
經過HttpSession對象實現了在屢次會話中共享數據內容,HttpSession對象底層究竟是如何實現這樣的效果?下面咱們來討論一下。
會發現實際獲得的是org.apache.catalina.session.StandardSession對象,該對象是由Tomcat服務器的Session池建立,併爲該對象建立惟一的ID值。
會發現服務器端向客戶端進行響應時,向客戶端發送了一個Cookie信息,具體內容以下:
Set-Cookie: JSESSIONID=0BD17B07E383FA86703B370560E823F2; Path=/11_session/; HttpOnly
會發現客戶端向服務器端發送請求時,向服務器端發送了一個Cookie信息,具體內容以下:
Cookie: JSESSIONID=0BD17B07E383FA86703B370560E823F2
經過上述操做,咱們會發如今第一次請求時,服務器端向客戶端響應Cookie信息,在第二次請求時,客戶端向服務器端發送了Cookie信息。進而能夠總結出Session的實現原理以下:
由於Session使用的是會話Cookie,因此當瀏覽器關閉後,Session會失效。從新打開瀏覽器訪問對應Servlet時,服務器端會從新建立Session對象。可使用持久Cookie來延長Session的有效時間。
經過Session的實現原理能夠知道,Session的實現是基於Cookie的。若是瀏覽器禁用Cookie的話,Session是否仍是有效的呢?下面咱們具體操做來看一看。
這個問題是否能夠解決呢?答案是能夠的,能夠利用URL重寫方式來解決,具體操做以下:
String url = request.getRequestURI(); url = response.encodeURL(url); response.getWriter().println("<a href='" + url + "'>second</a>");
禁用Cookie解決Session的問題,這種解決方案是具備理論意義的,但不具有實際意義。由於大部分的網站都是基於Cookie完成數據共享的,例如京東網站或淘寶網站等。若是瀏覽器禁用Cookie,網站會提示相關信息。
關於Sessioin的生命週期,在以前的內容都有學習到,只是沒有專門概括總結。下面總結一下Session的生命週期,主要是Session的建立和銷燬。
能夠利用setMaxInactiveInterval(int interval)方法設置Session的有效時間。
利用Session實現商品購物車的邏輯功能,具體操做以下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ page import="java.util.Map"%> <%@ page import="java.util.Set"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'show.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> </head> <body> <!-- 商品列表 --> <h1>商品列表</h1> Java編程思想<a href="/session/show?id=1">購買</a><br> Java設計模式<a href="/session/show?id=2">購買</a><br> Java語言入門<a href="/session/show?id=3">購買</a><br> Oracle數據庫<a href="/session/show?id=4">購買</a><br> MySQL數據庫<a href="/session/show?id=5">購買</a><br> <!-- 購物車記錄 --> <h1>購物車記錄</h1> <h2><a href="/session/clear">清空購物車</a></h2> <% Map<String,Integer> map = (Map<String,Integer>)request.getSession().getAttribute("cart"); if(map == null){ // 購物車對象不存在 out.println("<h2>購物車無任何商品信息!</h2>"); }else{ // 購物車對象已經存在 Set<String> keySet = map.keySet(); for(String productName: keySet){ int number = map.get(productName);// 購買數量 out.println("商品名稱: " + productName +", 購買數量:" + number + "<br/>"); } } %> </body> </html>
public class ShowServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 得到購買商品 id String id = request.getParameter("id"); // 得到id 對應商品名稱 String[] names = { "Java編程思想", "Java設計模式", "Java語言入門", "Oracle數據庫", "MySQL數據庫" }; String productName = names[Integer.parseInt(id) - 1]; // 判斷Session中購物車是否存在 HttpSession session = request.getSession(); Map<String, Integer> cart = (Map<String, Integer>) session.getAttribute("cart"); if (cart == null) { // 購物車不存在 cart = new HashMap<String, Integer>(); } // 判斷購買商品是否存在於購物車中,商品名稱就是map的key if (cart.containsKey(productName)) { // 商品已經在購物車中 int number = cart.get(productName);// 取出原來數量 cart.put(productName, number + 1);// 數量+1 放回購物車 } else { // 商品不在購物車中 cart.put(productName, 1);// 保存商品到購物車,數量爲1 } // 將購物車對象保存Session session.setAttribute("cart", cart); // 給用戶提示 response.setContentType("text/html;charset=utf-8"); response.getWriter().println("商品已經添加到購物車!<a href='/session/cart/show.jsp'>返回</a>"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
public class ClearServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 獲取購物車Session對象 HttpSession session = request.getSession(); // 刪除購物車cart對象 session.removeAttribute("cart"); // 跳轉show.jsp response.sendRedirect("/session/cart/show.jsp"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
<?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> <servlet> <servlet-name>ShowServlet</servlet-name> <servlet-class>app.java.session.ShowServlet</servlet-class> </servlet> <servlet> <servlet-name>ClearServlet</servlet-name> <servlet-class>app.java.session.ClearServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>ShowServlet</servlet-name> <url-pattern>/show</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>ClearServlet</servlet-name> <url-pattern>/clear</url-pattern> </servlet-mapping> </web-app>
所謂一次驗證碼,就是驗證碼生成後,只能使用一次,無論成功或者失敗,驗證碼都將失效。具體實現步驟以下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'login.jsp' starting page</title> </head> <script type="text/javascript"> function change(){ document.getElementById("myimg").src = "/session/checkimg?timeStamp="+new Date().getTime(); } </script> <body> <h1>登錄頁面</h1> <h2 style="color:red;">${requestScope.msg }</h2> <form action="/11_session/login" 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> <tr> <td>驗證碼</td> <td><input type="text" name="checkcode" /> <img src="/session/checkimg" onclick="change();" id="myimg" style="cursor: pointer;"/></td> </tr> <tr> <td colspan="2"><input type="submit" value="登錄" /></td> </tr> </table> </form> </body> </html>
public class CheckImgServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { int width = 120; int height = 30; // 步驟一 繪製一張內存中圖片 BufferedImage bufferedImage = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB); // 步驟二 圖片繪製背景顏色 ---經過繪圖對象 Graphics graphics = bufferedImage.getGraphics();//獲得畫圖對象 - 畫筆 // 繪製任何圖形以前 都必須指定一個顏色 graphics.setColor(getRandColor(200, 250)); graphics.fillRect(0, 0, width, height); // 步驟三 繪製邊框 graphics.setColor(Color.WHITE); graphics.drawRect(0, 0, width - 1, height - 1); // 步驟四 四個隨機數字 Graphics2D graphics2d = (Graphics2D) graphics; // 設置輸出字體 graphics2d.setFont(new Font("宋體", Font.BOLD, 18)); String words = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"; Random random = new Random();// 生成隨機數 // 爲了將驗證碼保存Session StringBuffer buffer = new StringBuffer(); // 定義x座標 int x = 10; for (int i = 0; i < 4; i++) { // 隨機顏色 graphics2d.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110))); // 旋轉 -30 --- 30度 int jiaodu = random.nextInt(60) - 30; // 換算弧度 double theta = jiaodu * Math.PI / 180; // 生成一個隨機數字 int index = random.nextInt(words.length());//生成隨機數0到 length-1 // 得到字母數字 char c = words.charAt(index); // 將生成漢字 加入buffer buffer.append(c); // 將c 輸出到圖片 graphics2d.rotate(theta, x, 20); graphics2d.drawString(String.valueOf(c), x, 20); graphics2d.rotate(-theta, x, 20); x += 30; } // 將驗證碼內容保存session request.getSession().setAttribute("checkcode_session",buffer.toString()); // 步驟五 繪製干擾線 graphics.setColor(getRandColor(160, 200)); int x1; int x2; int y1; int y2; for (int i = 0; i < 30; i++) { x1 = random.nextInt(width); x2 = random.nextInt(12); y1 = random.nextInt(height); y2 = random.nextInt(12); graphics.drawLine(x1, y1, x1 + x2, x2 + y2); } // 將上面圖片輸出到瀏覽器 ImageIO graphics.dispose();// 釋放資源 ImageIO.write(bufferedImage, "jpg", response.getOutputStream()); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } /** * 取其某一範圍的color * * @param fc * int 範圍參數1 * @param bc * int 範圍參數2 * @return Color */ private Color getRandColor(int fc, int bc) { // 取其隨機顏色 Random random = new Random(); if (fc > 255) { fc = 255; } if (bc > 255) { bc = 255; } int r = fc + random.nextInt(bc - fc); int g = fc + random.nextInt(bc - fc); int b = fc + random.nextInt(bc - fc); return new Color(r, g, b); } }
public class LoginServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 得到用戶名、密碼和 驗證碼 request.setCharacterEncoding("utf-8"); String username = request.getParameter("username"); String password = request.getParameter("password"); String checkcode = request.getParameter("checkcode"); // 判斷驗證碼是否正確 String checkcode_session = (String) request.getSession().getAttribute("checkcode_session"); request.getSession().removeAttribute("checkcode_session"); if (checkcode_session == null || !checkcode_session.equals(checkcode)) { // 驗證碼輸入錯誤 request.setAttribute("msg", "驗證碼輸入錯誤!"); request.getRequestDispatcher("/login/login.jsp").forward(request,response); return; } // 判斷用戶名和密碼是否正確 ,假設用戶名和密碼都是admin/admin if ("admin".equals(username) && "admin".equals(password)) { // 登錄成功 // 將登錄信息保存session request.getSession().setAttribute("username", username); response.sendRedirect("/session/login/welcome.jsp"); } else { // 登錄失敗 request.setAttribute("msg", "用戶名或者密碼錯誤!"); request.getRequestDispatcher("/login/login.jsp").forward(request,response); } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'welcome.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> </head> <body> <h1>登錄後的歡迎頁面</h1> <% String username = (String)request.getSession().getAttribute("username"); if(username == null){ // 未登錄 out.println("您還未登錄,<a href='/session/login/login.jsp'>去登錄</a>"); }else{ // 已經登錄 out.println("歡迎您,"+username); } %> </body> </html>