6 Filter(从Servlet学到JSP)

0 什么是Filter

Filter可认为是 Servlet的一种“加强版”,它主要用于对用户请求HttpServletRequest进行预处理,也可以对HttpServletResponse进行后处理,是个典型的处理链。Filter也可对用户请求生成响应,这一点与 servlet相同,但实际上很少会使用Filter向用户请求生成响应。使用Filter完整的流程是:Filter对用户请求进行预处理,接着将请求交给 Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。

Filter有如下几个用处:

  • 在 HttpServletRequest到达 Servlet之前,拦截客户的 HttpServletRequest:根据需要检查 HttpServletRequest,也可以修改 HttpServletRequest头和数据
  • 在 HttpServletResponse到达客户端之前,拦截 HttpServletResponse:根据需要检查 HttpServletResponse,也可以修改 HttpServletResponse头和数据

Filter有如下几个种类:

  • 用户授权的Filter:Filter负责检查用户请求,根据请求过滤用户非法请求
  • 日志Filter:详细记录某些特殊的用户请求
  • 负责解码的Filter:包括对非标准编码的请求解码
  • 能改变XML内容的 XSLT Filter等
  • Fer可负责拦截多个请求或响应:一个请求或响应也可被多个Fier拦截

创建一个Filter只需两个步骤:

  • 创建Filter处理类
  • web.xm文件中配置Filter

Filter执行顺序

1 创建 Filter

创建Filter必须实现 javax.servlet.Filter接口,在该接口中定义了如下三个方法,

  • void init (FilterConfig config):用于完成 Filter的初始化
  • void destroy():用于Filter销毁前,完成某些资源的回收
  • void doFilter( ServletRequest request, ServletResponse response, Filter Chain chain):实现过滤功能,该方法就是对每个请求及响应增加额外的处理

下面是一个日志Filter,负责拦截所有的用户请求,并将请求的信息记录在日志中。

----------------LogFilter.JAVA------;
package lee;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;

import java.io.*;

@WebFilter(filterName="log"
	,urlPatterns={"/*"})
public class LogFilter implements Filter {
	//FilterConfig可用于访问Filter的配置信息
	private FilterConfig config;
	//实现初始化方法
	public void init(FilterConfig config){
		this.config = config; 
	}
	//实现销毁方法
	public void destroy(){
		this.config = null; 
	}
	//执行过滤的核心方法
	public void doFilter(ServletRequest request,
		ServletResponse response, FilterChain chain)
		throws IOException,ServletException{
		//------1---对用户请求执行预处理---------
		//获取ServletContext对象,用于记录日志
		ServletContext context = this.config.getServletContext(); 
		long before = System.currentTimeMillis();
		System.out.println("开始过滤...");
		//将请求转换成HttpServletRequest请求
		HttpServletRequest hrequest = (HttpServletRequest)request;
		//输出提示信息
		System.out.println("Filter已经截获到用户的请求的地址: " + 
			hrequest.getServletPath());
        
		//-----2-----Filter只是链式处理,请求依然放行到目的地址----
		chain.doFilter(request, response);
        
		//-----3----对服务器响应执行后处理---------
		long after = System.currentTimeMillis();
		//输出提示信息
		System.out.println("过滤结束");
		//输出提示信息
		System.out.println("请求被定位到" + hrequest.getRequestURI() + 
			"   所花的时间为: " + (after - before)); 
	} 
}

实现了 doFilter()方法,实现该方法就可实现对用户请求进行预处理,也可实现对服务器响应进行后处理—它们的分界线为是否调用了 chain.doFilter(),执行该方法之前,即对用户请求进行预处理;执行该方法之后,即对服务器响应进行后处理

在上面的请求 Filter中,仅在日志中记录请求的URL,对所有的请求都执行 chain.doFilter( request, reponse)方法,当 Filter对请求过滤后,依然将请求发送到目的地址。如果需要检查权限,可以在Filter中根据用户请求的 HttpSession,判断用户权限是否足够。如果权限不够,直接调用重定向即可,无须调用 chain.doFilter(request, reponse方法

2 配置 Filter

前面己经提到,Filter可以认为是 Servlet的“增强版”,因此配置Flter与配置Servlet非常相似,
都需要配置如下两个部分:

  • 配置 Filter名
  • 配置Filter拦截URL模式。

区别在于,Servlet通常只配置一个URL,而Filter可以同时拦截多个请求的URL。因此,在配置Filter的URL模式时通常会使用模式字符串,使得Filter可以拦截多个请求。

与配置Servlet相似的是,配置Filter 同样有两种方式:

  • 在Filter类中通过@WebFilter注解 进行配置。
  • 在web.xml文件中通过配置文件进行配置。

上面Filter类的粗体字代码使用@WebFilter 配署该Filter的名字为log,它会拦截向/*发生的所有的请求。

方式1:@WebFilter注解常用属性
属性类型是否必需说明
asyncSupportedboolean指定Filter是否支持异步模式
dispatcherTypesDispatcherType[]指定Filter对哪种方式的请求进行过滤。支持的属性:ASYNC、ERROR、FORWARD、INCLUDE、REQUEST;默认过滤所有方式的请求
filterNameStringFilter名称
initParamsWebInitParam[]配置参数
displayNameStringFilter显示名
servletNamesString[]指定对哪些Servlet进行过滤
urlPatterns/valueString[]两个属性作用相同,指定拦截的路径
方式2:web.xml

在web.xml文件中配置Filter与配置Servlet非常相似,需要为Filter指定它所过滤的URL,并且可以为Filter配置参数

---------------web.xml---------------
<?xml version="1.0" encoding="GBK"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
	http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	version="3.0">


	<!-- 定义Filter -->
	<filter>
		<!-- Filter的名字,相当于指定@WebFilter
			的filterName属性 -->
		<filter-name>log</filter-name>
		<!-- Filter的实现类 -->
		<filter-class>lee.LogFilter</filter-class> 
	</filter>
	<!-- 定义Filter拦截的URL地址 -->
	<filter-mapping>
		<!-- Filter的名字 -->
		<filter-name>log</filter-name>
		<!-- Filter负责拦截的URL,相当于指定@WebFilter
			的urlPatterns属性 -->
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<!-- 定义Filter -->
	<filter>
		<!-- Filter的名字 -->
		<filter-name>authority</filter-name>
		<!-- Filter的实现类 -->
		<filter-class>lee.AuthorityFilter</filter-class>
		<!-- 下面三个init-param元素配置了三个参数 -->
		<init-param>
			<param-name>encoding</param-name>
			<param-value>GBK</param-value>
		</init-param>
		<init-param>
			<param-name>loginPage</param-name>
			<param-value>/login.jsp</param-value>
		</init-param>
		<init-param>
			<param-name>proLogin</param-name>
			<param-value>/proLogin.jsp</param-value>
		</init-param>
	</filter>
	<!-- 定义Filter拦截的URL地址 -->
	<filter-mapping>
		<!-- Filter的名字 -->
		<filter-name>authority</filter-name>
		<!-- Filter负责拦截的URL -->
		<url-pattern>/*</url-pattern>
	</filter-mapping>


</web-app>

配置/*代表会拦截所有用户请求。该Filter并未对客户端请求进行额外的处理,仅仅在日志中简要记录请求的信息。

3 常用方法

由于 Filter和 Servlet如此相似,所以Filter和 Servlet具有完全相同的生命周期行为,且 Filter也可以通过<init-param>元素或@ WebFilter的 initParams属性来配置初始化参数。获取 Filter的初始化参数则使用 FilterConfig的 getInitParameter()方法

下面将定义一个较为实用的Filter,该Filter对用户请求进行过滤,Filter将通过 doFilter方法设置 request编码的字符集,从而避免每个JSP、 Servlet都需要设置;而且还会验证用户是否登录,如果用户没有登录,系统直接跳转到登录页面。

-----------AuthorityFilter.JAVA------
package lee;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;

import java.io.*;

@WebFilter(filterName="authority"
	, urlPatterns={"/*"}
	, initParams={
		@WebInitParam(name="encoding", value="GBK"),
		@WebInitParam(name="loginPage", value="/login.jsp"),
		@WebInitParam(name="proLogin", value="/proLogin.jsp")})
public class AuthorityFilter implements Filter {
	//FilterConfig可用于访问Filter的配置信息
	private FilterConfig config;
	//实现初始化方法
	public void init(FilterConfig config){
		this.config = config; 
	}
    
	//实现销毁方法
	public void destroy(){
		this.config = null; 
	}
    
	//执行过滤的核心方法
	public void doFilter(ServletRequest request,ServletResponse response, FilterChain chain)throws IOException,ServletException{
		//获取该Filter的配置参数
		String encoding = config.getInitParameter("encoding");
		String loginPage = config.getInitParameter("loginPage");
		String proLogin = config.getInitParameter("proLogin");
		//设置request编码用的字符集
		request.setCharacterEncoding(encoding);			//①
		HttpServletRequest requ = (HttpServletRequest)request;
		HttpSession session = requ.getSession(true);
		//获取客户请求的页面
		String requestPath = requ.getServletPath();
		//如果session范围的user为null,即表明没有登录
		//且用户请求的既不是登录页面,也不是处理登录的页面
		if( session.getAttribute("user") == null
			&& !requestPath.endsWith(loginPage)
			&& !requestPath.endsWith(proLogin)){
			//forward到登录页面
			request.setAttribute("tip" , "您还没有登录");
			request.getRequestDispatcher(loginPage).forward(request, response);
		}
		//"放行"请求
		else{
			chain.doFilter(request, response);
		}
	} 
}

通过@WebFilter的initParams属性可以为该Filter配置初始化参数,它可以接受多个@WebInitParam,每个@WebInitParam指定一个初始化参数。

在web.xml文件中也使用<init-params…>元素为该Filter配置参数,与配置Servlet初始化参数完全相同

---------------web.xml---------------
<?xml version="1.0" encoding="GBK"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
	http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	version="3.0">


	<!-- 定义Filter -->
	<filter>
		<!-- Filter的名字,相当于指定@WebFilter
			的filterName属性 -->
		<filter-name>log</filter-name>
		<!-- Filter的实现类 -->
		<filter-class>lee.LogFilter</filter-class> 
	</filter>
	<!-- 定义Filter拦截的URL地址 -->
	<filter-mapping>
		<!-- Filter的名字 -->
		<filter-name>log</filter-name>
		<!-- Filter负责拦截的URL,相当于指定@WebFilter
			的urlPatterns属性 -->
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<!-- 定义Filter -->
	<filter>
		<!-- Filter的名字 -->
		<filter-name>authority</filter-name>
		<!-- Filter的实现类 -->
		<filter-class>lee.AuthorityFilter</filter-class>
		<!-- 下面三个init-param元素配置了三个参数 -->
		<init-param>
			<param-name>encoding</param-name>
			<param-value>GBK</param-value>
		</init-param>
		<init-param>
			<param-name>loginPage</param-name>
			<param-value>/login.jsp</param-value>
		</init-param>
		<init-param>
			<param-name>proLogin</param-name>
			<param-value>/proLogin.jsp</param-value>
		</init-param>
	</filter>
	<!-- 定义Filter拦截的URL地址 -->
	<filter-mapping>
		<!-- Filter的名字 -->
		<filter-name>authority</filter-name>
		<!-- Filter负责拦截的URL -->
		<url-pattern>/*</url-pattern>
	</filter-mapping>


</web-app>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值