Web三大组件——filter的使用


servlet、filter 和 listener 并称为web三大组件,本篇将讲解filter,并能通过filter经典的案例的实现加深学习。
关于servlet,可以看我之前的文章。 学习Servlet看这一篇就够了

Filter

filter与servlet在很多的方面极其相似,但是也有不同,例如filter和servlet一样都有三个生命周期方法,同时他们在web.xml中的配置文件也是差不多的、 但是servlet主要负责处理请求,而filter主要负责拦截请求,和放行。

1.概念

  • 当客户端访问服务器资源的时候,中间会存在一些过滤器,可以将请求拦截下来,完成一些特殊的功能。
  • 作用:一般用于完成通用的操作.比如:登录验证 统一编码处理 …

2.快速入门

1.步骤

  1. 定义一个类 实现一个接口Filter

  2. 重写接口中的方法

  3. 配置拦截路径(两种方式)

    1. web.xml

      <!--配置过滤器-->
      <filter>
      	<filter-name>demo02</filter-name>
      	<filter-class>com.huike.filter.FilterDemo02</filter-class>
      </filter>
      
      <filter-mapping>
      	<filter-name>demo02</filter-name>
      	<!--拦截路径-->
      	<url-pattern>/hello.jsp</url-pattern>
      	<!--拦截方式-->
          <dispatcher>FORWARD</dispatcher>
      </filter-mapping>
      
    2. 使用注解配置

      @WebFilter("/*") //访问所有资源之前,都会经过该过滤器
      

2.filter细节

  1. web.xml配置

  2. 过滤器执行流程:

    1. 发送请求消息时,经过过滤器,执行过滤器
    2. 过滤器放行后,执行放行后的资源
    3. 发送响应消息时,执行过滤器放行后的代码
  3. 过滤器生命周期方法:

    1. init():在服务器启动时,会创建Filter对象,然后调用init方法,只执行一次,主要用于资源的加载
    2. doFilter():拦截方法 每一次请求被拦截时,会执行,会执行多次
    3. destory():在服务器关闭时,Filter对象被销毁, 如果服务器正常关闭,则会执行Distory()方法,只会执行一次,用于释放资源
  4. 过滤器配置详解:

    1. 拦截路径配置

      1. 具体资源路径: /hello.jsp 只有访问特定资源时,过滤器才会执行

      2. 拦截目录: /user/* 访问user目录下的所有资源时,过滤器都会被执行

      3. 后缀名拦截; .jsp|.do 访问所有后缀名为jsp|do的资源时,过滤器都会被执行

      4. 拦截所有资源:/* 访问所有资源时,过滤器都会被执行

    2. 拦截方式配置:资源被访问的方式 拦截器

      • 注解配置:

        为注解设置 dispatcherTypes属性:

        1. REQUEST:默认值浏览器直接请求资源
        2. FORWARD:转发访问资源
        3. INCLUDE:包含访问资源
        4. ASYNC: 异步访问资源
        5. ERROR: 错误跳转资源
      • web.xml配置:

        在标签体中配置 FORWARD标签即可

  5. 过滤器链(如果配置多个过滤器)

    1. 多个过滤器的执行顺序问题: 过滤器1 过滤器2

      执行顺序:

      • 过滤器1
      • 过滤器2
      • 资源执行
      • 过滤器2
      • 过滤器1
    2. 过滤器执行的先后顺序的规则:

      1. 注解配置:按照类名的字符串比较规则 值小的先执行

        HelloFilter HiFilter

        FilterDemo06 FilterDemo07

      2. web.xml配置: 谁定义在前面,谁先执行

3.案例

3.1 使用过滤器filter实现登录验证
  • 需求:
    1. 访问UserListBigDemo案例时,验证其是否登录
    2. 如果登陆过,直接放行到 index.jsp页面
    3. 如果没有登陆过,则强制跳转到login.jsp登录页面,提示: “您尚未登录,请先登录…”
//loginFilter
@WebFilter("/*")
public class LoginFilter implements Filter {

    @Override
    public void init(FilterConfig config) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //1.通过访问路径判断是否为登录相关的路径
        //1.1:获取访问路径
        HttpServletRequest httpReq = (HttpServletRequest)req;
        //    /UserListBigDemo/findUserByPageServlet
        String requestURI = httpReq.getRequestURI();
        System.out.println(requestURI);

        //1.2存储包含登录相关的资源路径
        List<String> list = new ArrayList();
        list.add("/login.jsp");
        list.add("/loginServlet");
        list.add("/checkCodeServlet");
        list.add("/css/");
        list.add("/js/");
        list.add("/fonts/");

        for (String s:list) {
            if (requestURI.contains(s)) {
                //1.3含登录相关的资源路径的话就直接放行
                chain.doFilter(req, resp);
                return;
            }
        }
        //不包含登录相关的资源路径
        //2.登录过了,就不用重复登录了
        //2.1获取到loginServlet中的user
        LoginUser user = (LoginUser)httpReq.getSession().getAttribute("user");
        //2.2如果之前登陆过,则user不为空,放行
        if (user!=null){
            chain.doFilter(req, resp);
        }else{
            //2.3没登陆过,跳转登录页面
            req.setAttribute("login_msg", "您尚未登录,请先登录...");
            req.getRequestDispatcher("/login.jsp").forward(req,resp);
        }

    }

    @Override
    public void destroy() {
    }
}
3.2 敏感词汇过滤
@WebFilter("/*")
public class WordsFilter implements Filter {

    private List<String> list = new ArrayList();

    @Override
    public void init(FilterConfig config) throws ServletException {
        //1.将存储在txt文本文件中的不文明词汇读取出来
        //txt文本放于src目录下
        ServletContext servletContext = config.getServletContext();
        String realPath = servletContext.getRealPath("/WEB-INF/classes/敏感词汇.txt");

        try {
            BufferedReader br = new BufferedReader(new FileReader(realPath));
            String line = null;
            //1.2将流中的内容存储到list中
            while((line = br.readLine()) != null){
                list.add(line);
            }
            br.close();
            System.out.println(list);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //2.创建代理对象 增强getParameter方法  getParameterMap  getParameterValues()

        /**
         * Proxy.newProxyInstance的三个参数含义:
         *      1. 类加载器(固定写法):真实对象.getClass().getClassLoader()
         *      2. 接口数组(固定写法):真实对象.getClass().getInterfaces()
         *      3. 处理器: new InvocationHandler()
         */
        ServletRequest proxy_req = (ServletRequest) Proxy.newProxyInstance(req.getClass().getClassLoader(),
                req.getClass().getInterfaces(), new InvocationHandler() {
            /**
             * 代理模式:生成动态代理对象 去增强真实对象
             * @param proxy:代理对象
             * @param method:代理对象调用的方法 所封装的对象
             * @param args:代理对象调用的方法时,所传递的实际参数数组
             * @return Object:返回值
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                //2.1增强getParameter方法
                if ("getParameter".equals(method.getName())) {
                    System.out.println("getParameter执行了");
                    //2.1.1增强返回值
                    String value = (String) method.invoke(req, args);
                    if (value != null) {
                        for (String s : list) {
                            if (value.contains(s)) {
                                value = value.replaceAll(s, "**");
                            }
                        }
                    }
                    return value;
                }
                //2.2增强getParameterMap方法
                if ("getParameterMap".equals(method.getName())) {
                    System.out.println("getParameterMap执行了");
                    //2.1.1增强返回值
                    Map<String, String[]> parameterMap = (Map<String, String[]>) method.invoke(req, args);
                    Set<String> keys = parameterMap.keySet();
                    for (String key:keys) {
                        String value = parameterMap.get(key)[0];
                        if (value!=null && !value.equals("")){
                            for (String s:list){
                                if (value.contains(s)){
                                    parameterMap.get(key)[0] = value.replace(s, "**");
                                }
                            }
                        }
                    }
                    return parameterMap;
                }
                return method.invoke(req, args);
            }
        });
        //3.放行
        chain.doFilter(proxy_req, resp);
    }

    @Override
    public void destroy() {

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值