Java Web(四) 过滤器Filter

Filter概述

Filter意为滤镜或者过滤器,用于在Servlet之外对request或者response进行修改。Filter提出了过滤链的概念。一个FilterChain包括多个Filter。客户端请求request在抵达Servlet之前会经过FilterChian里的所有Filter,服务器响应response在从Servlet抵达客户端浏览器之前也会经过FileterChain里的所有Filter。Filter处理过程如图所示。

img

Filter接口

一个Filter必须实现javax.servlet.Filter接口。Filter有三个方法。

public interface Filter {
    default void init(FilterConfig filterConfig) throws ServletException {
    }

    void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;

    default void destroy() {
    }
}

这三个方法反映了Filter的生命周期,其中init与dstory只会被调用一次,分别在web程序加载和卸载的时候调用。而doFilter()方法每次有客户端请求时都会被调用一次。Filter的所有工作集中在doFilter方法中,另外可从init方法传入的filterConfig对象得到filter的初始化参数。

下面是Filter的一个简单实现。

public class TestFilter implements Filter {
    public void destroy() {
        System.out.println("我被销毁了");
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        System.out.println("在请求到达Servlet之前我输出了");
        chain.doFilter(req, resp);
        System.out.println("在响应到达客户端之前我输出了");
    }

    public void init(FilterConfig config) throws ServletException {
        System.out.println("我被初始化了");
        //得到初始化数据
        String value1 = config.getInitParameter("name1");
        String value2 = config.getInitParameter("name2");
        System.out.println(value1 + " " + value2);
    }

}

chain.doFilter(req, resp)将request递交给下一个FilterChain的下一个Filter,如果都走完了则交给Servlet处理。

Filter配置

Filter需要在web.xml或@WebFilter注解中配置才能生效。Filter的配置与Servlet的配置非常类似。

在web.xml中需要配置<filter>与<filter-mapping>标签。

<filter>
  <filter-name>filtername</filter-name>
  <filter-class>filter.TestFilter</filter-class>
  <init-param>
    <param-name>paraName</param-name>
    <param-value>paraValue</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>filtername</filter-name>
  <url-pattern>*.do</url-pattern>
  <dispatcher>REQUEST</dispatcher>
  <dispatcher>FORWARD</dispatcher>
</filter-mapping>

<filter>配置Filter名称,实现类,和初始化参数,可同时配置多个初始化参数,<filter-mapping>配置在什么规则下使用Filter,这两者的filter-name必须匹配。

<url-pattern>配置URL的规则,可以配置多个,可以使用通配符()。例如"/jsp/"适用于本contextPath下以"/jsp"开头的Serlvet,"*.do"适用于所有以".do"结尾的Servlet路径。

<dispatcher>配置到达Servlet的方式。有四种取值:REQUEST,FORWORD,INCLUDE,ERROR。可以同时配置多个<dispatcher>,如果没有配置<dispatcher>,默认为REQUEST。它们的区别为:

  • REQUEST:表示仅当直接请求Servlet时才生效。
  • FORWORD:表示仅当某Servlet通过FORWARD到该Servlet时才生效。
  • INCLUDE:JSP中可以通过 请求某Servlet,仅在这种情况下有效。
  • ERROR:JSP中可以通过<%@ page errorPage="error.jsp" %>指定错误处理页面,仅在这种情况下有效。

注意:一个Web程序可以配置多个Filter,这多个Filter的执行顺序有先有后,规则是<filter-mapping>配置在前面的Fliter执行要早与配置在后面的Filter,多个Filter之间可能会相互影响。

在@WebFilter注解中配置,这样就简单多了

@WebFilter(
        filterName = "MyFilter",
        urlPatterns = "*.do",
        initParams = {
                @WebInitParam(name="paramName", value = "paramValue")
        },
        dispatcherTypes = REQUEST
)

应用:字符过滤器

在Servlet里获取请求参数时经常遇到乱码问题,在每个Servlet里处理编码问题就非常麻烦,可以利用过滤器统一处理字符编码问题。你肯定会想到亲自实现那个HttpServletRequest接口,但是如果自己实现的话,要重写里面所有的方法,非常麻烦,所以java提供了HttpServletRequestWrapper类,它已经帮你实现了httpServletRequest接口,你只需要重写你想要重新定义的方法即可。

/**
    增强了所有的获取参数的方法
    request.getParameterValues("name");
    request.getParameter("name");
    request.getParameterMap();
 */
class MyRequest extends HttpServletRequestWrapper{
    private HttpServletRequest request;
    private boolean flag = true;
    public MyRequest(HttpServletRequest request) {
        super(request);
        this.request=request;
    }
    
    @Override
    public String getParameter(String name) {  
        if(name==null || name.trim().length()==0){
            return null;
        }
        String[] values = getParameterValues(name);
        if(values==null || values.length==0){
            return null;
        }
        return values[0];
    }
    
    @Override
    public String[] getParameterValues(String name) {
        if(name==null || name.trim().length()==0){
            return null;
        }
        Map<String, String[]> map = getParameterMap();
        if(map==null || map.size()==0){
            return null;
        }
        return map.get(name);
    }
    
    @Override
    public Map<String,String[]> getParameterMap() {  
        
        /**
         * 首先判断请求方式
         * 若为post  request.setchar...(utf-8)
         * 若为get 将map中的值遍历编码就可以了
         */
        String method = request.getMethod();
        if("post".equalsIgnoreCase(method)){
            try {
                request.setCharacterEncoding("utf-8");
                return request.getParameterMap();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }else if("get".equalsIgnoreCase(method)){
            Map<String,String[]> map = request.getParameterMap();
            if(flag){
                for (String key:map.keySet()) {
                    String[] arr = map.get(key);
                    //继续遍历数组
                    for(int i=0;i<arr.length;i++){
                        //编码
                        try {
                            arr[i]=new String(arr[i].getBytes("iso-8859-1"),"utf-8");
                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        }
                    }
                }
                flag=false;
            }
            return map;
        }
        return super.getParameterMap();
    }
    
}

接着编写EncodeFilter过滤器,对请求的文本进行编码处理。

/**
 * 统一编码
 */
@WebFilter(
        filterName = "EncodingFilter",
        urlPatterns = "/*"
)
public class EncodingFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException { }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request=(HttpServletRequest) req;
        HttpServletResponse response=(HttpServletResponse) resp;
        chain.doFilter(new MyRequest(request), response);
    }

    @Override
    public void destroy() { }

}

猜你喜欢

转载自www.cnblogs.com/kindleheart/p/9780703.html