javaWEB學習之filter

JavaWeb三大組件

1. 都需要在web.xml中進行配置
Servlet
Listener

Filter


2. 過濾器
      它通過web.xml管理着一大片資源,它會在一組資源(jsp、servlet、.css、.html等等)的前面執行!它當你想要訪問它管理的資源時,那麼就會攔截進行處理.它可以讓請求得到目標資源,也可以不讓請求達到!就好比如門衛.  只要是對很多的資源進行操作就應該想到filter

 


過濾器如何編寫

1. 寫一個類實現Filter接口
2. 在web.xml中進行配置管理哪些資源

 

1. Filter接口

    public void doFilter(ServletRequest request, ServletResponseresponse,
           FilterChain chain) throws IOException, ServletException{
       System.out.println("filterstart..."); 
       chain.doFilter(request,response);//放行 
       System.out.println("filterend..."); 
    }

 

void init(FilterConfig)
  * 創建之後,馬上執行;Filter會在服務器啓動時就創建!
void destory()
  * 銷燬之前執行!在服務器關閉時銷燬
void doFilter(ServletRequest,ServletResponse,FilterChain)
  * 每次過濾時都會執行

Filter是單例的!和servlet一樣

 

2. web.xml
<filter>
  <filter-name>xxx</filter-name>
  <filter-class>web.filter.AFitler</fitler-class>
</servlet>
<fitler-mapping>
  <filter-name>xxx</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

這個配置代表了這個filter管理哪些資源.訪問這些資源時,這個過濾器就會執行doFilter()..


FilterConfig-->與ServletConfig相似
  * 獲取初始化參數:getInitParameter()
  * 獲取過濾器名稱:getFilterName()
  * 獲取appliction:getServletContext()

FilterChain(這個用於放行)
  * doFilter(ServletRequest, ServletResponse):放行!
    就相當於調用了目標Servlet的service()方法!

-------------------------------

-------------------------------

多過濾器情況下FilterChain的doFilter()方法:執行目標資源,或是執行下一個過濾器!如果沒有下一個過濾器那麼執行的是目標資源,如果有,那麼就執行下一個過濾器!


-------------------------------

過濾器的四種攔截方式

  <dispatcher>REQUEST</dispatcher>默認的!攔截直接請求
  <dispatcher>FORWARD</dispatcher>            攔截請求轉發
  <dispatcher>INCLUDE</dispatcher>              攔截請求包含  
  <dispatcher>ERROR</dispatcher>                攔截錯誤轉發

在<filter-mapping>中進行配置!


-------------------------------

多個過濾器的執行順序

<filter-mapping>的配置順序決定了過濾器的執行順序!

 

過濾器的應用場景:

執行目標資源之前做預處理工作,例如設置編碼,這種試通常都會放行,只是在目標資源執行之前做一些準備工作;

通過條件判斷是否放行,例如校驗當前用戶是否已經登錄,或者用戶IP是否已經被禁用;

在目標資源執行後,做一些後續的特殊處理工作,例如把目標資源輸出的數據進行處理

 

實例:

統計IP

循環遍歷在ServletContext中的map,其中key是ip地址,value是訪問次數

jsp頁面

<body>
<h1>分IP統計訪問次數</h1>
<table align="center"width="50%" border="1">
    <tr>
       <th>IP地址</th>
       <th>次數</th>
    </tr>
<c:forEach items="${aplicationScope.ipCountMap}" var="entry">
    <tr>
       <td>${entry.key }</td>
       <td>${entry.value }</td>
    </tr>
</c:forEach>
 </table>  
</body>

filter代碼

public void init(FilterConfig fConfig) throws ServletException {
       context = fConfig.getServletContext();
       Map<String, Integer> ipCountMap = new LinkedHashMap<String, Integer>();
       context.setAttribute("ipCountMap", ipCountMap);
    }
 
  public void doFilter(ServletRequest request, ServletResponseresponse,
           FilterChain chain) throws IOException, ServletException{
       HttpServletRequest req = (HttpServletRequest) request;
       String ip = req.getRemoteAddr();
 
       Map<String, Integer> ipCountMap = (Map<String,Integer>) context
              .getAttribute("ipCountMap");
 
       Integer count = ipCountMap.get(ip);
       if (count == null) {
           count = 1;
       } else {
           count += 1;
       }
       ipCountMap.put(ip, count);
 
       context.setAttribute("ipCountMap", ipCountMap);
       chain.doFilter(request, response);
    }
 
    public void destroy() {}
}

 

解決全站字符亂碼

亂碼問題:

獲取請求參數中的亂碼問題;

  POST請求:request.setCharacterEncoding(“utf-8”)

  GET請求:newString(request.getParameter(“xxx”).getBytes(“iso-8859-1”), “utf-8”)

響應的亂碼問題:response.setContextType(“text/html;charset=utf-8”)

處理POST請求簡單,可是處理get請求需要獲取參數,filter獲取所有過濾資源的參數是不可能實現的.這裏可以調包request再發給servlet.增強request對象(改變getParamater()方法.讓每次獲取參數時直接解決亂碼問題).

    增強對象的方式有三種:(對a對象進行增強,fun1()方法)

  1. 繼承:  AA類繼承a對象的類型:A類,然後重寫fun1()方法,其中重寫的fun1()方法就是被增強的方法。但是,繼承必須要知道a對象的真實類型,然後才能去繼承。如果我們不知道a對象的確切類型,而只知道a對象是IA接口的實現類對象,那麼就無法使用繼承來增強a對象了;

  2. 裝飾者模式: AA類去實現a對象相同的接口:IA接口,還需要給AA類傳遞a對象,AA類所有方法的實現都是調用a對象相同方法實現,只有fun1()方法需要改變下內容,對fun1()進行增強;

  3. 動態代理:和增強者模式比較相似

這裏對request對象進行增強是通過繼承request對象的裝飾類,裝飾類是接口的包裝類,但是它不進行任何增強,我們通過繼承它然後重寫需要增強的方法,這樣就不用重寫需要增強的方法了.

 

(增強時一看繼承類,二看有沒有接口的包裝類,三接口的裝飾者模式)

public class EncodingFilter implements Filter {
 public void destroy() {
 }
 public void doFilter(ServletRequest request, ServletResponse response,
   FilterChain chain) throws IOException, ServletException {
  // 處理post請求編碼問題
  request.setCharacterEncoding("utf-8");
  
  HttpServletRequest req = (HttpServletRequest) request;
  
  /*
   * 處理GET請求的編碼問題
   */
//  String username = request.getParameter("username");
//  username = new String(username.getBytes("ISO-8859-1"), "UTF-8");
  
  /*
   * 調包request
   */
  if(req.getMethod().equals("GET")) {
   EncodingRequest er = new EncodingRequest(req);
   chain.doFilter(er, response);
  } else if(req.getMethod().equals("POST")) {
   chain.doFilter(request, response);
  }
 }
 public void init(FilterConfig fConfig) throws ServletException {
 }
}

 繼承包裝類增強request

/**
 * 裝飾reqeust
 */
public class EncodingRequest extends HttpServletRequestWrapper {
 private HttpServletRequest req;
 
 public EncodingRequest(HttpServletRequest request) {
  super(request);
  this.req = request;
 }
 public String getParameter(String name) {
  String value = req.getParameter(name); 
  // 處理編碼問題
  try {
   value = new String(value.getBytes("iso-8859-1"), "utf-8");
  } catch (UnsupportedEncodingException e) {
   throw new RuntimeException(e);
  } 
  return value;
 }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章