Servlet规范中 Servlet Listener Filter
1.开发Filter
想要开发一个过滤器需要如下两个步骤:
(1)写一个类实现特定的接口Filter
生命周期:
当服务器启动时,web应用加载后,立即创建这个web应用中的所有的过滤器,过滤器创建出来后立即调用init方法执行初始化的操作.
创建出来后一直驻留在内存中为后续的拦截进行服务.每次拦截到请求后都会导致doFilter方法执行.
在服务器关闭或web应用被移除出容器时,随着web应用的销毁过滤器对象销毁.销毁之前调用destory方法执行善后工作.
init
FilterConfig:代表web.xml中对当前过滤器的配置信息
~获取ServletContext对象
~获取初始化信息
getInitParameter
getInitParameterNames
doFilter
request
response
FilterChain:
代表过滤器链的对象.
一个资源可能被多个过滤器所拦截到,拦截的顺序和过滤器在web.xml中filter-mapping的配置顺序相同.
所有对当前资源访问进行拦截的过滤器按照拦截顺序就组成了一个过滤器链.这个过滤器链的最后一个节点是要访问的资源.
Filter中调用FilterChain提供了doFilter方法,这个方法一旦被调用就表明当前过滤器没有问题了,请执行过滤器链的下一个节点.如果下一个节点是资源则直接执行了资源
destory
(2)在web.xml中注册一下过滤器
<!-- 注册过滤器 -->
<filter>
<filter-name>Demo1Filter</filter-name> -- 给过滤器起一个名字
<filter-class>com.filter.Demo1Filter</filter-class> -- 过滤器的处理类
<init-param>--可以配置当前过滤器的初始化信息,可以配置多个,在Filter中利用FilterConfig对象来获取
<param-name>name1</param-name>
<param-value>value1</param-value>
</init-param>
</filter>
<!-- 配置过滤器去拦截哪个资源 -->
<filter-mapping> -- 一个Filter可以配置多个filter-mapping
<filter-name>Demo1Filter</filter-name>
<url-pattern>/servlet/Demo1Servlet</url-pattern>
-- 一个Filtermapping中可以配置多个url-partten,这个url-partten的写法和servlet-mapping中的写法相同
<url-pattern>/servlet/*</url-pattern>
<url-pattern>/*</url-pattern>
<url-pattern>*.do</url-pattern>
<servlet-name>Demo3Servlet</servlet-name>
--也可以配置多个servlet-name,其中填入servlet的名字明确的通知要拦截哪个名字的Servlet
<dispatcher>REQUEST</dispatcher>
--配置拦截哪种方式的对资源的访问可以是REQUEST/FORWARD/INCLUDE/ERROR四个值之中的一个,
可以配置多个dispatcher,如果一个都不配则默认是REQUEST
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
================================================================================================
3.客户端访问被拦截目标资源之前,服务器调用Filter的doFilter方法 ,执行过滤
4.Filter的doFilter方法中传入 FilterChain, 如果调用FilterChain的doFilter 就会执行目标资源,否则目标资源不会执行
chain.doFilter(request, response);
FilterChain
在客户端访问服务器web资源时,服务器端为一个web资源,配置多个过滤器拦截 ,这多个过滤器,就会组成过滤器链 FilterChain,
调用FilterChain的doFilter 表示要执行过滤器链下一个资源,如果当前过滤器已经是链上最后一个过滤器,就会执行目标资源
* web服务器根据Filter在web.xml文件中的注册顺序<mapping>,决定先调用哪个Filter
================================================================================================
Filter生命周期 init(FilterConfig) doFilter(request,response,filterChain) destroy()
1.Filter对象在tomcat服务器启动时 创建,调用init方法 (只会创建一个对象,init方法执行一次)
2.doFilter 每次拦截目标资源时,执行
3.destroy 服务器关闭时执行
================================================================================================
FilterConfig 作用和 ServletConfig 类似,用来在Filter初始化阶段,将参数传递给过滤器
1.通过 String getInitParameter(String name) 获得过滤器初始化参数
2.通过 ServletContext getServletContext() 获得ServletContext对象
* FilterConfig 提供参数,是Filter类私有参数,Filter2的初始化参数,不能在Filter1 中进行获取
* 配置全局参数,<context-param> 进行配置,通过ServletContext 获得
=================================================================================================================
<filter-mapping> 过滤器拦截配置
1 .如果连接目标资源是一个Servlet,可以选择url和servlet名称两种配置方式
<!-- 拦截/hello是Servlet 路径 -->
<url-pattern>/hello</url-pattern>
<!-- 拦截Servlet 还可以通过Servlet 名称进行拦截 -->
<servlet-name>HelloServlet</servlet-name>
2. url-pattern 和 Servlet中路径写法一样,有三种 : 完全匹配、目录匹配、扩展名匹配
3 .<dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式
容器调用服务器端资源 有四种方式
REQUEST、FORWARD、INCLUDE、ERROR
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class Demo1Filter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("Demo1Filter初始化了.....");
filterConfig.getServletContext();
//filterConfig:在Filter初始化阶段,将参数传递给过滤器
Enumeration<String> enumeration = filterConfig.getInitParameterNames();
while(enumeration.hasMoreElements()){
String name = enumeration.nextElement();
//获得过滤器初始化参数
String value = filterConfig.getInitParameter(name);
System.out.println(name+":"+value);
}
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("demo1filter 前");
//放行资源
chain.doFilter(request, response);
System.out.println("demo1filter 后");
}
public void destroy() {
System.out.println("Demo1Filter销毁了.....");
}
}
<filter>
<filter-name>Demo1Filter</filter-name>
<filter-class>com.filter.Demo1Filter</filter-class>
<init-param>
<param-name>name1</param-name>
<param-value>value1</param-value>
</init-param>
<init-param>
<param-name>name2</param-name>
<param-value>value2</param-value>
</init-param>
<init-param>
<param-name>name3</param-name>
<param-value>value3</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Demo1Filter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
================================================================================================
Filter应用
应用一:统一全站字符编码过滤器
案例:编写jsp 输入用户名,在Servlet中获取用户名,将用户名输出到浏览器上
处理请求post乱码代码
request.setCharacterEncoding("utf-8");
设置响应编码集代码
response.setContentType("text/html;charset=utf-8");
经常会使用,而过滤器可以在目标资源之前执行,将很多程序中处理乱码公共代码,提取到过滤器中 ,以后程序中不需要处理编码问题了
应用二:禁止浏览器缓存动态页面的过滤器
因为动态页面数据,是由程序生成的,所以如果有缓存,就会发生,客户端查看数据不是最新数据情况 ,对于动态程序生成页面,设置浏览器端禁止缓存页面内容
response.setDateHeader("Expires",-1);
response.setHeader("Cache-Control","no-cache");
response.setHeader("Pragma","no-cache");
将禁用缓存代码,提起到过滤器中,通过url配置,禁用所有JSP页面的缓存
应用三:控制浏览器缓存静态web资源
Tomcat缓存策略
对于服务器端经常不变化文件,设置客户端缓存时间,在客户端资源缓存时间到期之前,就不会去访问服务器获取该资源 -------- 比tomcat内置缓存策略更优手段
* 减少服务器请求次数,提升性能
设置静态资源缓存时间,需要设置 Expires 过期时间 ,在客户端资源没有过期之前,不会产生对该资源的请求的
* 设置Expires 通常使用 response.setDateHeader 进行设置 设置毫秒值
===============================================================================================================================================
应用四:自动登陆过滤器
在访问一个站点,登陆时勾选自动登陆(三个月内不用登陆),操作系统后,关闭浏览器;过几天再次访问该站点时,直接进行登陆后状态
在数据库中创建 user表
create table user (
id int primary key auto_increment,
username varchar(20),
password varchar(40),
role varchar(10)
);
insert into user values(null,'admin','123','admin');
insert into user values(null,'aaa','123','user');
insert into user values(null,'bbb','123','user');
自动登陆 :未登录、存在自动登陆信息、自动登陆信息正确
在用户完成登陆后,勾选自动登陆复选框,服务器端将用户名和密码 以Cookie形式,保存在客户端 。当用户下次访问该站点,AutoLoginFilter 过滤器从Cookie中获取 自动登陆信息
1、判断用户是否已经登陆,如果已经登陆,没有自动登陆的必要
2、判断Cookie中是否含有自动登陆信息 ,如果没有,无法完成自动登陆
3、使用cookie用户名和密码 完成自动登陆
-------------------------------------------------------------------
应用五:过滤器实现URL级别权限认证
系统中存在很多资源,将需要进行权限控制的资源,放入特殊路径中,编写过滤器管理访问特殊路径的请求,如果没有相应身份和权限,控制无法访问
认证:who are you ? 用户身份的识别 ------------ 登陆功能
权限:以认证为基础 what can you do ? 您能做什么? 必须先登陆,才有身份,有了身份,才能确定可以执行哪些操作
=====================================================================================================================================================
Filter高级应用
Decorator模式
1、包装类需要和被包装对象 实现相同接口,或者继承相同父类
2、包装类需要持有 被包装对象的引用
在包装类中定义成员变量,通过包装类构造方法,传入被包装对象
3、在包装类中,可以控制原来那些方法需要加强
不需要加强 ,调用被包装对象的方法
需要加强,编写增强代码逻辑
ServletRequestWrapper 和 HttpServletRequestWrapper 提供对request对象进行包装的方法,但是默认情况下每个方法都是调用原来request对象的方法,也就是说包装类并没有对request进行增强
在这两个包装类基础上,继承HttpServletRequestWrapper ,覆盖需要增强的方法即可
应用六:完全解决get和post乱码的过滤器
在Filter中,对request对象进行包装,增强获得参数的方法
getParameter
getParameterValues
getParameterMap
ServletResponseWrapper 和 HttpServletResponseWrapper 提供了对response 对象包装,继承 HttpServletResponseWrapper ,覆盖需要增强response的方法
应用七:增强Response对象,对响应数据进行压缩
Tomcat服务器内,提供对响应压缩 配置实现
在conf/server.xml 中
<Connector port="80" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"/> 添加 compressableMimeType 和 compression
没有压缩 : 00:00:00.000 0.063 7553 GET 200 text/html http://localhost/
<Connector port="80" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" compressableMimeType="text/html,text/xml,text/plain" compression="on"/>
压缩后 : 00:00:00.000 0.171 2715 GET 200 text/html http://localhost/
Content-Encoding: gzip
Content-Length : 2715
实际开发中,很多情况下,没有权限配置server.xml ,无法通过tomcat配置开启gzip 压缩
编写过滤器对响应数据进行gzip压缩
flush 方法
只有没有缓冲区字节流,FileOutputStream 不需要flush
而字节数组ByteArrayOutputStream、字节包装流、字符流 需要flush ----- 这些流在调用close方法时都会自动flush
==================================================================================================================
过滤器
1、过滤器编写步骤
2、全局编码、禁用缓存、设置过期时间 过滤器
3、自动登陆/URL级别权限控制 --- 必须掌握 ***** (网盘)
4、通用get/post乱码过滤器和响应压缩过滤器 ------------ 理解实现过程 ,保存起来会使用