过滤器实际上就是对web资源进行拦截,作一些处理后再交给下一个过滤器或servlet处理
一般都是用来拦截request进行处理的,也能够对返回的response进行拦截处理java
大概流程图以下web
应用场景
自动登陆
统一设置编码格式
访问权限控制
敏感字符过滤等服务器
在Servlet中咱们通常都会对request和response中的字符集编码进行配置,若是Servlet过多字符集编码发生变化时修改起码会很麻烦,这些通用的字符集编码配置等工做咱们能够放到Filter中来实现。
下面咱们来建立一个处理字符集编码的Filter。cookie
右键包名—>new ---->Filterapp
输入过滤器名称,跟建立Servlet同样,这里咱们直接使用**@WebFilter**注解,再也不去web,xml中进行配置了。异步
建立完成后默认代码,能够看到,CharsetFilter实现了Filter接口,实现了3个方法。3个方法的做用已经在注释中写清楚了。jsp
package filter; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; @WebFilter(filterName = "CharsetFilter") public class CharsetFilter implements Filter { public void destroy() { /*销毁时调用*/ } public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { /*过滤方法 主要是对request和response进行一些处理,而后交给下一个过滤器或Servlet处理*/ chain.doFilter(req, resp);//交给下一个过滤器或servlet处理 } public void init(FilterConfig config) throws ServletException { /*初始化方法 接收一个FilterConfig类型的参数 该参数是对Filter的一些配置*/ } }
可配置的属性有这些svg
经常使用配置项
urlPatterns
配置要拦截的资源网站
"/index.jsp"
"/servlet/*"
"*.jsp"
"/*"
**initParams **
配置初始化参数,跟Servlet配置同样编码
例如
initParams = { @WebInitParam(name = "key",value = "value") }
dispatcherTypes **
配置拦截的类型,可配置多个。默认为DispatcherType.REQUEST**
例如
dispatcherTypes = {DispatcherType.ASYNC,DispatcherType.ERROR}
其中DispatcherType是个枚举类型,有下面几个值
FORWARD,//转发的 INCLUDE,//包含在页面的 REQUEST,//请求的 ASYNC,//异步的 ERROR;//出错的
下面咱们来对CharsetFilter 代码进行一下修改
package 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 + "销毁"); } public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { /*过滤方法 主要是对request和response进行一些处理,而后交给下一个过滤器或Servlet处理*/ System.out.println(filterName + "doFilter()"); req.setCharacterEncoding(charset); resp.setCharacterEncoding(charset); chain.doFilter(req, resp); } public void init(FilterConfig config) throws ServletException { /*初始化方法 接收一个FilterConfig类型的参数 该参数是对Filter的一些配置*/ filterName = config.getFilterName(); charset = config.getInitParameter("charset"); System.out.println("过滤器名称:" + filterName); System.out.println("字符集编码:" + charset); } }
这样一个简单的字符集编码处理的过滤器就完成了
咱们看看执行打印的结果
须要注意的是
过滤器是在服务器启动时就会建立的,只会建立一个实例,常驻内存,也就是说服务器一启动就会执行Filter的init(FilterConfig config)方法.
当Filter被移除或服务器正常关闭时,会执行destroy方法
在咱们的请求到达Servle之间是能够通过多个Filter的,通常来讲,建议Filter之间不要有关联,各自处理各自的逻辑便可。这样,咱们也无需关心执行顺序问题。
若是必定要确保执行顺序,就要对配置进行修改了,执行顺序以下
<filter-mapping>
的顺序有关,先声明的先执行咱们写个小例子看一下
新建3个Filter,加上以前的CharsetFilter一共四个
其中CharsetFilter和ABFilter是经过注解声明的
CharsetFilter注解配置
@WebFilter(filterName = "CharsetFilter", urlPatterns = "/*",/*通配符(*)表示对全部的web资源进行拦截*/ initParams = { @WebInitParam(name = "charset", value = "utf-8")/*这里能够放一些初始化的参数*/ })
ABFilter
@WebFilter(filterName = "ABFilter",urlPatterns = "/*")
AFilter和BFilter是在web.xml配置的。
执行顺序跟<filter>
的顺序无关
<filter-mapping>
的顺序才决定执行顺序
<?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_4_0.xsd" version="4.0"> <filter> <filter-name>AFilter</filter-name> <filter-class>filter.AFilter</filter-class> </filter> <filter> <filter-name>BFilter</filter-name> <filter-class>filter.BFilter</filter-class> </filter> <!--这里BFilter在AFilter以前--> <filter-mapping> <filter-name>BFilter</filter-name> <url-pattern>/filter.jsp</url-pattern> </filter-mapping> <filter-mapping> <filter-name>AFilter</filter-name> <url-pattern>/filter.jsp</url-pattern> </filter-mapping> </web-app>
每一个Filter添加了打印语句,以下
以ABFilter为例
package filter; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; @WebFilter(filterName = "ABFilter",urlPatterns = "/*") public class ABFilter implements Filter { private String filterName; public void destroy() { } public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { System.out.println(filterName + " doFilter()"); chain.doFilter(req, resp); } public void init(FilterConfig config) throws ServletException { filterName= config.getFilterName(); System.out.println("过滤器名称:" + filterName +" init"); } }
下面咱们来访问filter.jsp看看打印结果
能够看到,执行结果符合预期。
BFilter和AFilter是在web.xml中声明的,且BFilter的<filter-mapping>
在前,故BFilter在AFilter以前执行。
ABFilter和CharsetFilter是经过注解声明的,故他俩在BFilter和AFilter以后执行,可是ABFilter的名称以A开头,故在CharsetFilter以前执行
下面咱们写一个访问控制权限控制的小例子。
咱们在浏览一些网站常常有这个状况,没有登陆时是不容许咱们访其主页的,只有登陆事后才能访问。
下面咱们就用Filter简单实现一下。
需求分析
咱们先来看一下项目结构
这里主要看一下LoginFilter的代码
咱们在LoginFilter中对非登陆页面的其余jsp都会进行过滤,判断cookie中是否携带了account和pwd。
若是有这两个数据表示以前登陆过,那么对数据进行校验,正确的话就进行下一个操做。
不然的话,跳转到登陆界面
package filter; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebFilter(filterName = "LoginFilter", urlPatterns = "*.jsp", dispatcherTypes = {}) public class LoginFilter implements Filter { public void destroy() { } public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { System.out.println("LoginFilter doFilter"); HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; String url = request.getRequestURI(); System.out.println("请求的url:" + url); /*登陆页面不须要过滤*/ int idx = url.lastIndexOf("/"); String endWith = url.substring(idx + 1); if (!endWith.equals("login.jsp")) { /*不是登陆页面 进行拦截处理*/ System.out.println("不是登陆页面,进行拦截处理"); if (!isLogin(request)) { System.out.println("没有登陆过或者帐号密码错误,跳转到登陆界面"); response.sendRedirect("login.jsp"); } else { System.out.println("已经登陆,进行下一步"); chain.doFilter(req, resp); } } else { System.out.println("是登陆页面,不进行拦截处理"); chain.doFilter(req, resp); } } private boolean isLogin(HttpServletRequest request) { Cookie[] cookies = request.getCookies(); String account = ""; String pwd = ""; if (cookies != null && cookies.length > 0) { for (Cookie cookie : cookies) { if (cookie.getName().equals("account")) { account = cookie.getValue(); } else if (cookie.getName().equals("pwd")) { pwd = cookie.getValue(); } } } if (account.equals("") || pwd.equals("")) { return false; } else if (account.equals("yzq") && pwd.equals("123")) { return true; } return false; } public void init(FilterConfig config) throws ServletException { System.out.println("LoginFilter init"); } }
执行效果
能够看到,咱们在没有登陆的状况下直接去访问index.jsp页面时会自动跳转到登陆页面,在登陆成功后,再次直接访问index页面则能够访问。