概述
1.过滤器的概念
过滤器是一个服务器端的组件,它可以拦截客户端的请求和响应信息,并对这些信息进行过滤。
Servlet API中提供了一个Filter接口,如果编写额类实现了这个接口,则称这个类为过滤器。Filter接口源码如下:
package javax.servlet;
import java.io.IOException;
public interface Filter {
public void init(FilterConfig filterConfig) throws ServletException;
public void doFilter ( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException;
public void destroy();
}
可以看到,接口里有三个抽象方法,分别是init(),doFilter()和destory(),下面我们来详细说一说这三个方法。
2.过滤器的生命周期
- 实例化———————————————–web.xml
- 初始化———————————————–init()
- 执行过滤——————————————–doFilter()
- 销毁————————————————–destory()
1.实例化:在web.xml中对过滤器进行配置和映射,也可以使用注解@WebFilter。下面是一种web.xml的示例
<!--配置过滤器-->
<filter>
<filter-name>FilterTest</filter-name>
<filter-class>com.codeliu.FilterTest</filter-class>
</filter>
<!--映射过滤器-->
<filter-mapping>
<filter-name>FilterTest</filter-name>
<!--“/*”表示拦截所有的请求 -->
<url-pattern>/*</url-pattern>
<dispatcher></dispatcher>
</filter-mapping>
在映射过滤器的时候,有一个dispatcher参数,在Servlet2.5中有四个取值,分别为REQUEST|INCLUDE|FORWARD|ERROR,不填时默认为REQUEST。下面分别来介绍一下这四个参数的作用
REQUEST:当用户直接访问页面时,web容器将会调用过滤器,如果目标资源是通过请求转发(request.getRequestDisPatcher)的include方法或forward方法进行访问,那么该过滤器就不会被调用。
INCLUDE:如果目标资源是通过request.getRequestDisPatcher的include方法进行访问,那么该过滤器将会被调用,其他情况下,不会被调用。
FORWAED:如果目标资源是通过request.getRequestDisPatcher的forward方法进行访问,那么该过滤器将会被调用,其他情况下,不会被调用。
ERROR:如果目标资源是通过声明或异常处理机制调用,那么该过滤器将会被调用,除此之外,不会被调用。
下面是通过注解的方式
@WebFilter(urlPatterns = {"/*"},
initParams = {@WebInitParam(name = "noFilterPath", value = "login.jsp;LoginServlet;fail.jsp", description = "不触发该过滤器的页面"), @WebInitParam(name = "charset", value = "UTF-8")})
2.初始化:web容器创建过滤器实例后将调用init方法,这个方法的参数FilterConfig对象可以获取web.xml文件中过滤器的初始化参数。在Filter的生命周期中,只会初始化一次。
3.执行过滤:这个方法完成实际的过滤操作,当用户访问的URL与web.xml中url-pattern配置的值一样时,就触发这个过滤器,web容器会先调用过滤器,过滤器会调用doFilter方法,这个方法的参数FilterChain对象可以调用doFilter方法,将请求传给下一个过滤器(过滤器链的情况下)或目标资源,也可以利用重定向或转发的方式将请求转发到其他资源。在Filter的生命周期中,可以执行0到n次过滤。
4.销毁:web容器在销毁过滤器实例前调用这个方法(比如stop tomcat),在这个方法中可以释放过滤器占用的资源。在Filter的生命周期中,只会进行一次销毁。
3.过滤器的执行过程
上图是一个过滤器链的执行过程,所谓过滤器链,就是当多个过滤器的URL相同时,就形成了过滤器链。那么在过滤器链里每个过滤器的执行顺序是怎么样的呢?有两种情况:
- 如果你是在web.xml中配置的过滤器,那么执行时就按照你配置的顺进行执行。
- 如果你是通过注解的方式配置的过滤器,那么执行时就按照首字母的大小进行执行,首字母相同看第二个字母。比如我在过滤器链里一个过滤器为TestFilter,一个过滤器为MyFilter,那显然先执行MyFilter再执行TestFilter。
4.过滤器是怎么进行过滤的?
Filter接口中有一个doFilter方法,每个过滤器都会实现Filter接口,所以每个过滤器都得重写doFilter方法。那么我们就可以在这个方法中编写代码达到以下目的:
- 调用目标资源之前,执行某些功能
- 是否调用目标资源(即是否让用户访问web资源)
- 调用目标资源之后,执行某些功能
过滤全过程:
说明一下,在Filter接口中的doFilter方法,形式如下
public void doFilter ( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException;
如果我们想让用户访问他请求的wen资源,就在doFilter方法中使用如下语句
chain.diFilter(request, response);
使用了该语句,就相当于放行,允许用户访问他想访问的资源,反之就是不允许用户访问。
5.用户登录使用过滤器的小案例
先大致说一下过程。首先是用户输入用户名密码,提交到一个Servlet,我们在这个Servlet的doPost方法里判断用户输入的用户名和密码是否匹配,匹配则跳转到登录成功界面,否则跳转到登录失败界面。那么过滤器在这个过程中起了什么作用呢?我们设想一下,如果用户直接输入登录成功界面的网址,那它是否直接就跳转到了登陆成功界面?或者他输入了其他页面的网址,而这些网址只有用户登录了,才可以进行访问,那又该怎么办呢?我们就可以使用过滤器,如果用户输入了这些网址,我们就进行过滤,跳转到登录界面。
// login.jsp
<form action = "servlet/LoginServlet" method = "post">
用户名:<input type = "text" name = "username">
密 码:<input type = "password" name = "password">
<input type = "submit" value = "submit">
</form>
登录界面,一个简单的form表单,将结果发送到Servlet包下的LoginServlet。
// success.jsp
欢迎您,<font color="red">${username}</font>
登录成功页面
// fail.jsp
登陆失败,请检查用户名和密码!
登录失败页面
// LoginServlet里面的doPost方法
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
if("admin".equals(username) && "admin".equals(password)) {
request.getSession().setAttribute("username", username);
//request.getRequestDispatcher(request.getContextPath() + "/success.jsp");
response.sendRedirect(request.getContextPath() + "/success.jsp");
} else {
response.sendRedirect(request.getContextPath() + "/fail.jsp");
}
}
@WebFilter(urlPatterns = {"/*"}, initParams = {@WebInitParam(name = "noFilterPath", value = "login.jsp;LoginServlet;fail.jsp", description = "不触发该过滤器的页面"), @WebInitParam(name = "charset", value = "UTF-8")})
public class LoginFilter implements Filter {
// 定义此对象,可以获取初始化参数等
private FilterConfig config;
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse res = (HttpServletResponse)response;
HttpSession session = req.getSession();
// 获取初始化参数中的路径
String paths = config.getInitParameter("noFilterPath");
// 获取字符编码
String charSet = config.getInitParameter("charset");
if(charSet == null) {
charSet = "UTF-8";
}
// 设置字符编码
req.setCharacterEncoding(charSet);
if(paths != null) {
// 将路径进行分割
String[] path = paths.split(";");
for(String s:path) {
if(s == null || "".equals(s)) {
continue;
}
// 初始化参数中的路径在请求路径中
if(req.getRequestURI().indexOf(s) != -1) {
chain.doFilter(request, response);
return;
}
}
}
// 防止直接输入success.jsp进入success.jsp页面
if(session.getAttribute("username") != null) {
// 如果用户登陆了,放行
chain.doFilter(request, response);
} else {
res.sendRedirect(req.getContextPath() + "/login.jsp");
}
}
public void init(FilterConfig fConfig) throws ServletException {
config = fConfig;
}
}
在Filter的配置中,URL我们使用的是/*,表示匹配所有页面,然后我们又使用了一些初始化参数,通过init方法里的FilterConfig对象获取。可以看到初始化参数里有fail.jsp,login.jsp等,我们获取这些参数后,进行一个判断,如果用户访问的是这些页面,则直接放行。所有该过滤器的功能就是过滤除了初始化参数里其他的所有页面。大家可以想一想为啥这些页面不能进行过滤。
好了,总结到此结束。
最后
以上就是危机鸵鸟为你收集整理的Java Web之过滤器总结的全部内容,希望文章能够帮你解决Java Web之过滤器总结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复