Tomcat伺服器狀態管理之Session
1. 狀態管理-Session
1.1. Session
1.1.1. 什麼是Session
伺服器為不同的客戶端在記憶體中建立了用於儲存資料的Session物件,並將用於標識該物件的唯一Id發回給與該物件對應的客戶端。當瀏覽器再次傳送請求時,SessionId也會被髮送過來,伺服器憑藉這個唯一Id找到與之對應的Session物件。在伺服器端維護的這些用於儲存與不同客戶端互動時的資料的物件叫做Session。
1.1.2. Session工作原理
圖– 1
如圖-1 所示,瀏覽器第一次訪問伺服器時,伺服器會為該客戶端分配一塊物件空間,並且使用不同的SID來進行標識,該標識SID會隨著響應發回到客戶端,且被儲存在記憶體中。當同一個客戶端再次傳送請求時,標識也會被同時傳送到伺服器端,而伺服器判斷要使用哪一個Session物件內的資料時,就會根據客戶端發來的這個SID來進行查詢。
1.1.3. 如何獲得Session
獲得session有兩種情況,要麼請求中沒有SID,則需要建立;要麼請求中包含一個SID,根據SID去找對應的物件,但也存在找到找不到的可能。但不管哪種情況都依賴於請求中的這個唯一標識,雖然對於程式設計人員來講不需要去檢視這個基本不會重複、編號很長的標識,但要想獲取到與客戶端關聯的這個session物件一定要基於請求,所以在Request型別的API中包含獲取到session物件的方法,程式碼如下所示:
- HttpSessions = request.getSession(boolean flag);
- HttpSessions = request.getSession
HttpSession s = request.getSession(boolean flag); HttpSession s = request.getSession( );
使用第一種獲取session物件的方法時,
flag = true:先從請求中找找看是否有SID,沒有會建立新Session物件,有SID會查詢與編號對應的物件,找到匹配的物件則返回,找不到SID對應的物件時則會建立新Session物件。所以,填寫true就一定會得到一個Session物件。
flag= false:不存在SID以及按照SID找不到Session物件時都會返回null,只有根據SID找到對應的物件時會返回具體的Session物件。所以,填寫false只會返回已經存在並且與SID匹配上了的Session物件。
request.getSession()方法不填寫引數時等同於填寫true,提供該方法主要是為了書寫程式碼時更方便,大多數情況下還是希望能夠返回一個Session物件的。
1.1.4. 如何使用Session繫結物件
Session作為伺服器端為各客戶端儲存互動資料的一種方式,採用name-value對的形式來區分每一組資料。向Session新增資料繫結的程式碼如下:
- void session.setAttribute(Stringname,Objectobj);
void session.setAttribute(String name,Object obj);
獲取繫結資料或移除繫結資料的程式碼如下:
- void session.getAttribute(Stringname);
- void session.removeAttribute(Stringname);
void session.getAttribute(String name); void session.removeAttribute(String name);
Session物件可以儲存更復雜的物件型別資料了,不像Cookie只能儲存字串。
1.1.5. 如何刪除Session物件
如果客戶端想刪除SID對應的Session物件時,可以使用Session物件的如下方法:
- void invalidate()
void invalidate()
該方法會使得伺服器端與該客戶端對應的Session物件不再被Session容器管理,進入到垃圾回收的狀態。對於這種立即刪除Session物件的操作主要應用於不再需要身份識別的情況下,如登出操作。
1.2. Session超時
1.2.1. 什麼是Session超時
Session會以物件的形式佔用伺服器端的記憶體,過多的以及長期的消耗記憶體會降低伺服器端的執行效率,所以Session物件存在於記憶體中時會有預設的時間限制,一旦Session物件存在的時間超過了這個預設的時間限制則認為是Session超時,Session會失效,不能再繼續訪問。
Web伺服器預設的超時時間設定一般是30分鐘。
1.2.2. 如何修改Session的預設時間限制
有兩種方式可以修改Session的預設時間限制,程式設計式和宣告式。
程式設計式:
- void setMaxInactiveInterval(int seconds)
void setMaxInactiveInterval(int seconds)
宣告式:
- <session-config>
- <session-timeout>30</session-timeout>
- </session-config>
<session-config> <session-timeout>30</session-timeout> </session-config>
使用宣告式來修改預設時間,那麼該應用建立的所有Session物件的生命週期都會應用這個規定的時間,單位為分鐘。
使用程式設計式來修改預設時間只會針對呼叫該方法的Session物件應用這一原則,不會影響到其他物件,所以更靈活。通常在需要特殊設定時使用這種方式。時間單位是秒,與宣告式的時間單位不同。
1.2.3. Session驗證
Session既然區分不同的客戶端,所以可以利用Session來實現對訪問資源的保護。如,可以將資源劃分為登入後才能訪問。Session多用於記錄身份資訊,在保護資源被訪問前可以通過判斷Session內的資訊來決定是否允許。這是依靠Session實現的驗證。
使用Session實現驗證的步驟如下:
步驟一、為Session物件繫結資料,程式碼如下:
- HttpSessions = request.getSession();
- s.setAttribute(“uname”,“Rose”);
HttpSession s = request.getSession(); s.setAttribute(“uname”,“Rose”);
步驟二、讀取Session物件中的繫結值,讀取成功代表驗證成功,讀取失敗則跳轉回登入頁面。
- HttpSessions = request.getSession();
- if(s.getAttribute(“uname”)==null){
- response.sendRedirect(“logIn.jsp”);
- }else{
- //… …
- }
HttpSession s = request.getSession(); if(s.getAttribute(“uname”)==null){ response.sendRedirect(“logIn.jsp”); }else{ //… … }
1.2.4. Session優缺點
Session物件的資料由於儲存在伺服器端,並不在網路中進行傳輸,所以安全一些,並且能夠儲存的資料型別更豐富,同時Session也能夠儲存更多的資料,Cookie只能儲存大約4kb的字串。
Session的安全性是以犧牲伺服器資源為代價的,如果使用者量過大,會嚴重影響伺服器的效能。
1.2.5. 瀏覽器禁用Cookie的後果
Session物件的查詢依靠的是SID,而這個ID儲存在客戶端時是以Cookie的形式儲存的。一旦瀏覽器禁用Cookie,那麼SID無法儲存,Session物件將不再能使用。
為了在禁用Cookie後依然能使用Session,那麼將使用其他的儲存方法來完成SID的儲存。URL地址在網路傳輸過程中不僅僅能夠起到標示地址的作用,還可以在其後攜帶一些較短的資料,SID就可以通過URL來實現儲存,及URL重寫。
1.2.6. 什麼是URL重寫
瀏覽器在訪問伺服器的某個地址時,會使用一個改寫過的地址,即在原有地址後追加SessionID,這種重新定義URL內容的方式叫做URL重寫。
如:原有地址的寫法為http://localhost:8080/test/some
重寫後的地址寫法為http://localhost:8080/test/some;jsessionid=4E113CB3
1.2.7. 如何實現URL重寫
生成連結地址和表單提交時,使用如下程式碼:
- <ahref=”<%=response.encodeURL(Stringurl)>”>連結地址</a>
<a href=”<%=response.encodeURL(String url)>”>連結地址</a>
如果是重定向,使用如下程式碼代替response.sendRedirect()
- response.encodeRedirectURL(Stringurl);
response.encodeRedirectURL(String url);
1.3. 驗證碼
1.3.1. 驗證碼的作用
驗證碼技術可以防止對於應用惡意傳送資料,因其不規律且不能由機器代勞,所以一定程度上避免了惡意程式對網站的攻擊。
驗證碼本質上是一張圖片,圖片內容的準確解析不容易用程式來實現,所以能避免內容被快速讀取。並且,圖片的內容是使用程式隨機生成後繪製得到。
註冊、登入這樣的功能一般都會配備驗證碼,一定程度上避免惡意程式碼的攻擊。
1.3.2. 驗證碼的繪製
繪製驗證碼圖片不僅僅需要隨機生成要繪製的內容,同時要配合Java中與繪圖有關的一套API來完成。繪製API將畫板、畫筆、顏料、字型等都解釋為物件,繪製的過程就是這些物件互相配合完成的。主要涉及Graphics、Font等型別。
1.3.3. 驗證碼圖片的繪製步驟
繪製圖片的基本步驟如下:
- 常見記憶體畫板物件
- 建立基於該畫板的畫筆
- 設定畫筆的顏色
- 設定畫板背景的顏色
- 使用畫筆的繪製方法繪製隨機內容
- 更改畫筆顏色
- 繪製隨機的兩點一線的干擾線
- 繪製完成後將圖片壓縮並輸出到客戶端
以上步驟對應的實現程式碼如下所示:
- package web;
- import java.awt.*;
- import java.awt.image.BufferedImage;
- import java.io.IOException;
- import java.io.OutputStream;
- import java.util.Random;
- import javax.servlet.*;
- import javax.servlet.http.*;
- public classCheckcodeServlet extends HttpServlet {
- private int width = 80; //圖片的寬度
- private int height = 30;//圖片的高度
- public void service(HttpServletRequestrequest,
- HttpServletResponseresponse)
- throws ServletException, IOException {
- /*
- * 繪圖
- */
- //step1,建立一個記憶體映像物件(畫板)
- BufferedImageimage = new BufferedImage(width,height,
- BufferedImage.TYPE_INT_RGB);
- //step2,獲得畫筆
- Graphicsg = image.getGraphics();
- //step3,給筆上色
- Randomr = new Random();
- g.setColor(new Color(r.nextInt(255), r.nextInt(255),r.nextInt(255)));
- //step4,給畫板設定背景顏色
- g.fillRect(0, 0, width, height);
- //step5,繪製一個隨機的字串
- Stringnumber = r.nextInt(99999) + "";
- g.setColor(new Color(0,0,0));
- //new Font(字型,風格,大小)
- g.setFont(new Font(null,Font.ITALIC,24));
- g.drawString(number, 5, 25);
- //step6,加一些干擾線
- for(int i=0;i < 8;i++){
- g.setColor(new Color(r.nextInt(255),
- r.nextInt(255),r.nextInt(255)));
- g.drawLine(r.nextInt(width),
- r.nextInt(height), r.nextInt(width),
- r.nextInt(height));
- }
- /*
- * 壓縮圖片並輸出到客戶端(瀏覽器)
- */
- response.setContentType("image/jpeg");
- OutputStreamops =response.getOutputStream();
- javax.imageio.ImageIO.write(image, "jpeg", ops);
- ops.close();
- }
- }
程式碼
配置web.xml檔案程式碼如下:
- <?xmlversion="1.0" encoding="UTF-8"?>
- <web-appversion="2.4"
- xmlns="http://java.sun.com/xml/ns/j2ee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
- http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
- <servlet>
- <servlet-name>CheckcodeServlet</servlet-name>
- <servlet-class>web.CheckcodeServlet</servlet-class>
- </servlet>
- <servlet-mapping>
- <servlet-name>CheckcodeServlet</servlet-name>
- <url-pattern>/checkcode</url-pattern>
- </servlet-mapping>
- </web-app>
程式碼
HTML頁面中新增如下程式碼加入該圖片:
- <imgsrc="checkcode"/>
<img src="checkcode"/>
1.4. 密碼加密
1.4.1. 摘要加密
摘要加密的特點:不適用金鑰,使用摘要加密演算法對明文進行加密之後會得到密文,無法反推出明文。唯一性:不同的明文有不同的密文。不可逆性:即使知道了摘要加密演算法,也無法反推出明文。
1.4.2. 如何實現摘要加密
- public classMD5Util{
- private static void test1() throws NoSuchAlgorithmException{
- Stringstr = "I love you";
- MessageDigestmd = MessageDigest.getInstance("md5");
- //依據指定的加密演算法進行加密
- byte[] buf = md.digest(str.getBytes());
- //因為位元組陣列不方便使用,所以,將其轉換成一個字串
- //BASE64Encoder的encode方法可以將任意的一個位元組陣列轉換成一個字串
- BASE64Encoderbase = new BASE64Encoder();
- Stringstr2 = base.encode(buf);
- System.out.println(str2);
- }
- public static Stringencrypt(StringorigStr){
- MessageDigestmd = MessageDigest.getInstance("md5");
- byte[] buf = md.digest(str.getBytes());
- BASE64Encoderbase = new BASE64Encoder();
- Stringstr = base.encode(buf);
- return str;
- }
- }
程式碼