码迷,mamicode.com
首页 > 其他好文 > 详细

26、过滤器

时间:2016-06-12 01:58:00      阅读:173      评论:0      收藏:0      [点我收藏+]

标签:

过滤器

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

注册 ---- 提交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() {
    }

}

26、过滤器

标签:

原文地址:http://blog.csdn.net/guanhang89/article/details/51636969

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!