zoukankan      html  css  js  c++  java
  • 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;
        }
        
    }
  • 相关阅读:
    OpenStack云桌面系列【2】—OpenStack和Spice
    Java中的读写锁 ReentrantReadWriteLock
    Spring Boot Actuator 监控实践
    java子线程中获取父线程的threadLocal中的值
    String源码解析
    Java基础一
    Java 8 Lambda表达式实现原理解析
    Rabbit MQ总结
    AtomicInteger及CAS源码解析
    Queue(队列)接口和其实现类PriorityQueue(优先级队列)源码解析
  • 原文地址:https://www.cnblogs.com/jiangbei/p/6705102.html
Copyright © 2011-2022 走看看