详细谈谈Java过滤器的作用?_过滤器java-程序员宅基地

技术标签: java  servlet  开发语言  

Java过滤器是处于客户端与服务器资源文件之间的一道过滤网,在访问资源文件之前,通过一系列的过滤器可以对请求进行修改、判断等,把不符合规则的请求在中途拦截或修改;也可以对响应进行过滤,拦截或修改响应。

一、初识Filter

简介

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

Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个Java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截,Filter接口源代码:

public abstract interface Filter {

public abstract void init(FilterConfig paramFilterConfig) throws ServletException;

public abstract void doFilter(ServletRequest paramServletRequest, ServletResponse paramServletResponse, FilterChainparamFilterChain) throws IOException, ServletException;

public abstract void destroy();

}

在web.xml文件中对Filter进行配置,这个配置和Servlet很像。

<filter>

<description>过滤器名称</description>

<filter-name>自定义的名字</filter-name>

<filter-class>全类名</filter-class>

<init-param>

<description>配置过滤器的初始化参数</description>

<param-name>name</param-name>

<param-value>gacl</param-value>

</init-param>

<init-param>

<description>配置FilterTest过滤器的初始化参数</description>

<param-name>like</param-name>

<param-value>java</param-value>

</init-param>

</filter>

Filter的工作原理

Filter接口中有一个doFilter方法,当我们编写好Filter,并配置对哪个web资源进行拦截后,WEB服务器每次在调用web资源的service方法之前,都会先调用一下filter的doFilter方法,因此,在该方法内编写代码可达到如下目的:

1. 调用目标资源之前,让一段代码执行。

2. 是否调用目标资源(即是否让用户访问web资源)。

3.调用目标资源之后,让一段代码执行。

web服务器在调用doFilter方法时,会传递一filterChain对象进来,filterChain对象是filter接口中最重要的一个对象,它也提供了一个doFilter方法,开发人员可以根据需求决定是否调用此方法,调用该方法,则web服务器就会调用web资源的service方法,即web资源就会被访问,否则web资源不会被访问。

注意:

  • Servlet对象默认情况下,在服务器启动的时候是不会创建对象的
  • Filter对象在默认情况下,在服务器启动的时候会新建对象
  • Servlet是单例的,Filter也是单例的。(单实例)

 

Filter的执行

1、目标Servlet是否执行取决于两个条件:

在过滤器中是否编写了:chain.doFilter(request, response);这条代码作用:执行下一个过滤器,如果下一个不是过滤器,则执行目标程序Servlet。

用户发送的请求路径是否和Servlet的请求路径一致。

2、Filter与Servlet的优先级

Filter比Servlet优先级高,/a.do对应一个Filter,也对应一个Servlet,一定是先执行Filter再执行Servlet。

3、关于Filter的配置路径

  • /a.do、/b.do、/dept/save。这些配置方式都是精确匹配。
  • /*匹配所有路径。
  • *.do后缀匹配,不要以“/”开始。
  • /dept/* 前缀匹配。

4、在web.xml文件中进行配置时,Filter的执行顺序是依靠filter-mapping标签的配置位置,越靠上优先级越高。

5、在注解中配置时,Filter的执行顺序是:

比较Filter的类名。例如FilterA和FilterB先执行FilterA。Filter1和Filter2先执行Filter1。

6、过滤器的调用顺序,遵循栈数据结构。

7、Filter过滤器的设计模式:责任链设计模式

  • 过滤器最大优点:在程序编译阶段不会确定调用顺序,因为Filter的调用顺序是配置到web.xml文件中的,只需要修改web.xml配置文件中的filter-mapping的顺序就可以调整Filter的执行顺序,显然Filter的执行顺序是在程序运行阶段动态组合的。那么这种设计模式被称为责任链设计模式。
  • 责任链设计模式的核心思想:在程序运行阶段,动态的组合程序的调用顺序。

二、Filter开发流程

开发步骤

Filter开发分为2步:

编写Java类实现Filter接口,并实现其doFilter方法。

在web.xml 文件中使用<filter>和<filter-mapping>元素对编写的filter类进行注册,并设置它所能拦截的资源。

过滤器处理字符集范例:

import java.io.IOException;

import javax.servlet.Filter;

import javax.servlet.FilterChain;

import javax.servlet.FilterConfig;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

/**

* @description 过滤器Filter的工作原理

*/

public class FilterTest implements Filter {

public void destroy() {

System.out.println("----Filter销毁----");

}

public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {

// 对request、response进行一些预处理

request.setCharacterEncoding("UTF-8");

response.setCharacterEncoding("UTF-8");

response.setContentType("text/html;charset=UTF-8");

System.out.println("----调用service之前执行一段代码----");

filterChain.doFilter(request, response);

// 执行目标资源,放行

System.out.println("----调用service之后执行一段代码----");

}

public void init(FilterConfig arg0) throws ServletException {

System.out.println("----Filter初始化----");

}

}

Filter链

在一个web应用中,可以开发编写多个Filter,这些Filter组合起来称之为一个Filter链。web服务器根据Filter在web.xml文件中的注册顺序,决定先调用哪个Filter,当第一个Filter的doFilter方法被调用时,web服务器会创建一个代表Filter链的FilterChain对象传递给该方法。在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2个filter,如果没有,则调用目标资源。

 

Spring框架下,过滤器的配置

如果项目中使用了Spring框架,那么,很多过滤器都不用自己来写了,Spring为我们写好了一些常用的过滤器。下面我们就以字符编码的过滤器CharacterEncodingFilter为例,来看一下Spring框架下,如果配置过滤器。

<filter>

<filter-name>encodingFilter</filter-name>

<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>

<init-param>

<param-name>encoding</param-name>

<param-value>UTF-8</param-value>

</init-param>

<init-param>

<param-name>forceEncoding</param-name>

<param-value>true</param-value>

</init-param>

</filter>

<filter-mapping>

<filter-name>encodingFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

接下来,我们看一下CharacterEncodingFilter这个过滤器的关键代码

package org.springframework.web.filter;

import java.io.IOException;

import javax.servlet.FilterChain;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.springframework.util.ClassUtils;

public class CharacterEncodingFilter extends OncePerRequestFilter {

private static final boolean responseSetCharacterEncodingAvailable = ClassUtils.hasMethod(class$javax$servlet$http$HttpServletResponse, "setCharacterEncoding", new Class[]{String.class});

// 需要设置的编码方式,为了支持可配置,Spring把编码方式设置成了一个变量

private String encoding;

// 是否强制使用统一编码,也是为了支持可配置

private boolean forceEncoding;

// 构造器,在这里,Spring把forceEncoding的值默认设置成了false

public CharacterEncodingFilter() {

this.forceEncoding = false;

}

// encoding/forceEncoding的setter方法

public void setEncoding(String encoding) {

this.encoding = encoding;

}

public void setForceEncoding(boolean forceEncoding) {

this.forceEncoding = forceEncoding;

}

// Spring通过GenericFilterBean抽象类,对Filter接口进行了整合,

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

if ((this.encoding != null) && (((this.forceEncoding) || (request.getCharacterEncoding() == null)))) {

request.setCharacterEncoding(this.encoding);

if ((this.forceEncoding) && (responseSetCharacterEncodingAvailable)) {

response.setCharacterEncoding(this.encoding);

}

}

filterChain.doFilter(request, response);

}

}

GenericFilterBean类

项目中使用过的一个过滤器:InvilidCharacterFilter(防止脚本攻击的过滤器)。

GenericFilterBean类:

public abstract class GenericFilterBean implements Filter, BeanNameAware, ServletContextAware, InitializingBean, DisposableBean

import java.io.IOException;

import java.util.Enumeration;

import javax.servlet.FilterChain;

import javax.servlet.RequestDispatcher;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;

import org.springframework.web.filter.CharacterEncodingFilter;

/** InvalidCharacterFilter:过滤request请求中的非法字符,防止脚本攻击* InvalidCharacterFilter继承了Spring框架的CharacterEncodingFilter过滤器,当然,我们也可以自己实现这样一个过滤器*/

public class InvalidCharacterFilter extends CharacterEncodingFilter{

// 需要过滤的非法字符

private static String[] invalidCharacter = new String[]{

"script","select","insert","document","window","function",

"delete","update","prompt","alert","create","alter","drop",

"iframe","link","where","replace","function","onabort",

"onactivate","onafterprint","onafterupdate","onbeforeactivate",

"onbeforecopy","onbeforecut","onbeforedeactivateonfocus",

"onkeydown","onkeypress","onkeyup","onload","expression",

"applet","layer","ilayeditfocus","onbeforepaste","onbeforeprint",

"onbeforeunload","onbeforeupdate","onblur","onbounce",

"oncellchange","oncontextmenu","oncontrolselect","oncopy",

"oncut","ondataavailable","ondatasetchanged","ondatasetcomplete",

"ondeactivate","ondrag","ondrop","onerror","onfilterchange",

"onfinish","onhelp","onlayoutcomplete","onlosecapture","onmouse",

"ote","onpropertychange","onreadystatechange","onreset","onresize",

"onresizeend","onresizestart","onrow","onscroll","onselect",

"onstaronsubmit","onunload","IMgsrc","infarction"};

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException{

String parameterName = null;String parameterValue = null;

// 获取请求的参数

@SuppressWarnings("unchecked")

Enumeration<String> allParameter = request.getParameterNames();

while(allParameter.hasMoreElements()){

parameterName = allParameter.nextElement();

parameterValue = request.getParameter(parameterName);

if(null != parameterValue){

for(String str : invalidCharacter){

if (StringUtils.containsIgnoreCase(parameterValue, str)){

request.setAttribute("errorMessage", "非法字符:" + str);

RequestDispatcher requestDispatcher = request.getRequestDispatcher("/error.jsp");

requestDispatcher.forward(request, response);return;

}

}

}

}

super.doFilterInternal(request, response, filterChain);

}

}

接下来需要在web.xml中进行配置:

<filter>

<filter-name>InvalidCharacterFilter</filter-name>

<filter-class>com.test.filter.InvalidCharacterFilter</filter-class>

</filter>

<filter-mapping>

<filter-name>InvalidCharacterFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

三、Filter的生命周期

Filter的创建

Filter的创建和销毁由web服务器负责。web应用程序启动时,web服务器将创建Filter的实例对象,并调用其init方法,完成对象的初始化

功能,从而为后续的用户请求作好拦截的准备工作,filter对象只会创建一次,init方法也只会执行一次。通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象。

Filter的销毁

web容器调用destroy方法销毁Filter。destroy方法在Filter的生命周期中仅执行一次。在destroy方法中,可以释放过滤器使用的资源。

FilterConfig接口

用户在配置filter时,可以使用<init-param>为filter配置一些初始化参数,当web容器实例化Filter对象,调用其init方法时,会把封装了filter初始化参数的filterConfig对象传递进来。因此开发人员在编写filter时,通过filterConfig对象的方法,就可获得:

  • String getFilterName():得到filter的名称。
  • String getInitParameter(String name):返回在部署描述中指定名称的初始化参数的值。如果不存在返回null.
  • Enumeration getInitParameterNames():返回过滤器的所有初始化参数的名字的枚举集合。
  • public ServletContext getServletContext():返回Servlet上下文对象的引用。

示例:利用FilterConfig得到filter配置信息

import java.io.IOException;

import java.util.Enumeration;

import javax.servlet.Filter;

import javax.servlet.FilterChain;

import javax.servlet.FilterConfig;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

public class FilterTest implements Filter {

/* 过滤器初始化* @see javax.servlet.Filter#init(javax.servlet.FilterConfig)*/

@Override

public void init(FilterConfig filterConfig) throws ServletException {

System.out.println("----过滤器初始化----");

//得到过滤器的名字

String filterName = filterConfig.getFilterName();

//得到在web.xml文件中配置的初始化参数

String initParam1 = filterConfig.getInitParameter("name");

String initParam2 = filterConfig.getInitParameter("like");

//返回过滤器的所有初始化参数的名字的枚举集合。

Enumeration<String> initParameterNames = filterConfig.getInitParameterNames();

System.out.println(filterName);

System.out.println(initParam1);

System.out.println(initParam2);

while (initParameterNames.hasMoreElements()) {

String paramName = (String) initParameterNames.nextElement();

System.out.println(paramName);

}

}

@Override

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

System.out.println("FilterDemo02执行前!!!");

chain.doFilter(request, response);

//让目标资源执行,放行

System.out.println("FilterDemo02执行后!!!");

}

@Override

public void destroy() {

System.out.println("----过滤器销毁----");

}

}

总结

过滤器一般用于登录权限验证、资源访问权限控制、敏感词汇过滤、字符编码转换等等操作,便于代码重用,不必每个servlet中还要进行相应的操作。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zjjcchina/article/details/131372844

智能推荐

c# 调用c++ lib静态库_c#调用lib-程序员宅基地

文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib

deepin/ubuntu安装苹方字体-程序员宅基地

文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang

html表单常见操作汇总_html表单的处理程序有那些-程序员宅基地

文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些

PHP设置谷歌验证器(Google Authenticator)实现操作二步验证_php otp 验证器-程序员宅基地

文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器

【Python】matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距-程序员宅基地

文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距

docker — 容器存储_docker 保存容器-程序员宅基地

文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器

随便推点

网络拓扑结构_网络拓扑csdn-程序员宅基地

文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn

JS重写Date函数,兼容IOS系统_date.prototype 将所有 ios-程序员宅基地

文章浏览阅读1.8k次,点赞5次,收藏8次。IOS系统Date的坑要创建一个指定时间的new Date对象时,通常的做法是:new Date("2020-09-21 11:11:00")这行代码在 PC 端和安卓端都是正常的,而在 iOS 端则会提示 Invalid Date 无效日期。在IOS年月日中间的横岗许换成斜杠,也就是new Date("2020/09/21 11:11:00")通常为了兼容IOS的这个坑,需要做一些额外的特殊处理,笔者在开发的时候经常会忘了兼容IOS系统。所以就想试着重写Date函数,一劳永逸,避免每次ne_date.prototype 将所有 ios

如何将EXCEL表导入plsql数据库中-程序员宅基地

文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql

Git常用命令速查手册-程序员宅基地

文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...

分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120-程序员宅基地

文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120

【C++缺省函数】 空类默认产生的6个类成员函数_空类默认产生哪些类成员函数-程序员宅基地

文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数

推荐文章

热门文章

相关标签