过滤器(Filter)
过滤器实际上就是对web资源进行拦截,做一些处理后再交给下一个过滤器或servlet处理
通常都是用来拦截request进行处理的,也可以对返回的进行拦截处理
大概流程图如下
应用场景
自动登录
统一设置编码格式
访问权限控制
敏感字符过滤等
创建Filter
在Servlet中我们一般都会对request和中的字符集编码进行配置,如果Servlet过多字符集编码发生变化时修改起码会很麻烦,这些通用的字符集编码配置等工作我们可以放到Filter中来实现。
下面我们来创建一个处理字符集编码的Filter。
右键包名—>new ---->Filter
输入过滤器名称,跟创建Servlet一样,这里我们直接使用 @ 注解,不再去web,xml中进行配置了。
创建完成后默认代码,可以看到,实现了Filter接口,实现了3个方法。3个方法的作用已经在注释中写清楚了。
package filter;
import javax.servlet.*;
import javax.servlet..;
import java.io.;
@( = “”)
public class 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的一些配置*/
}
配置Filter
可配置的属性有这些
常用配置项
配置要拦截的资源
以指定资源匹配。例如"/index.jsp"以目录匹配。例如"/servlet/*"以后缀名匹配,例如"*.jsp"通配符,拦截所有web资源。"/*"
** **
配置初始化参数,跟Servlet配置一样
例如
initParams = {
@WebInitParam(name = "key",value = "value")
}
**
配置拦截的类型,可配置多个。默认为.REQUEST**
例如
dispatcherTypes = {DispatcherType.ASYNC,DispatcherType.ERROR}
其中是个枚举类型,有下面几个值
FORWARD,//转发的
INCLUDE,//包含在页面的
REQUEST,//请求的
ASYNC,//异步的
ERROR;//出错的
下面我们来对 代码进行一下修改
package filter;
import javax.servlet.*;
import javax.servlet..;
import javax.servlet..;
import java.io.;
@( = “”,
= "/",/通配符()表示对所有的web资源进行拦截/
= {
@(name = “charset”, value = “utf-8”)/这里可以放一些初始化的参数/
})
public class Filter {
private String ;
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( config)方法.
当Filter被移除或服务器正常关闭时,会执行destroy方法
多个Filter的执行顺序
在我们的请求到达Servle之间是可以经过多个Filter的,一般来说,建议Filter之间不要有关联,各自处理各自的逻辑即可。这样,我们也无需关心执行顺序问题。
如果一定要确保执行顺序,就要对配置进行修改了,执行顺序如下
在web.xml中,filter执行顺序跟的顺序有关,先声明的先执行使用注解配置的话,filter的执行顺序跟名称的字母顺序有关,例如AFilter会比BFilter先执行如果既有在web.xml中声明的Filter,也有通过注解配置的Filter,那么会优先执行web.xml中配置的Filter
我们写个小例子看一下
新建3个Filter,加上之前的一共四个
其中和是通过注解声明的
注解配置
@WebFilter(filterName = "CharsetFilter", urlPatterns = "/*",/*通配符(*)表示对所有的web资源进行拦截*/ initParams = { @WebInitParam(name = "charset", value = "utf-8")/*这里可以放一些初始化的参数*/ })
ABFilter
@WebFilter(filterName = "ABFilter",urlPatterns = "/*")
AFilter和BFilter是在web.xml配置的。
执行顺序跟的顺序无关
的顺序才决定执行顺序
AFilter filter.AFilter BFilter filter.BFilter <!--这里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>
每个Filter添加了打印语句,如下
以为例
package filter;
import javax.servlet.*;
import javax.servlet..;
import java.io.;
@( = “”, = “/*”)
public class Filter {
private String ;
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的在前,故BFilter在AFilter之前执行。
和是通过注解声明的,故他俩在BFilter和AFilter之后执行,但是的名称以A开头,故在之前执行
访问权限控制小例子##
下面我们写一个访问控制权限控制的小例子。
我们在浏览一些网站经常有这个情况,没有登录时是不允许我们访其主页的,只有登录过后才能访问。
下面我们就用Filter简单实现一下。
需求分析
登录时将登录的账号密码保存到cookie中,下次访问时携带账号和密码,过滤器中进行校验用户没有登录直接访问主页时,要跳转到登录页面登录过滤器不对登录页面进行过滤
我们先来看一下项目结构
这里主要看一下的代码
我们在中对非登录页面的其他jsp都会进行过滤,判断cookie中是否携带了account和pwd。
如果有这两个数据表示之前登录过,那么对数据进行校验,正确的话就进行下一个操作。
否则的话,跳转到登录界面
package filter;
import javax.servlet.*;
import javax.servlet..;
import javax.servlet.http.Cookie;
import javax.servlet.http.;
import javax.servlet.http.;
import java.io.;
@( = “”, = “*.jsp”, = {})
public class 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页面则可以访问。
下面是demo
访问控制demo
如果你觉得本文对你有帮助,麻烦动动手指顶一下,可以帮助到更多的开发者,如果文中有什么错误的地方,还望指正,转载请注明转自喻志强的博客 ,谢谢!
*请认真填写需求信息,我们会在24小时内与您取得联系。