关于Filter
Filter是服务器端的组件,用来过滤web请求。流程是这样的,当一个web请求进来时,web容器会先检查请求的URL是否设置了Filter,如果设置了,则执行该Filter的doFilter方法。所有Filter都实现了javax.servlet.Filter接口,doFilter是定义在该接口中的最重要的方法。
最常见的使用过滤器的例子有:登录验证(有些页面只有登录了才能访问),错误日志记录(网站运行出现错误时记录下错误日志),编码转换等。
如果对一个URL设置了多个Filter,那么这些Filter会形成一个过滤链,对过滤链的处理其实是责任链模式,请参见我的博客五分钟一个设计模式之责任链模式
登录验证示例代码
今天我用一个验证登录例子,让大家对Filter(过滤器)有一个初步的认识。本例包含一个index.jsp页面,一个login.jsp页面,一个LoginFilter。我在配置文件中指定将LoginFilter用于index.jsp,当用户访问index.jsp页面时,如果未登录,则重定向到login.jsp进行登录。
新增一个index.jsp页面
代码如下:
Insert title here
欢迎访问主页
新增一个login.jsp页面
Insert title here
请登录
新增一个LoginFilter类
新增一个LoginFilter类,实现javax.servlet.Filter接口,在doFilter方法中验证session是否包含username属性,如果不包含,则重定向到login.jsp中。代码如下:
package com.zdk.test;
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;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class LoginFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest=(HttpServletRequest)request;
HttpServletResponse httpResponse=(HttpServletResponse)response;
HttpSession session=httpRequest.getSession();
if(session.getAttribute("username")!=null){
chain.doFilter(request, response);
}
else{
httpResponse.sendRedirect(httpRequest.getContextPath()+"/login.jsp");
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}
配置Filter
在web.xml中,将LoginFilter应用于index.jsp页面
HelloWorld
index.html
index.htm
index.jsp
default.html
default.htm
default.jsp
loginFilter
com.zdk.test.LoginFilter
loginFilter
/index.jsp
然后,发布站点,启动tomcat,在浏览器中输入localhost:8080:{projectname}/index.jsp,将{projectname}换成你的web projet的项目名称,页面将会重定向到login.jsp中,因为在index.jsp页面中我们读取不到登录信息。
将LoginFilter用于多个页面
如果顺利的话,到这里我们的LoginFilter已经能够完成工作了。但是我们不可能只对一个页面进行登录验证,也不可能对所有的页面都进行登录验证,如何灵活地设置呢?
我们要修改登录验证的范围,对除了login.jsp,page2.jsp以外的所有页面都进行登录验证。首先,我们修改web.xml
loginFilter
com.zdk.test.LoginFilter
passUrl
login.jsp;page2.jsp;
loginFilter
/*
我们为loginFilter指定了一个passUrl的参数,然后将该过滤器的url-pattern设置为/*。这样做的意思是,loginFilter将被用于所有请求,除了写在passUrl中的。当然,忽略的逻辑需要我们自己实现。下面是修改好的LoginFilter类
package com.zdk.test;
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;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class LoginFilter implements Filter {
@Override
public void destroy() {
}
String passUrl = "";
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String[] strArray = passUrl.split(";");
for (String str : strArray) {
if (str.equals(""))
continue;
if (httpRequest.getRequestURL().indexOf(str) >= 0) {
chain.doFilter(request, response);
return;
}
}
HttpSession session = httpRequest.getSession();
if (session.getAttribute("username") != null) {
chain.doFilter(request, response);
} else {
httpResponse.sendRedirect(httpRequest.getContextPath() + "/login.jsp");
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
passUrl = arg0.getInitParameter("passUrl");
}
}
首先在init方法中读取我们设置的passUrl,保存到变量中。如果当前请求的URL包含在了passURL中,则不对其进行登录校验。