一、HTTP(超文本傳輸協議),它是一種主流的B/S架構中應用的通訊協議。具備如下特色:
1.一、無狀態:服務不會記錄客戶端每次提交的請求,服務器一旦響應客戶端以後,就會結束本次的通訊過程,客戶端下一次的請求是一個新的鏈接,和上一次通訊沒有任何關係html
1.二、簡單靈活:HTTP是基於請求和響應的模型java
支持客戶端與服務端:web
1.三、支持主流的B/S以及C/S架構的通訊。C/S架構可選的協議有多種,列如:TCP/IP、UDP、HTTP、等,而B/S架構一般只支持HTTP協議。數據庫
二、服務器
2.一、概念
服務器同常由硬件和軟件部分構成,對用戶提供相應的服務express
硬件:包括相應的CPU、內存、磁盤、等等api
軟件:包括操做系統、運行環境、服務端軟件、數據庫等等瀏覽器
2.二、Web服務器
web服務器是提供服務端程序運行的一個環境,它自己也是一個軟件緩存
列如:將咱們編寫的html文件放到web容器服務器中,那麼外界就能夠經過瀏覽器來訪問咱們的HTML頁面,tomcat
常見的web服務器有Apache、Tomcat、Jetty、Nginx等等,而Tomcat、Jetty、這些web服務器更準確地來講是一個Servlet容器服務器
3. Web項⽬結構
錄,例 如: myweb、 ch01 |
一般存放靜態資源⽂件(如: html等等) |
WEB-INF | 這個⽬錄是當前項⽬私有的⼀個⽂件夾,只能提供給項⽬內部訪問,對於客戶端來講是訪問 不到了,一般這個⽬錄下存放的是Java源代碼、編譯後的字節碼⽂件以及Servlet的核⼼配置⽂件web.xml |
src | 存放Java源代碼的⽬錄 |
classes | 存放編譯後的字節碼⽂件 |
llib | lib⽬錄存放當前項⽬所須要的jar⽂件 |
jsp ⻚⾯ | ⽤於存放JSP動態 |
web.xml | 項⽬的配置⽂件,⽤於配置Servlet的請求映射、過濾器、監聽器等等信息。每⼀個web項⽬都對應⼀個web.xml配置⽂件 |
4. Servlet基礎
4.1 什麼是Servlet6
Servlet是JavaEE中的標準組件之⼀,專⻔⽤於處理客
戶端的HTTP請求。而且它必須依賴於Servlet容器
(Tomcat就是⼀個標準的Servlet容器)才能夠運⾏,
⽽不能脫離這個環境⽽單獨執⾏。由於Servlet實例的
建立和銷燬都是由容器負責管理的,咱們不能⾃⾏經過
new關鍵去建立和使⽤它。
4.2 編寫⼀個簡單的Servlet
1.在任意地⽅建立⼀個myweb⽂件夾,這個⽂件夾相
當於⼀個項⽬根⽬錄
2.在根⽬錄下建立WEB-INF⼦⽬錄
3.在WEB-INF⽬錄下建立src和classes⼦⽬錄
4.在src⽬錄下編寫⼀個類,繼承HttpServlet這個⽗類
public class HelloServlet extends HttpServlet { }
2.重寫⽗類的service⽅法,這個就是專⻔處理客戶端請
求的⽅法, web容器會爲這個⽅法傳⼊兩個參數
HttpServletRequest和HttpServletResponse,而且這個
⽅法還須要拋出ServletException和IOException給容
器捕獲
public class HelloServlet extends HttpServlet { public void service(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{ //設置響應類型及編碼 response.setContentType("text/html;charset =utf-8"); //獲取字符輸出流輸出html信息 response.getWriter().println(" <h1>Hello Servlet</h1>") } }
5.編譯Servlet,須要依賴servlet-api.jar⽂件,將它添加
到classpath中
javac -cp d:\servlet-api.jar; HelloServlet.java
6.將編譯後的HelloServlet.class⽂件剪切到classes⽬
錄中
7.在WEB-INF⽬錄下建立並編輯web.xml⽂件,爲
servlet配置請求映射
<?xml version="1.0" encoding="utf-8"?> <!-- 配置根節點 --> <web-app> <!-- 配置servlet類 --> <servlet> <!-- 指定servlet的別名 --> <servlet-name>hello</servlet-name> <!-- 指定Servlet的完整類名--> <servlet-class>HelloServlet</servletclass> </servlet> <!-- 配置請求映射--> <servlet-mapping> <!-- 這⾥的servlet-name和上⾯的 servlet-name要⼀⼀對應 --> <servlet-name>hello</servlet-name> <!-- 配置請求映射的url,必須以「/」開頭--> <url-pattern>/hello</url-pattern> </servlet-mapping> </web-app>
8.將項⽬部署都tomcat的webapps⽬錄中,並執⾏bin⽬
錄下的startup.bat啓動容器
9.打開瀏覽器,在地址欄輸⼊http://localhost:8080/m
yweb/hello訪問Servlet
4.3 Servlet的請求處理流程
瀏覽器發起http的請求,這個請求⾸先會被servlet容器
(Tomcat)截獲,而後容器會根據web.xml⽂件中配
置servlet的來找到相應的這個別名,而後再根據這個
別名找到具體Servlet的類,而後容器會建立這個
Servlet類的實例並調⽤service⽅法來處理這個請求。
4.4 Servlet的⽣命週期
所謂的⽣命週期,就是從Servlet的建立⼀直到它銷燬
的整個過程。而且它的這個⽣命週期都是由Servlet容
器(Tomcat)負責管理和維護的。(補充:在Tomcat
中, Servlet是以單實例多線程的⽅式處理客戶端請
求)
4.4.1 Servlet對象建立的過程
當第⼀次請求某個Servlet的時候,容器會先查找以前
有沒有建立過這個Servlet的實例,若是沒有則建立⼀
個並緩存起來。後續相同的請求都由這個緩存的對象來
處理。(注意:這⾥說的是第⼀次請求時建立。另外⼀
種狀況則是在容器啓動的時候就建立Servlet的實例,
4.4.2 ⽣命週期⽅法
⽅法名 | 描述 |
init | 在Servlet對象建立以後⽴即執⾏的初始化 ⽅法,且只執⾏⼀次 |
service | 核⼼的請求處理⽅法,這個⽅法能夠執⾏ 屢次 |
destroy | 容器準備銷燬Servlet實例以前執⾏這個⽅ 法,也是執⾏⼀次 |
在web.xml中爲Servlet指定配置,這個配置的值是⼀個整型,數值越⼩,則初始化的優先級別越⾼)
4.5 HTTP報⽂組成
4.5.1 請求報⽂
請求⾏:請求報⽂的第⼀⾏就是請求⾏。包括請求⽅
法、請求URL地址、 HTTP協議版本。
請求頭:請求⾏以後的信息就是請求頭,它是以「名稱:
內容」的格式體現。主要包括服務器主機地址及端⼝、
鏈接狀態、系統信息、編碼、語⾔等等。
請求體:請求頭結束以後會有⼀個空⾏,空⾏以後就是
請求體的內容。一般使⽤POST提交的數據信息會存放
在請求體當中,而後傳遞給服務器。
4.5.2 響應報⽂
狀態⾏:主要包括HTTP協議、響應狀態碼(例如:
200表示OK,成功響應)。
響應頭:主要包括服務器信息、響應的類型及編碼、內容的⻓度、響應的時間等。
響應體:服務端能夠將信息數據攜帶到響應體中,帶回客戶端。
4.6 HTTP請求⽅法
在HTTP/1.1協議中,請求⽅法主要包括8個,下⾯列舉
常⽤的請求⽅法進⾏說明。
⽅法 | 說明 |
GET | 向服務器請求指定的資源,並返回響應主 體。⼀般來講GET⽅法應該只⽤於數據的 讀取(相似於查詢) |
POST | 向指定的服務器提交數據(例如:表單數 據的提交、⽂件上傳等) ,而且提交的數據 會放⼊請求體中(相似於新增) |
PUT | 向服務器提交數據,可是和POST有所區 別。若是服務器不存在此資源的時候,則 執⾏新增,若是存在則執⾏修改(相似於 修改) |
DELETE | 根據uri的標識刪除服務器上的某個資源 (相似於刪除) |
其餘 | ... |
備註: GET與POST區別:
1.GET主要⽤於獲取數據, POST⽤於提交數據。
2.GET請求所帶的參數是放在請求⾏的url地址後⾯,⽽POST這是放在請求體中。
3.一般瀏覽器會對GET請求的url⻓度有所限制,⽽POST提交的數據在請求體中,能夠提交更多的內容。
⽅法 | 說明 |
service | 能夠處理任何的請求類型 |
doGet | 處理對應的GET請求 |
doPost | 處理對應的POST請求 |
doPut | 處理對應的PUT請求 |
doDelete | 處理對應的DELETE請求 |
其餘 | ... |
4.瀏覽器會對GET請求進⾏緩存
說明:經過HttpServlet的源代碼得知,默認的全部請求都會先通過service⽅法,而後service⽅法根據請求
的⽅法類型判斷來決定交給doGet或者是doPost⽅法來處理請求。若是⼦類重寫了⽗類的service⽅法同時
還重寫了其餘的doXxx的⽅法,那麼只有service⽅法會處理請求,其餘⽅法將失效。
4.8 Request與Response對象
當web容器調⽤某個Servlet的Service⽅法時,會建立⼀個HttpServletRequest和HttpServletRespinse對象
做爲參數傳⼊到這個⽅法中,那麼咱們能夠經過HttpServletRequest來獲取相關的請求內容等,⽽響應客戶端
能夠利⽤HttpServletResponse對象來完成。
4.9 Servlet之間的通訊
4.9.1轉發
所謂轉發就是在多個Servlet之間共享請求和響應對象,全部參與轉發的過程的Servlet均可以獲取同一個請求對象的信息。
在servlet的API中,轉發的操做有HttpServletRequest
示例代碼:
package edu.nf.ch06.servlet; import java.io.IOException; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ServletA extends HttpServlet{ public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ System.out.println("請求通過ServletA,準備轉發給ServletB..."); //獲取頁面提交的參數 String name = request.getParameter("userName"); System.out.println("ServletA獲取請求參數:"+name); //可使用請求做用域(requestScope)而外攜帶一些數據到ServletB request.setAttribute("age", 35); System.out.println("設置請求做用域:age = " + 35); //轉發由HttpServletRequest完成 //第一步先獲取一個請求轉發器RequestDispatcher //獲取請求轉發器的同時要告訴轉發器轉發到哪裏,轉發給誰 //若是要轉發給ServletB,那麼就是對應ServletB的url-pattern RequestDispatcher rd = request.getRequestDispatcher("servletB"); //調用轉發器的forward方法執行轉發,同時將request和response對象一併轉發ServletB rd.forward(request, response); } }
package edu.nf.ch06.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ServletB extends HttpServlet{ @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("請求到達ServletB,並接收了同一個請求和響應對象"); //這裏在同一個請求中再次獲取頁面的參數 String name = request.getParameter("userName"); //從請求做用域中取出相應的值 Integer age = (Integer)request.getAttribute("age"); System.out.println("ServletB獲取請求參數:"+name); System.out.println("ServletB獲取請求做用域的值:"+age); } }
<servlet> <servlet-name>servletA</servlet-name> <servlet-class>edu.nf.ch06.servlet.ServletA</servlet-class> </servlet> <servlet-mapping> <servlet-name>servletA</servlet-name> <url-pattern>/servletA</url-pattern> </servlet-mapping> <servlet> <servlet-name>servletB</servlet-name> <servlet-class>edu.nf.ch06.servlet.ServletB</servlet-class> </servlet> <servlet-mapping> <servlet-name>servletB</servlet-name> <url-pattern>/servletB</url-pattern> </servlet-mapping>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <a href="servletA?userName=wangl">測試轉發</a><br/> </body> </html>
轉發的特色:
一、url的地址欄是不會發生改變的
二、轉發的過程是在服務端自動完成的
4.9.2 重定向
重定向的機制和轉發不一樣,一次重定向的過程當中會有兩次請求和兩次響應,服務器在接受第一次請求後悔先作一次302響應(302表示重定向狀態碼)
告訴客戶端瀏覽器必須發起一個新的請求地址,服務端再次接受這個請求處理,最後再次響應到客戶端。因爲會產生不一樣的響應對象,所以並不一樣共享同一個請求的參數
重定向是服務器通知瀏覽器去訪問另外一個地址,即再發出另外一個請求。
下面用一張圖來簡單描述下:
重定向的特色:
一、URL地址欄會發生改變
二、重定向的操做是在客戶端瀏覽器完成的
示例代碼:
package edu.nf.ch06.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ServletC extends HttpServlet { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("請求到達ServletC"); System.out.println("ServletC獲取請求參數:"+request.getParameter("userName")); //執行重定向 //方式一:設置302響應狀態碼,並在響應頭中添加location屬性指定重定向的地址 //response.setStatus(302); //response.addHeader("location", "http://localhost:8080/ch06/servletD"); //方式二: response.sendRedirect("servletD"); } }
package edu.nf.ch06.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ServletD extends HttpServlet{ @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("重定向到ServletD"); System.out.println("ServletD獲取請求參數:"+request.getParameter("userName")); } }
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <a href="servletC?userName=wangl">測試重定向</a> </body> </html>
4.10會話跟蹤
因爲HTTP協議是無狀態的,服務器並不會記錄每個客服端的狀態,所以,若是想要實現服務器能記錄客服端的狀態的話,那麼就須要會話跟蹤技術
4.1.1cookie
cookie是客服端瀏覽器內部的一個文本文件,專門用於記錄服務器發送過來的一些文本信息,那麼再次請求的時候,都把這個cookie信息由提交回給
相應的服務器,那麼服務器就能夠獲取客服端保存的信息,達到會話跟蹤的目的,使用cookie的機制是基於客戶端瀏覽器來維護與服務端的狀態跟蹤
cookie的生命週期:
示例代碼:
默認cookie只會保存在瀏覽器進程的內存中,並不會寫入cookie文件,若是關閉了瀏覽器,那麼瀏覽器的進程也就會消失,那麼對應的內存就會釋放空間,
所以cookie也就銷燬。若是想要cookie寫入文件,那麼就必須設置cookie的生命時長,一旦設置了生命時長,那麼就表示這個cookie會在文件中保留多長
時間,到了這個時間以後,瀏覽器就會自動銷燬這個cookie
設置cookie:
public class SetCookieServlet extends HttpServlet{ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //建立⼀個Cookie的實例 Cookie cookie = new Cookie("userId","10001"); //將cookie對象設置到響應對象中 response.addCookie(cookie); System.out.println("成功設置 cookie"); } }
獲取cookie
public class GetCookieServlet extends HttpServlet{ @Override protected void service(HttpServletRequest request, HttpServletResponse repsonse) throws ServletException, IOException { //cookie是經過request對象來獲得的 //從請求中能夠獲取多個cookie對象 Cookie[] cookies = request.getCookies(); for (Cookie cookie : cookies) { //判斷cookie,只獲取name爲userId 的cookie對象 if("userId".equals(cookie.getName())) { System.out.println(cookie.getValue()); } } } }
cookie保存中文 :
在保存cookie的時候若是須要保存中⽂,那麼中⽂信息
須要通過編碼後才能夠寫⼊cookie
示例代碼:
編碼使⽤URLEncoder
String str = URLEncoder.encode("張三", "utf-8"); Cookie cookie = new Cookie("userName", str);
解碼使⽤URLDecoder :
String str = URLDecoder.decode(cookie.getValue(),"utf-8"); System.out.println(str);
設置cookie的存活時間:
示例代碼:
//設置爲0表示⽴即刪除cookie cookie.setMaxAge(0); //設置爲正數表示cookie在cookie⽂件的存活時間, 單位:秒 cookie.setMaxAge(5); //設置爲-1表示cookie只保留在瀏覽器器的進程中, 關閉瀏覽器以後會銷燬cookie cookie.setMaxAge(-1);
4.4.2 Session
Session是基於服務端來保存用戶的信息,這個是和cookie最大的區別。不一樣的客服端在請求的服務器的時候,服務器會爲每個客服端建立一個
Session對象並保存在服務器端,Session對象是每個客服端所獨有的,相互之間不能訪問。服務器爲了區別不一樣的Session屬於哪個客戶端,所以Session
對象也有一個惟一標識,叫作SessionID.而這個SessionID是以cookie的機制保存在客戶端瀏覽器。每次請求的時候,瀏覽器都會把這個SessionID帶回服務端,服務端
根據這個SessionID就能夠找到對應的Session對象
示例代碼:
public class SessionServlet extends HttpServlet{ @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //HttpSession對象是在第⼀次調⽤ request的getSession()⽅法時纔會建立 //注意: getSession()的⽅法會先判斷之 前是否爲客戶端建立了session實例, //若是建立了,則使⽤以前建立好的 Session對象,沒有則建立⼀個新的Session HttpSession session = request.getSession(); //建立HttpSession的同時,會建立⼀個惟 ⼀的標識SessionID //這個sessionId會保存在瀏覽器的cookie 中,每次請求會帶回這個id找到相應的session對象 String sessionId = session.getId(); System.out.println(sessionId); } }
Session的生命週期:Session是保存在瀏覽器的cookie中,可是不會寫入cookie文件中,這也就是表示當關閉瀏覽器以後,Sessionid就會銷燬,Sessionid銷燬以後,服務端
的Session就沒有如何做用了,可是,服務器並不會馬上銷燬這個Session對象,至於何時銷燬是由服務器本身決定的,除非咱們手動調用了Session.invalidate()
方法,服務器就會馬上銷燬這個session實例
例如:
HttpSession session = request.getSession();
//⽴即銷燬session
session.invalidate();
二、Session默認也有存活時間,服務器建立session的時候,session設置默認的存活時間爲30分鐘,若是在30分鐘以內,
客戶端沒有發起任何請求到服務器來到服務器,那麼服務器就會銷燬這個Session對象,咱們也能夠設置Session的存活時間,
能夠爲當前的Session設置,也能夠爲全局(服務端全部的Session)的Session設置
設置當前的Session的超時(存活)時間:
HttpSession session = request.getSession(); //設置當前Session的存活時間,單位:秒 session.setMaxInactiveInterval(3600);
設置全局的Session存活時間:
在web.xml中進⾏設置 :
<!-- 設置全局Session的存活時間,單位:分鐘 --> <session-config> <session-timeout>60</session-timeout> </session-config>
Session的做用域:
當咱們須要一些數據信息出入Session的時候,就須要操做Session做用域(SessionScope),它和請求做用域相似,也有相應的setAttribute和getAttribute
的方法,只不過Session做用域的範圍要比請求做用域更寬,請求的做用域在一次請求響應以後,就會消失,(由於響應以後請求對象就會銷燬)。而Session
對象只要瀏覽器不關閉或者Session對象會一直駐留在服務器端,所以無論從新請求多少次仍是轉發和重定向,均可以重Session中獲取以前保存的數據信息
代碼示例:
User user = new User(); user.setUid("1001"); user.setUserName("wangl"); HttpSession session = request.getSession(); //將數據保存在會話做⽤域中 session.setAttribute("user", user);
重回復做用域中取值:
HttpSession session = request.getSession(); //取值 User user = (Object)session.getAttribute("user");
URL的重寫:
瀏覽器是能夠禁⽤cookie的,⼀旦禁⽤了cookie,那麼SessionId將⽆法寫⼊cookie的緩存中,這樣就致使⽆
法實現會話跟蹤了,所以解決辦法就是使⽤URL重寫。URL重寫的⽬的就是把SessionId在放在請求URL地址
的後⾯提交回服務器(相似GET請求後⾯帶上參數,⽽這個參數就是⼀個SessionId),服務器會解析這個
URL的地址並獲得SessionId。
代碼示例:
//重寫請求的URL地址,這個地址後⾯會⾃動帶上 SessionId String url = response.encodeRedirectURL("getSession"); //重定向URL response.sendRedirect(url);
瀏覽器地址演示:
http://localhost:8080/ch07/getSession;jsess ionid=6F1BA8C92D7E5D7CC479ED8DD30D3ED0
4.11 Servlet上下文
web容器在啓動時會爲每個web應用建立惟一的上下文對象,這個對象就是Servlet上下文對象(ServletContext),這個上下文對象能夠理解爲是當前項目的一個共享內存空間,爲項目中的全部Servlet提供一個共享的區域。
經常使用API:
getContextPath() | 獲取項目的相對路徑 |
getRealPath(String path) | 獲取項目的絕對路徑 |
getInitParameter(String name) | 獲取上下文的初始化參數(web.xml中配置的) |
setAttribute(String name, String value) | 將數據放入上下文做用域 |
getAttribute(String name) | 從上下文做用域中去獲取數據 |
上下文做用域:
上下文做用域是爲當前項目全部Servlet提供的一個共享內存區域,能夠將須要的數據信息保存在做用域中。這個做用域的的範圍是最大的,只要容器沒有中止,它就會一直存在。
三種做用域:
結合前面所學的做用域,那麼一共有三個,分別是:請求做用域,會話做用域,上下文做用域。
範圍從小到大來劃分:
請求做用域>會話做用域>上下文做用域
4.12 過濾器
過濾器能夠在請求到達servlet以前和servlet響應客戶端以前進行攔截,至關於一個攔截器
主要用於進行一些請求和響應的預處理操做,一般用的場景有限制權限的控制、統一字符編碼
4.12.1編寫過濾器
要實現一個過濾器必需要實現一個Filter接口,只有實現了這個接口的類才稱之爲過濾器
示例代碼:
public class DemoFilter implements Filter { ... }
<filter> <filter-name>demoFilter</filter-name> <filter-class>edu.nf.ch09.filter.DemoFilter</filter-class> <!-- 初始化參數 --> <init-param> <param-name>param</param-name> <param-value>hello</param-value> </init-param> </filter> <filter-mapping> <filter-name>demoFilter</filter-name> <!-- 什麼請求能夠通過此過濾器,/*表示全部請求 --> <url-pattern>/*</url-pattern> </filter-mapping>
4.12.2過濾器的生命週期
與servlet相似,Filter一樣也是容器負責建立和銷燬,與servlet的區別在於,容器會在啓動的時候最早建立全部
的顧慮器,並執行init方法進行初始化
生命週期的方法:
方法 | 說明 |
---|---|
init | 初始化方法,容器啓動時執行一次 |
doFilter | 請求過濾方法,決定請求是否放行 |
destroy | 容器銷燬過濾器以前執行的方法 |
public class DemoFilter implements Filter{ @Override public void destroy() { System.out.println("準備銷燬DemoFilter"); }
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //FilterChain表示一個過濾鏈對象,由於過濾器可能會存在多個 //同時這個對象將決定是否放行當前請求, //放行的話則請求會繼續到達下一個過濾器或者servlet中 System.out.println("請求通過DemoFileer..放行"); chain.doFilter(request, response); System.out.println("響應前通過DemoFilter..."); } @Override public void init(FilterConfig config) throws ServletException { String name = config.getInitParameter("param"); System.out.println("初始化DemoFilter,獲取初始化參數:"+name); } }
4.12.3 過濾鏈
在一個web項目中可能存在多個過濾器,當有多個過濾器存在的時候就會造成一個過濾鏈。請求會按照過濾器鏈的順序一直傳遞下去,最終到達某個Servlet來處理請求。(注意:過濾鏈的順序是按照web.xml中的前後配置順序決定的)
配置示例:
<!-- 按前後順序配置 --> <!-- 配置第一個過濾器 --> <filter> <filter-name>firstFilter</filter-name> <filter-class>edu.nf.ch09.filter.FirstFilter</filter-class> </filter> <filter-mapping> <filter-name>firstFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 配置第二個過濾器--> <filter> <filter-name>secondFilter</filter-name> <filter-class>edu.nf.ch09.filter.SecondFilter</filter-class> </filter> <filter-mapping> <filter-name>secondFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
4.13 監聽器
監聽器用於監聽對象的上的事件發生,在Servlet中監聽器主要監聽請求對象、會話對象、上下文對象以及監聽這些對象的做用域操做。JavaEE爲咱們提供了一系列的監聽器接口,開發時按需實現相應的接口便可。
4.13.1 監聽做做用域對象的建立與銷燬
監聽器 | 說明 |
---|---|
ServletRequestListener | 監聽請求對象的建立和銷燬 |
HttpSesisonListener | 監聽會話對象的建立和銷燬 |
ServletContextListener | 監聽Servlet上下文對象的建立和銷燬 |
1.請求對象監聽器
public class DemoRequestListener implements ServletRequestListener{ /** * 當請求對象銷燬後容器執行此方法 * 銷燬方法中一樣也有一個ServletRequestEvent事件對象 */ @Override public void requestDestroyed(ServletRequestEvent event) { //經過這個事件對象就能夠獲取當前的請求對象 HttpServletRequest request = (HttpServletRequest)event.getServletRequest(); System.out.println("銷燬請求對象..."+request); } /** * 當請求對象建立以後容器調用此方法 * ServletRequestEvent這個參數就是一個事件對象 */ @Override public void requestInitialized(ServletRequestEvent event) { //經過這個事件對象就能夠獲取當前的請求對象 HttpServletRequest request = (HttpServletRequest)event.getServletRequest(); System.out.println("初始化了請求對象..."+request); } }
<!-- 配置監聽器 --> <listener> <!-- 指定監聽器的完整類名 --> <listener-class>edu.nf.ch10.listener.DemoRequestListener</listener-class> </listener>
public class DemoSessionListener implements HttpSessionListener{ /** * 監聽HttpSession對象的建立 * HttpSessionEvent參數是一個事件對象 * 經過它能夠得到當前的HttpSession */ @Override public void sessionCreated(HttpSessionEvent event) { HttpSession session = event.getSession(); System.out.println("建立了Session對象"+session); } /** * 監聽HttpSession對象的銷燬 */ @Override public void sessionDestroyed(HttpSessionEvent event) { HttpSession session = event.getSession(); System.out.println("銷燬了Session對象"+session); } }
注意:當第一次調用了request.getSesison()方法建立Session時,監聽器纔會起做用。
web.xml配置
<listener> <!-- 指定監聽器的完整類名 --> <listener-class>edu.nf.ch10.listener.DemoSessionListener</listener-class> </listener>
public class DemoContextListener implements ServletContextListener{ /** * 監聽ServletContext的銷燬 */ @Override public void contextDestroyed(ServletContextEvent event) { //經過事件對象獲取ServletContext ServletContext sc = event.getServletContext(); System.out.println("銷燬了ServletContext對象..."+sc); } /** * 監聽SerlvetContext的建立 */ @Override public void contextInitialized(ServletContextEvent event) { //經過事件對象獲取ServletContext ServletContext sc = event.getServletContext(); System.out.println("建立了ServletContext對象..."+sc); } }
<listener> <!-- 指定監聽器的完整類名 --> <listener-class>edu.nf.ch10.listener.DemoContextListener</listener-class> </listener>
4.13.2 監聽做用域的操做
監聽器 | 說明 |
---|---|
ServletRequestAttributeListener | 監聽請求做用域的操做 |
HttpSessionAttributeListener | 監聽會話做用域的操做 |
ServletContextAttributeListener | 監聽Servlet上下文做用域的操做 |
示例代碼:這裏以HttpSessionAttributeListener說明,其餘做用於監聽器用法類似。
public class DemoSessionAttributeListener implements HttpSessionAttributeListener{ /** * 當有數據添加到會話做用域時,執行此方法 */ @Override public void attributeAdded(HttpSessionBindingEvent event) { //獲取存入做用域的鍵和值 System.out.println("存入會話做用域..."+event.getName() + " : " + event.getValue()); } /** * 當從會話做用域移除數據時,執行此方法 */ @Override public void attributeRemoved(HttpSessionBindingEvent event) { System.out.println("移除會話做用域..."+event.getName() + " : " + event.getValue()); } /** * 當替換了會話做用域中的某個數據時,執行此方法 */ @Override public void attributeReplaced(HttpSessionBindingEvent event) { HttpSession session = event.getSession(); //從session中獲取的是替換以後的值 System.out.println("替換的值: "+session.getAttribute("userName").toString()); //注意:這裏event.getValue()獲取到的是替換以前的值 System.out.println("替換會話做用域..."+event.getName() + " : " + event.getValue()); } }
web.xml 配置
<listener> <!-- 指定監聽器的完整類名 --> <listener-class>edu.nf.ch10.listener.DemoSessionAttributeListener</listener-class> </listener>
4.14 註解配置
Servlet3.0開始提供了一系列的註解來配置Servlet、Fiilter、Listener等等。這種方式能夠極大的簡化在開發中大量的xml的配置。
從這個版本開始,web.xml能夠再也不須要,使用相關的註解一樣能夠完成相應的配置。徹底配置,
註解 | 說明 |
---|---|
@WebServlet | 這個註解標識在類上,用於配置Servlet。例如:@WebServlet(name="hello", urlPatterns="/hello") 也可簡化配置@WebServlet("/hello") |
@WebFilter | 這個註解標識在類上,用於配置Filter。例如:@WebFilter(filterName="encode",urlPatterns="/") 也可簡化配置@WebFilter("/"), |
@WebListener | 這個註解標識在類上,用於配置監聽器 |
5. JSP基礎
5.1 簡介
JSP全名爲java Server Pages,中文名叫java服務器頁面,是一種動態頁面技術,而HTML是屬於靜態頁面。JSP
能夠在HTML中嵌入java腳本代碼,由於JSP本質上仍是一個Servlet,所以JSP也必須依賴於web容器才能運行
JSP的出現並非爲了去掉Servlet,而是簡化了Servlet的工做,將Servlet中繁瑣的視圖呈現代碼脫離出來,交給
JSP來完成,讓Servlet專一於請求的處理,全部在開發中一般將jsp和Servlet結合一塊兒使用
5.2JSP引擎
因爲JSP本質上就是一個Servlet,那麼JSP文件轉義成一個Servlet的java源文件,而後經過javac將這個源文件編譯成class
字節碼文件並裝載到JVM中執行,JSP引擎的核心類是JSPServlet,位於Jasper.jar文件張總,而且在Tomcat的web
.xml中也默認就配置好了這個類(JSPServlet也是一個servlet,所以凡是以「.jsp」結尾的請求都會先通過JSPServlet
,那麼這個引擎就能夠開始工做了。一般引擎轉義和編譯後的文件放在容器的work工做目錄中)
注意:若是第一次訪問jsp文件的時候,因爲work目錄中並不存在源文件和字節碼文件,jsp引擎就必須完成這兩個工做,
所以,有可能在第一次訪問jsp時會比較緩慢,當字節碼編譯出來加載後,第二次訪問時的速度就會很快了
5.3JSP的三大元素
語法:<%@ %>
指令 | 說明 |
---|---|
page指令 | 用於設置JSP頁面的相關信息以及編碼 |
include指令 | 用於靜態包含其餘的JSP頁面代碼,所謂靜態包含,就是在編譯期,將另外的JSP頁面的代碼合併到當前的JSP中,最終只會產生一個Java源文件 |
taglib指令 | 這個指令用於引入標籤庫 |
5.3.2 動做元素
語法:jsp:xxx
動做 | 說明 |
---|---|
include | 動態包含其餘JSP頁面的內容,所謂的動態包含是指在編譯期將不一樣的JSP文件轉義成不一樣的Java源文件,而後在運行時纔將目標內容包含到當前的JSP頁面中 |
forward | 至關於Servlet中的轉發,轉發到其餘的JSP頁面或者Servlet |
param | 用於傳遞參數,一般結合其餘的動做一塊兒使用,例如轉發時須要提交一些而外的參數 |
useBean | 用於在JSP頁面中使用JavaBean對象,一般結合setProperty和getProperty來使用,完成bean對象的賦值和取值操做 |
5.3.3 腳本元素
腳本元素主要就是在JSP中嵌入Java腳本代碼,包括聲明、表達式、Java腳本
聲明語法:<%! %>
表達式: <%= %>
Java腳本: <% %>
代碼實例:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <%-- 聲明變量和方法,這裏聲明的變量a是實例變量 --%> <%! int a = 10; public void say(){ System.out.println("hello"); } %> <%-- 表達式,注意:表達式後面是不容許有;號結束的 --%> 3 + 1 = <%=3+1%><br/> <%-- Java腳本,腳本代碼最終會生成在servlet中的service方法中做爲代碼片斷 --%> <table border="1"> <tr> <th>Name</th> <th>Age</th> </tr> <% for(int i=0;i<5;i++){%> <tr> <td>user<%=i%></td> <td><%=10+i%></td> </tr> <%}%> </table> </body> </html>
5.4 JSP內置對象
內置對象,是在容器運行時將建立好的9個對象內嵌在JSP中,在JSP裏能夠直接拿來使用的對象。
對象 | 說明 |
---|---|
out | 字符流輸出對象 |
config | 等同於Servlet中的ServletConfig |
page | 表示當前JSP頁面 |
request | 等同於Servlet中的HttpServletRequest |
response | 等同於Servlet中的HttpServletResponse |
session | 等同於Servlet中的HttpSession |
application | 等同於Servlet中的ServletContext |
pageContext | 表示當前JSP頁面的上下文對象 |
exception | 表示當前JSP中的異常對象 |
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <%-- 經常使用內置對象 --%> <% //使用request,API使用同HttpServletRequest同樣 request.getParameter("userName"); request.setAttribute("user", "user1"); request.getAttribute("user"); //使用session,API使用等同於HttpSession session.setAttribute("user", "user2"); session.getAttribute("user"); session.getId(); //使用response //response.sendRedirect("demo.jsp"); //out對象,等同於字符輸出流對象,在JSP頁面輸出相關內容 out.println("hello world"); //這個是輸出在控制中 System.out.println("hello"); //使用application,等同於ServletContext application.setAttribute("userName", "user3"); //pageContext使用 //從pageContext中獲取相關的其餘對象 HttpServletRequest req = (HttpServletRequest)pageContext.getRequest(); HttpServletResponse res = (HttpServletResponse)pageContext.getResponse(); HttpSession ses = pageContext.getSession(); ServletConfig conf = pageContext.getServletConfig(); ServletContext sc = pageContext.getServletContext(); //也能夠經過pageContext來統一設置不一樣的做用域 //第三個參數表示要放入到哪一個做用域,是一個int類型的參數 //1表明page做用域(當前頁面有效) //2表明請求做用域 //3表明會話做用域 //4表明上下文做用域 pageContext.setAttribute("userName", "zhangsan", 2); //也能夠指定中哪一個做用域取出相應的值 String name = (String)pageContext.getAttribute("userName", 2); out.println(name); %> </body> </html>
5.5 EL表達式
EL(Expression Language),全稱叫作表達式語言,是JSP2.0推出的一種技術。主要簡化了在JSP中使用Java腳本表達式。EL表達式的特色在於使用簡單,支持四則運算、邏輯運算等,而且還能夠對Servlet API中的對象進行數據訪問。EL的語法: ${expression}
運算:
示例 | 結果 |
---|---|
${1+1} | 2 |
${2*2} | 4 |
${1==1} | true |
${2>5} | false |
其餘 | ... |
數據訪問:
1.使用「.」來訪問
示例 | 說明 |
---|---|
${param.參數名} | 獲取請求參數的值,至關於使用request.getParameter()方法 |
${requestScope.xxx} | 從請求做用域中訪問數據 |
${sessionScope.xxx} | 從會話做用域中訪問數據 |
${applicationScope.xxx} | 從上下文做用域中訪問數據 |
${xxx} | 不指定做用域範圍時,默認按照做用域範圍從小到大的順序自動查找 |
其餘 | ... |
2.使用"[]"來訪問
示例 | 說明 |
---|---|
${requestScope[「userName」]} | 從請求做用域中取值 |
${sessionScope[「userName」]} | 從會話做用域取值 |
其餘... | 同上 |
注意:一般使用"[]"來訪問數據的時候,主要是訪問一些特殊的名稱,例如:request.setAttribute("user.userName")
這種方式若是使用${requestScope.user.userName}是訪問不到的,應該改成
${requestScope["user.userName"]}來訪問
5.6 JSTL核心標籤庫
JSTL是JSP中的標準標籤庫,主要用於取代JSP中大量的Java腳本代碼,讓頁面看起來更趨向於HTML。使用也很簡單,一般結合EL表達式一塊兒使用
示例:
核心標籤庫(core) | 說明 |
---|---|
c:out | 輸出標籤 |
c:set | 聲明某個變量並存入指定的做用域 |
c:redirect | 重定向標籤 |
c:if | 條件判斷 |
c:forEach | 循環標籤 |
其餘 | ... |
備註:其餘標籤庫請參閱相關官方文檔