WEB過濾器是一個(gè)服務(wù)器端的組件,它可以截取用戶端的請(qǐng)求與相應(yīng)信息,并對(duì)這些信息過濾。
過濾器的工作原理和生命周期在沒有Web過濾器的情況下,用戶直接訪問服務(wù)器上的Web資源。但是如果存在過濾器,用戶就不可以直接訪問過濾器了。
Web容器啟動(dòng)的時(shí)候過濾器就已經(jīng)啟動(dòng)了,用戶的請(qǐng)求到達(dá)過濾器,過濾器判斷用戶的請(qǐng)求是否符合過濾規(guī)則,如果符合規(guī)則則將用戶的請(qǐng)求發(fā)送給Web資源,Web資源將響應(yīng)信息發(fā)送給過濾器,過濾器將Web資源的響應(yīng)發(fā)送給用戶。工作原理如下圖所示:

過濾器的生命周期:

其中實(shí)例化方法在Web容器開始裝載的時(shí)候就執(zhí)行,初始化方法配置一些初始化參數(shù),Web容器卸載(服務(wù)器關(guān)閉)的時(shí)候執(zhí)行銷毀方法。過濾方法會(huì)執(zhí)行多次,其他方法只會(huì)執(zhí)行一次。
第一個(gè)過濾器1.創(chuàng)建一個(gè)類實(shí)現(xiàn)javax.servlet.Filter接口。需要實(shí)現(xiàn)該接口中的3個(gè)方法。

1 package filter; 2 3 import java.io.IOException; 4 5 import javax.servlet.Filter; 6 import javax.servlet.FilterChain; 7 import javax.servlet.FilterConfig; 8 import javax.servlet.ServletException; 9 import javax.servlet.ServletRequest;10 import javax.servlet.ServletResponse;11 12 public class FirstFilter implements Filter {13 14 public void destroy() {15 System.out.FirstFilter.java- init(FilterConfig):過濾器的初始化方法,Web容器創(chuàng)建過濾器之后將調(diào)用這個(gè)方法,在這個(gè)方法中可以讀取web.xml中的過濾器參數(shù)。
- doFilter(ServletRequest,ServletResponse,FilterChain):完成實(shí)際的過濾操作,是過濾器的核心方法。當(dāng)用戶請(qǐng)求訪問與過濾器相關(guān)聯(lián)的URL的時(shí)候,Web容器將先調(diào)用過濾器的doFilter方法。FilterChain參數(shù)可以調(diào)用chain.doFilter方法【放行方法】,將請(qǐng)求傳送給下一個(gè)過濾器(或者目標(biāo)資源),或利用轉(zhuǎn)發(fā)、重定向?qū)⒄?qǐng)求轉(zhuǎn)發(fā)給其他資源。
- destroy():Web容器在銷毀過濾器實(shí)例前調(diào)用該方法,在這個(gè)方法中可以釋放過濾器占用的資源。【大多數(shù)情況下用不到】
2.在web.xml中配置過濾器(和再web.xml中注冊(cè)servlet類似)

在MyEclipse中提供了可視化的配置web.xml,如下圖:


1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app version="2.5" 3 xmlns="http://java.sun.com/xml/ns/javaee" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 6 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> 7 <display-name></display-name> 8 <welcome-file-list> 9 <welcome-file>index.jsp</welcome-file>10 </welcome-file-list>11 12 <!-- 配置過濾器開始 -->13 <filter>14 <filter-name>FirstFilter</filter-name>15 <filter-class>filter.FirstFilter</filter-class>16 </filter>17 <filter-mapping>18 <filter-name>FirstFilter</filter-name>19 <url-pattern>/*</url-pattern>20 </filter-mapping>21 <!-- 配置過濾器結(jié)束 -->22 23 </web-app>
web.xml 在index.jsp中我們?cè)诳刂婆_(tái)打印一行信息:"**********這是index.jsp*********";
將項(xiàng)目部署到服務(wù)器,啟動(dòng)服務(wù)器:

在Servlet容器裝載的時(shí)候,執(zhí)行過濾器的init方法,當(dāng)用戶請(qǐng)求頁面的時(shí)候首先執(zhí)行doFilter()方法,當(dāng)Servlet容器卸載的時(shí)候執(zhí)行過濾器的銷毀方法。【注意:用戶的請(qǐng)求先是到達(dá)過濾器并不是直接訪問的Web資源】
還有一點(diǎn)需要注意:用戶雖然能夠改變用戶請(qǐng)求的資源(例如:網(wǎng)上購物的時(shí)候點(diǎn)擊“立即購買”,這個(gè)請(qǐng)求先要到達(dá)過濾器,如果過濾器檢測(cè)到用戶沒有登錄,就會(huì)將頁面重定向到登陸頁),但是過濾器不能直接處理用戶的請(qǐng)求(過濾器不是Servlet),不能直接返回?cái)?shù)據(jù)。
過濾器鏈 針對(duì)同一個(gè)用戶請(qǐng)求(url-pattern),與之匹配的過濾器有多個(gè),這個(gè)時(shí)候用戶請(qǐng)求就會(huì)依次通過各個(gè)過濾器到達(dá)web資源。


新建2個(gè)過濾器:

1 package filter; 2 3 import java.io.IOException; 4 5 import javax.servlet.Filter; 6 import javax.servlet.FilterChain; 7 import javax.servlet.FilterConfig; 8 import javax.servlet.ServletException; 9 import javax.servlet.ServletRequest;10 import javax.servlet.ServletResponse;11 12 public class FirstFilter implements Filter {13 14 public void destroy() {15 System.out.println("*********過濾器1----->銷毀方法*******");16 17 }18 19 public void doFilter(ServletRequest request, ServletResponse response,20 FilterChain filterChain) throws IOException, ServletException {21 System.out.println("*******開始執(zhí)行過濾器1----->doFilter方法*********");22 filterChain.doFilter(request, response);23 System.out.println("*******結(jié)束執(zhí)行過濾器1----->doFilter方法**********");24 }25 26 public void init(FilterConfig arg0) throws ServletException {27 System.out.println("*******執(zhí)行過濾器1------>初始化方法***********");28 29 }30 31 }FirstFilter.java
1 package filter; 2 3 import java.io.IOException; 4 5 import javax.servlet.Filter; 6 import javax.servlet.FilterChain; 7 import javax.servlet.FilterConfig; 8 import javax.servlet.ServletException; 9 import javax.servlet.ServletRequest;10 import javax.servlet.ServletResponse;11 12 public class SecondFilter implements Filter {13 14 public void destroy() {15 System.out.println("*********過濾器2----->銷毀方法*******");16 }17 18 public void doFilter(ServletRequest request, ServletResponse response,19 FilterChain filterChain) throws IOException, ServletException {20 System.out.println("*******開始執(zhí)行過濾器2----->doFilter方法*********");21 filterChain.doFilter(request, response);22 System.out.println("*******結(jié)束執(zhí)行過濾器2----->doFilter方法**********");23 }24 25 public void init(FilterConfig arg0) throws ServletException {26 System.out.println("*******執(zhí)行過濾器2------>初始化方法***********");27 }28 29 }SecondFilter.java 在web.xml中配置兩個(gè)過濾器(第一個(gè)過濾器在前面,兩個(gè)過濾器都匹配index.jsp)

1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app version="2.5" 3 xmlns="http://java.sun.com/xml/ns/javaee" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 6 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> 7 <display-name></display-name> 8 <welcome-file-list> 9 <welcome-file>index.jsp</welcome-file>10 </welcome-file-list>11 12 <!-- 配置過濾器開始 -->13 <!-- 過濾器1 -->14 <filter>15 <filter-name>FirstFilter</filter-name>16 <filter-class>filter.FirstFilter</filter-class>17 </filter>18 <filter-mapping>19 <filter-name>FirstFilter</filter-name>20 <url-pattern>/index.jsp</url-pattern>21 </filter-mapping>22 <!-- 過濾器2 --> 23 <filter>24 <filter-name>SecondFilter</filter-name>25 <filter-class>filter.SecondFilter</filter-class>26 </filter>27 <filter-mapping>28 <filter-name>SecondFilter</filter-name>29 <url-pattern>/index.jsp</url-pattern>30 </filter-mapping>31 <!-- 配置過濾器結(jié)束 -->32 33 </web-app>
web.xml 在index.jsp中我們打印如下的一句話:System.out.println("******** 這是index.jsp,處理過程完成 *********");
運(yùn)行結(jié)果:

過濾器的分類: Servlet 2.5中將過濾器分為4種,如下圖所示:

1.REQUEST過濾器
新建一個(gè)過濾器FirstFilter(在web.xml中配置兩個(gè)過濾地址index.jsp和main.jsp):

1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app version="2.5" 3 xmlns="http://java.sun.com/xml/ns/javaee" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 6 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> 7 <display-name></display-name> 8 <welcome-file-list> 9 <welcome-file>index.jsp</welcome-file>10 </welcome-file-list>11 12 <!-- 配置過濾器開始 -->13 <filter>14 <filter-name>FirstFilter</filter-name>15 <filter-class>filter.FirstFilter</filter-class>16 </filter>17 <filter-mapping>18 <filter-name>FirstFilter</filter-name>19 <url-pattern>/index.jsp</url-pattern>20 <dispatcher>REQUEST</dispatcher>21 </filter-mapping>22 <filter-mapping>23 <filter-name>FirstFilter</filter-name>24 <url-pattern>/main.jsp</url-pattern>25 <dispatcher>REQUEST</dispatcher>26 </filter-mapping>27 <!-- 配置過濾器結(jié)束 -->28 29 </web-app>
web.xml 在FirstFilter的doFilter方法中將頁面重定向到main.jsp

1 package filter; 2 3 import java.io.IOException; 4 5 import javax.servlet.Filter; 6 import javax.servlet.FilterChain; 7 import javax.servlet.FilterConfig; 8 import javax.servlet.ServletException; 9 import javax.servlet.ServletRequest;10 import javax.servlet.ServletResponse;11 import javax.servlet.http.HttpServletRequest;12 import javax.servlet.http.HttpServletResponse;13 14 public class FirstFilter implements Filter {15 16 public void destroy() {17 System.out.println("*********過濾器1----->銷毀方法*******");18 19 }20 21 public void doFilter(ServletRequest request, ServletResponse response,22 FilterChain filterChain) throws IOException, ServletException {23 24 HttpServletRequest req = (HttpServletRequest) request;25 HttpServletResponse res = (HttpServletResponse) response;26 27 System.out.println("*******開始執(zhí)行過濾器1----->doFilter方法*********");28 res.sendRedirect(req.getContextPath() + "/main.jsp");//重定向29 System.out.println("*******結(jié)束執(zhí)行過濾器1----->doFilter方法**********");30 }31 32 public void init(FilterConfig arg0) throws ServletException {33 System.out.println("*******執(zhí)行過濾器1------>初始化方法***********");34 35 }36 37 }FirstFilter.java 啟動(dòng)服務(wù)器:


當(dāng)我們?cè)L問index.jsp的時(shí)候,過濾器將頁面重定向到main.jsp——相當(dāng)于我們又重新請(qǐng)求了main.jsp,main.jsp又會(huì)遇到過濾器,如此頁面不停重定向到main.jsp,產(chǎn)生了死循環(huán)不會(huì)輸出任何內(nèi)容!
換一種方式,我們?cè)谶^濾器中使用服務(wù)器內(nèi)部轉(zhuǎn)發(fā)的方式將頁面轉(zhuǎn)發(fā)到main.jsp(main.jsp向頁面打印"這是main.jsp")。

1 package filter; 2 3 import java.io.IOException; 4 5 import javax.servlet.Filter; 6 import javax.servlet.FilterChain; 7 import javax.servlet.FilterConfig; 8 import javax.servlet.ServletException; 9 import javax.servlet.ServletRequest;10 import javax.servlet.ServletResponse;11 import javax.servlet.http.HttpServletRequest;12 import javax.servlet.http.HttpServletResponse;13 14 public class FirstFilter implements Filter {15 16 public void destroy() {17 System.out.println("*********過濾器1----->銷毀方法*******");18 19 }20 21 public void doFilter(ServletRequest request, ServletResponse response,22 FilterChain filterChain) throws IOException, ServletException {23 24 HttpServletRequest req = (HttpServletRequest) request;25 HttpServletResponse res = (HttpServletResponse) response;26 27 System.out.println("*******開始執(zhí)行過濾器1----->doFilter方法*********");28 req.getRequestDispatcher("main.jsp").forward(request, response);//使用服務(wù)器內(nèi)部轉(zhuǎn)發(fā)29 System.out.println("*******結(jié)束執(zhí)行過濾器1----->doFilter方法**********");30 }31 32 public void init(FilterConfig arg0) throws ServletException {33 System.out.println("*******執(zhí)行過濾器1------>初始化方法***********");34 35 }36 37 }FirstFilter.java 運(yùn)行結(jié)果:

2.FORWARD過濾器
將main.jsp的過濾規(guī)則改為FORWARD。
1 …… 2 <filter-mapping>3 <filter-name>FirstFilter</filter-name>4 <url-pattern>/main.jsp</url-pattern>5 <dispatcher>FORWARD</dispatcher>6 </filter-mapping>7 ……
重新訪問index.jsp

3.INCLUDE過濾器
INCLUDE和FORWARD過濾器的使用類似,對(duì)應(yīng)的jsp動(dòng)作是include。
4.ERROR過濾器
例如我們?cè)L問一個(gè)錯(cuò)誤的頁面時(shí),系統(tǒng)會(huì)給出一個(gè)錯(cuò)誤,用戶看不懂這個(gè)錯(cuò)誤是什么概念——我們需要給出一些人性化的提示。
以下是沒有在web.xml中配置錯(cuò)誤頁,用戶訪問一個(gè)不存在的頁面:

在web.xml中配置錯(cuò)誤頁:

1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app version="2.5" 3 xmlns="http://java.sun.com/xml/ns/javaee" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 6 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> 7 <display-name></display-name> 8 <welcome-file-list> 9 <welcome-file>index.jsp</welcome-file>10 </welcome-file-list>11 12 <!-- 配置錯(cuò)誤頁面 -->13 <error-page>14 <error-code>404</error-code>15 <location>/error.jsp</location>16 </error-page>17 18 </web-app>
web.xml 在web.xml中配置404錯(cuò)誤的頁面為error.jsp則當(dāng)用戶訪問一個(gè)不存在的頁面時(shí)將會(huì)將error.jsp中的內(nèi)容輸出(以人性化的方式提示用戶):

當(dāng)頁面出現(xiàn)錯(cuò)誤或者異常的時(shí)候,ERROR過濾器可以將錯(cuò)誤或者異常捕捉到,系統(tǒng)會(huì)記錄下錯(cuò)誤的信息,程序員就可以查找錯(cuò)誤的來源。
新建一個(gè)ErrorFilter,并在web.xml中進(jìn)行如下配置:

1 <!-- 配置錯(cuò)誤頁面 --> 2 <error-page> 3 <error-code>404</error-code> 4 <location>/error.jsp</location> 5 </error-page> 6 …… 7 <filter> 8 <filter-name>ErrorFilter</filter-name> 9 <filter-class>filter.ErrorFilter</filter-class>10 </filter>11 <filter-mapping>12 <filter-name>ErrorFilter</filter-name>13 <url-pattern>/error.jsp</url-pattern>14 <dispatcher>ERROR</dispatcher>15 </filter-mapping>16 ……
web.xml 錯(cuò)誤過濾器ErrorFilter

1 package filter; 2 3 import java.io.IOException; 4 5 import javax.servlet.Filter; 6 import javax.servlet.FilterChain; 7 import javax.servlet.FilterConfig; 8 import javax.servlet.ServletException; 9 import javax.servlet.ServletRequest;10 import javax.servlet.ServletResponse;11 12 public class ErrorFilter implements Filter {13 14 public void destroy() {15 16 }17 18 public void doFilter(ServletRequest request, ServletResponse response,19 FilterChain filterChain) throws IOException, ServletException {20 System.out.println("檢測(cè)到錯(cuò)誤信息!");21 filterChain.doFilter(request, response);//注意打印錯(cuò)誤后要放行,不然頁面不會(huì)顯示22 }23 24 public void init(FilterConfig filterConfig) throws ServletException {25 26 }27 28 }ErrorFilter.java 
J2EE5默認(rèn)的web.xml是Servlet 2.5,J2EE6默認(rèn)的web.xml是Servlet 3.0【支持異步處理】。
異步處理:如果在過濾器的doFilter()方法中頁面跳轉(zhuǎn)到了一個(gè)Servlet用于業(yè)務(wù)的處理,加入Servlet處理的業(yè)務(wù)時(shí)間花費(fèi)很多,這時(shí)過濾器就會(huì)一直等待Servlet執(zhí)行完成。這樣用戶體驗(yàn)就會(huì)非常差。Servlet 3.0支持異步處理。
在Servlet中新加入了@WebFilter Annotation。該Annotation用于將一個(gè)類聲明為過濾器,該注解將會(huì)在部署時(shí)被容器處理,容器將根據(jù)具體的屬性配置相應(yīng)的類,將響應(yīng)的類部署為過濾器。——因此我們不需要在web.xml中配置過濾器,只需要用注解的方式。@WebFilter的常用屬性如下:

下面使用J2EE6.0創(chuàng)建一個(gè)Web項(xiàng)目,創(chuàng)建一個(gè)過濾器名稱為AsyncFilter,使用@WebFilter Annotation配置該過濾器(PS:可以不再web.xml中注冊(cè)該過濾器):

1 package filter; 2 3 import java.io.IOException; 4 5 import javax.servlet.DispatcherType; 6 import javax.servlet.Filter; 7 import javax.servlet.FilterChain; 8 import javax.servlet.FilterConfig; 9 import javax.servlet.ServletException;10 import javax.servlet.ServletRequest;11 import javax.servlet.ServletResponse;12 import javax.servlet.annotation.WebFilter;13 14 @WebFilter(filterName = "AsyncFilter", value = { "/servlet/AsyncServlet" }, asyncSupported = true, dispatcherTypes = {15 DispatcherType.ASYNC, DispatcherType.REQUEST })16 public class AsyncFilter implements Filter {17 18 @Override19 public void destroy() {20 System.out.println("***** 銷毀AsyncFilter *****");21 }22 23 @Override24 public void doFilter(ServletRequest request, ServletResponse response,25 FilterChain filterChain) throws IOException, ServletException {26 System.out.println("***** 開始AsyncFilter *****");27 filterChain.doFilter(request, response);//放行28 System.out.println("***** 結(jié)束AsyncFilter *****");29 }30 31 @Override32 public void init(FilterConfig filterConfig) throws ServletException {33 System.out.println("***** 初始化AsyncFilter *****");34 }35 36 }AsyncFilter.java 創(chuàng)建一個(gè)處理業(yè)務(wù)的Servlet(該Servlet在doGet方法中使用了線程的休眠方法休眠了10s模擬業(yè)務(wù)的花費(fèi)時(shí)間)

1 package servlet; 2 3 import java.io.IOException; 4 import java.util.Date; 5 6 import javax.servlet.AsyncContext; 7 import javax.servlet.ServletException; 8 import javax.servlet.http.HttpServlet; 9 import javax.servlet.http.HttpServletRequest;10 import javax.servlet.http.HttpServletResponse;11 12 public class AsyncServlet extends HttpServlet {13 14 public class Excutor implements Runnable{15 private AsyncContext context;16 public Excutor(AsyncContext context) {17 this.context = context;18 }19 20 @Override21 public void run() {22 // 執(zhí)行相關(guān)的復(fù)雜業(yè)務(wù)23 try {24 Thread.sleep(1000*10);//休眠10s25 // context.getRequest();26 // context.getResponse();27 System.out.println("業(yè)務(wù)完成執(zhí)行時(shí)間:"+new Date());28 } catch (InterruptedException e) {29 e.printStackTrace();30 }31 }32 33 }34 35 public AsyncServlet() {36 super();37 }38 39 public void destroy() {40 super.destroy(); // Just puts "destroy" string in log41 }42 43 public void doGet(HttpServletRequest request, HttpServletResponse response)44 throws ServletException, IOException {45 46 AsyncContext context = request.startAsync(); //HttpServletRequest對(duì)象開始異步方法47 // context.getRequest();48 // context.getResponse();49 50 System.out.println("Servlet執(zhí)行開始時(shí)間:"+new Date());51 new Thread(new Excutor(context)).start();52 request.getRequestDispatcher("/index.jsp").forward(request, response);53 System.out.println("Servlet執(zhí)行結(jié)束時(shí)間:"+new Date());54 }55 56 public void doPost(HttpServletRequest request, HttpServletResponse response)57 throws ServletException, IOException {58 59 doGet(request, response);60 }61 62 public void init() throws ServletException {63 64 }65 66 }AsyncServlet.java 編寫好異步處理業(yè)務(wù)的Servlet類之后一定要在web.xml中配置該Servlet啟用異步,如下圖所示:

在index.jsp中有一個(gè)鏈接指向AsyncServlet:
<a href="<%=request.getContextPath() %>/servlet/AsyncServlet">點(diǎn)擊跳轉(zhuǎn)到AsyncServlet處理業(yè)務(wù)</a>
運(yùn)行結(jié)果:

過濾器在實(shí)際項(xiàng)目中的應(yīng)用場(chǎng)景
用戶身份的驗(yàn)證 例如現(xiàn)在有一個(gè)web項(xiàng)目,登陸頁login.jsp將用戶名和密碼提交給LoginServlet處理,Servlet使用request.getParameter方法獲得表單中的用戶名和密碼,將用戶名和密碼進(jìn)行驗(yàn)證,驗(yàn)證成功則頁面重定向到success.jsp,顯示登陸成功和登錄的用戶名【保存在session中再從session中取出】;如果登錄失敗則重定向到failure.jsp。
在不使用過濾器的情況下,即使用戶不進(jìn)行登錄也可以訪問到success.jsp——任何人都可以訪問到success.jsp,這顯然來說不安全。
驗(yàn)證用戶身份的Servlet(驗(yàn)證用戶名和密碼都是admin):

1 package servlet; 2 3 import java.io.IOException; 4 5 import javax.servlet.ServletException; 6 import javax.servlet.http.HttpServlet; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 import javax.servlet.http.HttpSession;10 11 public class LoginServlet extends HttpServlet {12 13 public LoginServlet() {14 super();15 }16 17 public void destroy() {18 super.destroy(); // Just puts "destroy" string in log19 }20 21 public void doPost(HttpServletRequest request, HttpServletResponse response)22 throws ServletException, IOException {23 String username = request.getParameter("username");24 String passWord = request.getParameter("password");25 26 if ("admin".equals(username)&&"admin".equals(password)) {27 // 驗(yàn)證通過28 HttpSession session = request.getSession();29 session.setAttribute("username", username);//把用戶名放入session中30 response.sendRedirect(request.getContextPath()+"/success.jsp");31 }else {32 // 驗(yàn)證失敗33 response.sendRedirect(request.getContextPath()+"/failure.jsp");34 }35 }36 37 public void init() throws ServletException {38 39 }40 41 }LoginServlet.java如下圖所示:

現(xiàn)在我們要做這樣一件事:只有用戶登錄成功才可以訪問到success.jsp,反之跳轉(zhuǎn)到登錄界面。即:不允許未登錄用戶訪問success.jsp。
創(chuàng)建一個(gè)登錄校驗(yàn)的過濾器LoginFilter并在web.xml中配置該過濾器的url為success.jsp

1 package servlet; 2 3 import java.io.IOException; 4 5 import javax.servlet.ServletException; 6 import javax.servlet.http.HttpServlet; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 import javax.servlet.http.HttpSession;10 11 public class LoginServlet extends HttpServlet {12 13 public LoginServlet() {14 super();15 }16 17 public void destroy() {18 super.destroy(); // Just puts "destroy" string in log19 }20 21 public void doPost(HttpServletRequest request, HttpServletResponse response)22 throws ServletException, IOException {23 String username = request.getParameter("username");24 String password = request.getParameter("password");25 26 if ("admin".equals(username)&&"admin".equals(password)) {27 // 驗(yàn)證通過28 HttpSession session = request.getSession();29 session.setAttribute("username", username);//把用戶名放入session中30 response.sendRedirect(request.getContextPath()+"/success.jsp");31 }else {32 // 驗(yàn)證失敗33 response.sendRedirect(request.getContextPath()+"/failure.jsp");34 }35 }36 37 public void init() throws ServletException {38 39 }40 41 }LoginFilter.java
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app version="2.5" 3 xmlns="http://java.sun.com/xml/ns/javaee" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 6 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> 7 <display-name></display-name> 8 <servlet> 9 <description>This is the description of my J2EE component</description>10 <display-name>This is the display name of my J2EE component</display-name>11 <servlet-name>LoginServlet</servlet-name>12 <servlet-class>servlet.LoginServlet</servlet-class>13 </servlet>14 15 <servlet-mapping>16 <servlet-name>LoginServlet</servlet-name>17 <url-pattern>/servlet/LoginServlet</url-pattern>18 </servlet-mapping> 19 <welcome-file-list>20 <welcome-file>index.jsp</welcome-file>21 </welcome-file-list>22 <filter>23 <filter-name>LoginFilter</filter-name>24 <filter-class>filter.LoginFilter</filter-class>25 </filter>26 <filter-mapping>27 <filter-name>LoginFilter</filter-name>28 <url-pattern>/success.jsp</url-pattern>29 </filter-mapping>30 </web-app>
web.xml 加入過濾器之后(只有成功登錄的用戶【session中保存了該用戶的用戶名】才可以訪問index.jsp):

在實(shí)際的開發(fā)中一個(gè)網(wǎng)站的頁面成百上千,這時(shí)我們可以使用通配符"/*"來匹配所有的url。但是這樣帶來一個(gè)問題:
當(dāng)我們新建立一個(gè)session的時(shí)候,訪問任何頁面都會(huì)被重定向到login.jsp,login.jsp自己也重定向到login.jsp,這樣就形成了重定向循環(huán)

這時(shí)就需要在過濾器中判斷頁面是否是login.jsp,如果是login.jsp或者請(qǐng)求的是LoginServlet就直接放行。在LoginFilter的doFilter方法中添加這樣幾行代碼:
1 if (req.getRequestURI().indexOf("login.jsp")!=-1||req.getRequestURI().indexOf("LoginServlet")!=-1) {2 filterChain.doFilter(request, response); // 如果用戶請(qǐng)求的是login.jsp直接放行3 return; // 這一行代碼一定要加上啊!4 } 運(yùn)行結(jié)果:

上述程序看似已經(jīng)沒有問題,但是還存在一個(gè)小bug,當(dāng)我們?cè)诘顷戫撦斎胍粋€(gè)錯(cuò)誤的用戶名和密碼頁面并不會(huì)重定向到failure.jsp而是重定向到了login.jsp。如下圖所示:

這是因?yàn)殡m然我們?cè)赟ervlet驗(yàn)證失敗的時(shí)候?qū)㈨撁嬷囟ㄏ虻搅薴ailure.jsp,failure.jsp又被過濾器重定向到了login.jsp【因?yàn)檫^濾規(guī)則為所有的頁面,并且session中沒有用戶名】
這時(shí)我們就會(huì)發(fā)現(xiàn)我們?cè)赿oFilter中需要例外的頁面越來越多(登陸頁面、成功頁面、失敗頁面、錯(cuò)誤頁面……)。為了減輕工作的復(fù)雜度,我們可以使用過濾器的init方法中的FilterConfig對(duì)象。
1. 在web.xml中配置不過濾頁面的初始化參數(shù):

2. 在過濾方法中使用以上初始化參數(shù)。
1 public class LoginFilter implements Filter{ 2 3 private FilterConfig filterConfig;// 聲明一個(gè)FilterConfig對(duì)象 4 5 public void init(FilterConfig filterConfig) throws ServletException { 6 this.filterConfig = filterConfig; // 初始化方法的時(shí)候給filterConfig賦值 7 } 8 9 public void destroy() {10 11 }12 13 public void doFilter(ServletRequest request, ServletResponse response,14 FilterChain filterChain) throws IOException, ServletException {15 // 代碼省略16 }17 18 } 3. 在doFilter方法中使用FilterConfig對(duì)象獲得初始化參數(shù)。
1 public void doFilter(ServletRequest request, ServletResponse response, 2 FilterChain filterChain) throws IOException, ServletException { 3 HttpServletRequest req = (HttpServletRequest) request; 4 HttpServletResponse res = (HttpSer
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注