歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> 淺析Java過濾器

淺析Java過濾器

日期:2017/3/1 9:27:20   编辑:Linux編程

閱讀目錄

  • 一、過濾器概述
  • 二、一個簡單過濾器的實現過程
  • 三、過濾器的部署
  • 四、過濾器的應用舉例

一、過濾器概述

  過濾器是Java Web三大組件之一,它與Servlet很相似。對於Web應用程序來說,過濾器是一個駐留在服務器端的Web組件,它可以截取客戶端和資源之間的請求和響應信息並對這些信息進行過濾。本文將對過濾器的和實現機制和應用進行簡單的總結。

  當Web容器接收到一個對資源的請求時,它將判斷是否有過濾器與這個資源相關聯,如果有那麼容器將請求交給過濾器進行處理。下圖所示為過濾器的工作過程。

  

  在web應用程序中可以部署多個過濾器形成一個過濾器鏈,在請求資源時,過濾器鏈中的過濾器將依次對請求進行處理(執行順序是在web.xml文件中的部署順序),並將請求傳遞給下一個過濾器,直到目標資源。在發送響應時,則是按照相反的順序對響應進行處理的,直到客戶端。

  過濾器的應用場景主要有幾下幾點:

  • 執行目標資源之前做預處理工作,例如設置編碼
  • 通過條件判斷是否放行,例如校驗當前用戶是否已經登錄
  • 在目標資源執行後做一些後續的處理工作,例如把目標資源輸出的數據進行處理

二、一個簡單過濾器的實現過程

  寫一個過濾器就是寫一個類,並且這個類要實現Filter接口。Filter接口定義了三個方法,init()、doFilter()和destory()。它們的執行構成了過濾器的生命周期。

  • init(FilterConfig):在服務器啟動時會創建Filter實例,並且每個類型的Filter只創建一個實例,從此不再創建!在創建完Filter實例後,會馬上調用init()方法完成初始化工作,這個方法只會被執行一次;
  • doFilter(ServletRequest req,ServletResponse res,FilterChain chain):這個方法會在用戶每次訪問“目標資源(<url->pattern>index.jsp</url-pattern>)”時執行,如果需要“放行”,那麼需要調用FilterChain的doFilter(ServletRequest,ServletResponse)方法,如果不調用FilterChain的doFilter()方法,那麼目標資源將無法執行;
  • destroy():服務器會在創建Filter對象之後,把Filter放到緩存中一直使用,通常不會銷毀它。一般會在服務器關閉時銷毀Filter對象,在銷毀Filter對象之前,服務器會調用Filter對象的destory()方法。

  下面代碼既是一個實現了Filter接口的過濾器:

public class FilterDemo1 implements Filter
{
    public void init(FilterConfig filterConfig) throws ServletException
    {
    }
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException
    {
        response.setContentType("text/html;charset=GB2312");
        PrintWriter out=response.getWriter();
        out.println("過濾器攔截你!");
        chain.doFilter(request, response);
        out.close();
    }
    public void destroy()
    {
    }
}

  過濾器寫好之後要通過在web.xml文件對其進行配置,配置的方法類似於Servlet的。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>day_0701</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <filter>
    <filter-name>FilterDemo1</filter-name>
    <filter-class>com.test.filter.FilterDemo1</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>FilterDemo1</filter-name>
    <url-pattern>/1.jsp</url-pattern>
  </filter-mapping>
</web-app>

  然後在WebContent目錄下,新建一個jsp文件:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <title>在此處插入標題</title>
    </head>
    
    <body>
        這是測試頁面!
    </body>
</html>

  當請求訪問1.jsp文件時,顯示結果如下:

  結果分析:因為上述過濾器是與1.jsp文件相關聯,所以web容器將請求先交給過濾器進行處理,輸出“過濾器攔截你”後,過濾器對請求進行“放行”,所以又輸出“這是測試頁面”。

三、過濾器的部署

  過濾器的部署是在<filter>和<filter-mapping>元素來完成的。

3.1 過濾器的攔截方式

  過濾器有四種攔截方式,分別是:REQUEST、FORWARD、INCLUDE、ERROR。

  1. REQUEST:直接訪問目標資源時執行過濾器。包括:在地址欄中直接訪問、表單提交、超鏈接、重定向,只要在地址欄中可以看到目標資源的路徑,就是REQUEST;
  2. FORWARD:轉發訪問執行過濾器。包括RequestDispatcher#forward()方法、<jsp:forward>標簽都是轉發訪問;
  3. INCLUDE:包含訪問執行過濾器。包括RequestDispatcher#include()方法、<jsp:include>標簽都是包含訪問;
  4. ERROR:當目標資源在web.xml中配置為<error-page>中時,並且真的出現了異常,轉發到目標資源時,會執行過濾器。

  攔截方式是在<dispatcher></dispatcher>中設置的,默認情況是REQUEST方式。

3.2 設置目標資源

  可以通過<url-pattern>或者<servlet-name>中設置目標資源,在<url-pattern>中指定過濾器關聯的URL樣式;在<servlet-name>指定過濾器指定的Servlet,用戶在訪問<url-pattern>元素指定的URL上的資源或<servlet-name>元素指定的Servlet時,該過濾器才會被容器調用。

 <filter-mapping>
    <filter-name>LoginFilter</filter-name>
    <url-pattern>/2.jsp</url-pattern>
    <servlet-name>DemoServlet</servlet-name>
  </filter-mapping>

四、過濾器的應用舉例

  通過過濾器可以解決頁面的亂碼問題,代碼如下:

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請求的編碼問題
         
         * 調包request
         * 1. 寫一個request的裝飾類
         * 2. 在放行時,使用我們自己的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 {

    }
}
/**
 * 裝飾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;
    }
} 

Copyright © Linux教程網 All Rights Reserved