java Web三大組件--過濾器

參考博客:http://www.cnblogs.com/coderland/p/5902878.htmlhtml

http://www.javashuo.com/article/p-qhrjwvaw-mv.htmljava

基本概念在參考博客中,已經講的很清楚了。這裏,簡單總結一下,並貼一個完整實例。web

總結:服務器

1)Filter稱爲過濾器。它是一個服務器端的組件。經過Filter技術,對web服務器管理的全部web資源:例如Jsp, Servlet, 靜態圖片文件或靜態 html 文件等進行攔截,從而實現一些特殊的功能。例如實現URL級別的權限訪問控制、過濾敏感詞彙、壓縮響應信息等一些高級功能。session

2)Filter技術主要進行對用戶請求的預處理,也能夠對服務器響應進行後處理。app

這兩種狀況都屬於直接訪問頁面(也包括直接訪問Servlet),故在配置<filter-mapping>時,能夠不寫<dispatcher>,使用默認的REQUEST。(也能夠寫出來直接指定爲REQUEST)jsp

通常地,客戶端提交請求信息經過HttpServletRequest到達Servlet,而後Servlet進行處理併產生響應,響應經過HttpServletResponse傳遞到客戶端。ide

Filter在HttpServletRequest到達Servlet以前,攔截客戶的HttpServletRequest,根據須要檢查HttpServletRequest,或者修改HttpServletRequest 頭和數據,稱爲對用戶請求的預處理。post

Filer在HttpServletResponse從Servlet到達客戶端以前,攔截HttpServletResponse ,根據須要檢查HttpServletResponse,或者修改HttpServletResponse頭和數據,稱爲對服務器響應進行後處理。ui

3)Filer的生命週期:

實例化(web.xml)——>初始化(init()方法)——>過濾(doFilter()方法)——>銷燬(destroy()方法)

public void init(FilterConfig filterConfig) throws ServletException;//初始化 //filter對象只會建立一次,init方法也只會執行一次
 和咱們編寫的Servlet程序同樣,Filter的建立和銷燬由WEB容器負責。 web 應用程序啓動時,web 容器讀取web.xml配置文件, 將建立Filter 的實例對象,並調用其init方法(這個init方法中能夠讀取web.xml文件中過濾器的參數)完成對象的初始化功能, 從而爲後續的用戶請求做好攔截的準備工做。開發人員能夠經過init方法的參數FilterConfig對象,得到當前filter配置信息。 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;//攔截請求 //可執行n次
 這個方法完成實際的過濾操做。當客戶請求訪問與過濾器關聯的URL的時候執行該方法。FilterChain參數的doFilter方法用於訪問後續過濾器或者調用目標資源。 public void destroy();//銷燬 //該方法在Filter的生命週期中僅執行一次。
 Filter對象建立後會駐留在內存,當web應用移除或服務器中止時才銷燬。在Web容器卸載 Filter 對象以前被調用。在這個方法中,能夠釋放過濾器使用的資源。 

4)Filter開發步驟:

  (1)編寫java類實現javax.servlet.Filter接口,並實現其doFilter方法;

  (2)在web.xml文件中對編寫的filter類進行註冊,並設置它所能攔截的資源。

5)Filter鏈:

  在一個web應用中,能夠開發編寫多個Filter,這些Filter組合起來稱之爲一個Filter鏈。

  web服務器根據Filter在web.xml文件中的註冊順序,決定先調用哪一個Filter,當第一個Filter的doFilter方法被調用時,web服務器會建立一個表明Filter鏈的FilterChain對象傳遞給該方法。在doFilter方法中,開發人員若是調用了FilterChain對象的doFilter方法,則web服務器會檢查FilterChain對象中是否還有filter,若是有,則調用第2個filter,若是沒有,則調用目標資源。

6)FilterConfig接口:

用戶在配置filter時,可使用爲filter配置一些初始化參數(<init-param>),當web容器實例化Filter對象,調用其init方法時,會把封裝了filter初始化參數的filterConfig對象傳遞進來。所以開發人員在編寫filter時,經過filterConfig對象的方法獲取相關初始化信息。

7)在檢查URI路徑中的是否含有某個初始值,對於servlet來講,是指配置servlet時指定的url-pattern的值,而不是servlet類名。

8)在實現Filter的類中的doFilter()方法中,須要將傳進來的ServletRequest轉換爲HttpServletRequest,將傳進來的ServletResponse轉換爲HttpServletResponse,才能進行相關方法的調用。

9)過濾器的分類: 

  (1)REQUEST:當用戶直接訪問頁面(包括用戶請求的預處理和對服務器響應進行後處理)時,Web容器將會調用過濾器。若是目標資源是經過RequestDispatcher的include()或forward()方法訪問時,那麼該過濾器就不會被調用。 
  (2)INCLUDE:若是目標資源是經過RequestDispatcher的include()方法訪問時,那麼該過濾器將被調用。除此以外,該過濾器不會被調用。
  (3)FORWARD:若是目標資源是經過RequestDispatcher的forward()方法訪問時,那麼該過濾器將被調用,除此以外,該過濾器不會被調用。
  (4)ERROR:若是目標資源是經過聲明式異常處理機制調用時,那麼該過濾器將被調用。除此以外,過濾器不會被調用。

貼個例子,實現兩個過濾器一個判斷用戶是否登陸而後跳轉指定頁面,一個用來處理亂碼問題:

login.jsp:

<form action="doLogin" method="post"> 用戶名:<input type="text" name="userName"/><br/> 密碼:<input type="password" name="password"/><br/>
<input type="submit" value="登陸"/>
<input type="reset" value="重置"/>
</form>

建立一個success.jsp用於展現跳轉成功。

建立登陸跳轉Servlet:

package com.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @SuppressWarnings("serial") public class DoLoginServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String userName=req.getParameter("userName"); String password=req.getParameter("password"); System.out.println(userName); if("張三".equals(userName)&&"123".equals(password)){ //校驗經過
            HttpSession session = req.getSession(); session.setAttribute("userName", userName);
       //這裏必須使用重定向,不能使用請求轉發
       //請求轉發:request.getRequestDispatcher().forward()是屬於FORWARD類型的過濾器,須要在配置過濾器時,寫明FORWARD類型的<dispatcher> resp.sendRedirect(
"success.jsp"); }else { resp.sendRedirect("login.jsp"); } } }

 注意:

請求轉發:即request.getRequestDispatcher().forward(),是一種服務器的行爲,客戶端只有一次請求,服務器端轉發後會將請求對象保存,地址欄中的URL地址不會改變,獲得響應後服務器端再將響應發給客戶端;

請求重定向:即response.sendRedirect(),是一種客戶端行文,從本質上講等同於兩次請求,前一次請求對象不會保存,地址欄的URL地址會改變。

請求轉發與請求重定向的區別,參考博客:http://blog.csdn.net/u012877472/article/details/50804568

 

建立第一個過濾器(解決亂碼):

package com.filter; 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 SetEconding implements Filter { @Override public void destroy() { // TODO Auto-generated method stub
 } @Override public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException { HttpServletRequest req=(HttpServletRequest)arg0; //解決亂碼問題
        req.setCharacterEncoding("UTF-8"); //別忘了放行
 arg2.doFilter(arg0, arg1); } @Override public void init(FilterConfig arg0) throws ServletException { // TODO Auto-generated method stub
 } }

建立第二個過濾器(是否登陸):

package com.filter; 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; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; public class LoginFilter implements Filter { 
  //定義一個FilterConfig,用於傳遞出初始化方法init()中的FilterConfig對象
private FilterConfig config=null;
@Override
public void destroy() { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException { HttpServletRequest req=(HttpServletRequest)arg0; HttpServletResponse resp=(HttpServletResponse)arg1; HttpSession session=req.getSession(); //獲取配置文件中配置的初始化參數,在這裏是獲取不過濾頁面名單 String initParam=config.getInitParameter("NotFilter"); String[] notFilterPages=initParam.split(";");
     //不過濾的頁面直接調用FilterChain的doFilter()方法跳轉到下個過濾器或者目標資源
if(notFilterPages!=null){ for(int i=0;i<notFilterPages.length;++i){ //跳過字段爲空和空字符串的狀況 if(notFilterPages[i]==null||"".equals(notFilterPages[i]))continue; //注意這裏是URI路徑中的是否含有某個初始值,對於servlet來講,是指配置servlet時指定的url-pattern的值,而不是servlet類名 if(req.getRequestURI().indexOf(notFilterPages[i])!=-1){ arg2.doFilter(arg0, arg1); return; } } }
     //當登陸成功(即session中存在「userName」的值),則跳轉到下一個過濾器或者目標資源
//只要未登陸成功,全部的頁面跳轉請求(免除過濾的頁面和servlet處理類除外)都將跳轉到登陸頁面 if(session.getAttribute("userName")!=null){ arg2.doFilter(arg0, arg1); return; }else{ resp.sendRedirect("login.jsp"); return; } } @Override public void init(FilterConfig arg0) throws ServletException { config=arg0; } }

web.xml配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>javaEE_filter</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>
  
  <!-- 第1個過濾器 -->
  <!-- 配置解決亂碼過濾器 -->
  <filter>
  <filter-name>SetEcondingFilter</filter-name>
  <filter-class>com.filter.SetEconding</filter-class>
  </filter>
  
  <!-- 配置解決亂碼過濾器映射 -->
  <filter-mapping>
  <filter-name>SetEcondingFilter</filter-name>
  <url-pattern>/*</url-pattern>
  </filter-mapping>
  
  
  <!-- 第2個過濾器 -->
  <!-- 配置登陸過濾器 -->
  <filter>
  <filter-name>LoginFilter</filter-name>
  <filter-class>com.filter.LoginFilter</filter-class>
  <init-param>
  <param-name>NotFilter</param-name>
  <param-value>login;doLogin</param-value>
  </init-param>
  </filter>
  
  <!-- 配置登陸過濾器映射 -->
  <filter-mapping>
  <filter-name>LoginFilter</filter-name>
  <url-pattern>/*</url-pattern>
  </filter-mapping>
  
  
  <!-- 配置處理登陸的Servlet -->
  <servlet>
  <servlet-name>LoginServlet</servlet-name>
  <servlet-class>com.servlet.DoLoginServlet</servlet-class>
  </servlet>
  
  <!-- 配置處理登陸Servlet的映射 -->
  <servlet-mapping>
  <servlet-name>LoginServlet</servlet-name>
  <url-pattern>/doLogin</url-pattern>
  </servlet-mapping>
</web-app>

亂碼問題的解決方案:


 

亂碼問題的解決代碼主要有兩種即便用request對象的setCharacterEncoding()方法和String的構造器方法。

例:

req.setCharacterEncoding("UTF-8");

 

userName=new String(userName.getBytes("ISO-8859-1"),"UTF-8");

 

1)使用過濾器:

在本例中,爲了說明過濾器的執行順序,而定義了兩個過濾器並在配置時將處理亂碼的過濾器放在了靠前的位置,可是對於處理亂碼的過濾器徹底能夠將代碼

req.setCharacterEncoding("UTF-8");

放在判斷是否登陸的過濾器的doFilter方法體中(最好放在方法體靠前位置,以保證過濾時先進行代碼亂碼的過濾)。而無需建立第二個過濾器。

2)固然,也可使用javaBean的方式解決代碼亂碼問題

相關文章
相關標籤/搜索