Servlet高階Fliter(過濾器)&Listener(監聽器)
“別小看任何人,越不起眼的人。往往會做些讓人想不到的事。"你好我是夢陽辰,快來和我一起學習吧!
文章目錄
01.Filter概述
Filter和Listener是Servlet規範中的兩個高階特性,不同於Servlet,他們不用於處理客戶端請求。
Filter用於對request,response物件進行修改。
Filter被稱作過濾器,其基本功能就是對Servlet容器呼叫Servlet的過程進行攔截,從而在Servlet進行響應處理前後實現一些特殊的功能。這就好比現實中的汙水淨化裝置,它可以看作一個過濾器,專門用於過濾汙水雜質。
當瀏覽器訪問伺服器中的目標資源時,會被Filter攔截,在Filter中進行預處理操作,然後再將請求轉發給目標資源。
當伺服器接收到這個請求後會對其進行響應,在伺服器處理響應的過程中,也需要先將響應結果傳送給過濾器,在過濾器中對響應結果進行處理後,才會傳送給客戶端。
過濾器的作用:
一般完成通用性的操作。
比如:登入驗證,判斷使用者是否登入;統一編碼處理,敏感字元處理等。
其實Filter過濾器就是實現了javax.servlet.Filter介面的類,在javax.servlet.Filter定義了三個方法。
Listener用於對context,session,request事件進行監聽。
02.Filter快速入門
步驟:
1.定義一個類,實現介面javax.servlet.Filter。
2.複寫方法
3.配置攔截路徑
3.1.web.xml配置
3.2.註解配置
javax.servlet.Filter定義了三個方法
@WebFilter("/*")//攔截所有資源
public class FilterTest1 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//初始化過濾器,在Web程式載入的時候呼叫,配置初始化引數
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.print("我是過濾器!");
//是否放行,即轉發到請求資源
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
//用於釋放被Filter開啟的資源,當Web伺服器解除安裝Filter物件之前被呼叫
}
}
web.xml配置
取消註解配置,使用web.xml配置。
<filter>
<filter-name>FilterTest1</filter-name>
<filter-class>filter.FilterTest1</filter-class>
</filter>
<filter-mapping>
<filter-name>FilterTest1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
03.Filter深入
過濾器的流程:
@WebFilter("/*")
public class FilterTest2 implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//用於攔截使用者的請求,如果和當前過濾器的攔截路徑匹配,此方法會被呼叫
//對request物件請求訊息增強
System.out.println("我被執行了request!");
chain.doFilter(req, resp);
//對response物件的響應訊息增強
System.out.println("我被又執行了response!");
}
public void init(FilterConfig config) throws ServletException {
}
}
攔截路徑的配置:
具體資源路徑:/index.jsp 只有訪問index.jsp資源時,過濾器才會被執行。
2.攔截目錄:/user/* 訪問/uer下的所有資源時,過濾器都會被執行。
3.字尾名攔截:*.jsp 訪問所有後綴名為jsp資源時,過濾器執行。
4.攔截所有資源:/*
攔截方式的配置:
資源被訪問的方式:
請求轉發過濾器不會被執行。
1.註解配置,可以配置多個值
設定dispatcherTypes屬性
REQUEST:預設值,瀏覽器直接請求資源
FORWARD:轉發訪問資源
INCLUDE:包含訪問資源
ERROR:錯誤跳轉資源
ASYNC:非同步訪問資源
2.web.xml註釋
//瀏覽器直接請求資源時,會被執行,轉發不會
@WebFilter(value = "/*",dispatcherTypes = DispatcherType.REQUEST)
public class FilterTest3 implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
System.out.println("我被執行啦!");
chain.doFilter(req, resp);
}
public void init(FilterConfig config) throws ServletException {
}
}
@WebFilter(value = "/*",
dispatcherTypes = {DispatcherType.REQUEST,DispatcherType.FORWARD})
<filter>
<filter-name>FilterTest1</filter-name>
<filter-class>filter.FilterTest1</filter-class>
</filter>
<filter-mapping>
<filter-name>FilterTest1</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
過濾器鏈(多個過濾器):
執行順序
先執行過濾器1,再執行過濾器2,回來先執行過濾器2,再執行過濾器1。
怎麼判斷過濾器誰在前面:
1.註解配置
按照類名的字串比較規則,較小的先執行。
如:AFilter,BFilter
AFilter就先執行。
2.web.xml配置:
<filter-mapping>
誰定義在上面,誰就先執行。
04.Filter案例
案例一:登入驗證
1.訪問某些資源,驗證其是否登入
2.如果登入了,則直接放行。
3.如果沒有登入,則跳轉到登入頁面,提示,“你尚未登入,請先登入”。
/**
* 登入驗證的過濾器
*/
@WebFilter("/*")//除了登入相關資源外(如login.jsp)
public class FilterTest4 implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//1.強轉
HttpServletRequest request = (HttpServletRequest)req;
//2.獲取資源請求路徑
String uri = request.getRequestURI();
//排除登入相關資源,css/js/fonts等
if(uri.contains("/login.jsp")||uri.contains("/loginServlet")||uri.contains("/css/")||uri.contains("/js/")){
//使用者就是像登入,放行
chain.doFilter(req, resp);
}else{
//不包含,需要驗證使用者是否登入
//3.從獲取session中獲取user
Object user = request.getSession().getAttribute("user");
if(user!=null){
//登入了,放行
chain.doFilter(req, resp);
}else{
//沒有登入,跳轉到登入頁面
request.setAttribute("login_msg","你為登入,請先登入!");
request.getRequestDispatcher("/login.jsp");
}
}
}
public void init(FilterConfig config) throws ServletException {
}
}
案例二:敏感詞彙的過濾
分析:
案例需要對request物件進行增強。
那如進行增強呢?
增強物件的功能
設計模式:一些通用的解決固定問題的方式。
裝飾模式:
代理模式:
概念:
1.真實物件:被代理的物件。
2.代理物件
3.代理模式:代理物件代理真實物件,達到增強真實物件的目的。
實現方式:
1.靜態代理
在一個類檔案描述代理模式。
2.動態代理
在記憶體中形成代理類(在記憶體中動態生成)。
注:請先看以下動態代理相關知識再看案例二的實現
案例二實現:
1.對requset物件進行增強,增強獲取引數相關方法。
2.放行,傳遞代理物件。
程式碼實現:
/**
* 敏感詞彙過濾器
*/
@WebFilter("/*")
public class FilterSensitiveWords implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//建立代理物件,增強getParameter方法
ServletRequest proxy_req=(ServletRequest) Proxy.newProxyInstance(req.getClass().getClassLoader(), req.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增強getParameter方法
//判斷是否是該方法
if(method.getName().equals("getParameter")){
//增強返回值
//獲取返回值
String value = (String)method.invoke(req,args);
if(value!=null){
for(String str:list){
if(value.contains(str)){
value = value.replaceAll(str,"**");
}
}
}
return value;
}
return method.invoke(req,args);
}
});
//2.放行
chain.doFilter(proxy_req, resp);
}
private List<String> list = new ArrayList<>();//敏感詞彙
public void init(FilterConfig config) throws ServletException {
try {
//1.載入配置檔案(獲取檔案的真實路徑)
ServletContext servletContext = config.getServletContext();
String realPath = servletContext.getRealPath("/WEB-INF/classes/SensitiveWords.txt");
//2.讀取檔案
BufferedReader br = new BufferedReader(new FileReader(realPath));
//3.將檔案的每一行載入到list中
String line =null;
while ((line = br.readLine())!=null){
list.add(line);
}
br.close();
System.out.println(list);
} catch (FileNotFoundException e) {
e.