26、过滤器

过滤器

项目开发中,经常会涉及到重复代码的实现!

注册 ---- 提交Servlet 【1. 设置编码格式】 ----转到JSP
修改 ---- 提交Servlet 【1. 设置编码格式】 --- 转到JSP

其他:

如判断用户是否登陆,只有登陆才能有操作权限!
涉及到重复判断: 获取session,取出session数据,判断是否为空,为空说明没有登陆,不能操作
只有登陆后,才能操作!

如何解决:

  1. 抽取重复代码,封装
  2. 每个用到重复代码的地方,手动的调用!

过滤器,设计执行流程:

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

    (过滤器就像回家的门!)

基本知识

过滤器:
 * 概述:
   * Filter的作用:起到过滤的作用.
   * Filter执行的时机:
     * 在执行对应的Servlet之前.(过滤Request对象中的内容)
     * 在执行对应的Servlet之后.(过滤Respons对象中的内容)
   * 发展:
     * Filter最早在Servlet 2.3版本提供.
     * Filter在Servlet 2.5版本完善.
 * 如何使用Filter:
   * Filter是JavaEE提供的一个接口.(自定义Filter需要实现该接口,并重写所有方法)
   * Filter提供的方法:
     * init()
     * doFilter()
     * destroy()
   * 实现步骤:
     * 创建Java类,实现Filter接口,并且重写所有方法.
     * 在web.xml文件中进行配置.
      <filter>
        <filter-name>MyFilter1</filter-name>
        <filter-class>app.java.filter.MyFilter1</filter-class>
      </filter>
      <filter-mapping>
        <filter-name>MyFilter1</filter-name>
        <url-pattern>/*</url-pattern>
      </filter-mapping>
 * Filter的生命周期:
   * 出生:Hello World
     * init()方法
   * 活着:Love World
     * doFilter()方法
   * 死去:GoodBye World
     * destroy()方法
 * 过滤器链:
   * 问题:
     * 如何定义过滤器被执行的先后顺序?
     * Filter的doFilter()方法具有一个参数FilterChain,通过调用chain.doFilter()方法可以放行.
       * 在过滤器链中,执行chain.doFilter()方法,是否还是放行的作用?
       * 如果是,应该被放行到哪里去了?(单个Filter时,直接被放行到对应的Web资源[Servlet、JSP])
   * 解决以上问题:
     * chain.doFilter()方法依旧是放行方法.
     * 如果执行的不是过滤器链中最后一个过滤器的话,执行chain.doFilter()方法,会被放行到下一个过滤器里.
     * 如果执行的是过滤器链中最后一个过滤器的话,chain.doFilter()方法,才会被放行到对应Web资源中.
     * 过滤器链中的过滤器执行的先后顺序由web.xml文件中的<filter-mapping>标签定义的先后顺序决定.
   * 实际开发的意义:
     * 单个Filter完成单个任务.
 * FilterConfig
   * 读取web.xml文件中的初始化参数.
   * 在web.xml文件中是如何配置的:
      <filter>
        <filter-name>MyFilter2</filter-name>
        <filter-class>app.java.filter.MyFilter2</filter-class>
        <init-param>
            <param-name>mingjiao</param-name>
            <param-value>zhangwuji</param-value>
        </init-param>
      </filter>
   * FilterConfig的用法与ServletConfig一致.
   * 在web.xml文件中配置全局初始化参数<context-param>,通过ServletContext对象读取.
 * Filter的映射配置:<url-pattern>
   * 完全匹配:/xxxx
   * 目录匹配:/aaaa/
   * 扩展名匹配:*.do
   * 优先级别:完全匹配 -> 目录匹配 -> 扩展名匹配

   * 如果当前Filter拦截对应Servlet的话:
     * 还可以使用<servlet-name>标签

   * Filter拦截Servlet默认情况是拦截直接请求.
     * 在web.xml文件中配置<filter-mapping>标签中具有<dispatcher>
     * <dispatcher>标签在同一个Filter的配置中,可以配置多个.
     * <dispatcher>标签的值:
       * REQUEST:是默认值,表示一次请求.
       * FORWARD:表示请求转发到.
       * INCLUDE:表示包含(例如JSP包含另一个JSP等)
       * ERROR:表示JSP的<%@ page errorPage=""%>

 * Filter的案例:
   * 全站乱码案例:
     * 利用Servlet的doGet()和doPost()方法中,可以解决中文乱码:
       * doGet()
         String value = request.getParameter("");
     value = new String(value.getBytes("ISO8859-1"),"utf-8");

     response.setContentType("text/html;charset=utf-8");
       * doPost()
         request.setCharacterEncoding("utf-8");
     response.setContentType("text/html;charset=utf-8");
     * 以上问题:
       * 实际开发时,Web应用程序的逻辑比较复杂(多个Servlet).
       * 上述的解决方案,仅能解决当前Servlet的中文乱码问题.
       * 如果使用上述方案,解决中文乱码问题:代码重复性太多.

过滤器案例:

接口:

|-- 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);
    //执行下一个过滤器或放行
public class HelloFilter implements Filter{

    // 创建实例
    public HelloFilter(){
        System.out.println("1. 创建过滤器实例");
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("2. 执行过滤器初始化方法");

        // 获取过滤器在web.xml中配置的初始化参数
        String encoding = filterConfig.getInitParameter("encoding");
        System.out.println(encoding);

        // 获取过滤器在web.xml中配置的初始化参数 的名称
        Enumeration<String> enums =  filterConfig.getInitParameterNames();
        while (enums.hasMoreElements()){
            // 获取所有参数名称:encoding、path
            String name = enums.nextElement();
            // 获取名称对应的值
            String value = filterConfig.getInitParameter(name);
            System.out.println(name + "\t" + value);
        }
    }

    // 过滤器业务处理方法: 在请求到达servlet之前先进入此方法处理公用的业务逻辑操作
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        System.out.println("3. 执行过滤器业务处理方法");
        // 放行 (去到Servlet)
        // 如果有下一个过滤器,进入下一个过滤器,否则就执行访问servlet
        chain.doFilter(request, response);

        System.out.println("5. Servlet处理完成,又回到过滤器");
    }

    @Override
    public void destroy() {
        System.out.println("6. 销毁过滤器实例");
    }
}
public class HelloFilter2 implements Filter{
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        System.out.println("第二个过滤器");
        // 放心
        chain.doFilter(request, response);
        System.out.println("第二个过滤器执行结束");
    }
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub

    }
    @Override
    public void destroy() {
        // TODO Auto-generated method stub
    }
}

xml配置:

<!-- 过滤器配置
    <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>c:/...</param-value>
        </init-param>

        <filter-name>hello_filter</filter-name>
        <filter-class>cn.itcast.a_filter_hello.HelloFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>hello_filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    -->

    <!-- 配置第二个过滤器 -->
    <!-- 演示: 拦截指定的请求 -->
    <filter>
        <filter-name>hello_filter2</filter-name>
        <filter-class>cn.itcast.a_filter_hello.HelloFilter2</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>hello_filter2</filter-name>
        <!-- 1. 拦截所有
        <url-pattern>/*</url-pattern>
         -->

         <!-- 2. 拦截指定的jsp
         <url-pattern>/index.jsp</url-pattern>
         <url-pattern>/list.jsp</url-pattern>
         -->
         <!-- 拦截所有的jsp
         <url-pattern>*.jsp</url-pattern>
          -->
          <!-- 3. 根据servlet的内部名称拦截
          <servlet-name>IndexServlet</servlet-name>
           -->
          <!-- 拦截指定的servlet
          <url-pattern>/index</url-pattern>
          -->

          <!-- 4. 指定拦截指定的类型 -->
          <url-pattern>/*</url-pattern>
          <!-- 拦截直接访问的请求或者重定向的资源 -->
          <dispatcher>REQUEST</dispatcher>
          <!--<dispatcher>FORWARD</dispatcher>-->
    </filter-mapping>

编码处理过滤器

public class EncodingFilter implements Filter {

    // 过滤器业务处理方法:处理的公用的业务逻辑操作
    @Override
    public void doFilter(ServletRequest req, ServletResponse res,
            FilterChain chain) throws IOException, ServletException {
        // 转型
        final HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        // 一、处理公用业务
        request.setCharacterEncoding("UTF-8");                  // POST提交有效
        response.setContentType("text/html;charset=UTF-8");
        /*
         * 出现GET中文乱码,是因为在request.getParameter方法内部没有进行提交方式判断并处理。
         * String name = request.getParameter("userName");
         *
         * 解决:对指定接口的某一个方法进行功能扩展,可以使用代理!
         *      对request对象(目标对象),创建代理对象!
         */
        HttpServletRequest proxy =  (HttpServletRequest) Proxy.newProxyInstance(
                request.getClass().getClassLoader(),        // 指定当前使用的累加载器
                new Class[]{HttpServletRequest.class},      // 对目标对象实现的接口类型
                new InvocationHandler() {                   // 事件处理器
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args)
                            throws Throwable {
                        // 定义方法返回值
                        Object returnValue = null;
                        // 获取方法名
                        String methodName = method.getName();
                        // 判断:对getParameter方法进行GET提交中文处理
                        if ("getParameter".equals(methodName)) {

                            // 获取请求数据值【 <input type="text" name="userName">】
                            String value = request.getParameter(args[0].toString());    // 调用目标对象的方法

                            // 获取提交方式
                            String methodSubmit = request.getMethod(); // 直接调用目标对象的方法

                            // 判断如果是GET提交,需要对数据进行处理  (POST提交已经处理过了)
                            if ("GET".equals(methodSubmit)) {
                                if (value != null && !"".equals(value.trim())){
                                    // 处理GET中文
                                    value = new String(value.getBytes("ISO8859-1"),"UTF-8");
                                }
                            }
                            return value;
                        }
                        else {
                            // 执行request对象的其他方法
                            returnValue = method.invoke(request, args);
                        }

                        return returnValue;
                    }
                });

        // 二、放行 (执行下一个过滤器或者servlet)
        chain.doFilter(proxy, response);        // 传入代理对象
    }
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }
    @Override
    public void destroy() {

    }
}

数据过滤器

/**
 * 无效数据过滤
 * @author Jie.Yuan
 *
 */
public class DateFilter implements Filter {

    // 初始化无效数据
    private List<String> dirtyData;
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 模拟几个数据
        dirtyData = new ArrayList<String>();
        dirtyData.add("NND");
        dirtyData.add("炸使馆");
    }
    @Override
    public void doFilter(ServletRequest req, ServletResponse res,
            FilterChain chain) throws IOException, ServletException {

        // 转型
        final HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        // 一、处理公用业务
        request.setCharacterEncoding("UTF-8");                  // POST提交有效
        response.setContentType("text/html;charset=UTF-8");

        HttpServletRequest proxy =  (HttpServletRequest) Proxy.newProxyInstance(
                request.getClass().getClassLoader(),        // 指定当前使用的累加载器
                new Class[]{HttpServletRequest.class},      // 对目标对象实现的接口类型
                new InvocationHandler() {                   // 事件处理器
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args)
                            throws Throwable {
                        // 定义方法返回值
                        Object returnValue = null;
                        // 获取方法名
                        String methodName = method.getName();
                        // 判断:对getParameter方法进行GET提交中文处理
                        if ("getParameter".equals(methodName)) {

                            // 获取请求数据值【 <input type="text" name="userName">】
                            String value = request.getParameter(args[0].toString());    // 调用目标对象的方法

                            // 获取提交方式
                            String methodSubmit = request.getMethod(); // 直接调用目标对象的方法

                            // 判断如果是GET提交,需要对数据进行处理  (POST提交已经处理过了)
                            if ("GET".equals(methodSubmit)) {
                                if (value != null && !"".equals(value.trim())){
                                    // 处理GET中文
                                    value = new String(value.getBytes("ISO8859-1"),"UTF-8");
                                }
                            } 

                            // 中文数据已经处理完: 下面进行无效数据过滤
                            //【如何value中出现dirtyData中数据,用****替换】
                            for (String data : dirtyData) {
                                // 判断当前输入数据(value), 是否包含无效数据
                                if (value.contains(data)){
                                    value = value.replace(data, "*****");
                                }
                            }
                            // 处理完编码、无效数据后的正确数据
                            return value;
                        }
                        else {
                            // 执行request对象的其他方法
                            returnValue = method.invoke(request, args);
                        }

                        return returnValue;
                    }
                });

        // 二、放行 (执行下一个过滤器或者servlet)
        chain.doFilter(proxy, response);        // 传入代理对象
    }
    @Override
    public void destroy() {

    }
}

拦截过滤器

/**
 * 登陆验证过滤器
 *
 *  http://localhost:8080/emp_sys/login.jsp   可以直接访问
    http://localhost:8080/emp_sys/login      可以直接访问
    http://localhost:8080/emp_sys/index   不能直接访问
    http://localhost:8080/emp_sys/list.jsp   不能直接访问

 * @author Jie.Yuan
 *
 */
public class LoginFilter implements Filter {

    private String uri;

    /**
     * 分析:
     *
        1. 先指定放行的资源,哪些资源不需要拦截:
              login.jsp   +    /login  (request对象可以获取)
        2. 获取session,从session中获取登陆用户
        3. 判断是否为空:
              为空, 说明没有登陆, 跳转到登陆
               不为空, 已经登陆,放行!
     */
    public void doFilter(ServletRequest req, ServletResponse res,
            FilterChain chain) throws IOException, ServletException {

        //0. 转换
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        //1. 获取请求资源,截取
        String uri = request.getRequestURI();   // /emp_sys/login.jsp
        // 截取 【login.jsp或login】
        String requestPath = uri.substring(uri.lastIndexOf("/") + 1, uri.length());  

        //2. 判断: 先放行一些资源:/login.jsp、/login
        if ("login".equals(requestPath) || "login.jsp".equals(requestPath)) {
            // 放行
            chain.doFilter(request, response);
        }
        else {
            //3. 对其他资源进行拦截
            //3.1 先获取Session、获取session中的登陆用户(loginInfo)
            HttpSession session = request.getSession(false);
            // 判断
            if (session != null) {

                Object obj = session.getAttribute("loginInfo");

                //3.2如果获取的内容不为空,说明已经登陆,放行
                if (obj != null) {
                    // 放行
                    chain.doFilter(request, response);
                } else {
                    //3.3如果获取的内容为空,说明没有登陆; 跳转到登陆
                    uri = "/login.jsp";
                }

            } else {
                // 肯定没有登陆
                uri = "/login.jsp";
            }
            request.getRequestDispatcher(uri).forward(request, response);
        }
    }

    public void init(FilterConfig filterConfig) throws ServletException {
    }

    public void destroy() {
    }

}
时间: 2024-08-05 16:07:29

26、过滤器的相关文章

【JavaWeb学习】过滤器Filter

一.简介 Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能.例如实现URL级别的权限访问控制.过滤敏感词汇.压缩响应信息等一些高级功能. Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter.通过Filter技

Django中自定义过滤器的使用

我在这里做的是: 从数据库查出id递增的一些信息,展示在前台. 编写一个过滤器判断查出数据的id是偶数的返回True 奇数返回False 1 创建项目,创建应用,注册应用,配置settings.py文件,配置urls映射,编写views试图,编写模板templates,编写models模块 切记 注册应用.  很多伙伴找不到自己定义的过滤器,是因为忘记注册应用! 2 创建过滤器的目录: 实际上,在项目目录或者应用目录下创建都是可以的,创建一个名为templatetags的python模块 在我这

如何angular过滤器进行排序???

首先定义一个json文件: 然后写HTML文件: 1 <div id="box"> 2 <!--第一个下拉框--> 3 <select ng-model="a"> 4 <option value="age">按照年龄排序</option> 5 <option value="code">按照编码排序</option> 6 <option v

java过滤器、监听器、拦截器机制

一.过滤器 Filter也称之为过滤器,它是Servlet技术中最实用的技术,Web开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能.例如实现URL级别的权限访问控制.过滤敏感词汇.压缩响应信息等一些高级功能. 它主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理.使用Filter的完整流程:Filter对用户请求进行预处理,接着将请求交给Se

MySQL 复制过滤器、监控维护及主从复制的读写分离

MySQL 复制过滤器.监控维护及基于SSL的主从复制 =============================================================================== 概述: 本章将主要介绍MySQL复制中如何过滤,监控维护,以及基于SSL的主从复制,具体内容如下: MySQL 复制过滤器 ·从服务器库级别过滤 MySQL 清理日志:PURGE 复制监控 ·Master ·Slave 如何确定主从节点的数据是否一致 MySQL基于SSL的主从复制(

django中模板变量与内置标签以及过滤器

本文参考 官方文档 . 一  模板变量 格式: {{ variable_name }} variable_name   命名规则与变量命名规则类似,允许字符数字下划线,不允许标点. variable_name后面可以跟dot  .  以此来访问变量的属性.查询顺序: 字典查询 属性或者方法查询: 若为方法查询,则要求该方法不需要传入任何参数.调用该方法后,会将该方法返回的结果赋予该变量. 数字索引查询 二  内置标签 格式: {% tag %} 1  block  定义一个可以被子模板覆盖的区域

ASP.NET MVC过滤器(一)

MVC过滤器是加在 Controller 或 Action 上的一种 Attribute,通过过滤器,MVC 网站在处理用户请求时,可以处理一些附加的操作,如:用户权限验证.系统日志.异常处理.缓存等.MVC 中包含Authorization filter.Action filter.Result filter.Exception filter 四种过滤器. APS.NET MVC中的每一个请求,都会分配给相应的控制器和对应的行为方法去处理,而在这些处理的前前后后如果想再加一些额外的逻辑处理.这

[原创]java WEB学习笔记44:Filter 简介,模型,创建,工作原理,相关API,过滤器的部署及映射的方式,Demo

本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 ---------------------------------

javaweb学习总结(四十六)——Filter(过滤器)常见应用

一.统一全站字符编码 通过配置参数charset指明使用何种字符编码,以处理Html Form请求参数的中文问题 1 package me.gacl.web.filter; 2 3 import java.io.IOException; 4 import javax.servlet.Filter; 5 import javax.servlet.FilterChain; 6 import javax.servlet.FilterConfig; 7 import javax.servlet.Serv