JavaWeb之Filter过滤器
1.什么是Filter
Filter过滤器,顾名思义是用来过滤的,过滤什么呢?在JavaWeb中,客户端通过地址去访问服务器中的资源,比如html页面,jsp页面,txt文件,音频,视频,图片等等。但是这些放在服务器上的资源我们有时候并不想让所有请求都能访问到,我们希望这种访问是有条件的,是加以约束的。比如:网页的某些页面我们希望只有登陆了的用户才可以看到,而没有登陆的用户不希望他看到,这时候我们就需要用到过滤器。
2.为什么用Filter
考虑这样一个场景,一个网站的后端在用户登陆后将用户的登陆信息保存到了Session域中,而此时我们有这样一个需求,在用户没有登陆的情况下,拦截用户访问target.jsp这一资源的请求。先来看一下,我们首先可以想到的办法是,既然用户登陆后信息保存到Session域,那么我们可以通过检查Session域中是否有用户信息来判断用户是否登陆进而去拦截请求,此时我们直接在请求target.jsp的位置(可能是一个按钮,可能是一个超链接标签,我们在单击事件方法中进行判断)进行判断,便有以下代码
<%
User user = session.getAttribute("user");
if(user==null){
request.getRequestDispatcher("登陆页面的地址").forward(request,response);
}
%>
试想如果有许多这样的需要进行能否访问的判断的页面,而我们依然以这样的方式去判断,必然造成代码冗余和维护的困难,而Filter过滤器可以很简单的完成这样的任务。
3.怎么用Filter
使用Filter之前我们先来看一幅图来更好的理解Filter(客户端其实就是浏览器)
这里的指定页面其实就是我们可以在过滤器中自定义当不满足条件时跳转到的页面。
Filter是一个接口,我们需要创建类去实现这个接口,并且实现接口中的方法。我们需要关注的是这三个方法
//初始化方法,在启动工程时执行
void init()
//这个方法是重点,在里面去写过滤的条件
void doFilter()
//销毁方法,在结束工程时执行
void destroy()
现在我们来创建MyFilter类来实现这个接口
//记得导包!!
public class MyFilter implements Filter {
@override
public void init() {
}
@override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filter) {
//在这个方法中我们迁移之前写的代码
//首先获取session,这里进行类型转换是因为servletRequset没有getSession()方法
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
HttpSession session = httpServletRequest.getSession();
//过滤
if (session.getAttribute("user") == null) {
//请求转发
servletRequest.getRequsetDispacher("要跳转到的路径").forward(servletRequset, servletResponse);
} else {
//这句代码可以理解为该Filter放行请求,请求继续向服务器的方向行进,关于FilterChain后面解释
filterChain.doFilter(servletRequset, servletResponse);
}
}
@override
public void destory() {
}
}
仅仅写完了接口的实现类和过滤方法并不能起到拦截请求的作用,我们还需要最后一步也就是在web.xml配置文件中配置这个过滤器和拦截地址,拦截地址可以配置多个!
<filter>
<filter-name>MyFilter</filter-name>
<!--这里写的是全类名-->
<filter-class>xxx.xxx.xxx.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<!--这里配置拦截路径,从工程名开始写路径-->
<url-pattern>/xxx/xxx/xxx</url-pattern>
</filter-mapping>
经过以上的步骤,一个基本Filter就写好了,这个Filter可以帮我们实现拦截对配置文件中地址的请求,并根据我们所写的条件去决定是否放行请求。
4.深入Filter
在理解了第三条简单使用Filter之后,我们再来想一想,有时候我们其实会写多个Filter,那么这多个Filter和服务器和客户端的关系又是如何,它们之间又是靠什么连接在一起的呢?在这里我先告诉你答案:服务器,过滤器,客户端之间是通过FilterChain连接的。我们先来看这个示意图。
第一眼看上去是不有点懵,别着急,我先告诉你图中abc的含义,你就会豁然开朗。首先,这幅图描述的是这样一个过程:客户端(浏览器)请求服务器上的某个资源,而中间我们设置了两个过滤器,这两个过滤器全部放行了这个请求,最后服务器响应了客户端的请求。对于在某一个过滤器上就被拦截的请求我们上面已经说了,这个请求被请求转发到别的地方,这里我们不与讨论。关于abc的含义:我们知道Filter真正去起到过滤作用的其实是doFilter方法,a表示doFilter方法中filterChain.doFilter方法之前的代码,c表示doFilter方法中filterChain.doFilter方法之后的代码,而b表示filterChain.doFilter方法。这个图现在就很清楚了:我可以这样去描述这个图——一个经过多个过滤器且没有被过滤掉的请求应该是先去经过Filter1中的a,b,再经过Filter2中的a,b然后到达服务器,服务器将资源响应给客户端,此时客户端可以看到自己请求的资源,然后Filter2的c被执行,然后Filter1的c被执行,图中白色数字表示执行的顺序!那么下一个问题来了,当存在多个过滤器时请求经过过滤器的顺序是怎样呢?答案很简单:这取决于你在web.xml中配置Filter的顺序!