Filter过滤器简介
Filter是拦截Request请求的对象, 在用户的请求访问到目标资源之前处理request和response,它可以用于日志记录/加密解密/Session检查/文件保护.通过Filter可以拦截处理某个或者某些资源
Filter的配置可以通过注解或者部署在web.xml中来完成,一般情况下来说要访问到一个资源要部署很多的Filter,除非对Filter的触发顺序有要求,否则都可以使用注解来配置Filter
所有过滤器都应该实现Filter接口,接口定义了init(),doFilter(),distory()三个方法
1.init(FilterConfig filterConfig)
在Web程序启动时根据web.xml中的配置信息创建Filter实例化对象并保存在服务器端的内存中,同时调用Filter的init()方法,初始化方法在一个Filter对象的生命周期中只会被调用一次,init()方法在被调用的时候会传递一个包含Filter配置和运行环境的FilterConfig对象,以用来部署Filter的初始化参数.
2.doFilter(ServletRequest request,ServletResponse response,FilterChain chain)
在客户端请求服务器资源的时候, 容器就会调用和目标资源相关联过滤器的doFilter()方法,方法中的request和response是上一个Filter传递过来的请求/响应对象,chain参数代表当前的Filter链对象,在当前Filter指定的操作执行完后,在doFilter()方法中调用FilterChain对象的doFilter方法。之后请求会被交给Filter链的下一个Filter去继续处理。如果当前的Filter是Filter链的最后一个Filter。那么就会直接执行目标Servlet,也可以直接向客户端返回响应信息,或者利用RequestDispatcher的forward()和include()方法,以及 HttpServletResponse的sendRedirect()方法将请求转向到其他资源。 反之:如果Filter链中任意一个doFilter()方法在执行的过程中出现了错误,那么将不会继续执行接下来Filter中的doFIlter方法, 过滤器的使用并不会依赖具体的协议
3.destory()
在容器销毁Filter对象之前被调用,在一个Filter的生命周期里只会被执行一次,同时可以释放过滤器使用的资源
4.1:配置Filter注意事项
1.确认需要拦截的Servlet
2.确认初始化的参数值,例如日志过滤器文件名,日志前缀等。这些属性可以在Filter的初始化时通过调用filterConfig.getInitParameter(“web.xml中配置的参数名称”)来获得
3.起好Filter的名字,一般来说一个页面都会有很多Filter,所以便于区分
4.2:Filter的xml配置
Filter的xml配置类似于Servlet的配置
首先需要配置一个Filter
<filter>
<--Filter的名字,这个Filter是用来记访问的记录的-->
<filter-name>AccessFilter</filter-name>
<--Filter实现类的具体位置-->
<filter-class>com.dxy.web.filter.AccessFilter</filter-class>
<--对该Filter加上一些初始化参数,在Web程序启动的时候这些参数会自动被部署好-->
<--例如我需要写一个访问记录器,那么我可以配置一个日志文件的文件名-->
<init-param>
<param-name>FileName</param-name>
<param-value>filter.logging</param-value>
</init-param>
<--再加上一个日志的前缀-->
<init-param>
<param-name>prefix</param-name>
<param-value>Request:</param-value>
</init-param>
</filter>
现在Filter配置好了,需要把Filter放在指定的Servlet上
<--Filter映射到Servlet上-->
<filter-mapping>
<--要映射的Filter的名字-->
<filter-name>AccessFilter</filter-name>
<!-- 访问过滤 -->
<servlet-name>AccessServlet</servlet-name>
</filter-mapping>
Hmmm......直白点来说意思就是每当这个叫做AccessServlet的Servlet要处理访问请求的时候都会先执行这个Filter中doFilter的内容。而这个Filter中会记录下用户访问的请求
注:在Filter映射的过程中也可以根据URL进行拦截
<url-pattern>/xxx</url-pattern><url-pattern>/xxx</url-patt
这样Filter也会将处理该地址的Servlet进行拦截
4.3:Filter实现类
package com.dxy.web.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
//所有的Filter实现累都要实现Filter接口
public class AccessFilter implements Filter {
//输出流记录日志
private PrintWriter logger;
//Filter初始化参数中的前缀名称
private String prefix;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//获取前缀名称
prefix = filterConfig.getInitParameter("prefix");
//获取日志文件名
String filename = filterConfig.getInitParameter("FileName");
//获取应用的运行时位置
String Path = filterConfig.getServletContext().getRealPath("/");
try {
File file = new File(Path, filename);
file.createNewFile();
logger = new PrintWriter(file);
} catch (FileNotFoundException e) {
throw new ServletException(e.getMessage());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("UTF-8");
//因为处理的是Http请求,所以这里要进行类型转换
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
//获取请求的URI
String host = httpServletRequest.getRemoteHost();
String uri = httpServletRequest.getRequestURI();
//打印出的访问日志信息
String in =new String ((new Date() + " " + prefix + uri+" host:"+host
+ " Port:"+request.getRemotePort()).getBytes("ISO-8859-1"),"UTF-8");
logger.println(in);
//打印一次刷新一次,不能关闭输出流
logger.flush();
//继续下一个Filter
chain.doFilter(request, response);
}
@Override
public void destroy() {
if (logger != null) {
logger.close();
}
}
}
这样子一个简单的Filter就算是写好了,只要Filter映射到的Servlet接受到访问请求,访问的记录就会被记录下来。
会有后续,仅供个人学习使用。