# 一、过滤器执行流程
过滤器,设计执行流程:
1. 用户访问服务器
2. 过滤器: 对Servlet请求进行拦截
3. 先进入过滤器, 过滤器处理
4. 过滤器处理完后, 在放行, 此时,请求到达Servlet/JSP
5. Servlet处理
6. Servlet处理完后,再回到过滤器, 最后在由tomcat服务器相应用户;

# 二、自定义类实现过滤器

## 1、编写DemoFilter类实现Filter接口:

```
package webCustomFilter;
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;public class DemoFilter implements Filter {
    public DemoFilter() {
        System.out.println("1、调用构造方法...创建DemoFilter实例对象");
    }    public void init(FilterConfig arg0) throws ServletException {
        System.out.println("2、初始化过滤器方法...执行init方法...");
    }    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("3、开始执行doFilter方法...");
        chain.doFilter(request, response);
        System.out.println("5、返回执行doFilter方法...");
    }    public void destroy() {
        System.out.println("6、销毁DemoFilter对象方法...");
    }
}
```

## 2、编写DemoServlet的Servlet

```
package webCustomFilter;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class DemoServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("4、servlet中的业务逻辑方法被执行了......");
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }
}
```
其中web.xml中关于Filter的配置如下:
```
  <!-- 过滤器配置 -->
    <filter>
        <!-- 过滤器内部名称 -->
        <filter-name>DemoFilter</filter-name>
        <!-- 过滤器类的全名 -->
        <filter-class>webCustomFilter.DemoFilter</filter-class>
    </filter>
    <filter-mapping>
        <!-- filter内部名称 -->
        <filter-name>DemoFilter</filter-name>
        <!-- 需要拦截的servlet资源 -->
        <url-pattern>/*</url-pattern>
    </filter-mapping>
```

# 三、过滤器相关API
|-- interface Filter 过滤器核心接口
Void init(filterConfig); 初始化方法,在服务器启动时候执行
Void doFilter(request,response,filterChain); 过滤器拦截的业务处理方法
Void destroy(); 销毁过滤器实例时候调用

|-- interface FilterConfig 获取初始化参数信息
String getInitParameter(java.lang.String name)
Enumeration getInitParameterNames()

|-- interface FilterChain 过滤器链参数;一个个过滤器形成一个执行链;
void doFilter(ServletRequest request, ServletResponse response) ; 执行下一个过滤器或放行

FilterConfig案例:
比如在web.xml中关于Filter的初始化配置如下

```
<filter>
        <!-- 过滤器初始化配置 -->
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
        <init-param>
            <param-name>path</param-name>
            <param-value>D://xrk</param-value>
        </init-param>
        <!-- 过滤器内部名称 -->
        <filter-name>DemoFilter</filter-name>
        <!-- 过滤器类的全名 -->
        <filter-class>webCustomFilter.DemoFilter</filter-class>
    </filter>
    <filter-mapping>
        <!-- filter内部名称 -->
        <filter-name>DemoFilter</filter-name>
        <!-- 需要拦截的servlet资源 -->
        <url-pattern>/*</url-pattern>
    </filter-mapping>
```


如果需要获取init-param标签中name为encoding和path的值,则在init方法中的代码如下:

```
public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("2、初始化过滤器方法...执行init方法...");
        Enumeration<String> enumeration = filterConfig.getInitParameterNames();
        while(enumeration.hasMoreElements()){
            String name=enumeration.nextElement();
            String initParameter = filterConfig.getInitParameter(name);
            System.out.println(name+"\t"+initParameter);
        }
    }
```



# 四、对指定的请求进行拦截
1、/*表示拦截所有的请求

```
<filter-mapping>
        <!-- filter内部名称 -->
        <filter-name>DemoFilter</filter-name>
        <!-- 需要拦截的servlet资源 -->
        <url-pattern>/*</url-pattern>
    </filter-mapping>
```


2、拦截指定的jsp

```
<filter-mapping>
        <filter-name>DemoFilter</filter-name>
        <url-pattern>/index.jsp</url-pattern>
    </filter-mapping>
```

3、拦截指定的多个jsp

```
<filter-mapping>
        <filter-name>DemoFilter</filter-name>
        <url-pattern>/index.jsp</url-pattern>
        <url-pattern>/list.jsp</url-pattern>
    </filter-mapping>
```

4、拦截所有的jsp

```
<filter-mapping>
        <filter-name>DemoFilter</filter-name>
        <url-pattern>*.jsp</url-pattern>
    </filter-mapping>
```

5、默认拦截的类型:

```
默认拦截的类型:(直接访问或者重定向)
        <dispatcher>REQUEST</dispatcher>
    拦截转发:
        <dispatcher>FORWARD</dispatcher>
    拦截包含的页面(RequestDispatcher.include(/page.jsp);    对page.jsp也执行拦截)
        <dispatcher>INCLUDE</dispatcher>
    拦截声明式异常信息:
        <dispatcher>ERROR</dispatcher>
```

 

# 五、过滤器案例
几乎每一个Servlet都要涉及编码处理:处理请求数据中文问题!
【GET/POST】
每个servlet都要做这些操作,把公用的代码抽取-过滤器实现!

代码实现思路:
1. Login.jsp 登陆,输入“中文”
2. LoginServlet.java 直接处理登陆请求
3. EncodingFilter.java 过滤器处理请求数据编码:GET/POST

新建一个DemoFilter实现Filter接口,代码如下:

```
package webCustomFilter;import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Enumeration;
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;public class DemoFilter implements Filter {
    public DemoFilter() {
    }    public void init(FilterConfig filterConfig) throws ServletException {
    }    public void doFilter(ServletRequest req, ServletResponse rep, FilterChain chain)
            throws IOException, ServletException {
         //System.out.println("3、开始执行doFilter方法...");
        // 1、因为目前的request属于ServletRequest类型,而不是HttpServletRequest类型,需要进行类型转换
        final HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) rep;
        // 处理编码


// 2、针对post提交方式处理编码模式

request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");



// 3、针对get方式提交的数据,是因为request.getParameter方法内部没有进行提交方式判断并处理,因此会出现乱码

//String name = request.getParameter("username");
        //解决办法:使用代理的方式对指定的接口的某一个方法进行功能扩展:即对request对象(目标对象),创建代理对象!
        HttpServletRequest proxy =  (HttpServletRequest)Proxy.newProxyInstance(
                request.getClass().getClassLoader(), 
                new Class[]{HttpServletRequest.class}, 
                new InvocationHandler() {

                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object result=null;


//3.1、获取方法名
                        String methodname=method.getName();
                        //3.2、判断:对getParameter方法进行GET提交中文处理
                        if("getParameter".equals(methodname)){
                            //3.3、获取当前request提交方式
                            String submitMethod=request.getMethod();
                            //3.4、获取当前请求的数值:<input type="text" name="username" />
                            String requestValue=request.getParameter(args[0].toString());
                            //3.5、如果当前提交方式为GET提交
                            if("GET".equals(submitMethod)){
                                if(requestValue!=null && !"".equals(requestValue.trim())){
                                    //转码
                                    requestValue=new String(requestValue.getBytes("ISO8859-1"),"UTF-8");
                                }
                            }
                            return requestValue;
                        }else{
                            result=method.invoke(request, args);
                        }
                        return result;
                    }
                });



//4、放行

chain.doFilter(proxy, response);
    }    public void destroy() {
    }
}
```