概述
起到在 客户端 和 服务器端的资源 中间对 请求和响应 进行处理的作用。
当客户端请求资源的时候,过滤器将这个请求拦截下来,完成一些特殊的功能。
当服务器资源响应的时候,将响应拦截,完成一些特殊的功能,处理后返回给前台。
一般用于完成 通用 的操作,如:登录验证、统一编码处理、敏感字符过滤
使用
- 需要实现 Filter 接口
- 配置web.xml 或者使用 @WebFilter() 注解进行配置
@WebFilter("/*") //“/*”表示所有页面都要经过这个过滤器
public class FilterDemo1 implements Filter {//需要实现这个接口
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//服务器启动时,服务器会自动调用Filter对象执行init方法
//一般用于加载资源
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("doFilter1");
filterChain.doFilter(servletRequest, servletResponse);//放行让其访问资源或交给下一个过滤器处理
System.out.println("doFilter2");
}
@Override
public void destroy() {
//服务器关闭时,服务器会自动调用Filter对象执行destroy方法
//一般用于释放资源
}
}
上面的注解配置和doFilter方法中的代码就表示,所有请求都会被这个过滤器拦截,拦截之后,先会打印doFilter1,让后放行请求,让它请求资源,执行完请求的资源中的代码之后,会打印doFilter2
比如,我在index.jsp 中加了一行java代码 让它打印index.jsp,然后启动服务器,访问这个页面,控制台的打印输出如下
关于init();destroy()两个方法的基本理解我也写在上面代码块的注释中了。
配置详解
配置拦截路径
这里我全部都用注解的方式来配置了, 用web.xml配置的方式和配置Servlet的方式很像,可以去网上查看
@WebFilter("/index.jsp") //表示执行index.jsp时才会拦截
@WebFilter("/user/") //表示执行/user下的资源时拦截
@WebFilter("/*") //表示所有资源都拦截
@WebFilter("*.jsp") //表示所有后缀为jsp的资源都拦截
这里详细说一下第二种配置方式
你可以创建一个Servlet 在其配置中的地址前面加上/user即可
如下面这种情况,在请求/user/ServletDemo1的时候就会触发上面第二种配置的过滤器。
@WebServlet("/user/ServletDemo1")
public class ServletDemo1 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
配置拦截方式
配置之后,资源在固定的被访问方式访问时才会被拦截
比如:配置了重定向,那么只有资源在被重定向访问时,才会被拦截。
同样,这里也只讲解注解形式的配置
我们需要在注解中设置dispatcherTypes属性
它有以下5个值,这五个值是枚举类型的
- 1、REQUEST:请求访问资源,默认为这个
- 2、FORWARD:转发访问资源
- 3、INCLUDE:包含访问资源
- 4、ERROR:错误跳转资源
- 5、ASYNC:异步访问资源
//表示浏览器请求所有资源时,会被拦截
@WebFilter(value = "/*", dispatcherTypes = DispatcherType.REQUEST)
//表示请求转发访问所有资源时,会被拦截
@WebFilter(value = "/*", dispatcherTypes = DispatcherType.FORWARD)
//表示 浏览器请求所有资源 或者 请求转发访问所有资源 时,都会被拦截
@WebFilter(value = "/*", dispatcherTypes = {DispatcherType.FORWARD, DispatcherType.REQUEST})
//如果浏览器直接请求一个servlet,而这个servlet转发到了一个jsp页面,则上面这个过滤器执行两次。即请求一次,转发一次
多个过滤器
如果有多个过滤器拦截同一个请求,那么哪一个先拦截呢?
注解配置的情况下,根据过滤器名字怕排序执行,即过滤器A在B之前执行
web.xml的情况下,根据配置的先后顺序, filter-mapping 谁在上面谁先执行
登录过滤器
主要是实现识别用户有没有登录,登录了的话可以访问资源,没有登录的话则访问除登录页面以外的资源都跳转到登录页面
这里主要写一下思路,没有做具体实现
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest) request; //doFilter方法中的请求和响应对象都是ServletRequest,ServletResponse类型的,这里需要强转一下来获取
String uri = req.getRequestURI();//返回除去host(域名或者ip)部分的路径
//如果获取到的路径包含这以下几个:登录页面、登录的servlet、css样式、js代码、验证码实现类,则不拦截放行,如果少了哪个的话,页面会显示不完整,过滤器就会把没有写到下面的资源给拦截了
if(uri.contains("login.jsp") || uri.contains("/LoginServlet") || uri.contains("/css/") || uri.contains("/image/") || uri.contains("/CheckCode")){
//包含登录的资源
//放行
chain.doFilter(request, response);
}else {
//不包含
//说明请求的不是登录页面,此时要判断用户登没登陆来确定给不给他访问资源
Object user = req.getSession().getAttribute("user");//这里是登录返回过来的User实体类对象
if (user == null) {
//user为null说明没登陆
//要跳转到登录页面
}else {
//否则说明用户登录了
//放行
chain.doFilter(request, response);
}
}
}