JavaWeb基础—过滤器Filter

一、概念 

  JavaWeb三大组件之一(组件都有一个特性,需要在web.xml中配置
    过滤器:会在一组资源(jsp servlet等)的前面执行,可以让请求得到目标资源,也可以终止请求,不再继续
    也就是过滤器拥有拦截请求的能力
    与sevlet的拦截自身的单个资源不同,过滤器可以拦截一组资源(单个房间与一座大楼)

二、如何编写Filter

过滤器如何编写:
  写一个类,实现Filter接口(当然Myeclipse支持直接NEW 一个Filter)
  在web.xml中进行配置

  Filter接口三个方法(生命周期) 是单例的
  init() 创建之后马上执行(会在服务器启动时就创建)
  destory() 销毁之前执行(服务器关闭时销毁)
  doFilter() 执行过滤操作(注意三个参数)

  web.xml中配置
  和servlet非常类似
    <filter>
    <filter-name></filter-name>
    <filter-class></filter-class>
    </filter>
    <filter-mapping>
    <filter-name></filter-name>
    <url-pattern>/*</url-parrent> (使用/*偏多)
    </filter-mapping>

   FilterConfig ->类似 ServletConfig 能获取初始化参数
  获取Applicatio(最有用的方法)
  FilterChain
  doFilter()方法 (与上面的区分,这个类是上面的一个参数)
  功能:放行(相当于调用了目标Servlet的service()方法,执行完了还得回来)

==============================================
多过滤器的优先顺序:
大的先运行,小的后运行
例:先/* 后/AServlet
先执行图书馆的门禁,再执行各自习室的门禁,出来时放行当然相反

如何控制执行顺序:
在filter-mapping的配置顺序决定了过滤器的执行顺序

==============================================
四种拦截方式:
1.拦请求 REQUEST
2.拦转发 FORWARD
3.拦包含 INCLUDE
4.拦错误 ERROR

在filter-mapping中配置 <dispatcher>REQUEST</dispatcher> 默认为此种方式

==============================================
应用场景:
1.执行目标资源之前做一些预处理工作,例如编码的设置,这种操作通常是放行的。(发传单的,不拦截)
2.通过条件判断是否放行。(保安,可拦截),如拦截IP地址
3.目标资源执行后,做一些特殊的处理工作。如把目标资源输出数据进行处理。

=============================================
五个小案例(day21):
1.分IP统计网站访问次数(只统计,不拦截,在所有资源之前执行,放到过滤器,参考应用场景1)
使用map装载数据(key是IP value是次数(Integer))
map保存到ServletContext中(因为它既不属于某个请求,也不属于某个session)
需要在服务器开启的时候创建,使用ServletContextListener监听器初始化时创建

2.粗粒度权限控制(游客,管理员,会员等)
不同文件(不同角色的jsp等)放不同文件夹中,每个文件夹派一个Filter把守

3.解决全站字符乱码问题(两种请求都要处理)
POST:request.setCharacterEncoding("utf-8");
GET:拿到字符串再重新编码
增强request(继承HttpServletRequestWrapper),装饰者模式的是你还有你,一切拜托你
response类同

4.页面静态化
(针对的是长期不更改的,不会轻易地发生变化)
首次访问去数据库访问数据,把数据保存到一个HTML中
二次访问时直接显示HTML内容

三、给出几个实例

  统计IP

package cn.itcast.web.filter;

import java.io.IOException;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

/**
 * 分IP统计访问次数
 */
@WebFilter("/*")
public class AFilter implements Filter {
  private FilterConfig config;//将Init()中的config保存起来

    public void destroy() {
        
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        //得到application中的map,如果存在IP,次数增加,不存在则创建此IP,次数初识为1
        ServletContext sc = config.getServletContext();
        //得到map
        Map<String,Integer> map = (Map<String, Integer>) sc.getAttribute("map");
        //获取IP地址
        String ip = request.getRemoteAddr();
        //进行判断
        if(map.containsKey(ip)){//不是第一次访问
            int count = map.get(ip);
            map.put(ip, count+1);
        }else{//首次访问
            map.put(ip,1);
        }
        //最后再放进去
        sc.setAttribute("map", map);
        //必须要放行
        chain.doFilter(request, response);
    }

    public void init(FilterConfig fConfig) throws ServletException {
        this.config = fConfig;
    }

}

 

 处理全站乱码

package cn.itcast.web.filter;

import java.io.IOException;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

/**
 * 分IP统计访问次数
 */
@WebFilter("/*")
public class AFilter implements Filter {
  private FilterConfig config;//将Init()中的config保存起来

    public void destroy() {
        
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        //得到application中的map,如果存在IP,次数增加,不存在则创建此IP,次数初识为1
        ServletContext sc = config.getServletContext();
        //得到map
        Map<String,Integer> map = (Map<String, Integer>) sc.getAttribute("map");
        //获取IP地址
        String ip = request.getRemoteAddr();
        //进行判断
        if(map.containsKey(ip)){//不是第一次访问
            int count = map.get(ip);
            map.put(ip, count+1);
        }else{//首次访问
            map.put(ip,1);
        }
        //最后再放进去
        sc.setAttribute("map", map);
        //必须要放行
        chain.doFilter(request, response);
    }

    public void init(FilterConfig fConfig) throws ServletException {
        this.config = fConfig;
    }

}

  request的装饰类

  (装饰者模式(Decorator)的核心总结是经典的 是你还有你,一切拜托你

  具体的步骤如下:

  1.首先看需要被增强对象继承了什么接口或父类,编写一个类也去继承这些接口或父类。
  2.在类中定义一个变量,变量类型即需增强对象的类型。
  3.在类中定义一个构造函数,接收需增强的对象。
  4.覆盖需增强的方法,编写增强的代码。

  一个简单的例子见下:

package cn.itcast.web.filter;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.Principal;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Map;

import javax.servlet.AsyncContext;
import javax.servlet.DispatcherType;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.Part;

/**
 * 自己写的request的装饰类
 * 实际上java已经帮我们处理了那一大堆为实现的一切拜托你
 * @author jiangbei01
 *
 */
public class EncodingRequest extends HttpServletRequestWrapper {
    private HttpServletRequest request;
    public EncodingRequest(HttpServletRequest request) {
        super(request);
        this.request = request;//存一个底层对象
    }

    
    
    @Override
    public String getParameter(String name) {
        String value = request.getParameter(name);
        //处理value的编码问题
        try {
            value = new String(value.getBytes("ISO-8859-1"),"utf-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        return value;
    }
    
}
原文地址:https://www.cnblogs.com/jiangbei/p/6705102.html