1.1 什麼是JSPjavascript
JSP(Java Server Pages)是JavaWeb服務器端的動態資源。它與html頁面的做用是相同的,顯示數據和獲取數據。html
1.2 JSP的組成java
JSP = html + Java腳本(代碼片斷) + JSP動態標籤web
2.1 JSP腳本數據庫
JSP腳本就是Java代碼片斷,它分爲三種:c#
l <%...%>:Java語句;windows
l <%=…%>:Java表達式;瀏覽器
l <%!...%>:Java定義類成員;緩存
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>服務器 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>JSP演示</title> </head>
<body> <h1>JSP演示</h1> <% // Java語句 String s1 = "hello jsp"; // 不會輸出到客戶端,而是在服務器端的控制檯打印 System.out.println(s1); %> <!-- 輸出到客戶端瀏覽器上 --> 輸出變量:<%=s1 %><br/> 輸出int類型常量:<%=100 %><br/> 輸出String類型常量:<%="你好" %><br/> <br/> 使用表達式輸出常量是很傻的一件事,由於能夠直接使用html便可,下面是輸出上面的常量:<br/> 100<br/> 你好 </body> </html> |
2.2 內置對象out
out對象在JSP頁面中無需建立就可使用,它的做用是用來向客戶端輸出。
<body> <h1>out.jsp</h1> <% //向客戶端輸出 out.print("你好!"); %> </body> |
其中<%=…%>與out.print()功能是相同的!它們都是向客戶端輸出,例如:
<%=s1%>等同於<% out.print(s1); %>
<%=」hello」%>等同於<% out.print(「hello」); %>,也等同於直接在頁面中寫hello同樣。
2.3 多個<%...%>能夠通用
在一個JSP中多個<%...%>是相通的。例如:
<body> <h1>out.jsp</h1> <% String s = "hello"; %> <% out.print(s); %> </body> |
循環打印表格:
<body> <h1>表格</h1>
<table border="1" width="50%"> <tr> <th>序號</th> <th>用戶名</th> <th>密碼</th> </tr> <% for(int i = 0; i < 10; i++) { %> <tr> <td><%=i+1 %></td> <td>user<%=i %></td> <td><%=100 + 1 %></td> </tr> <% } %> </table> </body> |
3.1 JSP是特殊的Servlet
JSP是一種特殊的Servlet,當JSP頁面首次被訪問時,容器(Tomcat)會先把JSP編譯成Servlet,而後再去執行Servlet。因此JSP其實就是一個Servlet!
3.2 JSP真身存放目錄
JSP生成的Servlet存放在${CATALANA}/work目錄下,我常常開玩笑的說,它是JSP的「真身」。咱們打開看看其中的內容,瞭解一下JSP的「真身」。
你會發現,在JSP中的靜態信息(例如<html>等)在「真身」中都是使用out.write()完成打印!這些靜態信息都是做爲字符串輸出給了客戶端。
JSP的整篇內容都會放到名爲_jspService的方法中!你可能會說<@page>不在「真身」中,<%@page>咱們明天再講。
a_jsp.java的_jspService()方法:
public void _jspService(final javax.servlet.http.HttpServletRequest request[崔1] , final javax.servlet.http.HttpServletResponse response[崔2] ) throws java.io.IOException, javax.servlet.ServletException {
final javax.servlet.jsp.PageContext pageContext[崔3] ; javax.servlet.http.HttpSession session [崔4] = null; final javax.servlet.ServletContext application[崔5] ; final javax.servlet.ServletConfig config[崔6] ; javax.servlet.jsp.JspWriter out [崔7] = null; final java.lang.Object page [崔8] = this; javax.servlet.jsp.JspWriter _jspx_out = null; javax.servlet.jsp.PageContext _jspx_page_context = null;
try { response.setContentType("text/html;charset=UTF-8"); pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 8192, true); _jspx_page_context = pageContext; application = pageContext.getServletContext(); config = pageContext.getServletConfig(); session = pageContext.getSession(); out = pageContext.getOut(); _jspx_out = out;
…[崔9] } |
JSP腳本一共三種形式:
l <%...%>:內容會直接放到「真身」中;
l <%=…%>:內容會放到out.print()中,做爲out.print()的參數;
l <%!…%>:內容會放到_jspService()方法以外,被類直接包含;
前面已經講解了<%...%>和<%=…%>,但尚未講解<%!...%>的做用!
如今咱們已經知道了,JSP其實就是一個類,一個Servlet類。<%!...%>的做用是在類中添加方法或成員的,因此<%!...%>中的內容不會出如今_jspService()中。
<%! private String name; public String hello() { return "hello JSP!"; } %> |
咱們如今已經知道JSP是須要先編譯成.java,再編譯成.class的。其中<%-- ... --%>中的內容在JSP編譯成.java時會被忽略的,即JSP註釋。
也能夠在JSP頁面中使用html註釋:<!-- … -->,但這個註釋在JSP編譯成的.java中是存在的,它不會被忽略,並且會被髮送到客戶端瀏覽器。可是在瀏覽器顯示服務器發送過來的html時,由於<!-- … -->是html的註釋,因此瀏覽器是不會顯示它的。
咱們須要先了解一下什麼是會話!能夠把會話理解爲客戶端與服務器之間的一次會晤,在一次會晤中可能會包含屢次請求和響應。例如你給10086打個電話,你就是客戶端,而10086服務人員就是服務器了。從雙方接通電話那一刻起,會話就開始了,到某一方掛斷電話表示會話結束。在通話過程當中,你會向10086發出多個請求,那麼這多個請求都在一個會話中。
在JavaWeb中,客戶向某一服務器發出第一個請求開始,會話就開始了,直到客戶關閉了瀏覽器會話結束。
在一個會話的多個請求中共享數據,這就是會話跟蹤技術。例如在一個會話中的請求以下:
l 請求銀行主頁;
l 請求登陸(請求參數是用戶名和密碼);
l 請求轉帳(請求參數與轉帳相關的數據);
l 請求信譽卡還款(請求參數與還款相關的數據)。
在這上會話中當前用戶信息必須在這個會話中共享的,由於登陸的是張三,那麼在轉帳和還款時必定是相對張三的轉帳和還款!這就說明咱們必須在一個會話過程當中有共享數據的能力。
咱們知道HTTP協議是無狀態協議,也就是說每一個請求都是獨立的!沒法記錄前一次請求的狀態。但HTTP協議中可使用Cookie來完成會話跟蹤!
在JavaWeb中,使用session來完成會話跟蹤,session底層依賴Cookie技術。
1.1 什麼叫Cookie
Cookie翻譯成中文是小甜點,小餅乾的意思。在HTTP中它表示服務器送給客戶端瀏覽器的小甜點。其實Cookie就是一個鍵和一個值構成的,隨着服務器端的響應發送給客戶端瀏覽器。而後客戶端瀏覽器會把Cookie保存起來,當下一次再訪問服務器時把Cookie再發送給服務器。
Cookie是由服務器建立,而後經過響應發送給客戶端的一個鍵值對。客戶端會保存Cookie,並會標註出Cookie的來源(哪一個服務器的Cookie)。當客戶端向服務器發出請求時會把全部這個服務器Cookie包含在請求中發送給服務器,這樣服務器就能夠識別客戶端了!
1.2 Cookie規範
l Cookie大小上限爲4KB;
l 一個服務器最多在客戶端瀏覽器上保存20個Cookie;
l 一個瀏覽器最多保存300個Cookie;
上面的數據只是HTTP的Cookie規範,但在瀏覽器大戰的今天,一些瀏覽器爲了戰勝對手,爲了展示本身的能力起見,可能對Cookie規範「擴展」了一些,例如每一個Cookie的大小爲8KB,最多可保存500個Cookie等!但也不會出現把你硬盤佔滿的可能!
注意,不一樣瀏覽器之間是不共享Cookie的。也就是說在你使用IE訪問服務器時,服務器會把Cookie發給IE,而後由IE保存起來,當你在使用FireFox訪問服務器時,不可能把IE保存的Cookie發送給服務器。
1.3 Cookie與HTTP頭
Cookie是經過HTTP請求和響應頭在客戶端和服務器端傳遞的:
l Cookie:請求頭,客戶端發送給服務器端;
l Set-Cookie:響應頭,服務器端發送給客戶端;
Set-Cookie: a=A
Set-Cookie: b=B
Set-Cookie: c=C
1.4 Cookie的覆蓋
若是服務器端發送重複的Cookie那麼會覆蓋原有的Cookie,例如客戶端的第一個請求服務器端發送的Cookie是:Set-Cookie: a=A;第二請求服務器端發送的是:Set-Cookie: a=AA,那麼客戶端只留下一個Cookie,即:a=AA。
1.5 Cookie第一例
咱們這個案例是,客戶端訪問AServlet,AServlet在響應中添加Cookie,瀏覽器會自動保存Cookie。而後客戶端訪問BServlet,這時瀏覽器會自動在請求中帶上Cookie,BServlet獲取請求中的Cookie打印出來。
AServlet.java
package cn.itcast.servlet;
import java.io.IOException; import java.util.UUID;
import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
/** * 給客戶端發送Cookie * @author Administrator * */ public class AServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8");
String id = UUID.randomUUID().toString();//生成一個隨機字符串 Cookie cookie = new Cookie("id", id);//建立Cookie對象,指定名字和值 response.addCookie(cookie);//在響應中添加Cookie對象 response.getWriter().print("已經給你發送了ID"); } } |
BServlet.java
package cn.itcast.servlet;
import java.io.IOException;
import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
/** * 獲取客戶端請求中的Cookie * @author Administrator * */ public class BServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8");
Cookie[] cs = request.getCookies();//獲取請求中的Cookie if(cs != null) {//若是請求中存在Cookie for(Cookie c : cs) {//遍歷全部Cookie if(c.getName().equals("id")) {//獲取Cookie名字,若是Cookie名字是id response.getWriter().print("您的ID是:" + c.getValue());//打印Cookie值 } } } } } |
2.1 什麼是Cookie的生命
Cookie不僅是有name和value,Cookie仍是生命。所謂生命就是Cookie在客戶端的有效時間,能夠經過setMaxAge(int)來設置Cookie的有效時間。
l cookie.setMaxAge(-1):cookie的maxAge屬性的默認值就是-1,表示只在瀏覽器內存中存活。一旦關閉瀏覽器窗口,那麼cookie就會消失。
l cookie.setMaxAge(60*60):表示cookie對象可存活1小時。當生命大於0時,瀏覽器會把Cookie保存到硬盤上,就算關閉瀏覽器,就算重啓客戶端電腦,cookie也會存活1小時;
l cookie.setMaxAge(0):cookie生命等於0是一個特殊的值,它表示cookie被做廢!也就是說,若是原來瀏覽器已經保存了這個Cookie,那麼能夠經過Cookie的setMaxAge(0)來刪除這個Cookie。不管是在瀏覽器內存中,仍是在客戶端硬盤上都會刪除這個Cookie。
2.2 瀏覽器查看Cookie
下面是瀏覽器查看Cookie的方式:
l IE查看Cookie文件的路徑:C:\Documents and Settings\Administrator\Cookies;
l FireFox查看Cooke:
l Google查看Cookie:
2.3 案例:顯示上次訪問時間
l 建立Cookie,名爲lasttime,值爲當前時間,添加到response中;
l 在AServlet中獲取請求中名爲lasttime的Cookie;
l 若是不存在輸出「您是第一次訪問本站」,若是存在輸出「您上一次訪問本站的時間是xxx」;
AServlet.java
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8");
Cookie cookie = new Cookie("lasttime", new Date().toString());[崔10] cookie.setMaxAge(60 * 60);[崔11] response.addCookie(cookie);[崔12]
Cookie[] cs = request.getCookies();[崔13] String s = "您是首次訪問本站!"; if(cs != null) {[崔14] for(Cookie c : cs) {[崔15] if(c.getName().equals("lasttime")) {[崔16] s = "您上次的訪問時間是:" + c.getValue();[崔17] } } }
response.getWriter().print(s);[崔18] } |
3.1 什麼是Cookie的路徑
如今有WEB應用A,向客戶端發送了10個Cookie,這就說明客戶端不管訪問應用A的哪一個Servlet都會把這10個Cookie包含在請求中!可是也許只有AServlet須要讀取請求中的Cookie,而其餘Servlet根本就不會獲取請求中的Cookie。這說明客戶端瀏覽器有時發送這些Cookie是多餘的!
能夠經過設置Cookie的path來指定瀏覽器,在訪問什麼樣的路徑時,包含什麼樣的Cookie。
3.2 Cookie路徑與請求路徑的關係
下面咱們來看看Cookie路徑的做用:
下面是客戶端瀏覽器保存的3個Cookie的路徑:
a: /cookietest;
b: /cookietest/servlet;
c: /cookietest/jsp;
下面是瀏覽器請求的URL:
A: http://localhost:8080/cookietest/AServlet;
B: http://localhost:8080/cookietest/servlet/BServlet;
C: http://localhost:8080/cookietest/servlet/CServlet;
l 請求A時,會在請求中包含a;
l 請求B時,會在請求中包含a、b;
l 請求C時,會在請求中包含a、c;
也就是說,請求路徑若是包含了Cookie路徑,那麼會在請求中包含這個Cookie,不然不會請求中不會包含這個Cookie。
l A請求的URL包含了「/cookietest」,因此會在請求中包含路徑爲「/cookietest」的Cookie;
l B請求的URL包含了「/cookietest」,以及「/cookietest/servlet」,因此請求中包含路徑爲「/cookietest」和「/cookietest/servlet」兩個Cookie;
l B請求的URL包含了「/cookietest」,以及「/cookietest/jsp」,因此請求中包含路徑爲「/cookietest」和「/cookietest/jsp」兩個Cookie;
3.3 設置Cookie的路徑
設置Cookie的路徑須要使用setPath()方法,例如:
cookie.setPath(「/cookietest/servlet」);
若是沒有設置Cookie的路徑,那麼Cookie路徑的默認值當前訪問資源所在路徑,例如:
l 訪問http://localhost:8080/cookietest/AServlet時添加的Cookie默認路徑爲/cookietest;
l 訪問http://localhost:8080/cookietest/servlet/BServlet時添加的Cookie默認路徑爲/cookietest/servlet;
l 訪問http://localhost:8080/cookietest/jsp/BServlet時添加的Cookie默認路徑爲/cookietest/jsp;
Cookie的domain屬性可讓網站中二級域共享Cookie,次要!
百度你是瞭解的對吧!
http://www.baidu.com
http://zhidao.baidu.com
http://news.baidu.com
http://tieba.baidu.com
如今我但願在這些主機之間共享Cookie(例如在www.baidu.com中響應的cookie,能夠在news.baidu.com請求中包含)。很明顯,如今不是路徑的問題了,而是主機的問題,即域名的問題。處理這一問題其實很簡單,只須要下面兩步:
l 設置Cookie的path爲「/」:c.setPath(「/」);
l 設置Cookie的domain爲「.baidu.com」:c.setDomain(「.baidu.com」)。
當domain爲「.baidu.com」時,不管前綴是什麼,都會共享Cookie的。可是如今咱們須要設置兩個虛擬主機:www.baidu.com和news.baidu.com。
第一步:設置windows的DNS路徑解析
找到C:\WINDOWS\system32\drivers\etc\hosts文件,添加以下內容
127.0.0.1 localhost 127.0.0.1 www.baidu.com 127.0.0.1 news.baidu.com |
第二步:設置Tomcat虛擬主機
找到server.xml文件,添加<Host>元素,內容以下:
<Host name="www.baidu.com" appBase="F:\webapps\www" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false"/> <Host name="news.baidu.com" appBase="F:\webapps\news" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false"/> |
第三步:建立A項目,建立AServlet,設置Cookie。
Cookie c = new Cookie("id", "baidu"); c.setPath("/"); c.setDomain(".baidu.com"); c.setMaxAge(60*60); response.addCookie(c); response.getWriter().print("OK"); |
把A項目的WebRoot目錄複製到F:\webapps\www目錄下,並把WebRoot目錄的名字修改成ROOT。
第四步:建立B項目,建立BServlet,獲取Cookie,並打印出來。
Cookie[] cs = request.getCookies(); if(cs != null) { for(Cookie c : cs) { String s = c.getName() + ": " + c.getValue() + "<br/>"; response.getWriter().print(s); } } |
把B項目的WebRoot目錄複製到F:\webapps\news目錄下,並把WebRoot目錄的名字修改成ROOT。
第五步:訪問www.baidu.com\AServlet,而後再訪問news.baidu.com\BServlet。
Cookie的name和value都不能使用中文,若是但願在Cookie中使用中文,那麼須要先對中文進行URL編碼,而後把編碼後的字符串放到Cookie中。
向客戶端響應中添加Cookie
String name = URLEncoder.encode("姓名", "UTF-8"); String value = URLEncoder.encode("張三", "UTF-8"); [崔19] Cookie c = new Cookie(name, value);[崔20] c.setMaxAge(3600); response.addCookie(c); |
從客戶端請求中獲取Cookie
response.setContentType("text/html;charset=utf-8"); Cookie[] cs = request.getCookies(); if(cs != null) { for(Cookie c : cs) { String name = URLDecoder.decode(c.getName(), "UTF-8"); String value = URLDecoder.decode(c.getValue(), "UTF-8"); [崔21] String s = name + ": " + value + "<br/>"; response.getWriter().print(s); } } |
index.jsp
<body> <h1>商品列表</h1> <a href="/day06_3/GoodServlet?name=ThinkPad">ThinkPad</a><br/> <a href="/day06_3/GoodServlet?name=Lenovo">Lenovo</a><br/> <a href="/day06_3/GoodServlet?name=Apple">Apple</a><br/> <a href="/day06_3/GoodServlet?name=HP">HP</a><br/> <a href="/day06_3/GoodServlet?name=SONY">SONY</a><br/> <a href="/day06_3/GoodServlet?name=ACER">ACER</a><br/> <a href="/day06_3/GoodServlet?name=DELL">DELL</a><br/>
<hr/> 您瀏覽過的商品: <% Cookie[] cs = request.getCookies(); if(cs != null) { for(Cookie c : cs) { if(c.getName().equals("goods")) { out.print(c.getValue()); } } } %> </body> |
GoodServlet
public class GoodServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String goodName = request.getParameter("name"); String goods = CookieUtils.getCookValue(request, "goods");
if(goods != null) { String[] arr = goods.split(", "); Set<String> goodSet = new LinkedHashSet(Arrays.asList(arr)); goodSet.add(goodName); goods = goodSet.toString(); goods = goods.substring(1, goods.length() - 1); } else { goods = goodName; } Cookie cookie = new Cookie("goods", goods); cookie.setMaxAge(1 * 60 * 60 * 24); response.addCookie(cookie);
response.sendRedirect("/day06_3/index.jsp"); } } |
CookieUtils
public class CookieUtils { public static String getCookValue(HttpServletRequest request, String name) { Cookie[] cs = request.getCookies(); if(cs == null) { return null; } for(Cookie c : cs) { if(c.getName().equals(name)) { return c.getValue(); } } return null; } } |
1.1 什麼是HttpSesssion
javax.servlet.http.HttpSession接口表示一個會話,咱們能夠把一個會話內須要共享的數據保存到HttSession對象中!
1.2 獲取HttpSession對象
l HttpSession request.getSesssion():若是當前會話已經有了session對象那麼直接返回,若是當前會話還不存在會話,那麼建立session並返回;
l HttpSession request.getSession(boolean):當參數爲true時,與requeset.getSession()相同。若是參數爲false,那麼若是當前會話中存在session則返回,不存在返回null;
1.3 HttpSession是域對象
咱們已經學習過HttpServletRequest、ServletContext,它們都是域對象,如今咱們又學習了一個HttpSession,它也是域對象。它們三個是Servlet中可使用的域對象,而JSP中能夠多使用一個域對象,明天咱們再講解JSP的第四個域對象。
l HttpServletRequest:一個請求建立一個request對象,因此在同一個請求中能夠共享request,例如一個請求從AServlet轉發到BServlet,那麼AServlet和BServlet能夠共享request域中的數據;
l ServletContext:一個應用只建立一個ServletContext對象,因此在ServletContext中的數據能夠在整個應用中共享,只要不啓動服務器,那麼ServletContext中的數據就能夠共享;
l HttpSession:一個會話建立一個HttpSession對象,同一會話中的多個請求中能夠共享session中的數據;
下載是session的域方法:
l void setAttribute(String name, Object value):用來存儲一個對象,也能夠稱之爲存儲一個域屬性,例如:session.setAttribute(「xxx」, 「XXX」),在session中保存了一個域屬性,域屬性名稱爲xxx,域屬性的值爲XXX。請注意,若是屢次調用該方法,而且使用相同的name,那麼會覆蓋上一次的值,這一特性與Map相同;
l Object getAttribute(String name):用來獲取session中的數據,當前在獲取以前須要先去存儲才行,例如:String value = (String) session.getAttribute(「xxx」);,獲取名爲xxx的域屬性;
l void removeAttribute(String name):用來移除HttpSession中的域屬性,若是參數name指定的域屬性不存在,那麼本方法什麼都不作;
l Enumeration getAttributeNames():獲取全部域屬性的名稱;
須要的頁面:
l login.jsp:登陸頁面,提供登陸表單;
l index1.jsp:主頁,顯示當前用戶名稱,若是沒有登陸,顯示您還沒登陸;
l index2.jsp:主頁,顯示當前用戶名稱,若是沒有登陸,顯示您還沒登陸;
Servlet:
l LoginServlet:在login.jsp頁面提交表單時,請求本Servlet。在本Servlet中獲取用戶名、密碼進行校驗,若是用戶名、密碼錯誤,顯示「用戶名或密碼錯誤」,若是正確保存用戶名session中,而後重定向到index1.jsp;
當用戶沒有登陸時訪問index1.jsp或index2.jsp,顯示「您尚未登陸」。若是用戶在login.jsp登陸成功後到達index1.jsp頁面會顯示當前用戶名,並且不用再次登陸去訪問index2.jsp也會顯示用戶名。由於屢次請求在一個會話範圍,index1.jsp和index2.jsp都會到session中獲取用戶名,session對象在一個會話中是相同的,因此均可以獲取到用戶名!
login.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>login.jsp</title> </head>
<body> <h1>login.jsp</h1> <hr/> <form action="/day06_4/LoginServlet" method="post"> 用戶名:<input type="text" name="username" /><br/> <input type="submit" value="Submit"/> </form> </body> </html> |
index1.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>index1.jsp</title> </head>
<body> <h1>index1.jsp</h1> <% String username = (String)session.getAttribute("username");[崔22] if(username == null) { out.print("您尚未登陸!");[崔23] } else { out.print("用戶名:" + username);[崔24] } %> <hr/> <a href="/day06_4/index2.jsp">index2</a> </body> </html> |
index2.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>index2.jsp</title> </head>
<body> <h1>index2.jsp</h1> <% String username = (String)session.getAttribute("username"); if(username == null) { out.print("您尚未登陸!"); } else { out.print("用戶名:" + username); } %> <hr/> <a href="/day06_4/index1.jsp">index1</a> </body> </html> |
LoginServlet
public class LoginServlet extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8");
String username = request.getParameter("username");[崔25]
if(username.equalsIgnoreCase("itcast")[崔26] ) { response.getWriter().print("用戶名或密碼錯誤!"); } else { HttpSession session = request.getSession();[崔27] session.setAttribute("username", username);[崔28] response.sendRedirect("/day06_4/index1.jsp");[崔29] } } } |
session底層是依賴Cookie的!咱們來理解一下session的原理吧!
當我首次去銀行時,由於尚未帳號,因此須要開一個帳號,我得到的是銀行卡,而銀行這邊的數據庫中留下了個人帳號,個人錢是保存在銀行的帳號中,而我帶走的是個人卡號。
當我再次去銀行時,只須要帶上個人卡,而無需再次開一個帳號了。只要帶上個人卡,那麼我在銀行操做的必定是個人帳號!
當首次使用session時,服務器端要建立session,session是保存在服務器端,而給客戶端的session的id(一個cookie中保存了sessionId)。客戶端帶走的是sessionId,而數據是保存在session中。
當客戶端再次訪問服務器時,在請求中會帶上sessionId,而服務器會經過sessionId找到對應的session,而無需再建立新的session。
session保存在服務器,而sessionId經過Cookie發送給客戶端,但這個Cookie的生命不-1,即只在瀏覽器內存中存在,也就是說若是用戶關閉了瀏覽器,那麼這個Cookie就丟失了。
當用戶再次打開瀏覽器訪問服務器時,就不會有sessionId發送給服務器,那麼服務器會認爲你沒有session,因此服務器會建立一個session,並在響應中把sessionId中到Cookie中發送給客戶端。
你可能會說,那原來的session對象會怎樣?當一個session長時間沒人使用的話,服務器會把session刪除了!這個時長在Tomcat中配置是30分鐘,能夠在${CATALANA}/conf/web.xml找到這個配置,固然你也能夠在本身的web.xml中覆蓋這個配置!
web.xml
<session-config> <session-timeout>30</session-timeout> </session-config> |
session失效時間也說明一個問題!若是你打開網站的一個頁面開始長時間不動,超出了30分鐘後,再去點擊連接或提交表單時你會發現,你的session已經丟失了!
l String getId():獲取sessionId;
l int getMaxInactiveInterval():獲取session能夠的最大不活動時間(秒),默認爲30分鐘。當session在30分鐘內沒有使用,那麼Tomcat會在session池中移除這個session;
l void setMaxInactiveInterval(int interval):設置session容許的最大不活動時間(秒),若是設置爲1秒,那麼只要session在1秒內不被使用,那麼session就會被移除;
l long getCreationTime():返回session的建立時間,返回值爲當前時間的毫秒值;
l long getLastAccessedTime():返回session的最後活動時間,返回值爲當前時間的毫秒值;
l void invalidate():讓session失效!調用這個方法會被session失效,當session失效後,客戶端再次請求,服務器會給客戶端建立一個新的session,並在響應中給客戶端新session的sessionId;
l boolean isNew():查看session是否爲新。當客戶端第一次請求時,服務器爲客戶端建立session,但這時服務器尚未響應客戶端,也就是尚未把sessionId響應給客戶端時,這時session的狀態爲新。
咱們知道session依賴Cookie,那麼session爲何依賴Cookie呢?由於服務器須要在每次請求中獲取sessionId,而後找到客戶端的session對象。那麼若是客戶端瀏覽器關閉了Cookie呢?那麼session是否是就會不存在了呢?
其實還有一種方法讓服務器收到的每一個請求中都帶有sessioinId,那就是URL重寫!在每一個頁面中的每一個連接和表單中都添加名爲jSessionId的參數,值爲當前sessionid。當用戶點擊連接或提交表單時也服務器能夠經過獲取jSessionId這個參數來獲得客戶端的sessionId,找到sessoin對象。
index.jsp
<body> <h1>URL重寫</h1> <a href='/day06_5/index.jsp;jsessionid=<%=session.getId() %>'[崔30] >主頁</a>
<form action='/day06_5/index.jsp;jsessionid=<%=session.getId() %>' method="post"> <input type="submit" value="提交"/> </form> </body> |
也可使用response.encodeURL()對每一個請求的URL處理,這個方法會自動追加jsessionid參數,與上面咱們手動添加是同樣的效果。
<a href='<%=response.encodeURL("/day06_5/index.jsp") %>' >主頁</a>
<form action='<%=response.encodeURL("/day06_5/index.jsp") %>' method="post"> <input type="submit" value="提交"/> </form> |
使用response.encodeURL()更加「智能」,它會判斷客戶端瀏覽器是否禁用了Cookie,若是禁用了,那麼這個方法在URL後面追加jsessionid,不然不會追加。
在咱們註冊時,若是沒有驗證碼的話,咱們可使用URLConnection來寫一段代碼發出註冊請求。甚至可使用while(true)來註冊!那麼服務器就廢了!
驗證碼能夠去識別發出請求的是人仍是程序!固然,若是聰明的程序能夠去分析驗證碼圖片!但分析圖片也不是一件容易的事,由於通常驗證碼圖片都會帶有干擾線,人都看不清,那麼程序必定分析不出來。
如今咱們已經有了cn.itcast.utils.VerifyCode類,這個類能夠生成驗證碼圖片!下面來看一個小例子。
public void fun1() throws IOException { // 建立驗證碼類 VerifyCode vc = new VerifyCode(); // 獲取隨機圖片 BufferedImage image = vc.getImage(); // 獲取剛剛生成的隨機圖片上的文本 String text = vc.getText()[崔31] ; System.out.println(text); // 保存圖片 FileOutputStream out = new FileOutputStream("F:/xxx.jpg"); VerifyCode.output(image, out);[崔32] } |
咱們須要寫一個VerifyCodeServlet,在這個Servlet中咱們生成動態圖片,而後它圖片寫入到response.getOutputStream()流中!而後讓頁面的<img>元素指定這個VerifyCodServlet便可。
VerifyCodeServlet
public class VerifyCodeServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { VerifyCode vc = new VerifyCode(); BufferedImage image = vc.getImage(); String text = vc.getText(); System.out.println("text:" + text); VerifyCode.output(image, response.getOutputStream()); } } |
index.jsp
<script type="text/javascript"> function _change() { var imgEle = document.getElementById("vCode");[崔33] imgEle.src = "/day06_6/VerifyCodeServlet?" + new Date().getTime();[崔34] } </script> ... <body> <h1>驗證碼</h1> <img id="vCode" src="/day06_6/VerifyCodeServlet"/> <a href="javascript:_change()">看不清,換一張</a>[崔35] </body> |
<form action="/day06_6/RegistServlet[崔36] " method="post"> 用戶名:<input type="text" name="username"/><br/> 驗證碼:<input type="text" name="code" size="3"/> <img id="vCode" src="/day06_6/VerifyCodeServlet"/> <a href="javascript:_change()">看不清,換一張</a> <br/> <input type="submit" value="Submit"/> </form> |
修改VerifyCodeServlet
public class VerifyCodeServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { VerifyCode vc = new VerifyCode(); BufferedImage image = vc.getImage(); request.getSession().setAttribute("vCode", vc.getText());[崔37] VerifyCode.output(image, response.getOutputStream()); } } |
RegistServlet
public class RegistServlet extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8");
String username = request.getParameter("username"); String vCode = request.getParameter("code");[崔38]
String sessionVerifyCode = (String)request.getSession().getAttribute("vCode");[崔39]
if(vCode.equalsIgnoreCase(sessionVerifyCode)[崔40] ) { response.getWriter().print(username + ", 恭喜!註冊成功!"); } else { response.getWriter().print("驗證碼錯誤!"); } } } |
l VerifyCodeServlet:
l regist.jsp:
l RegistServlet:
[崔1]在<%=%>和<%%>中不用建立便可使用的對象!
[崔2]在<%=%>和<%%>中不用建立便可使用的對象!
[崔3]在<%=%>和<%%>中不用建立便可使用的對象!
[崔4]在<%=%>和<%%>中不用建立便可使用的對象!
[崔5]在<%=%>和<%%>中不用建立便可使用的對象!
[崔6]在<%=%>和<%%>中不用建立便可使用的對象!
[崔7]在<%=%>和<%%>中不用建立便可使用的對象!
[崔8]在<%=%>和<%%>中不用建立便可使用的對象!
[崔9]JSP頁面中的內容都會在這個位置出現!這時上面所說的對象已經建立完了,因此在JSP頁面中是可使用的。
[崔10]建立Cookie對象,名爲lasttime,值爲當前時間
[崔11]設置Cookie在客戶端的有效時間爲1小時
[崔12]添加Cookie到response中
[崔13]獲取請求中的Cookie
[崔14]若是請求中存在Cookie
[崔15]循環遍歷請求中的Cookie
[崔16]若是Cookie名爲lasttime
[崔17]設置s
[崔18]打印s到響應端
[崔19]使用URL編碼
[崔20]編碼後的字符串保存到Cookie中
[崔21]把Cookie的name和value使用URL解碼後再打印。
[崔22]在JSP頁面中能夠直接使用session不用建立。使用session獲取用戶名,若是沒有用戶名說明尚未登陸。
[崔23]若是session中沒有username,說明尚未登陸
[崔24]若是session中存在username,那麼輸出用戶名
[崔25]獲取表單參數username
[崔26]若是用戶爲itcast表示登陸失敗
[崔27]獲取session對象
[崔28]在session中保存用戶名
[崔29]重定向到index1.jsp
[崔30]請求注意,在index.jsp後面使用的是分號,而不是問號,這是服務器對jsessionid這個參數的特殊要求。
[崔31]這個方法必須在調用了getImage()方法以後才能使用。由於圖片沒有生成以前是不存在圖片上的文本的。
[崔32]把image圖片保存到out流中!
[崔33]獲取<img>元素
[崔34]從新指定src!由於有些瀏覽器會對其進行緩存,因此須要添加不一樣的參數,保證每次URL的參數都不一樣。
[崔35]點擊這個連接會執行_change()函數
[崔36]請求RegistServlet
[崔37]在session中保存驗證碼文本
[崔38]獲取表單中的驗證碼,這是用戶在表單中填寫的。
[崔39]獲取session中的驗證碼,這是在生成驗證碼圖片後,保存在session中的正確的驗證碼文本。
[崔40]比較用戶輸入的與真正的是否相同。