Filter是什么
Java Web开发中的过滤器(filter)是从Servlet 2.3规范开始增加的功能,并在Servlet 2.4规范中得到增强。对Web应用来说,过滤器是一个驻留在服务器端的Web组件,它可以截取客户端和服务器之间的请求与响应信息,并对这些信息进行过滤。当Web容器接受到一个对资源的请求时,它将判断是否有过滤器与这个资源相关联。如果有,那么容器将把请求交给过滤器进行处理。在过滤器中,你可以改变请求的内容,或者重新设置请求的报头信息,然后再将请求发送给目标资源。当目标资源对请求作出响应时候,容器同样会将响应先转发给过滤器,在过滤器中你可以对响应的内容进行转换,然后再将响应发送到客户端。
和过滤器相关的接口主要有:Filter、FilterConfig和FilterChain。
过滤器 , 其实就是对客户端发出来的请求进行过滤。 浏览器发出, 然后服务器派servlet处理。 在中间就可以过滤, 其实过滤器起到的是拦截的作用。
Filter常见作用
- 对一些敏感词汇进行过滤
2. 统一设置编码
3. 自动登录
4. 对用户的访问请求进行记录和审核、对用户发送的数据进行过滤或替换、转换图象格式、对响 应内容进行压缩以减少传输量、对请求或响应进行加解密处理、触发资源访问事件、对XML的输出应用XSLT等
如何使用Filter
- 定义一个类, 实现Filter
public class FilterDemo implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("来到过虑器了。。。");
chain.doFilter(request, response);
}
public void init(FilterConfig fConfig) throws ServletException {
}
}
- 注册过滤器
在web.xml里面注册,注册的手法与servlet基本一样。
<filter>
<display-name>FilterDemo</display-name>
<filter-name>FilterDemo</filter-name>
<filter-class>com.itheima.filter.FilterDemo</filter-class>
</filter>
<filter-mapping>
<filter-name>FilterDemo</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Filter的生命周期
- 创建
在服务器启动的时候就创建。
- 销毁
服务器停止的时候。
init(FilterConfig):在服务器启动时会创建Filter实例,并且每个类型的Filter只创建一个实例,从此不再创建!在创建完Filter实例后,会马上调用init()方法完成初始化工作,这个方法只会被执行一次;
doFilter(ServletRequest req,ServletResponse res,FilterChain chain):这个方法会在用户每次访问“目标资源(pattern>index.jsp)”时执行,如果需要“放行”,那么需要调用FilterChain的doFilter(ServletRequest,ServletResponse)方法,如果不调用FilterChain的doFilter()方法,那么目标资源将无法执行;
destroy():服务器会在创建Filter对象之后,把Filter放到缓存中一直使用,通常不会销毁它。一般会在服务器关闭时销毁Filter对象,在销毁Filter对象之前,服务器会调用Filter对象的destory()方法。
FilterConfig
Filter接口中的init()方法的参数类型为FilterConfig类型。它的功能与ServletConfig相似,与web.xml文件中的配置信息对应。下面是FilterConfig的功能介绍:
ServletContext getServletContext():获取ServletContext的方法;
String getFilterName():获取Filter的配置名称;与元素对应;
String getInitParameter(String name):获取Filter的初始化配置,与元素对应;
Enumeration getInitParameterNames():获取所有初始化参数的名称。
FilterChain
doFilter()方法的参数中有一个类型为FilterChain的参数,它只有一个方法:doFilter(ServletRequest,ServletResponse)
filterChain.doFilter(request, response); // 放行
Filter执行顺序
-
客户端发出请求,先经过过滤器, 如果过滤器放行,那么才能到servlet
-
如果有多个过滤器, 那么他们会按照注册的映射顺序 来 排队。 只要有一个过滤器, 不放行,那么后面排队的过滤器以及咱们的servlet都不会收到请求。
Filter细节:
-
init方法的参数 FilterConfig , 可以用于获取filter在注册的名字 以及初始化参数。 其实这里的设计的初衷与ServletConfig是一样的。
-
如果想放行,那么在doFilter 方法里面操作,使用参数 chain
chain.doFilter(request, response); 放行, 让请求到达下一个目标。
-
< url-pattern > /* < /url-pattern > 写法格式与servlet一样。
全路径匹配 以 / 开始
/LoginServlet
-
以目录匹配 以 / 开始 以 * 结束
/demo01/*
-
以后缀名匹配 以 * 开始 以后缀名结束
*.jsp *.html *.do
-
针对 dispatcher 设置
REQUEST : 只要是请求过来,都拦截,默认就是REQUEST FORWARD : 只要是转发都拦截。 ERROR : 页面出错发生跳转 INCLUDE : 包含页面的时候就拦截。
Filter自动登录案例
- 需求分析
1. 搭建环境
-
搭建数据库
-
搭建页面
###登录servlet代码
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
String userName = request.getParameter("username");
String password = request.getParameter("password");
String autoLogin = request.getParameter("auto_login");
UserBean user = new UserBean();
user.setUsername(userName);
user.setPassword(password);
UserDao dao = new UserDaoImpl();
UserBean userBean = dao.login(user);
if(userBean != null){
//成功了,进入首页
request.getSession().setAttribute("userBean", userBean);
response.sendRedirect("index.jsp");
}else{
//不成功...
request.getRequestDispatcher("login.jsp").forward(request, response);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
##过滤器代码
过滤器的核心不是完成拦截不给 , 还是放行显示。 它的核心是在放行之前,帮用户完成登录的功能。
- 实现思路
-
先判断session是否有效, 如果有效,就不用取cookie了,直接放行。
-
如果session失效了,那么就取 cookie。
-
没有cookie 放行
-
有cookie
取出来cookie的值,然后完成登录
把这个用户的值存储到session中
放行。
-
/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest req, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
HttpServletRequest request = (HttpServletRequest) req;
//先判断,现在session中还有没有那个userBean.
UserBean userBean = (UserBean) request.getSession().getAttribute("userBean");
//还有,有效。
if(userBean != null){
chain.doFilter(request, response);
}else{
//代表session失效了。
//2. 看cookie。
//1. 来请求的时候,先从请求里面取出cookie , 但是cookie有很多的key-value
Cookie[] cookies = request.getCookies();
//2. 从一堆的cookie里面找出我们以前给浏览器发的那个cookie
Cookie cookie = CookieUtil.findCookie(cookies, "auto_login");
//第一次来
if(cookie == null){
chain.doFilter(request, response);
}else{
//不是第一次。
String value = cookie.getValue();
String username = value.split("#")[0];
String password = value.split("#")[1];
//完成登录
UserBean user = new UserBean();
user.setUsername(username);
user.setPassword(password);
UserDao dao = new UserDaoImpl();
userBean = dao.login(user);
//使用session存这个值到域中,方便下一次未过期前还可以用。
request.getSession().setAttribute("userBean", userBean);
chain.doFilter(request, response);
}
}
} catch (Exception e) {
e.printStackTrace();
chain.doFilter(req, response);
}
}
编码过滤器的例子
@WebFilter(urlPatterns = { "*" },
initParams = {@WebInitParam(name="encoding", value="utf-8")})
public class CodingFilter implements Filter {
private String defaultEncoding = "utf-8";
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
req.setCharacterEncoding(defaultEncoding);
resp.setCharacterEncoding(defaultEncoding);
chain.doFilter(req, resp);
}
@Override
public void init(FilterConfig config) throws ServletException {
String encoding = config.getInitParameter("encoding");
if (encoding != null) {
defaultEncoding = encoding;
}
}
}
下载计数过滤器的例子
@WebFilter(urlPatterns = {"/*"})
public class DownloadCounterFilter implements Filter {
private ExecutorService executorService = Executors.newSingleThreadExecutor();
private Properties downloadLog;
private File logFile;
@Override
public void destroy() {
executorService.shutdown();
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
final String uri = request.getRequestURI();
executorService.execute(new Runnable() {
@Override
public void run() {
String value = downloadLog.getProperty(uri);
if(value == null) {
downloadLog.setProperty(uri, "1");
}
else {
int count = Integer.parseInt(value);
downloadLog.setProperty(uri, String.valueOf(++count));
}
try {
downloadLog.store(new FileWriter(logFile), "");
}
catch (IOException e) {
e.printStackTrace();
}
}
});
chain.doFilter(req, resp);
}
@Override
public void init(FilterConfig config) throws ServletException {
String appPath = config.getServletContext().getRealPath("/");
logFile = new File(appPath, "downloadLog.txt");
if(!logFile.exists()) {
try {
logFile.createNewFile();
}
catch(IOException e) {
e.printStackTrace();
}
}
downloadLog = new Properties();
try {
downloadLog.load(new FileReader(logFile));
} catch (IOException e) {
e.printStackTrace();
}
}
}