一.基本定义:
过滤器实际上就是对web资源进行拦截,做一些处理后再交给下一个过滤器或servlet处理
通常都是用来拦截request进行处理的,也可以对返回的response进行拦截处理
二.新建一个Filter:
可以直接new一个Filter类.输入过滤器名称,跟创建Servlet一样,这里我们直接使用**@WebFilter**注解,不再去web,xml中进行配置了。创建完成后默认代码,可以看到,CharsetFilter实现了Filter接口,实现了3个方法。3个方法的作用已经在注释中写清楚了。
package com.fym.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(filterName = "CharSetFilter")
public class CharSetFilter implements Filter {// 销毁时调用public void destroy() {}//过滤方法(真正做事的方法) 主要是对request和response进行一些处理,然后交给下一个过滤器或Servlet处理public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {//doFilter()之前是,对请求的过滤chain.doFilter(req, resp);//放行操作,交给下一个过滤器或者是servlet处理//doFilter()之后是,对响应的过滤}//初始化方法 接收一个FilterConfig类型的参数 该参数是对Filter的一些配置public void init(FilterConfig config) throws ServletException {}
}
三.Filter的相关配置(@webFilter):
可配置的属性和常用的配置项:
①urlPatterns
配置要拦截的资源
以指定资源匹配。例如"/index.jsp"
以目录匹配。例如"/servlet/"
以后缀名匹配,例如".jsp"
通配符,拦截所有web资源。"/*"
②initParams
配置初始化参数,跟Servlet配置一样
③.dispatcherTypes (枚举类型)
配置拦截的类型,可配置多个。默认为DispatcherType.REQUEST**
例如
下面是一个最简单的字符编码的过滤器
package com.fym.filter;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import java.io.IOException;
@WebFilter(filterName = "CharSetFilter", urlPatterns = "/*",//通配符(*)表示对所有的web资源进行拦截initParams = {@WebInitParam(name = "charset", value = "utf-8")//这里可以放一些初始化的参数,例如设置编码})
public class CharSetFilter implements Filter {private String filterName;private String charset;// 销毁时调用public void destroy() {System.out.println(filterName + "销毁");}//过滤方法(真正做事的方法) 主要是对request和response进行一些处理,然后交给下一个过滤器或Servlet处理public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {System.out.println(filterName + "doFilter()");//doFilter()之前是,对请求的过滤req.setCharacterEncoding(charset);chain.doFilter(req, resp);//放行操作,交给下一个过滤器或者是servlet处理//doFilter()之后是,对响应的过滤resp.setCharacterEncoding(charset);}//初始化方法 接收一个FilterConfig类型的参数 该参数是对Filter的一些配置public void init(FilterConfig config) throws ServletException {filterName = config.getFilterName();charset = config.getInitParameter("charset");System.out.println("过滤器名称:" + filterName);System.out.println("字符集编码:" + charset);}
}
启动服务器是,执行init()方法
需要注意的是
过滤器是在服务器启动时就会创建的,只会创建一个实例,常驻内存,也就是说服务器一启动就会执行Filter的init(FilterConfig config)方法.
当Filter被移除或服务器正常关闭时,会执行destroy方法
四.多个Filter的执行顺序:
在我们的请求到达Servle之间是可以经过多个Filter的,一般来说,建议Filter之间不要有关联,各自处理各自的逻辑即可。这样,我们也无需关心执行顺序问题。
如果一定要确保执行顺序,就要对配置进行修改了,执行顺序如下
①在web.xml中,filter执行顺序跟的顺序有关,先声明的先执行
②使用注解配置的话,filter的执行顺序跟名称的字母顺序有关,例如AFilter会比BFilter先执行
③如果既有在web.xml中声明的Filter,也有通过注解配置的Filter,那么会优先执行web.xml中配置的Filter
五.设计一个登录校验的过滤器:
①注册过滤器,并设置不需要过滤的资源
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"version="3.1"><filter><filter-name>CheckLoginFilter</filter-name><filter-class>com.fym.filter.CheckLoginFilter</filter-class><!-- 设置不需要过滤的资源 --><init-param><param-name>UnCheckURI</param-name><param-value>/login,/login.jsp</param-value></init-param></filter><filter-mapping><filter-name>CheckLoginFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>
</web-app>
②.servlet,做一个简单的页面跳转,并把登录信息保存到session中
package com.fym.filter;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/login")
public class CheckLoginServlet extends HttpServlet{private static final long serialVersionUID = 1L;protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {//获取请求参数String username = req.getParameter("username");String password = req.getParameter("password");//这里是直接写死的,实际应用中应该是与数据库中的数据作比较if("admin".equals(username)&&"123".equals(password)){//将用户信息添加到session中req.getSession().setAttribute("USER_IN_SESSION", username);}//跳转到welcome.jsp页面中req.getRequestDispatcher("/welcome.jsp").forward(req, resp);}
}
③过滤器代码,判断是否登录
package com.fym.filter;import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;public class CheckLoginFilter implements Filter{//定义一个list,用来存放那些不需要过滤的资源private List<String> list ;@Overridepublic void init(FilterConfig arg0) throws ServletException {//得到初始化参数,并存放到list集合中String unCheckURI = arg0.getInitParameter("UnCheckURI");list = Arrays.asList(unCheckURI.split(","));}@Overridepublic void doFilter(ServletRequest requset, ServletResponse response,FilterChain chain) throws IOException, ServletException {//servletRequest里没有获取请求资源的方法(该方法存在于它的子类中,所以需要进行强转)HttpServletRequest req = (HttpServletRequest) requset;HttpServletResponse resp = (HttpServletResponse) response;// 获取当前客户的发出请求的资源String requestURI = req.getRequestURI();//判断是否有和不需要过滤的资源相等的资源(取反,就是需要进行检查登录的资源)if (!list.contains(requestURI)) {// 登录检查过滤器(先获取session对象,再获取session中的数据)Object obj = req.getSession().getAttribute("USER_IN_SESSION");if (obj == null) {resp.sendRedirect("/login.jsp");return;}}// 放行(这一步是是必须要做的,但是往往会忽略这个,需要牢记)chain.doFilter(req, resp);}@Overridepublic void destroy() {}
}
④.效果:访问/login.jsp和/login资源时,过滤器不做拦截,访问其他资源时,先判断是否登录,登录即可访问,没有登录,即跳转到登录页面.