1. HTML 是靜態的,JSP是動態的,交互式的,而且可由用戶定製。
2. 服務器:可能是物理主機(硬件),也可能是Web服務器應用(軟件)。
客戶:指人類用戶,或瀏覽器應用。
Web客戶允許用戶請求服務器上的某個資源,並且向用戶顯示請求結果。
3. 服務器和客戶的通信
服務器和客戶之間對話的共同的語言是HTTP。
服務器使用HTTP向客戶發送信息。
4. HTTP
請求:HTTP方法(Get、Post),要訪問的頁面,表單參數。
響應:狀態碼,內容類型(文本、圖片、HTML等),內容(具體的HTML、圖片等)。
5. HTTP請求:Get請求和Post請求
Get請求:資源的路徑URL以及所有參數都會包括在”請求行”中。
請求行: GET /select/selectBeer.jsp?color=dark&taste=malty HTTP/1.1
請求首部:Host: www.wickedlysmart.com
User-Agent: Mozilla/5.0……
Accept: text/html,application/xml,application./xhtml+xml,
text/html;q=0.9
Accept-Language: en-us, en;q=0.5
Accept-Encoding: gizp,deflate
Accept-Charset: ISO-8859-1,utf;q=0.7,*;q=0.7
Keep-Alive:300
Connection: keep-alive
GET請求,沒有體,參數只能放在請求行中,並且會顯示在瀏覽器的輸入地址中,不夠安全。
POST請求:又稱爲“消息體”或“有效負載”,放在消息體中,長度不受限制。
請求行:POST /advisor/selectBeer.do HTTP/1.1
請求首部:同上
消息體:(空行)color=dark&taste=malty
簡單的超鏈接默認是GET方法,如:<a href=”http://www.baidu.com”>link</a>
Form表單默認也是GET方法。
GET、HEAD、PUT是冪等的(注:GET和doGet()不同,GET方法是HTTP的,doGet()是Servlet的);POST不是冪等的。
6. HTTP響應
包括響應首部和體
首部告訴瀏覽器使用的協議,請求是否成功,以及體中放入內容是什麼類型
HTTP/1.1 200 OK
Set-Cookie: jsessionID=adfiifeeni23499v99wernnwerr; Pat=/testEL
Content-Type: text/html(內容類型響應首部的值稱爲MIME類型,MIME類型告訴瀏覽器要接受的數據是什麼類型,其值與HTTP請求首部中的Accept所列的值相關)
Content-Length:397
Date: Wed, 19 Nov 2003 03:25:40 GMT
Server: Apache-Coyote/1.1
Connection: close
體中包含了讓瀏覽器顯示的具體內容:
(空行)
<html>……</html>
7. URL(Uniform Resource Locators)
http://www.smart.com:80/beeradvice/select/beer1.html
協議 服務器 端口 路徑 資源
FTP的端口是 31,Telnet:23,SMTP:25,Time:37,POP3:110,HTTPS:443
8. Web服務器不做的兩件事情
a) 動態內容。Web服務器應用只提供靜態頁面,動態內容由Web服務器輔助應用(CGI)來完成。
b) 在服務器上保存數據。Web服務器把這些功能轉給輔助應用進行處理。
9. Web容器
Web服務器(Apache)得到一個指向servlet的請求,服務器不是把這個請求直接交給servlet本身,而是交給Web容器(Tomcat),由Web容器調用servlet。
Web容器管理和運行servlet,容器知道自己與Web服務器之間的協議,Web容器控制者servlet的生命週期,容器會自動地爲它接收每個servlet請求並創建一個新的線程,Web容器負責把JSP代發翻譯成真正的Java代碼。
利用配置文件(web.xml)將servlet部署到容器
一個完全兼容的J2EE應用服務器必須有一個Web容器和一個EJB容器
Tomcat是一個Web容器,而不是一個完整的j2ee應用服務器,因爲Tomcat沒有EJB容器。
10. JSP-Servlet執行流程
1) 瀏覽器把請求數據發送給容器
2) 容器根據URL找到正確的Servlet,並把請求傳遞給這個Servlet
3) Servlet調用輔助應用尋求幫助
4) 這個輔助應用返回一個回答,Servlet把這個回答增加到請求對象
5) Servlet把請求轉發給JSP
6) JSP 從請求對象得到回答
7) JSP爲容器生成一個頁面
8) 容器把這個頁面返回給客戶
11. Servlet的生命週期
12. Servlet的屬性和參數
a) 屬性
有三種類型的屬性,應用上下文(ServletContext)、請求(HttpRequest)和會話(HttpSession)。
設置方法: setAttribute(String name,Object value)
獲取方法:getAttribute(String name), 返回類型是Object
上下文(ServletContext)屬性不是線程安全的,因爲每個Servlet都可以訪問。讓上下文屬性線程安全的做法:
同步服務器方法(即對doGet()或doPost()方法添加synchronized)
同步服務器方法意味着servlet中一次只能運行一個線程,但是並不能阻止其它servlet或JSP訪問這個屬性。
同步上下文(即 synchronized(getServletContext()))
synchronized(getServletContext()){
getServletContext().setAttribute("foo", "22");
getServletContext().setAttribute("bar", "42");
}
會話屬性:通常,一個客戶同時只有一個請求,就算多個servlet能在單獨的線程中訪問會話屬性,每個線程都是單獨的請求,所以,這時會話屬性是線程安全的。但是一個用戶同時有多個請求時(用戶同時打開多個瀏覽器去訪問),會話屬性是非線程安全的,通過同步HttpSession來達到線程安全。代碼如下:
HttpSession session=request.getSession();
synchronized(session){
session.setAttribute("foo", "22");
session.setAttribute("bar", "42");
}
b) 參數
應用上下文初始化參數、請求參數、servlet初始化參數
設置方法:servlet初始化參數只能在DD中設置
獲取方法:getInitParameter(String name)
13. Servlet接受提交的參數
a) 接受單個參數
String username=request.getParameter(“username”);
b) 接受多個參數
String [] parameters=request.getParameterValues(“sizes”);//sizes可以看做是表單中的複選框,如:
<form action=”**.do”>
<intput type=checkbox name=sizes value=”1”>1
<intput type=checkbox name=sizes value=”2”>2
<intput type=checkbox name=sizes value=”3”>3
<input type=”submit”>
</from>
14. ServletConfig和ServletContext
a) ServletConfig對象
每個servlet都有一個ServletConfig對象,用於向servlet傳遞部署信息。
在servlet初始化之前不能使用servlet初始化參數。
ServletConfig構建過程如下:
1) 容器讀取當前servlet的DD(web.xml),包括servlet初始化參數(<init-param>)
2) 容器爲這個servlet創建(new)一個新的ServletConfig實例
3) 容器爲這個servlet初始化參數創建一個String 名/值對
4) 容器向ServletConfig提供名/值初始化參數的引用
5) 容器創建(new)serlvet類的實例
6) 容器調用servlet的init()方法,傳入ServletConfig的引用
容器初始化一個servlet時,會爲這個servlet創建一個唯一的ServletConfig,容器從DD中讀出servlet初始化參數,並把這些參數交給ServletConfig,然後把ServletConfig傳遞給servlet的init()方法。
初始化參數:在web.xml配置文件中的<servlet>標籤中
<init-param>
<param-name>adminEmail</param-name>
<param-value>[email protected]</param-value>
</init-param>
在servlet中調用:getServletConfig().getInitParameter(“adminEmail”);
b) ServletContext對象
每個Web應用纔有一個ServletContext,用於訪問Web應用參數。Web應用中的各個servlet和JSP都能訪問ServletContext。
初始化參數:在web.xml配置文件中的<web-app>標籤中<servlet>標籤外
<context-param>
<param-name>contextname1</param-name>
<param-value>contextvalue1</param-value>
</context-param>
在servlet中調用:getServletContext().getInitParameter(“adminEmail”);
或者 ServletContext context=getServletContext();
context.getInitParameter(“adminEmail”);
在JSP中調用:
15. 使用響應
通常,使用響應只是向客戶發回數據,會調用兩個方法:setContentType()和getWriter()。當然,還可以使用響應設置其它首部、發送錯誤以及增加cookie。
response.setContentType(“application/jar”);
完成I/O
ServletContext ctx=getServletContext();
InputStream is=ctx.getResourceAsStream(“/book.jar”);//必須以“/”開頭,表示Web應用的根。
兩種輸出方式
字符形式:PrintWriter writer=response.getWriter();
writer.println(“some text and HTML”);
字節流形式: ServletOutputStream out=response.getOutputStream();
out.write(aByteArray);
16. 請求分派和重定向
a) 請求分派
RequestDispatcher view=request.getRequestDispatcher(“***.jsp”);// 爲 JSP 實例化一個請求分派器
view.forward(request , response);// 使用請求分派器要求容器準備好 JSP ,並向 JSP 發送請求和響應
b) 重定向
response.sendRedirect(“URL”);
其中 URL 是相對的 URL ,有兩種類型:前面有斜線和沒有斜線
例: 客戶原來的請求是 http://www.wick.com/myApp/cool/bar.do ,請求到達名爲“ bar.do ”的 Servlet 時,該 Servlet 中會基於一個相對的 URL 來調用 sendRedirect() 。 不帶斜線: sendRedirect(“foo/stuff.html”); 容器會相對於原先的請求 URL 建立完整的 URL ,即 http://www.wick.com/myApp/cool/foo/stuff.html
帶斜線的: sendRedirect(“/foo/stuff.html”); 容器會相對於 Web 應用本身建立完整的 URL ,而不是相對於原來的請求 URL ,即: http://www.wick.com/foo/stuff.html
請求分派是在服務器端發生,瀏覽器地址上的 URL 沒有改變 ( 相當於被請求的 Servlet 把請求傳遞給服務器上的另一個組件,而客戶並不知道 ) ;重定向是在客戶端進行,用戶會在瀏覽器地址欄中看到新的 URL( 相當於服務器又告訴瀏覽器去訪問另一個 URL) 。
17. HttpSession
http://www.blogjava.net/cheneyfree/archive/2007/05/26/120168.html
可以跨多個請求保存會話狀態,與一個特定可和的整個會話期間, HttpSession 對象會持久存儲。
在響應中發送一個會話:
HttpSession session=request.getSession();// 等價於 request.getSession(true)
//HttpSession session=request.getSession(false); 返回一個已經存在的會話,如果沒有與此客戶相關聯的會話,返回 null
Web 容器會自己生成會話 ID 、建立新的 Cookie 對象、把會話 ID 放到 cookie 中、在響應中設置 Cookie ( set-Cookie )首部。在後續的請求中,容器會從請求中的 cookie 得到會話 ID ,將這個 ID 與一個現有的會話匹配,並把會話與當前請求關聯。
如果用戶瀏覽器禁止使用 Cookie ,則在客戶的請求首部中就不會含有 ID Cookie 。這時可重寫 URL 讓客戶和容器交換會話 ID 信息。容器總是默認地先使用 cookie ,如果 cookie 不能工作,容器就會求助於 URL 重寫。 URL 重寫是自動的,但是必須對 URL 完成了編碼它才湊效。如:
out.println(“<a href=\””+response.encodeURL(“/beerTest.do”)+”\”>click </a>”)
重新定向時對 URL 的重編碼: response.encodeRedirectURL(“/beerTest.do”);
URL 編碼只與響應有關,不能在請求中和上下文調用這個方法。
URL重定向是服務器自動完成的,對開發人員來說是透明的。(經測,iteye使用Cookie保存用戶通行證的,禁用Cookie後,iteye登陸後,無法正常訪問)
實驗步驟:
1.兩個頁面 hello1.jsp,hello2.jsp
- hello1.jsp
- <body>
- <%
- String num ="100";
- session.setAttribute("num",num);
- //String url =response.encodeUrl("hello2.jsp");
- //String url =("hello2.jsp");
- %>
- <a href=<%=url%>>hello2.jsp</a>
- </body>
- hello2.jsp
- <body>
- <%=session.getAttribute("num")%>
- </body>
hello1.jsp
<body>
<%
String num ="100";
session.setAttribute("num",num);
//String url =response.encodeUrl("hello2.jsp");
//String url =("hello2.jsp");
%>
<a href=<%=url%>>hello2.jsp</a>
</body>
hello2.jsp
<body>
<%=session.getAttribute("num")%>
</body>
瀏覽器Cookie禁用,
打開hello1.jsp中的String url=response.encodeUrl("hello2.jsp");註釋
訪問http://localhost:8080/SessionTest/hello1.jsp,點擊hello2.jsp
會跳轉至hello2.jsp,瀏覽器地址欄顯示爲:
http://localhost:8080/SessionTest/hello2.jsp;jsessionid=85227A80E09D4443B0A037576B3270AF
頁面結果顯示爲 100
關閉hello1.jsp中的String url=response.encodeUrl("hello2.jsp");打開String url="hello2.jsp";註釋
訪問http://localhost:8080/SessionTest/hello1.jsp,點擊hello2.jsp
會跳轉至hello2.jsp,瀏覽器地址欄顯示爲:
http://localhost:8080/SessionTest/hello2.jsp
頁面結果顯示爲 null
2. 新建測試頁面index.jsp、test.jsp和SessionTestServlet.java
- index.jsp頁面
- <body>
- <a href="servlet/SesstionTest?userName=zzqrj">test1</a>
- </body>
- SessionTestServlet.java
- public void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- response.setContentType("text/html");
- PrintWriter out = response.getWriter();
- String userName = request.getParameter("userName");
- HttpSession session = request.getSession();
- session.setAttribute("userName", userName);
- //String url=response.encodeRedirectUrl("../test.jsp");
- //String url="../test.jsp";
- System.out.println(url);
- response.sendRedirect(url);
- //RequestDispatcher view=request.getRequestDispatcher(url);
- //view.forward(request, response);
- }
- test.jsp
- <body>
- <%=session.getAttribute("userName") %>
- <a href="<%=response.encodeUrl("servlet/SesstionTest") %>">test1</a>
- </body>
index.jsp頁面
<body>
<a href="servlet/SesstionTest?userName=zzqrj">test1</a>
</body>
SessionTestServlet.java
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String userName = request.getParameter("userName");
HttpSession session = request.getSession();
session.setAttribute("userName", userName);
//String url=response.encodeRedirectUrl("../test.jsp");
//String url="../test.jsp";
System.out.println(url);
response.sendRedirect(url);
//RequestDispatcher view=request.getRequestDispatcher(url);
//view.forward(request, response);
}
test.jsp
<body>
<%=session.getAttribute("userName") %>
<a href="<%=response.encodeUrl("servlet/SesstionTest") %>">test1</a>
</body>
測試方法同1,結果也同1.
3. 打開瀏覽器Cookie,分別對1,2中的頁面進行測試
不管是String url=response.encodeUrl("hello2.jsp");打開或是String url="hello2.jsp";打開,瀏覽器地址欄均不顯示" ;jsessionid=***** "。並且結果頁面總不爲null。
18. 刪除會話
a) 超時設置
程序: session.setMaxInactiveInterval(20*60);
// 改變特定會話實例的 session-timeout 值,不會影響應用中其他會話的超時時間。
DD 描述: 相當於在每個會話上調用 setMaxInactiveInterval() 方法
< session-config >
< session-timeout > 15 </ session-timeout > 單位是分鐘
</ session-config >
b) 在會話對象上調用 invalidate() : session.invalidate();
c) 應用程序結束
19. Cookie
Cookie 的作用
a) 支持會話狀態 。
b) 可以使用 cookie 在服務器和客戶之間交換名 / 值對 。
服務器把 cookie 發送給客戶,客戶再在以後的每個請求中把 cookie 發回,當客戶的瀏覽器退出時,會話 cookie 會自動消失,但是可以設置 cookie 在客戶端持久保存 。
使用 Cookie
( 1 )可以從 HTTP 請求和響應中得到與 Cookie 相關的首部 。
( 2 )利用 ServletAPI 使用 Cookie
創建新 Cookie : Cookie cookie=new Cookie(“username”,name);
設置 cookie 在客戶端存活時間: cookie.setMaxAge(30*60);
把 cookie 發送到客戶: response.addCookie(cookie);
從客戶請求得到 cookie :
Cookie[] cookies=request.getCookies();
for(int i=0;i<cookies.length;i++){
Cookie cookie=cookies[i];
if(cookie.getName().equals(“username”)){out.println(cookie.getValue());}
}
20. 會話生命週期
21. Servlet
是一種跨平臺語言的服務器端技術, 採用 Servlet 開發的應用,不用考慮平臺,多線程等讓人頭疼的問題,使得開發人員專注於業務邏輯的實現,大大解放了生產力。
Servlet 中嵌入 HTML 代碼是開發人員的噩夢