Java Web之过滤器(Filter)「建议收藏」

Java Web之过滤器(Filter)「建议收藏」过滤器(Filter)过滤器实际上就是对web资源进行拦截,做一些处理后再交给servlet。通常都是用来拦截request进行处理的,也可以对返回的response进行拦截处理大概流程图如下应用场景自动登录统一设置编码格式访问权限控制敏感字符过滤等…

大家好,又见面了,我是你们的朋友全栈君。

过滤器(Filter)


过滤器实际上就是对web资源进行拦截,做一些处理后再交给下一个过滤器或servlet处理
通常都是用来拦截request进行处理的,也可以对返回的response进行拦截处理

大概流程图如下

这里写图片描述

应用场景
自动登录
统一设置编码格式
访问权限控制
敏感字符过滤等


创建Filter

在Servlet中我们一般都会对request和response中的字符集编码进行配置,如果Servlet过多字符集编码发生变化时修改起码会很麻烦,这些通用的字符集编码配置等工作我们可以放到Filter中来实现。
下面我们来创建一个处理字符集编码的Filter。

右键包名—>new —->Filter

这里写图片描述

输入过滤器名称,跟创建Servlet一样,这里我们直接使用 @WebFilter 注解,不再去web,xml中进行配置了。

这里写图片描述

创建完成后默认代码,可以看到,CharsetFilter实现了Filter接口,实现了3个方法。3个方法的作用已经在注释中写清楚了。

package filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter(filterName = "CharsetFilter")
public class CharsetFilter implements Filter { 
   
    public void destroy() { 
   
        /*销毁时调用*/
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { 
   
        /*过滤方法 主要是对request和response进行一些处理,然后交给下一个过滤器或Servlet处理*/
       
        chain.doFilter(req, resp);//交给下一个过滤器或servlet处理
    }

    public void init(FilterConfig config) throws ServletException { 
   

        /*初始化方法 接收一个FilterConfig类型的参数 该参数是对Filter的一些配置*/

    }

}

配置Filter

可配置的属性有这些

这里写图片描述

常用配置项
urlPatterns
配置要拦截的资源

  1. 以指定资源匹配。例如"/index.jsp"
  2. 以目录匹配。例如"/servlet/*"
  3. 以后缀名匹配,例如"*.jsp"
  4. 通配符,拦截所有web资源。"/*"

initParams
配置初始化参数,跟Servlet配置一样

例如

initParams = { 
   
        @WebInitParam(name = "key",value = "value")
}

dispatcherTypes
配置拦截的类型,可配置多个。默认为DispatcherType.REQUEST
例如

dispatcherTypes = { 
   DispatcherType.ASYNC,DispatcherType.ERROR}

其中DispatcherType是个枚举类型,有下面几个值

	FORWARD,//转发的
    INCLUDE,//包含在页面的
    REQUEST,//请求的
    ASYNC,//异步的
    ERROR;//出错的

下面我们来对CharsetFilter 代码进行一下修改

package filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import java.io.IOException;

@WebFilter(filterName = "CharsetFilter",
        urlPatterns = "/*",/*通配符(*)表示对所有的web资源进行拦截*/
        initParams = { 
   
                @WebInitParam(name = "charset", value = "utf-8")/*这里可以放一些初始化的参数*/
        })
public class CharsetFilter implements Filter { 
   
    private String filterName;
    private String charset;

    public void destroy() { 
   
        /*销毁时调用*/

        System.out.println(filterName + "销毁");
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { 
   
        /*过滤方法 主要是对request和response进行一些处理,然后交给下一个过滤器或Servlet处理*/
		System.out.println(filterName + "doFilter()");
        req.setCharacterEncoding(charset);
        resp.setCharacterEncoding(charset);
        chain.doFilter(req, resp);
    }

    public void init(FilterConfig config) throws ServletException { 
   

        /*初始化方法 接收一个FilterConfig类型的参数 该参数是对Filter的一些配置*/

        filterName = config.getFilterName();
        charset = config.getInitParameter("charset");

        System.out.println("过滤器名称:" + filterName);
        System.out.println("字符集编码:" + charset);

    }

}

这样一个简单的字符集编码处理的过滤器就完成了
我们看看执行打印的结果
这里写图片描述

需要注意的是
过滤器是在服务器启动时就会创建的,只会创建一个实例,常驻内存,也就是说服务器一启动就会执行Filter的init(FilterConfig config)方法.
当Filter被移除或服务器正常关闭时,会执行destroy方法


多个Filter的执行顺序

在我们的请求到达Servle之间是可以经过多个Filter的,一般来说,建议Filter之间不要有关联,各自处理各自的逻辑即可。这样,我们也无需关心执行顺序问题。
如果一定要确保执行顺序,就要对配置进行修改了,执行顺序如下

  1. 在web.xml中,filter执行顺序跟<filter-mapping>的顺序有关,先声明的先执行
  2. 使用注解配置的话,filter的执行顺序跟名称的字母顺序有关,例如AFilter会比BFilter先执行
  3. 如果既有在web.xml中声明的Filter,也有通过注解配置的Filter,那么会优先执行web.xml中配置的Filter

我们写个小例子看一下

新建3个Filter,加上之前的CharsetFilter一共四个

这里写图片描述

其中CharsetFilterABFilter是通过注解声明的

CharsetFilter注解配置


@WebFilter(filterName = "CharsetFilter",
        urlPatterns = "/*",/*通配符(*)表示对所有的web资源进行拦截*/
        initParams = { 
   
                @WebInitParam(name = "charset", value = "utf-8")/*这里可以放一些初始化的参数*/
        })

ABFilter

@WebFilter(filterName = "ABFilter",urlPatterns = "/*")

AFilterBFilter是在web.xml配置的。
执行顺序跟<filter>的顺序无关
<filter-mapping>的顺序才决定执行顺序

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">
    <filter>
        <filter-name>AFilter</filter-name>
        <filter-class>filter.AFilter</filter-class>
    </filter>
    <filter>
        <filter-name>BFilter</filter-name>
        <filter-class>filter.BFilter</filter-class>
    </filter>

    <!--这里BFilter在AFilter之前-->
    <filter-mapping>
        <filter-name>BFilter</filter-name>
        <url-pattern>/filter.jsp</url-pattern>
    </filter-mapping>

    <filter-mapping>
        <filter-name>AFilter</filter-name>
        <url-pattern>/filter.jsp</url-pattern>
    </filter-mapping>

   
</web-app>

每个Filter添加了打印语句,如下
以ABFilter为例

package filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter(filterName = "ABFilter",urlPatterns = "/*")
public class ABFilter implements Filter { 
   
    private String filterName;

    public void destroy() { 
   
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { 
   
        System.out.println(filterName + " doFilter()");
        chain.doFilter(req, resp);
    }

    public void init(FilterConfig config) throws ServletException { 
   
        filterName= config.getFilterName();
        System.out.println("过滤器名称:" + filterName +" init");
    }

}

下面我们来访问filter.jsp看看打印结果

这里写图片描述

可以看到,执行结果符合预期。
BFilter和AFilter是在web.xml中声明的,且BFilter的<filter-mapping>在前,故BFilter在AFilter之前执行。
ABFilter和CharsetFilter是通过注解声明的,故他俩在BFilter和AFilter之后执行,但是ABFilter的名称以A开头,故在CharsetFilter之前执行

这里写图片描述


访问权限控制小例子

下面我们写一个访问控制权限控制的小例子。
我们在浏览一些网站经常有这个情况,没有登录时是不允许我们访其主页的,只有登录过后才能访问。
下面我们就用Filter简单实现一下。

需求分析

  1. 登录时将登录的账号密码保存到cookie中,下次访问时携带账号和密码,过滤器中进行校验
  2. 用户没有登录直接访问主页时,要跳转到登录页面
  3. 登录过滤器不对登录页面进行过滤

我们先来看一下项目结构

这里写图片描述

这里主要看一下LoginFilter的代码

我们在LoginFilter中对非登录页面的其他jsp都会进行过滤,判断cookie中是否携带了account和pwd。
如果有这两个数据表示之前登录过,那么对数据进行校验,正确的话就进行下一个操作。
否则的话,跳转到登录界面

package filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter(filterName = "LoginFilter", urlPatterns = "*.jsp", dispatcherTypes = { 
   })
public class LoginFilter implements Filter { 
   
    public void destroy() { 
   
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { 
   


        System.out.println("LoginFilter doFilter");

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;

        String url = request.getRequestURI();

        System.out.println("请求的url:" + url);
        /*登录页面不需要过滤*/

        int idx = url.lastIndexOf("/");
        String endWith = url.substring(idx + 1);


        if (!endWith.equals("login.jsp")) { 
   
            /*不是登录页面 进行拦截处理*/

            System.out.println("不是登录页面,进行拦截处理");

            if (!isLogin(request)) { 
   
                System.out.println("没有登录过或者账号密码错误,跳转到登录界面");
                response.sendRedirect("login.jsp");
            } else { 
   
                System.out.println("已经登录,进行下一步");
                chain.doFilter(req, resp);
            }

        } else { 
   

            System.out.println("是登录页面,不进行拦截处理");
            chain.doFilter(req, resp);
        }


    }


    private boolean isLogin(HttpServletRequest request) { 
   

        Cookie[] cookies = request.getCookies();

        String account = "";
        String pwd = "";

        if (cookies != null && cookies.length > 0) { 
   
            for (Cookie cookie : cookies) { 
   
                if (cookie.getName().equals("account")) { 
   
                    account = cookie.getValue();
                } else if (cookie.getName().equals("pwd")) { 
   
                    pwd = cookie.getValue();
                }
            }
        }

        if (account.equals("") || pwd.equals("")) { 
   
            return false;

        } else if (account.equals("yzq") && pwd.equals("123")) { 
   
            return true;
        }


        return false;
    }

    public void init(FilterConfig config) throws ServletException { 
   
        System.out.println("LoginFilter init");
    }

}

执行效果

这里写图片描述

可以看到,我们在没有登录的情况下直接去访问index.jsp页面时会自动跳转到登录页面,在登录成功后,再次直接访问index页面则可以访问。

下面是demo

访问控制demo

下一篇我们来看看

JavaWeb之监听器Listener


感兴趣的话可以关注下 Java Web入门专栏


如果你觉得本文对你有帮助,麻烦动动手指顶一下,可以帮助到更多的开发者,如果文中有什么错误的地方,还望指正,转载请注明转自喻志强的博客 ,谢谢!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/131600.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • A星算法说明「建议收藏」

    A星算法说明「建议收藏」A*算法说明文章目录前言原理说明如何构造h(n)h(n)h(n)一、欧氏距离二、曼哈顿距离三、其他关于g(n)g(n)g(n)路况设置如何实现完整的流程核心代码a_star.ha_star.cppmap_matrix.hmap_matrix.cpp代码使用示例GUI程序下载链接GUI程序使用说明前言  因为最近要写一个毕业设计,有用到自动寻路的功能,因为我要在一个机器里跑算法然后控制机器人自动按照路线到达目的地,所以用Python等解释型语言或Unity等游戏引擎写这个算法都不太合适,我使用的机器要尽

  • 预训练模型还要训练吗_多模态预训练模型

    预训练模型还要训练吗_多模态预训练模型若使用已保存好的镜像reid_mgn:v1,在本机上可按如下操作训练#1.进入已保存环境的镜像(reid_mgn:v1(8.48G)、pytorch/pytorch:1.0.1-cuda10.0-cudnn7-devel_mgnreid(6.37G))nvidia-dockerrun-it–rm-v/home/lc-deep/sdr:/home/personReID…

  • 什么是字节码指令?[通俗易懂]

    什么是字节码指令?[通俗易懂]字节码指令简介: Java虚拟机的指令由一个字节长度的、代表着某种特定含义的数字(称为操作码,Opcode)以及跟随其后的零至多个代表此操作所需参数(称为操作数,Operands)而构成。由于Java虚拟机采用面向操作数栈而不是寄存器的架构,所以大多数的指令都不包含操作数,只有一个操作码。由于限制了Java虚拟机操作码的长度为一个字节,所以指令集的操作码总数不可能超过256条。字节码与数据…

  • js 判断数组中是否包含某个元素(转载)「建议收藏」

    js 判断数组中是否包含某个元素(转载)「建议收藏」来源:https://www.cnblogs.com/yunshangwuyou/p/10539090.html方法一:array.indexOf(item,start):元素在数组中的位置,如果没与搜索到则返回-1。参数 描述 item 必须。查找的元素。 start 可选的整数参数。规定在数组中开始检索的位置。它的合法取值是0到stringObject.length-1。 如省略该参数,则将从字符串的首字符开始检索。 ..

    2022年10月19日
  • acwing-1080. 骑士(基环树dp)[通俗易懂]

    acwing-1080. 骑士(基环树dp)[通俗易懂]Z 国的骑士团是一个很有势力的组织,帮会中聚集了来自各地的精英。他们劫富济贫,惩恶扬善,受到了社会各界的赞扬。可是,最近发生了一件很可怕的事情:邪恶的 Y 国发起了一场针对 Z 国的侵略战争。战火绵延五百里,在和平环境中安逸了数百年的 Z 国又怎能抵挡得住 Y 国的军队。于是人们把所有希望都寄托在了骑士团身上,就像期待有一个真龙天子的降生,带领正义打败邪恶。骑士团是肯定具备打败邪恶势力的能力的,但是骑士们互相之间往往有一些矛盾。每个骑士有且仅有一个他自己最厌恶的骑士(当然不是他自己),他是绝对不

  • 图标变成了一张白纸_电脑图标是白纸形式但能打开

    图标变成了一张白纸_电脑图标是白纸形式但能打开大家好,我是波导终结者。WIN10到现在也有些年头了,虽然好的不学学坏的,天天搞强制升级有些烦人,有时候新版本的BUG也比较致命,但是整体的性能,功能和稳定性上还是有飞跃性的提升。其实WIN10自带不少实用工具,而且兼容性和稳定性没得说,很多时候我们可以不必寻找第三方工具,省了很多钱,也提高了不少效率。今天就一起来看看吧。WIN10自带截图工具WIN10自带截图工具,虽然肯定不比专业的截图工具强,…

    2022年10月19日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号