zoukankan      html  css  js  c++  java
  • java Web 过滤器Filter详解

    简介

    Filter也称之为过滤器,Web开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。

    过滤器可以拦截请求和响应,,操作请求和响应中的数据,,控制是否允许访问目标资源,,url级别的拦截 (粗粒度)。

    原理

    一个过滤器

    首先在HttpServletRequest到达 Servlet 之前,拦截客户的HttpServletRequest 。根据需要检查HttpServletRequest,也可以修改HttpServletRequest 头和数据。
    然后在HttpServletResponse到达客户端之前,拦截HttpServletResponse 。根据需要检查HttpServletResponse,也可以修改HttpServletResponse头和数据。

    基本应用

    1,创建一个Filter

    public class Filter1 implements Filter {
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
            // 为了调用子类的方法
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            System.out.println("***** 执行过滤器1 ... ...拦截路径: " + httpServletRequest.getRequestURI());
            // 允许访问目标资源,简称 放行
            chain.doFilter(httpServletRequest, response);
        }
    
        @Override
        public void destroy() {
        }
    
    }

    2,web.xml配置

    <!-- 注册过滤器 -->
    <filter>
        <filter-name>filter1</filter-name>
        <filter-class>com.test.web.filter.Filter1</filter-class>
        <!-- 配置当前过滤器的配置信息 -->
        <init-param>
            <param-name>safeNum</param-name>
            <param-value>10</param-value>
        </init-param>
    </filter>
    <!-- 映射过滤器需要拦截的路径 -->
    <filter-mapping>
      <filter-name>filter1</filter-name>
      <url-pattern>/hello.jsp</url-pattern>
      <url-pattern>/HelloServlet</url-pattern>
    </filter-mapping>

    过滤器链(多个过滤器共同拦截)

    注意:我们下面的两个过滤器都拦截了同样的路径,先后顺序是由映射决定的,而不是注册顺序,也就是说下面这两个过滤器先执行的是filter2而不是filter1

      <!-- 注册过滤器 -->
      <filter>
          <filter-name>filter1</filter-name>
          <filter-class>com.test.web.filter.Filter1</filter-class>
      </filter>
        <filter>
          <filter-name>filter2</filter-name>
          <filter-class>com.test.web.filter.Filter2</filter-class>
      </filter>
      <!-- 映射过滤器需要拦截的路径 -->
      <filter-mapping>
          <filter-name>filter2</filter-name>
          <url-pattern>/hello.jsp</url-pattern>
          <url-pattern>/HelloServlet</url-pattern>
      </filter-mapping>
      <filter-mapping>
          <filter-name>filter1</filter-name>
          <url-pattern>/hello.jsp</url-pattern>
          <url-pattern>/HelloServlet</url-pattern>
      </filter-mapping>

    生命周期

    如下所示,1:实例化  2,初始化  3,拦截工作  4,销毁

    public class Filter2 implements Filter {
    
        public Filter2() {
            System.out.println("----------- 1 执行Filter2的构造方法");
        }
    
        public void init(FilterConfig fConfig) throws ServletException {
            System.out.println("----------- 2 执行Filter2的初始化方法");
        }
    
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
            // 为了调用子类的方法
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            System.out.println("----------- 3 执行Filter2的执行拦截的方法 , 拦截路径:" + httpServletRequest.getRequestURI());// 放行
            chain.doFilter(request, response);
        }
    
        public void destroy() {
            System.out.println("----------- 4 执行Filter2的销毁的方法 ");
        }
    
    }

    过滤器拦截方式

    1 直接请求(默认)

    2 请求转发(forward)

    3 错误页面跳转(error)

    4 引入其他页面(include)

    如果你修改拦截方式,需要在web.xml中 通过 dispatcher标签指定。

        <filter>
            <display-name>Filter2</display-name>
            <filter-name>Filter2</filter-name>
            <filter-class>com.test.web.filter.Filter2</filter-class>
            <!-- 配置当前过滤器的配置信息 -->
            <init-param>
                <param-name>safeNum</param-name>
                <param-value>10</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>Filter2</filter-name>
            <url-pattern>/hello.jsp</url-pattern>
            <!-- 配置拦截jsp的方式: 请求转发 -->
            <dispatcher>FORWARD</dispatcher>
            <!-- 增加拦截方式: 直接请求 -->
            <dispatcher>REQUEST</dispatcher>
        </filter-mapping>
        <filter-mapping>
            <filter-name>Filter2</filter-name>
            <url-pattern>/HelloServlet</url-pattern>
        </filter-mapping>

    案例演示一:解决post方式获取参数乱码和浏览器乱码

    Filter:

    public class EncodingFilter implements Filter {
    
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
            // 1 解决获取参数中文乱码(post)
            request.setCharacterEncoding("utf-8");
            // 2 解决浏览器出现的中文乱码
            response.setContentType("text/html;charset=utf-8");
            chain.doFilter(request, response);
        }
    
        public void destroy() {
        }
    
        public void init(FilterConfig fConfig) throws ServletException {
        }
    
    }

    web.xml:

      <filter>
        <display-name>EncodingFilter</display-name>
        <filter-name>EncodingFilter</filter-name>
        <filter-class>com.test.web.filter.EncodingFilter</filter-class>
      </filter>
      <filter-mapping>
        <filter-name>EncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
      </filter-mapping>

    案例演示二:统一解决get和post获取参数乱码

    Filter:

    public class GenericEncodingFilter implements Filter {
    
        public void destroy() {
        }
    
        public void init(FilterConfig fConfig) throws ServletException {
        }
    
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
            // 为了能够使用 子类的方法, 向下转型
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            // 对子类获取参数的方法进行增强: 包装
            HttpServletRequest myRequest = new MyRequest(httpServletRequest);
            // 放行
            chain.doFilter(myRequest, response);
        }
    
        class MyRequest extends HttpServletRequestWrapper {
    
            private HttpServletRequest request;
            
            // 标识: 表示map是否处理过
            private boolean isUpdate = false; // 表示没有处理
    
            public MyRequest(HttpServletRequest request) {
                super(request); // 注意: 这行代码不能丢失
    
                this.request = request;
            }
    
            @Override
            public Map<String, String[]> getParameterMap() {
                // 1 获取请求方式
                String method = request.getMethod();
                // 2 判断
                if ("post".equalsIgnoreCase(method)) {
                    // 2.1 如果是post方式, 设置请求编码集, 返回map即可
                    try {
                        request.setCharacterEncoding("utf-8");
                        return request.getParameterMap(); // 结束当前方法
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                } else if ("get".equalsIgnoreCase(method)) {
                    // 2.2 如果是get方式
                    // 2.2.1 获取map(没有处理)
                    Map<String, String[]> parameterMap = request.getParameterMap();
                    // 2.2.2 遍历map中的值, 使用先编码,再解码 解决乱码问题
                    if (parameterMap != null && isUpdate==false) { // 如果map没有处理过且不为null,才会被处理
                        for (Entry<String, String[]> en : parameterMap.entrySet()) {
                            String[] valArr = en.getValue(); // 数组是一个引用(地址)
                            for (int i = 0; i < valArr.length; i++) { // 注意:
                                                                        // 这里不能使用增强for循环
                                try {
                                    valArr[i] = new String(valArr[i].getBytes("iso-8859-1"), "utf-8");
                                } catch (UnsupportedEncodingException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                        // 处理完map需要将状态修改为true
                        isUpdate = true;
                    }
                    // 2.2.3 返回map(处理过)
                    return parameterMap;
                }
                return super.getParameterMap();
            }
    
            // 改造获取非多选的值
            @Override
            public String getParameter(String name) {
                // 1 获取已经处理好的map
                Map<String, String[]> parameterMap = this.getParameterMap();
                // 2 从map中获取正确的值
                String[] valArr = parameterMap.get(name);
                // 3 判断
                if (valArr != null) {
                    return valArr[0];
                } else {
                    return null;
                }
            }
    
            @Override
            public String[] getParameterValues(String name) {
                // 1 获取已经处理好的map
                Map<String, String[]> parameterMap = this.getParameterMap();
                // 2 从map中获取正确的值
                String[] valArr = parameterMap.get(name);
                return valArr;
            }
    
        }
    
    }

    web.xml:

      <filter>
        <display-name>GenericEncodingFilter</display-name>
        <filter-name>GenericEncodingFilter</filter-name>
        <filter-class>com.test.web.filter.GenericEncodingFilter</filter-class>
      </filter>
      <filter-mapping>
        <filter-name>GenericEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
      </filter-mapping>
  • 相关阅读:
    centos7 docker安装awvs
    screen命令简介-实现linux多窗口
    linux命令重命名
    iptables防止nmap扫描
    cobal strike could not start listener address already in use (bind failed)
    docker简介及安装
    「Sqlserver」数据分析师有理由爱Sqlserver之二-像使用Excel一般地使用Sqlserver
    「Sqlserver」数据分析师有理由爱Sqlserver之一-好用的插件工具推荐
    「PowerBI」分析服务多维数据结构重回关系数据库的一大绝招
    「数据分析」Sqlserver中的窗口函数的精彩应用之数据差距与数据岛(含答案)
  • 原文地址:https://www.cnblogs.com/blazeZzz/p/9246530.html
Copyright © 2011-2022 走看看