提出问题
1、我们在进入后台很多页面的时候都需要登录。 只有登录的用户才能看到这些页面。 我们每次请求都需要检查用户是否登录。 这很麻烦。 有没有办法在我们要求之前帮我做这些事? 有!
2、我们的网络APP经常接收中文字符。 因为可能会导致中文乱码,所以我们每次都需要在方法的开头使用request.setcharacterencoding (“utf-8”)。 我们要获取参数值,可以直接自己设置代码吗? 我能行!
这个问题的解决方法我们想出了一个方法。 那就是,我们每次要求都拦截它,当我们安装好一切东西时,就放弃要求。 类似于我们地铁站的检票系统。 每个人进站的时候都必须刷卡。 取钱后才能坐车。
web上也有这个机制,我们叫它过滤器。 是我们接下来要学习的掩体
过滤器介绍
什么是菲尔
1 )过滤器(Filter )过滤器的基本功能是阻止servlet容器调用servlet (JSP )的过程,从而在servlet处理请求之前和servlet响应请求之后提供特殊功能。
2 ) servlet API为开发人员创建Filter程序定义了三个接口类。 是过滤器、过滤器通道和过滤器配置
3 ) Filter程序是实现Filter接口的Java类,它与servlet程序一样由servlet容器调用和执行
4 ) Filter程序必须在web.xml文件中注册,并设置可以侦听的资源。 过滤器程序可以侦听Jsp、servlet、静止图像文件和静止html文件
过滤器的工作原理是什么
这个servlet过滤器就是我们的过滤器
1 )如果web.xml包含用于阻止servlet的Filter,则此Filter是Tomcat和servlet通信线路上的级别。 此过滤器可以侦听从servlet容器发送到servlet的请求,以及servlet返回到servlet容器的响应,确定是否将请求传递给servlet,以及是否更改请求和相应的信息
2 )可以在一个web APP应用程序中注册多个Filter程序,每个Filter程序可以侦听一个或一系列servlet。
3 )如果多个Filter程序拦截了某个servlet的访问进程,则当访问该servlet的请求到达时,web容器会将这些Filter程序合并到一个Filter链(过滤器链)中过滤器链中每个过滤器的拦截顺序与在APP应用程序的web.xml中映射的顺序匹配
过滤器-故障诊断
赫尔洛-世界
过滤器创建三个步骤。
1、创建过滤器实现类,实现过滤器接口
2、创建web.xml配置文件,配置过滤器信息
3、运行项目后,可以看到过滤器在发挥作用
代码:
//1,过滤器实现类
publicclassmyfirstfilterimplementsfilter {
@ overridepublicvoidinit (filterconfigfilterconfig ) throwsServletException {
System.out.println (初始化方法);
}
@ overridepublicvoiddofilter (servletrequestrequest,ServletResponse response,FilterChain chain ) throwsIOException,servle
system.out.println(dofilter方法);
}
@ override公共语音目录(
System.out.println ('销毁方法. ';
}
//2,web.xml配置
我的第一过滤器
com.atguigu.filter.my first filter
我的第一过滤器
/index.jsp
//3,运行程序后,index.jsp页面不再显示,后台输出“dofilter方法”,表示我们写的filter已运行。
过滤器的生命周期
1 )服务器启动时,filter创建并初始化,init )方法执行。
2 )请求通过filter时执行doFilter方法。
3)服务器停止时,调用 destroy 方法。
filter放行请求
我们发现,刚才的 filter 配置好后,index.jsp 页面没法访问了,访问这个页面的时候 filter的 dofilter 方法被调用了。说明 dofilter 这个方法拦截了我们的请求。
我们如何显示页面呢。也就是如何将请求放行呢。我们观察发现有个 filterChain 被传入到这个方法里面了。filterChain 里面有个 doFilter()方法。放行请求只需要调用 filterChain 的 dofilter 方法。
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throwsIOException,ServletException {
System.out.println("dofilter方法");
chain.doFilter(request, response);//放行请求
}
filter拦截原理
我们在 chain.doFilter(request, response);方法后也写一句话,System.out.println
(“doFilter 方法执行后…”),在 index.jsp 页面也写上 jsp 脚本片段,输出我是 jsp 页面。运行程序发现控制台输出了这几句话:
dofilter 方法… 我是 jsp 页面
dofilter 方法后…
我们不难发现 filter 的运行流程
FilterChain
doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
在 doFilter 执行之前,由容器将 filterChain 对象传入方法。调用此对象的.doFilter()方法可以将请求放行,实际上是执行过滤器链中的下一个 doFilter 方法,但是如果只有一个过滤器,则为放行。
FilterConfig
FilterConfig 类似 ServletConfig,是 filter 的配置信息对象。FilterConfig 对象具有以下方法。
getFilterName():获取当前 filter 的名字。获取的是在 web.xml 中配置的 filter-name 的值
getInitParameter(String name):获取 filter 的初始化参数。在 web.xml 中配置
getInitParameterNames():获取 filter 初始化参数名的集合。
getServletContext():获取当前 web 工程的 ServletContext 对象。
Filter的 url-pattern
url-pattern 是配置 filter 过滤哪些请求的。主要有以下几种配置:
web.xml 中配置的/都是以当前项目路径为根路径的
1)精确匹配:
/index.jsp/user/login 会在请求/index.jsp、/user/login 的时候执行过滤方法
2)路径匹配:
/user/* /* 凡是路径为/user/下的所有请求都会被拦截,/*表示拦截系统的所有请求,包括静态资源文件。
3)扩展匹配:
*.jsp *.action 凡是后缀名为.jsp .action 的请求都会被拦截。
注意:/login/*.jsp 这种写法是错误的,只能是上述三种的任意一种形式。不能组合新形式。
*jsp 也是错误的,扩展匹配必须是后缀名
4)多重 url-pattern 配置
上面的三种形式比较有局限性,但是 url-pattern 可以配置多个,这样这三种组合基本就能解决所有问题了
多 Filter执行顺序
如果同一个资源有多个 filter 都对其拦截,则拦截的顺序是按照 web.xml 中配置的顺序进行的
执行流程图如下
请求总是在处理之后再回来执行 doFilter 之后的方法。
HttpServletWrapper 和 HttpServletResponseWrapper
定义
Servlet API 中提供了一个 HttpServletRequestWrapper 类来包装原始的 request 对象,HttpServletRequestWrapper 类实现了 HttpServletRequest 接口中的所有方法, 这些方法的内部实现都是仅仅调用了一下所包装的的 request 对象的对应方法
//包装类实现 ServletRequest 接口.
public class ServletRequestWrapper implementsServletRequest {//被包装的那个 ServletRequest 对象
privateServletRequest request;//构造器传入 ServletRequest 实现类对象
publicServletRequestWrapper(ServletRequest request) {if (request == null) {throw new IllegalArgumentException("Request cannot be null");
}this.request =request;
}//具体实现 ServletRequest 的方法: 调用被包装的那个成员变量的方法实现。
publicObject getAttribute(String name) {return this.request.getAttribute(name);
}publicEnumeration getAttributeNames() {return this.request.getAttributeNames();
}//...
}
相类似 Servlet API 也提供了一个 HttpServletResponseWrapper 类来包装原始的 response 对象
作用
用于对 HttpServletRequest 或 HttpServletResponse 的某一个方法进行修改或增强.
public class MyHttpServletRequest extendsHttpServletRequestWrapper{publicMyHttpServletRequest(HttpServletRequest request) {super(request);
}
@OverridepublicString getParameter(String name) {
String val= super.getParameter(name);if(val != null && val.contains(" fuck ")){
val= val.replace("fuck", "****");
}returnval;
}
}
使用
在 Filter 中, 利用 MyHttpServletRequest 替换传入的 HttpServletRequest
HttpServletRequest req = newMyHttpServletRequest(request);
filterChain.doFilter(req, response);
此时到达目标 Servlet 或 JSP 的 HttpServletRequest 实际上是 MyHttpServletRequest