Java过滤器详细文档,简介,实例,应用
简介
Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
Filter技术是servlet 2.3新增加的功能。它能够对Servlet容器的请求和响应对象进行检查和修改。
Filter本身并不生成请求和响应对象,只是提供过滤功能。
Filter能够在Servlet被调用之前检查Request对象,并修改Request Header和Request内容;在Servlet被调用之后检查Response对象,修改Response Header和Response的内容。
Filter可以过滤的Web组件包括Servlet,JSP和HTML等文件。
Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截。
2.Filter的工作原理
当客户端发出Web资源的请求时,Web服务器根据应用程序配置文件设置的过滤规则进行检查,若客户请求满足过滤规则,则对客户请求/响应进行拦截,对请求头和请求数据进行检查或改动,并依次通过过滤器链,最后把请求/响应交给请求的Web资源处理。请求信息在过滤器链中可以被修改,也可以根据条件让请求不发往资源处理器,并直接向客户机发回一个响应。当资源处理器完成了对资源的处理后,响应信息将逐级逆向返回。同样在这个过程中,用户可以修改响应信息,从而完成一定的任务。
两个过滤器同时过滤一个请求时,就要用到过滤链FilterChain。Filter的FilterChain中,服务器会按照web.xml中过滤器定义的先后循序组装成一条链,然后一次执行其中的doFilter()方法。执行的顺序就如下图所示,执行第一个过滤器的chain.doFilter()之前的代码,第二个过滤器的chain.doFilter()之前的代码,请求的资源,第二个过滤器的chain.doFilter()之后的代码,第一个过滤器的chain.doFilter()之后的代码,最后返回响应。
Filter的执行流程就是:
执行第一个过滤器的chain.doFilter()之前的代码——
>第二个过滤器的chain.doFilter()之前的代码——>……——
>第n个过滤器的chain.doFilter()之前的代码——
>所请求servlet的service()方法中的代码——>
所请求servlet的doGet()或doPost()方法中的代码——
>第n个过滤器的chain.doFilter()之后的代码——>……——
>第二个过滤器的chain.doFilter()之后的代码——
>第一个过滤器的chain.doFilter()之后的代码。
3、Filter生命周期
1> 和Servlet一样Filter的创建和销毁也是由WEB服务器负责。不过与Servlet区别的是,它是1>在应用启动的时候就进行装载Filter类(与Servlet的load-on-startup配置效果相同)。
2>容器创建好Filter对象实例后,调用init()方法。接着被Web容器保存进应用级的集合容器中去了等待着,用户访问资源。
3>当用户访问的资源正好被Filter的url-pattern拦截时,容器会取出Filter类调用doFilter方法,下次或多次访问被拦截的资源时,Web容器会直接取出指定Filter对象实例调用doFilter方法(Filter对象常驻留Web容器了)。
4>当应用服务被停止或重新装载了,则会执行Filter的destroy方法,Filter对象销毁。
注意:init方法与destroy方法只会直接一次。
也可以简单理解:
(1)实例化:Web容器在部署Web应用程序时对所有过滤器进行实例化。Web容器回调它的无参构造方法。
(2)初始化:实例化完成之后,马上进行初始化工作。Web容器回调init()方法。
(3)过滤:请求路径匹配过滤器的URL映射时。Web容器回调doFilter()方法——主要的工作方法。
(4)销毁: Web容器在卸载Web应用程序前,Web容器回调destroy()方法。
4,Filter的部署
分为两个步骤:
1、注册Filter
<description>用于添加描述信息,该元素的内容可为空,<description>可以不配置。
<filter-name>用于为过滤器指定一个名字,该元素的内容不能为空。
<filter-class>元素用于指定过滤器的完整的限定类名。
<init-param>元素用于为过滤器指定初始化参数,它的子元素<param-name>指定参数的名字,<param-value>指定参数的值。在过滤器中,可以使用FilterConfig接口对象来访问初始化参数。如果过滤器不需要指定初始化参数,那么<init-param>元素可以不配置。
2、映射Filter
在web.xml文件中注册了Filter之后,还要在web.xml文件中映射Filter
<!--映射过滤器-->
<filter-mapping>
<filter-name>FilterDemo02</filter-name>
<!--“/*”表示拦截所有的请求 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>元素用于设置一个 Filter 所负责拦截的资源。一个Filter拦截的资源可通过两种方式来指定:Servlet 名称和资源访问的请求路径
<filter-name>子元素用于设置filter的注册名称。该值必须是在<filter>元素中声明过的过滤器的名字
<url-pattern>设置 filter 所拦截的请求路径(过滤器关联的URL样式)
<servlet-name>指定过滤器所拦截的Servlet名称。
<dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认REQUEST。
用户可以设置多个<dispatcher> 子元素用来指定 Filter 对资源的多种调用方式进行拦截。如下:
<filter-mapping>
<filter-name>testFilter</filter-name>
<url-pattern>/index.jsp</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
<dispatcher> 子元素可以设置的值及其意义:
REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。
INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。
FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。
ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。
Filter开发步骤
Filter开发分为二个步骤:
编写java类实现Filter接口,并实现其doFilter方法。
在 web.xml 文件中使用<filter>和<filter-mapping>元素对编写的filter类进行注册,并设置它所能拦截的资源。
<!-- 自定义的过滤器 -->
<filter>
<filter-name>authorityFilter</filter-name> <span style="font-family: Arial, Helvetica, sans-serif;"> </span>
<filter-class>cn.thinknet.filter.AuthorityFilter</filter-class><span style="font-family: Arial, Helvetica, sans-serif;"><!-- 自定义过滤器的位置 --></span>
<init-param>
<param-name>allowAuthorityURL</param-name><!-- 不需要过滤的地址 -->
<param-value>login.jsp,register.jsp,login.action,sendMail.action,register.action,getbackPwdOne.jsp,getbackPwdTwo.jsp,getbackPwdThree.jsp,getbackOne.action,getbackTwo.action,getbackThree.action,forget_pwd.action,getHomePageResult.action,index.jsp,index.html,userAuthen.action</param-value>
</init-param>
<init-param>
<param-name>authorityURL</param-name><!-- 只对指定过滤参数后缀进行过滤 -->
<param-value>.action,.jsp,.do</param-value>
</init-param>
<init-param>
<param-name>redirectPath</param-name><!-- 未通过跳转到登录界面 -->
<param-value>/wrtPlatformVt/wrt/login.jsp</param-value>
</init-param>
<init-param>
<param-name>disableFilter</param-name><!-- Y:过滤无效 -->
<param-value>N</param-value>
</init-param>
</filter>
<filter-mapping> <!-- 拦截所有的请求信息 如想通过扩展名匹配拦截。 如:.action后缀的请求 配置则为 *.action-->
<!-- 精确匹配 顾名思义精确到单个请求 如:/manage/login.action 配置则为/manage/login.action -->
<!-- 路劲匹配 通过*配符的方式进行相对匹配,如下的/* 则表示拦截所有信息 -->
<filter-name>authorityFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
附上:servlet url-pattern匹配规则:http://zy19982004.iteye.com/blog/1751695
<init-param> 标签对应的是参数名和值,可以用于在init()时通过FilterConfig的对象 filterConfig.getInitParameter("参数名")获取。
附上:<init-param>标签的基本使用:http://blog.csdn.net/yakson/article/details/9203231
自定义过滤器代码:
[java] view plain copy
package cn.thinknet.filter;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import cn.thinknet.utils.others.AKKeysUtil;
/**
* 过滤器
*
*
*
*/
public class AuthorityFilter extends HttpServlet implements Filter
{
private static final long serialVersionUID = 4504557649329493897L;
public String[] allowAuthorityURLs;
public String[] authorityURLs;
public FilterConfig config;
/**
* 过滤不能访问的地址
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException
{
// 未登录需要跳转的地址
String redirectPath = config
.getInitParameter(AKKeysUtil.WEB_CONTEXT_REDIRECT_PATH);
// 过滤是否启用
boolean isEnable = true; // 过滤器可用
String disableStr = config
.getInitParameter(AKKeysUtil.WEB_CONTEXT_DISABLE_FILTER);
if (StringUtils.isNotEmpty(disableStr))
{
isEnable = disableStr.equals("N");
}
HttpServletRequest req = (HttpServletRequest) request;
// 判断过滤器是否启用
if (!isEnable)
{
filterChain.doFilter(request, response);
return;
}
// 需要过滤的后缀
String authorityURL = config
.getInitParameter(AKKeysUtil.WEB_CONTEXT_AUTHORITY_URL);
if (StringUtils.isNotEmpty(authorityURL))
{
authorityURLs = authorityURL.split(",");
}
// 判断当前的请求地址中是否存在需要过滤的后缀
if (authorityURL(req))
{
// 不需要过滤的地址
String allowAuthorityURL = config
.getInitParameter(AKKeysUtil.WEB_CONTEXT_ALLOW_AUTHORITY_URL);
if (StringUtils.isNotEmpty(allowAuthorityURL))
{
allowAuthorityURLs = allowAuthorityURL.split(",");
}
// 过滤不拦截的url
if (allowAuthorityURL(req))
{
filterChain.doFilter(request, response);
return;
} else
{
// 判断当前用户是否登录,没有登录直接跳转到登录页面
if (!relogin(redirectPath, response, req))
{
return;
}
}
// 最后对action与jsp进行权限校验
// if (authorityRequestAddress(req))
// {
// 【暂时不实现纵向越权控制】
filterChain.doFilter(request, response);
// }
// else
// {
// 没有权限时
// noAuthority();
// }
} else
{
// 例如js,image,css等文件不列入权限控制范围内
filterChain.doFilter(request, response);
}
}
@Override
public void init(FilterConfig filterConfig) throws ServletException
{
config = filterConfig;
// WebApplicationContext ctx = WebApplicationContextUtils
// .getWebApplicationContext(this.getServletContext());
// menuService = (MenuService) ctx.getBean("menuService");
}
/**
* 在未登陆的情况下允许访问的URL
*
* @return Boolean
*/
private boolean allowAuthorityURL(HttpServletRequest request)
{
boolean isAllow = false;
// 获得当前访问的地址
String current_url = request.getRequestURI();
if (ArrayUtils.isNotEmpty(allowAuthorityURLs))
{
for (String allowUrl : allowAuthorityURLs)
{
if (StringUtils.containsIgnoreCase(current_url, allowUrl))
{
isAllow = true;
break;
}
}
}
return isAllow;
}
/**
* 需要过滤的后缀
*
* @return Boolean
*/
private boolean authorityURL(HttpServletRequest request)
{
boolean isFilter = false;
if (ArrayUtils.isNotEmpty(authorityURLs))
{
for (String suffix : authorityURLs)
{
if (request.getRequestURI().indexOf(suffix) != -1)
{
isFilter = true;
break;
}
}
}
return isFilter;
}
/**
* 判断员工回话是否失效
*
* @param redirectPath
* 需要跳转的页面
* @param response
* 请求响应
*
* @param request
* 请求
*
* @throws IOException
*
* @return boolean 假:代表重新登录,真:代表session存在
*/
private boolean relogin(String redirectPath, ServletResponse response,
HttpServletRequest request) throws IOException
{
response.setContentType("text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
// 判断该用户是否存在session中,如果有直接进入当前action
if (null == request.getSession(true).getAttribute(
AKKeysUtil.USER_EMPLOY_SESSION_KEY))
{
// 跳转到登录界面
out.print("<script language='javascript'>alert('身份验证失效,请重新登录!');window.parent.location.href='"
+ redirectPath + "';</script>");
return false;
}
// 如果用户禁用掉cookie,则跳转到登录界面,提示用户启用cookie
Cookie[] cookies = request.getCookies();
if (null == cookies)
{
// 1.可能用户清除过cookie 2.可能是由于用户禁用了cookie 此时都会跳转到登录界面
// 跳转到登录界面
out.print("<script language='javascript'>alert('Cookie被清理或是已禁用,请尝试重新登录!');window.parent.location.href='"
+ redirectPath + "';</script>");
return false;
}
return true;
}
}
注意,AKKeysUtil这个是封装好的一个工具类,所有使用到的地方对应的均是 <init-param>标签的参数名,自行对应更改即可。
servlet过滤器并不等同于拦截器,常用的拦截器莫过于框架所自带的,如:Struts2,spring mvc等。 如想达到权限认证(是否登陆、未登录返回登陆页面),通过框架的拦截器达到其效果,当然也可以直接使用servlet的filter.
Java过滤器详细文档,简介,实例,应用的更多相关文章
- Java解析XML文档(简单实例)——dom解析xml
一.前言 用Java解析XML文档,最常用的有两种方法:使用基于事件的XML简单API(Simple API for XML)称为SAX和基于树和节点的文档对象模型(Document Object ...
- SQLmap超详细文档和实例演示
第一部分,使用文档的说明 Options(选项): -h, -–help 显示此帮助消息并退出 -hh 显示更多帮助信息并退出 –-version 显示程序的版本号并退出 -v VERBOSE 详细级 ...
- NVelocity介绍,NVelocity中文手册文档及实例下载
NVelocity是什么velocity英音:[vi'lɔsiti]美音:[və'lɑsətɪ]近在做一个项目,客户要求有网站模板功能,能够自主编辑网站的风格,因为这个系统是为政府部门做子站系统,举个 ...
- Django内置过滤器详解附代码附效果图--附全部内置过滤器帮助文档
前言 基本环境 Django版本:1.11.8 Python版本:3.6 OS: win10 x64 本文摘要 提供了常用的Django内置过滤器的详细介绍,包括过滤器的功能.语法.代码和效果示例. ...
- Java解析XML文档——dom解析xml
一.前言 用Java解析XML文档,最常用的有两种方法:使用基于事件的XML简单API(Simple API for XML)称为SAX和基于树和节点的文档对象模型(Document Object M ...
- Java版office文档在线预览
java将office文档pdf文档转换成swf文件在线预览 第一步,安装openoffice.org openoffice.org是一套sun的开源office办公套件,能在widows,linux ...
- 使用Aspose.word (Java) 填充word文档数据(包含图片填充)
Aspose填充word数据 本文介绍了如何使用aspose进行word文档的生成,并提供了工具类供参考. 有问题欢迎 call 微信:905369866,小弟尽力而为..毕竟这玩意没吃透. 目录 A ...
- Java复制Word文档
Microsoft Word 提供了许多易于使用的文档操作工具,同时也提供了丰富的功能集供创建复杂的文档使用.在使用的时候,你可能需要复制一个文档里面的内容到另一个文档.本文介绍使用Spire.Doc ...
- Java实现office文档与pdf文档的在线预览功能
最近项目有个需求要java实现office文档与pdf文档的在线预览功能,刚刚接到的时候就觉得有点难,以自己的水平难以在三四天做完.压力略大.后面查找百度资料.以及在同事与网友的帮助下,四天多把它做完 ...
随机推荐
- logback-spring.xml的schema
<?xml version="1.0" encoding="utf-8" ?> <configuration xmlns:xsi=" ...
- 【bzoj1050】[HAOI2006]旅行comf
1050: [HAOI2006]旅行comf Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2813 Solved: 1534[Submit][St ...
- Linux下cacti的安装
Cacti安装手册 第一步. Cacti的架构 第二步. Cacti的工作流程 第三步. Cacti简介 1. cacti是用php语言实现的一个软件,它的主要功能是用snmp服务获取数据,然后用r ...
- laravel tinker测试模型添加属性
php artisan tinker 新建一个模型对象 $post=new \App\Posts(); 给对象的属性挨个赋值 $post->title="this is title&q ...
- 1-new对象与直接构建对象
#include <iostream> using namespace std; class A { public: A(){} A (int a){ this->a = a; } ...
- 运单waybill快速录入
运单waybill快速录入 前台页面: 1修改页面onAfterEdit事件, 后台代码:ajax响应回请求1 为成功,0 为失败
- 面试题:hibernate 有用
1. Hibernate的工作流程? 答案: 1.通过Configuration对象读取并解析配置文件 2.读取并解析映射信息,创建SessionFactory对象 3.打开session 4.创建事 ...
- 运用alarm系统调用检测网络是否断开
比如对于一个Server/Client程序,Client会每隔一定时间(比如TIME_OUT_CLIENT)会向Server发送“CheckConnect”信息,Server收到这个信息会调用回调函数 ...
- R语言读取MySQL数据表
1.R中安装RODBC包 install.packages("RODBC") 2.在Windows系统下安装MySQL的ODBC驱动 注意区分32位和64位版本: http://d ...
- Luogu 4213 【模板】杜教筛(Sum)
当作杜教筛的笔记吧. 杜教筛 要求一个积性函数$f(i)$的前缀和,现在这个东西并不是很好算,那么我们考虑让它卷上另外一个积性函数$g(i)$,使$(f * g)$的前缀和变得方便计算,然后再反推出这 ...