首先來看一下Servlet的過濾器內容:
一、Servlet過濾器的概念:
***************************************************************************************Servlet過濾器是在Java Servlet規範2.3中定義的,它能夠對Servlet容器的請求和響應對象進行檢查和修改。
Servlet過濾器本身並不產生請求和響應對象,它只能提供過濾作用。Servlet過期能夠在Servlet被調用之前檢查Request對象,修改Request Header和Request內容;在Servlet被調用之後檢查Response對象,修改Response Header和Response內容。
Servlet過期負責過濾的Web組件可以是Servlet、JSP或者HTML文件。
***************************************************************************************
二、Servlet過濾器的特點:
***************************************************************************************
A.Servlet過濾器可以檢查和修改ServletRequest和ServletResponse對象
B.Servlet過濾器可以被指定和特定的URL關聯,只有當客戶請求訪問該URL時,纔會觸發過濾器
C.Servlet過濾器可以被串聯在一起,形成管道效應,協同修改請求和響應對象
***************************************************************************************
三、Servlet過濾器的作用:
***************************************************************************************
A.查詢請求並作出相應的行動。
B.阻塞請求-響應對,使其不能進一步傳遞。
C.修改請求的頭部和數據。用戶可以提供自定義的請求。
D.修改響應的頭部和數據。用戶可以通過提供定製的響應版本實現。
E.與外部資源進行交互。
***************************************************************************************
四、Servlet過濾器的適用場合:
***************************************************************************************
A.認證過濾
B.登錄和審覈過濾
C.圖像轉換過濾
D.數據壓縮過濾
E.加密過濾
F.令牌過濾
G.資源訪問觸發事件過濾
H.XSL/T過濾
I.Mime-type過濾
***************************************************************************************
五、Servlet過濾器接口的構成:
***************************************************************************************
所有的Servlet過濾器類都必須實現javax.servlet.Filter接口。這個接口含有3個過濾器類必須實現的方法:
A.init(FilterConfig):
這是Servlet過濾器的初始化方法,Servlet容器創建Servlet過濾器實例後將調用這個方法。在這個方法中可以讀取web.xml文件中Servlet過濾器的初始化參數
B.doFilter(ServletRequest,ServletResponse,FilterChain):
這個方法完成實際的過濾操作,當客戶請求訪問於過濾器關聯的URL時,Servlet容器將先調用過濾器的doFilter方法。FilterChain參數用於訪問後續過濾器
C.destroy():
Servlet容器在銷燬過濾器實例前調用該方法,這個方法中可以釋放Servlet過濾器佔用的資源
***************************************************************************************
六、Servlet過濾器的創建步驟:
***************************************************************************************
A.實現javax.servlet.Filter接口
B.實現init方法,讀取過濾器的初始化函數
C.實現doFilter方法,完成對請求或過濾的響應
D.調用FilterChain接口對象的doFilter方法,向後續的過濾器傳遞請求或響應
E.銷燬過濾器
***************************************************************************************
七、Servlet過濾器對請求的過濾:
***************************************************************************************
A.Servlet容器創建一個過濾器實例
B.過濾器實例調用init方法,讀取過濾器的初始化參數
C.過濾器實例調用doFilter方法,根據初始化參數的值判斷該請求是否合法
D.如果該請求不合法則阻塞該請求
E.如果該請求合法則調用chain.doFilter方法將該請求向後續傳遞
***************************************************************************************
八、Servlet過濾器對響應的過濾:
***************************************************************************************
A.過濾器截獲客戶端的請求
B.重新封裝ServletResponse,在封裝後的ServletResponse中提供用戶自定義的輸出流
C.將請求向後續傳遞
D.Web組件產生響應
E.從封裝後的ServletResponse中獲取用戶自定義的輸出流
F.將響應內容通過用戶自定義的輸出流寫入到緩衝流中
G.在緩衝流中修改響應的內容後清空緩衝流,輸出響應內容
***************************************************************************************
九、Servlet過濾器的發佈:
***************************************************************************************
A.發佈Servlet過濾器時,必須在web.xml文件中加入<filter>元素和<filter-mapping>元素。
B.<filter>元素用來定義一個過濾器:
屬性 含義
filter-name 指定過濾器的名字
filter-class 指定過濾器的類名
init-param 爲過濾器實例提供初始化參數,可以有多個
C.<filter-mapping>元素用於將過濾器和URL關聯:
屬性 含義
filter-name 指定過濾器的名字
url-pattern 指定和過濾器關聯的URL,爲”/*”表示所有URL
***************************************************************************************
十一、Servlet過濾器使用的注意事項
***************************************************************************************
A.由於Filter、FilterConfig、FilterChain都是位於javax.servlet包下,並非HTTP包所特有的,所以其中所用到的請求、響應對象ServletRequest、ServletResponse在使用前都必須先轉換成HttpServletRequest、HttpServletResponse再進行下一步操作。
B.在web.xml中配置Servlet和Servlet過濾器,應該先聲明過濾器元素,再聲明Servlet元素
C.如果要在Servlet中觀察過濾器生成的日誌,應該確保在server.xml的localhost對應的<host>元素中配置如下<logger>元素:
<Logger className = “org.apache.catalina.logger.FileLogger”
directory = “logs”prefix = “localhost_log.”suffix=”.txt”
timestamp = “true”/>
***************************************************************************************
十二、一個實例
首先來看一下web.xml的配置:
<!-- 請求url日誌記錄過濾器 -->
<filter>
<filter-name>logfilter</filter-name>
<filter-class>com.weijia.filterservlet.LogFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>logfilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 編碼過濾器 -->
<filter>
<filter-name>setCharacterEncoding</filter-name>
<filter-class>com.weijia.filterservlet.EncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>setCharacterEncoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
然後看一下編碼過濾器:
package com.weijia.filterservlet;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class EncodingFilter implements Filter {
private String encoding;
private HashMap<String,String> params = new HashMap<String,String>();
// 項目結束時就已經進行銷燬
public void destroy() {
System.out.println("end do the encoding filter!");
params=null;
encoding=null;
}
public void doFilter(ServletRequest req, ServletResponse resp,FilterChain chain) throws IOException, ServletException {
System.out.println("before encoding " + encoding + " filter!");
req.setCharacterEncoding(encoding);
chain.doFilter(req, resp);
System.out.println("after encoding " + encoding + " filter!");
System.err.println("----------------------------------------");
}
// 項目啓動時就已經進行讀取
public void init(FilterConfig config) throws ServletException {
System.out.println("begin do the encoding filter!");
encoding = config.getInitParameter("encoding");
for (Enumeration<?> e = config.getInitParameterNames(); e.hasMoreElements();) {
String name = (String) e.nextElement();
String value = config.getInitParameter(name);
params.put(name, value);
}
}
}
日誌過濾器:
package com.weijia.filterservlet;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
public class LogFilter implements Filter {
public FilterConfig config;
public void destroy() {
this.config = null;
System.out.println("end do the logging filter!");
}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
System.out.println("before the log filter!");
// 將請求轉換成HttpServletRequest 請求
HttpServletRequest hreq = (HttpServletRequest) req;
// 記錄日誌
System.out.println("Log Filter已經截獲到用戶的請求的地址:"+hreq.getServletPath() );
try {
// Filter 只是鏈式處理,請求依然轉發到目的地址。
chain.doFilter(req, res);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("after the log filter!");
}
public void init(FilterConfig config) throws ServletException {
System.out.println("begin do the log filter!");
this.config = config;
}
}
測試Servlet:
package com.weijia.filterservlet;
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 FilterServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setDateHeader("expires", -1);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
}
訪問FilterServlet
運行結果:
before the log filter!
Log Filter已經截獲到用戶的請求的地址:/FilterServlet
before encoding utf-8 filter!
after encoding utf-8 filter!
----------------------------------------
after the log filter!
我們從運行結果可以看到這個過濾器的調用關係:
類似於C++中的構造函數和析構函數的調用順序,
這裏我們在web.xml中註冊的是先註冊日誌過濾器的,然後再註冊
當我們重新部署應用的時候發現:
會先銷燬上次的過濾器,然後再重新註冊一下
下面在來看一下Servlet的監聽器
Servlet監聽器用於監聽一些重要事件的發生,監聽器對象可以在事情發生前、發生後可以做一些必要的處理。下面將介紹幾種常用的監聽器,以及它們都適合運用於那些環境。
分類及介紹:
1. ServletContextListener:用於監聽WEB 應用啓動和銷燬的事件,監聽器類需要實現javax.servlet.ServletContextListener 接口。
public class QuartzListener implements ServletContextListener {
private Logger logger = LoggerFactory.getLogger(QuartzListener.class);
public void contextInitialized(ServletContextEvent sce) {
}
/**
*在服務器停止運行的時候停止所有的定時任務
*/
@SuppressWarnings("unchecked")
public void contextDestroyed(ServletContextEvent arg0) {
try {
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
List<JobExecutionContext> jobList = scheduler.getCurrentlyExecutingJobs();
for (JobExecutionContext jobContext : jobList) {
Job job = jobContext.getJobInstance();
if (job instanceof InterruptableJob) {
((InterruptableJob) job).interrupt();
}
}
scheduler.shutdown();
} catch (SchedulerException e) {
logger.error("shut down scheduler happened error", e);
}
}
}
2. ServletContextAttributeListener:用於監聽WEB應用屬性改變的事件,包括:增加屬性、刪除屬性、修改屬性,監聽器類需要實現javax.servlet.ServletContextAttributeListener接口。
3. HttpSessionListener:用於監聽Session對象的創建和銷燬,監聽器類需要實現javax.servlet.http.HttpSessionListener接口或者javax.servlet.http.HttpSessionActivationListener接口,或者兩個都實現。
/**
*
* 會話監聽器
* <p />
*
*/
public class SessionListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent arg0) {
}
@Override
public void sessionDestroyed(HttpSessionEvent event) {
HttpSession session = event.getSession();
User user = (BrsSession) session.getAttribute("currUser");
if (user != null) {
//TODO something
}
}
}
4. HttpSessionActivationListener:用於監聽Session對象的鈍化/活化事件,監聽器類需要實現javax.servlet.http.HttpSessionListener接口或者javax.servlet.http.HttpSessionActivationListener接口,或者兩個都實現。
5. HttpSessionAttributeListener:用於監聽Session對象屬性的改變事件,監聽器類需要實現javax.servlet.http.HttpSessionAttributeListener接口。
部署:
監聽器的部署在web.xml文件中配置,在配置文件中,它的位置應該在過濾器的後面Servlet的前面
web.xml配置文件:
<!-- Quartz監聽器 -->
<listener>
<listener-class>
com.flyer.lisenter.QuartzListener
</listener-class>
</listener>