1.过滤器
1.1 什么是过滤器
请求到达服务端的目标资源(动态,静态)前,先执行一段java程序
Web开发人员通过Filter技术,对web服务器管理的所有web资源:例如 Jsp, Servlet,静态图片文件或静态html 文件等进行拦截,从而实现一些特殊的功能.例如实现URL级别的权限访问控制,过滤敏感词汇,压缩响应信息等一些高级功能.
1.2 过滤器作用
在HttpServletRequest到达 目标资源(Servlet/jsp,png,css.js) 之前,拦截客户的HttpServletRequest .根据需要检查HttpServletRequest,也可以修改HttpServletRequest 头和数据.
1.3 入门案例
public class MyFirstFilter implements Filter {
public MyFirstFilter() {
System.out.println("构造函数被执行了");
}
static{
/*
* 加载:JVM将硬盘上的MyFirstFilter.class字节码中的内容通过流的方式读取到内存
*/
System.out.println("字节码正在被加载到内存.....");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("正在初始化");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("doFilter begin");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("doFilter end");
}
@Override
public void destroy() {
System.out.println("destroy被执行了");
}
}
web.xml
<filter>
<filter-name>MyFilter01</filter-name>
<filter-class>cn.itcast.filters.MyFilter01</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter01</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
注意点:
1.过滤器需要配置在Servlet(DispatherServlet)上,它是先于Servlet执行的,所以我们可以拿到原始的http请求(HttpServletRequest、HpptServletResponse),但我们拿不到请求路径对应的控制器和请求控制器中的方法的信息。(因为通过请求路径找handler是DispatherServlet通过映射器来找的)
思考:如果在过滤器做权限控制?
1.4 过滤器生命周期
- 服务器启动就创建
- 当过滤器文件发生改变/服务器正常关闭,会执行destroy方法,销毁过滤器;如果中断服务器,destroy方法没有执行,过滤器会被销毁
Filter的生命周期和WEB应用的生命周期一致ServletContext
1.5 过滤器执行流程
- 服务器tomcat启动的时候读取WEB.XML文件,获取到WEB.XML中所有的<filter-class>标签中的内容.将字节码加载到内存,通过反射调用无参数的构造函数创建各个过滤器对象,执行过滤器上的init方法(仅执行一次)
- 每次客户端发请求到服务端的时候,如果当前的过滤器配置的路径和被请求的目标资源的路径匹配,执行过滤器中的doFilter方法,将tomcat创建好的request,response传递给doFilter方法
- 执行过滤器中doFilter方法中的代码,如果在执行过程中遇到chain.doFilter(request, response); 相当于放行,tomcat执行本次目标资源,目标资源执行完毕之后,继续执行doFilter方法中放行之后的语句什么是目标资源:如果本次请求的是一个HTML文件,那么目标资源就是这个HTML文件如果本次请求的是一个SERVLET,那么本次的目标资源就是这个SERVLET
- 执行过滤器中doFilter方法中的代码,如果在执行过程中没有遇到放行语句Tomcat仅仅是对本次请求响应 HTTP响应部分的响应行,响应头信息
- 当发生以下2种情况时,执行过滤器中的destroy方法
*_项目正常停止,
*_项目中JAVA源码发生改变,需要重新加载项目
1.6 过滤器链
(1)多个过滤器组合在一起形成过滤器链
(2)为什么要有过滤器链?
过滤器可以实现很多功能,如果把多个功能放在一个过滤器中,不利于项目维护,将不同的功能放在不同的过滤器中实现,这样不需用某个功能的时候,移除其配置即可.当需要某个功能时,单独为其配置一下即可
. 过滤器可以当做”可拔插式的组件”
,和系统仅仅是在配置文件中耦合
(3)过滤器链执行流程?
(4)代码
FilterDemo01
public class FilterDemo01 implements Filter {
public void destroy() {}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("demo01 11111");
chain.doFilter(request, response);
System.out.println("demo01 22222");
}
public void init(FilterConfig fConfig) throws ServletException {}
}
FilterDemo02
public class FilterDemo02 implements Filter {
public void destroy() {}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("demo02 11111");
chain.doFilter(request, response);
System.out.println("demo02 22222");
}
public void init(FilterConfig fConfig) throws ServletException {}
}
FilterDemo03
public class FilterDemo03 implements Filter {
public void destroy() {}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("demo03 11111");
chain.doFilter(request, response);
System.out.println("demo03 22222");
}
public void init(FilterConfig fConfig) throws ServletException {}
}
配置文件如下:
<filter>
<filter-name>FilterDemo01</filter-name>
<filter-class>cn.itcast.web.filter.FilterDemo01</filter-class>
</filter>
<filter-mapping>
<filter-name>FilterDemo01</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>FilterDemo02</filter-name>
<filter-class>cn.itcast.web.filter.FilterDemo02</filter-class>
</filter>
<filter-mapping>
<filter-name>FilterDemo02</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>FilterDemo03</filter-name>
<filter-class>cn.itcast.web.filter.FilterDemo03</filter-class>
</filter>
<filter-mapping>
<filter-name>FilterDemo03</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
1.7 过滤器的配置
url-pattern的三种配置
- 完全路径匹配: 以 / 开始
- /aaa
- /aaa/bbb
- 目录匹配: 以 / 开始
- /*
- /download/*
- 扩展名匹配: 不能以 / 开始
- *.do
- *.jsp
- *.action
dispatcher的配置
- REQUEST:默认值。浏览器直接请求资源,新的请求到来时拦截
- FORWARD:转发访问资源。只有转发的请求才会拦截。
servlet-name的配置
通过url-pattern拦截一个Servlet的资源.也可以通过servlet-name标签进行拦截.
1.8 运行方式
- 单实例多线程
- Servlet能做的事情,过滤器都能做,过滤器更像是横跨在tomcat和目标资源的透明代码,这段代码能否执行取决于是否在配置文件中配置,目标资源是否允许被当前用户请求被调用,取决于过滤器中是否有放行语句
- 过滤器本质还是一段JAVA小程序,只不过存放的位置不一样,执行的时机不一样,承担的职责也不一样了,美其名曰”过滤器”
2.拦截器
HandlerExecutionChain是一个执行链,当请求到达DispatchServlet时,DispatchServlet根据请求路径到HandlerMapping查询具体的Handler,从HandlerMapping返回给DispatcherServlet,其中包含了一个具体的Handler对象和Interceptors(拦截器集合)。
如何自定义拦截器:
springmvc的拦截器接口(HandlerInterceptor)定义了三个方法:
- preHandle调用Handler之前执行,称为前置方法
- 返回值:
true表示放行,后续业务逻辑继续执行
false表示被拦截,后续业务逻辑不再执行,但之前返回true的拦截器的完成方法会倒叙执行
- 返回值:
- postHandle调用Handler之后执行,称为后置方法
- afterCompletion视图渲染完成之后执行
2.1 拦截器的执行过程