我是靠谱客的博主 伶俐星月,最近开发中收集的这篇文章主要介绍java servlet过滤器简解及实例,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

     在整个概念中,个人觉得有一篇文章写得不错,通俗易懂,这里就直接套用以上原博文,

 


一、概念:

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

Java Web 之过滤器Filter详解

二、Filter简介

        Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截。简单说,就是可以实现web容器对某资源的访问前截获进行相关的处理,还可以在某资源向web容器返回响应前进行截获进行处理。

三、快速入门

1、新建一个类,实现Filter接口

2、实现doFilter()方法,打印一句话,来证明能够进行拦截

3、在web.xml中进行配置(参照Servlet配置)

4、访问一个页面,看看能不能拦截

[java]  view plain  copy
  1. package com.test.filter;    
  2.   
  3.      
  4.   
  5. import java.io.IOException;    
  6.   
  7. import javax.servlet.Filter;    
  8.   
  9. import javax.servlet.FilterChain;    
  10.   
  11. import javax.servlet.FilterConfig;    
  12.   
  13. import javax.servlet.ServletException;    
  14.   
  15. import javax.servlet.ServletRequest;    
  16.   
  17. import javax.servlet.ServletResponse;    
  18.   
  19. public class Demo1Filter implements Filter {    
  20.   
  21.     private FilterConfig filterConfig;    
  22.   
  23.      
  24.   
  25.     public void doFilter(ServletRequest request, ServletResponse response,    
  26.   
  27.             FilterChain chain) throws IOException, ServletException {    
  28.   
  29.         System.out.println("Demo1过滤前");    
  30.   
  31.         System.out.println(filterConfig.getInitParameter("param1"));    
  32.   
  33.         chain.doFilter(request, response);//放行。让其走到下个链或目标资源中    
  34.   
  35.         System.out.println("Demo1过滤后");    
  36.   
  37.     }    
  38.   
  39.      
  40.   
  41.     public void init(FilterConfig filterConfig) throws ServletException {    
  42.   
  43.         System.out.println("初始化了");    
  44.   
  45.         this.filterConfig = filterConfig;    
  46.   
  47.     }    
  48.   
  49.      
  50.   
  51.     public void destroy() {    
  52.   
  53.         System.out.println("销毁了");    
  54.   
  55.     }    
  56.   
  57. }   


web.xml中进行配置

[html]  view plain  copy
  1. <filter>  
  2.     <filter-name>Demo1Filter</filter-name>  
  3.     <filter-class>com.itheima.filter.Demo1Filter</filter-class>  
  4.     <init-param>  
  5.         <param-name>param1</param-name>  
  6.         <param-value>value在这里呢</param-value>  
  7.     </init-param>  
  8. </filter>  
  9. <filter-mapping>  
  10.     <filter-name>Demo1Filter</filter-name>  
  11.     <url-pattern>/*</url-pattern>  
  12.     <dispatcher>REQUEST</dispatcher> <!-- 没有配置dispatcher就是默认request方式的 -->  
  13.     <dispatcher>FORWARD</dispatcher>  
  14.     <dispatcher>ERROR</dispatcher>  
  15.     <dispatcher>INCLUDE</dispatcher>  
  16. </filter-mapping>  


 

四、Filter的应用场景

通过对filter过滤器的了解,可以得知在以下三种情况下可以做些处理:

1> 通过控制对chain.doFilter的方法的调用,来决定是否需要访问目标资源。

比如,可以在用户权限验证等等。判断用户是否有访问某些资源的权限,有权限放行,没权限不执行chain.doFilter方法。

2> 通过在调用chain.doFilter方法之前,做些处理来达到某些目的。

比如,解决中文乱码的问题等等。可以在doFilter方法前,执行设置请求编码与响应的编码。甚至可以对request接口进行封装装饰来处理get请求方式的中文乱码问题(重写相应的request.getParameter方法)

3> 通过在调用chain.doFilter方法之后,做些处理来达到某些目的。

比如对整个web网站进行压缩。在调用chain.doFilter方法之前用类Aresponse对象进行封装装饰,重写getOutputStream和重写getWriter方法。在类A内部中,将输出内容缓存进ByteArrayOutputStream流中,然后在chain.doFilter方法执行后,获取类AByteArrayOutputStream流缓存数据,用GZIPOutputStream流进行压缩下。

五、Filter实现拦截的原理

Filter接口中有一个doFilter方法,当开发人员编写好Filter类实现doFilter方法,并配置对哪个web资源进行拦截后,WEB服务器每次在调用web资源的service方法之前(服务器内部对资源的访问机制决定的),都会先调用一下filterdoFilter方法

六、Filter生命周期

Servlet一样Filter的创建和销毁也是由WEB服务器负责。不过与Servlet区别的是,它是1>在应用启动的时候就进行装载Filter(Servletload-on-startup配置效果相同)2>容器创建好Filter对象实例后,调用init()方法。接着被Web容器保存进应用级的集合容器中去了等待着,用户访问资源。3>当用户访问的资源正好被Filterurl-pattern拦截时,容器会取出Filter类调用doFilter方法,下次或多次访问被拦截的资源时,Web容器会直接取出指定Filter对象实例调用doFilter方法(Filter对象常驻留Web容器了)4>应用服务被停止或重新装载了,则会执行Filterdestroy方法,Filter对象销毁。

注意:init方法与destroy方法只会直接一次。

七、Filter部署应用注意事项

1> filter-mapping标签中servlet-nameurl-pattern

Filter不仅可以通过url-pattern来指定拦截哪些url匹配的资源。而且还可以通过servlet-name来指定拦截哪个指定的servlet(专门为某个servlet服务了,servlet-name对应Servlet的相关配置)

2> filter-mapping标签中dispatcher

指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARDERROR之一,默认REQUEST。用户可以设置多个<dispatcher> 子元素用来指定 Filter 对资源的多种调用方式进行拦截。

REQUEST

当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcherinclude()forward()方法访问或ERROR情况时,那么该过滤器就不会被调用。

INCLUDE

如果目标资源是通过RequestDispatcherinclude()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。

FORWARD

如果目标资源是通过RequestDispatcherforward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。

ERROR

如若在A.jsp页面page指令中指定了error属性=examError.jsp,那么A.jsp中若出现了异常,会跳转到examError.jsp中处理。而在跳转到examError.jsp时,若过滤器配置了ERRORdispather那么则会拦截,否则不会拦截。


总结:

一个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 servlet过滤器简解及实例的全部内容,希望文章能够帮你解决java servlet过滤器简解及实例所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(53)

评论列表共有 0 条评论

立即
投稿
返回
顶部