一、过滤器入门
1. 概念:
Filter 过滤器,又称拦截器
实现 Filter 接口的类我们称之为 Filter (过滤器或拦截器)
Filter能对用户访问的资源进行拦截
在Filter里面可以只用 request获得请求消息 用response写入响应消息
chain.doFilter(request, response) 方法放行 目标Servlet使用的是同一个请求和响应
doFilter 方法后面的代码会执行,在目标Servlet 返回响应后执行, 也可以使用同一个请求和响应
2. 实现:
1) 写一个类实现 Filter 接口 , 在doFilter 方法中写功能代码
public class Filter1 implements Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("before");
chain.doFilter(request, response);
System.out.println("after");
}
2) 在web.xml中配置Filter拦截的资源路径
<filter>
<filter-name>filter1</filter-name>
<filter-class>cn.itcast.filter.Filter1</filter-class>
</filter>
<filter-mapping>
<filter-name>filter1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3. Filter 链
可以针对某一个url配置多个Filter, 这些Filter就会组成一个Filter链, 用FilterChain对象表示
FilterChain对象的doFilter方法作用就是让Filter链上的当前拦截器放行,请求进入下一个Filter
response 的中文编码问题, 只能在response.getWriter() 第一次被调用之前指定编码才有效
一旦指定了编码,当前Filter链和目标Servlet使用的response都是同一个编码,因为用的本来就是一个
response
4. Filter 与 Servlet
Filter 就像一个特殊的Servlet
Filter 在web容器启动是就初始化
Filter 可以实现拦截功能,因为有个 FilterChain 对象,有个 doFilter方法可以实现对访问资源的放行
二、 Filter细节
1. Filter 的生命周期
实现Filter的init和destroy方法就可以观察Filter的声明周期
web容器启动时,会读web.xml文件,将所有的Filter都初始化
Filter对象创建后会驻留在内存,当web应用移除或服务器停止时才销毁
Filter链中所有的Filter的拦截顺序 按照 在 web.xml 文件中的配置的先后顺序来进行拦截
2. 获得 Filter 的初始化参数
在 web.xml 文件中为Filter 配置初始化参数
<init-param>
<param-name>name</param-name>
<param-value>xxxx</param-value>
</init-param>
在 init 方法中读取配置文件
public void init(FilterConfig filterConfig) throws ServletException {
String name = filterConfig.getInitParameter("name");
}
3. 拦截 html 页面
1) 文件缓存
由于html页面的url是没有在 web.xml 文件中配置的 服务器会调用DefaultServlet
在DefaultServlet 中会检查文件的修改时间, 如果没有修改则发送 304头
这样就会导致过滤器也被缓存
可以通过发送 200 状态码,但是 html 页面的数据仍然得不到读取
2) html 页面乱码
在 Filter 和 Html 中指定编码为 utf-8 , 这样会导致 html 页面中文乱码
原因是 html 页面数据会通过 DefaultServlet 发送
查看 web.xml 文件 发现DefaultServlet默认使用 gbk编码
修改配置 加初始化参数
<init-param>
<param-name>fileEncoding</param-name>
<param-value>utf-8</param-value>
</init-param>
4. Filter拦截方式
Filter的dispatcher元素有4种取值, 分别代表四种拦截方式
REQUEST 拦截直接的请求方式
INCLUDE 拦截页面包含的访问方式
FORWARD 拦截请求转发访问方式
ERROR 拦截出错页面的访问方式
5. filter-mapping元素配置
拦截的url地址可以使用 /* *.扩展名
<filter-mapping> 元素中可以配置多个地址 用于拦截多个url或servlet
对于多个条件都符合的url, filter会进行多次拦截
三、 过滤器案例
1. 缓存
禁止浏览器缓存所有动态页面
response.setDateHeader("Expires",-1);
response.setHeader("Cache-Control","no-cache");
response.setHeader("Pragma","no-cache");
强制浏览器缓存所有的静态页面 html jpg css
String uri = request.getRequestURI();
String time = null;
if(uri.endsWith(".html"))
time = config.getInitParameter("html");
else if(uri.endsWith(".jpg"))
time = config.getInitParameter("jpg");
long l = Long.parseLong(time);
response.setDateHeader("Expires",System.currentTimeMillis() + l);
2. 实现用户自动登陆
1)在用户登陆成功后,发送一个名称为user的cookie给客户端,cookie的值为用户名和md5加密后的密码
2)编写过滤器检查用户是否带名为user的cookie来,如果有,检查用户名和密码做自动登陆
核心思路:
用户登陆后找LoginServlet , LoginServlet中做登陆,如果登陆成功, 获得用户选择的自动登陆时间
创建一个新的cookie 将用户名和密码用 “_”连接作为value,autoLogin作为name
设置cookie 的有效路径 request.getContextPath() 作用于整个web应用
设置cookie的有效时间为 autologintime
发送 cookie
写一个过滤器,对全站的资源进行拦截, 检查用户发送的cookie有没有一个名为autologin的
如果有 取出用户名和密码 再次做登陆处理 如果登陆成功, 将 user 存入session ,放行
出于安全性考虑, cookie 中的密码应该进行 md5 加密
3. 统一全站字符编码
response和request的post的方式好办
// 解决全站的乱码问题 request response
response.setContentType("text/html;charset=utf-8");
request.setCharacterEncoding("utf-8"); // 只对 post 方式起作用,对get方式不起作用
对于request的get方式需要手工转换,此时就需要用到 包装设计模式decorator
包装 getParameter方法
4. 为全站添加页眉和页脚
添加用户模块
5. 发送压缩后的响应数据
给 IE 浏览器会送的数据 需要进行gzip 压缩 访问速度快 省点浏览
在最后将数据打给浏览器的时候, 将 response 中的数据全部压缩
在过滤器放行的时候传入一个 假的 response 提供缓冲区, 这样后面的资源都会写入我的缓冲区
缓冲区满了 或者 请求快结束的时候 将缓冲区的数据压缩后写入 真的 response
j2se 提供了一个流GZIPOutputStream 用于 gzip压缩
j2se 提供了一个流 ZIPOutputStream 用于 zip 压缩
6. 跟踪用户上次访问时间
7. 统计站内各个页面的访问次数
8. 实现某些资源只能被某些ip访问
9. 实现防盗链功能
针对所有的下载页面
10. 实现html标签转义、过滤敏感词汇