java servlet过滤器简解及实例
2016-07-20 14:34
429 查看
在整个概念中,个人觉得有一篇文章写得不错,通俗易懂,这里就直接套用以上原博文,
一、概念:
Filter也称之为过滤器,它是Servlet技术中比较激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
二、Filter简介
Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截。简单说,就是可以实现web容器对某资源的访问前截获进行相关的处理,还可以在某资源向web容器返回响应前进行截获进行处理。
三、快速入门
1、新建一个类,实现Filter接口
2、实现doFilter()方法,打印一句话,来证明能够进行拦截
3、在web.xml中进行配置(参照Servlet配置)
4、访问一个页面,看看能不能拦截
[java] view
plain copy
package com.test.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;
public class Demo1Filter implements Filter {
private FilterConfig filterConfig;
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("Demo1过滤前");
System.out.println(filterConfig.getInitParameter("param1"));
chain.doFilter(request, response);//放行。让其走到下个链或目标资源中
System.out.println("Demo1过滤后");
}
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("初始化了");
this.filterConfig = filterConfig;
}
public void destroy() {
System.out.println("销毁了");
}
}
在web.xml中进行配置
[html] view
plain copy
<filter>
<filter-name>Demo1Filter</filter-name>
<filter-class>com.itheima.filter.Demo1Filter</filter-class>
<init-param>
<param-name>param1</param-name>
<param-value>value在这里呢</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Demo1Filter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher> <!-- 没有配置dispatcher就是默认request方式的 -->
<dispatcher>FORWARD</dispatcher>
<dispatcher>ERROR</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
四、Filter的应用场景
通过对filter过滤器的了解,可以得知在以下三种情况下可以做些处理:
1> 通过控制对chain.doFilter的方法的调用,来决定是否需要访问目标资源。
比如,可以在用户权限验证等等。判断用户是否有访问某些资源的权限,有权限放行,没权限不执行chain.doFilter方法。
2> 通过在调用chain.doFilter方法之前,做些处理来达到某些目的。
比如,解决中文乱码的问题等等。可以在doFilter方法前,执行设置请求编码与响应的编码。甚至可以对request接口进行封装装饰来处理get请求方式的中文乱码问题(重写相应的request.getParameter方法)。
3> 通过在调用chain.doFilter方法之后,做些处理来达到某些目的。
比如对整个web网站进行压缩。在调用chain.doFilter方法之前用类A对response对象进行封装装饰,重写getOutputStream和重写getWriter方法。在类A内部中,将输出内容缓存进ByteArrayOutputStream流中,然后在chain.doFilter方法执行后,获取类A中ByteArrayOutputStream流缓存数据,用GZIPOutputStream流进行压缩下。
五、Filter实现拦截的原理
Filter接口中有一个doFilter方法,当开发人员编写好Filter类实现doFilter方法,并配置对哪个web资源进行拦截后,WEB服务器每次在调用web资源的service方法之前(服务器内部对资源的访问机制决定的),都会先调用一下filter的doFilter方法。
六、Filter生命周期
和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方法只会直接一次。
七、Filter部署应用注意事项
1> filter-mapping标签中servlet-name与url-pattern。
Filter不仅可以通过url-pattern来指定拦截哪些url匹配的资源。而且还可以通过servlet-name来指定拦截哪个指定的servlet(专门为某个servlet服务了,servlet-name对应Servlet的相关配置)。
2> filter-mapping标签中dispatcher。
指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认REQUEST。用户可以设置多个<dispatcher> 子元素用来指定 Filter 对资源的多种调用方式进行拦截。
REQUEST:
当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问或ERROR情况时,那么该过滤器就不会被调用。
INCLUDE:
如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。
FORWARD:
如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。
ERROR:
如若在A.jsp页面page指令中指定了error属性=examError.jsp,那么A.jsp中若出现了异常,会跳转到examError.jsp中处理。而在跳转到examError.jsp时,若过滤器配置了ERROR的dispather那么则会拦截,否则不会拦截。
总结:
1. 在servlet被调用之前截获;
2. 在servlet被调用之前检查servlet request;
3. 根据需要修改request头和request数据;
4. 根据需要修改response头和response数据;
5. 在servlet被调用之后截获.
你能够配置一个filter 到一个或多个servlet;单个servlet或servlet组能够被多个filter 使用.几个实用的filter 包括:用户辨认filter,日志filter,审核filter,加密filter,符号filter,能改变xml内容的XSLT filter等.
====================================割割割======================
以上为文章原文,此处尊重原作者附上出处:http://blog.csdn.net/jzhf2012/article/details/8476997
表示自己一直处于仅仅只会用的级别,而不懂得原理不懂得由来,所以此处也只能是需要使用的代码块进行自我复习.
filter作用及原理上面其实已经讲得差不多(要我写还写不出来这么高大上的东西),那么我附上一个简单而实用的代码,
附上: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
自定义过滤器代码:
注意,AKKeysUtil这个是封装好的一个工具类,所有使用到的地方对应的均是 <init-param>标签的参数名,自行对应更改即可。
以上过滤器经测试是可用的,不过由于源码并不是我所写(公司前辈所留),所以这里只能是拿出来分享之说,servlet过滤器并不等同于拦截器,常用的拦截器莫过于框架所自带的,如:Struts2,spring mvc等。 如想达到权限认证(是否登陆、未登录返回登陆页面),通过框架的拦截器达到其效果,当然也可以直接使用servlet的filter,毕竟我就是直接使用它的。。。
一、概念:
Filter也称之为过滤器,它是Servlet技术中比较激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
二、Filter简介
Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截。简单说,就是可以实现web容器对某资源的访问前截获进行相关的处理,还可以在某资源向web容器返回响应前进行截获进行处理。
三、快速入门
1、新建一个类,实现Filter接口
2、实现doFilter()方法,打印一句话,来证明能够进行拦截
3、在web.xml中进行配置(参照Servlet配置)
4、访问一个页面,看看能不能拦截
[java] view
plain copy
package com.test.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;
public class Demo1Filter implements Filter {
private FilterConfig filterConfig;
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("Demo1过滤前");
System.out.println(filterConfig.getInitParameter("param1"));
chain.doFilter(request, response);//放行。让其走到下个链或目标资源中
System.out.println("Demo1过滤后");
}
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("初始化了");
this.filterConfig = filterConfig;
}
public void destroy() {
System.out.println("销毁了");
}
}
在web.xml中进行配置
[html] view
plain copy
<filter>
<filter-name>Demo1Filter</filter-name>
<filter-class>com.itheima.filter.Demo1Filter</filter-class>
<init-param>
<param-name>param1</param-name>
<param-value>value在这里呢</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Demo1Filter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher> <!-- 没有配置dispatcher就是默认request方式的 -->
<dispatcher>FORWARD</dispatcher>
<dispatcher>ERROR</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
四、Filter的应用场景
通过对filter过滤器的了解,可以得知在以下三种情况下可以做些处理:
1> 通过控制对chain.doFilter的方法的调用,来决定是否需要访问目标资源。
比如,可以在用户权限验证等等。判断用户是否有访问某些资源的权限,有权限放行,没权限不执行chain.doFilter方法。
2> 通过在调用chain.doFilter方法之前,做些处理来达到某些目的。
比如,解决中文乱码的问题等等。可以在doFilter方法前,执行设置请求编码与响应的编码。甚至可以对request接口进行封装装饰来处理get请求方式的中文乱码问题(重写相应的request.getParameter方法)。
3> 通过在调用chain.doFilter方法之后,做些处理来达到某些目的。
比如对整个web网站进行压缩。在调用chain.doFilter方法之前用类A对response对象进行封装装饰,重写getOutputStream和重写getWriter方法。在类A内部中,将输出内容缓存进ByteArrayOutputStream流中,然后在chain.doFilter方法执行后,获取类A中ByteArrayOutputStream流缓存数据,用GZIPOutputStream流进行压缩下。
五、Filter实现拦截的原理
Filter接口中有一个doFilter方法,当开发人员编写好Filter类实现doFilter方法,并配置对哪个web资源进行拦截后,WEB服务器每次在调用web资源的service方法之前(服务器内部对资源的访问机制决定的),都会先调用一下filter的doFilter方法。
六、Filter生命周期
和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方法只会直接一次。
七、Filter部署应用注意事项
1> filter-mapping标签中servlet-name与url-pattern。
Filter不仅可以通过url-pattern来指定拦截哪些url匹配的资源。而且还可以通过servlet-name来指定拦截哪个指定的servlet(专门为某个servlet服务了,servlet-name对应Servlet的相关配置)。
2> filter-mapping标签中dispatcher。
指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认REQUEST。用户可以设置多个<dispatcher> 子元素用来指定 Filter 对资源的多种调用方式进行拦截。
REQUEST:
当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问或ERROR情况时,那么该过滤器就不会被调用。
INCLUDE:
如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。
FORWARD:
如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。
ERROR:
如若在A.jsp页面page指令中指定了error属性=examError.jsp,那么A.jsp中若出现了异常,会跳转到examError.jsp中处理。而在跳转到examError.jsp时,若过滤器配置了ERROR的dispather那么则会拦截,否则不会拦截。
总结:
一个filter 包括:
1. 在servlet被调用之前截获;2. 在servlet被调用之前检查servlet request;
3. 根据需要修改request头和request数据;
4. 根据需要修改response头和response数据;
5. 在servlet被调用之后截获.
你能够配置一个filter 到一个或多个servlet;单个servlet或servlet组能够被多个filter 使用.几个实用的filter 包括:用户辨认filter,日志filter,审核filter,加密filter,符号filter,能改变xml内容的XSLT filter等.
====================================割割割======================
以上为文章原文,此处尊重原作者附上出处:http://blog.csdn.net/jzhf2012/article/details/8476997
表示自己一直处于仅仅只会用的级别,而不懂得原理不懂得由来,所以此处也只能是需要使用的代码块进行自我复习.
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
自定义过滤器代码:
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过滤器与SpringMVC拦截器之间的关系与区别
- Java过滤器与SpringMVC拦截器之间的关系与区别
- 在Java Filter 中注入 Service方案一
- Java中的Filter过滤器
- (三)基于SSM+Redis+Nginx+FastDFS的博客网站
- Java Servlet 过滤器与 SpringMVC 拦截器的区别?
- eclipse调试的基本意义
- java内部类的作用
- SpringJDBC
- JAVA获取时间戳,哪个更快
- jmap,jhat分析内存
- MiniDao_1.6-SNAPSHOT 版本发布,轻量级Java持久化框架
- Java Calendar 类的时间操作
- 各种排序算法的分析及java实现
- 找不到javax.servlet包
- Android Studio与eclipse的区别
- spring 3.2 后 annotation-driven 注册新的类
- 快速搭建ibatis+tddl+spring工程构造数据
- SpringMVC Controller介绍及常用注解
- Spring数据源支持之Mybatis