Servlet Filter
JavaEE Servlet规范中描述到的三种技术,Servlet Filter Listener
Servlet技术是生成动态web资源
Filter技术对服务器web资源进行拦截(权限控制)
Filter也称之为过滤器,它是Servlet技术中最实用的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
Filter实现原理
Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截。
Filter接口中有一个doFilter方法,当开发人员编写好Filter,并配置对哪个web资源(拦截url)进行拦截后,WEB服务器每次在调用web资源之前,都会先调用一下filter的doFilter方法,因此,在该方法内编写代码可达到如下目的:1.调用目标资源之前,让一段代码执行
2,是否调用目标资源(即是否让用户访问web资源)。
web服务器在调用doFilter方法时,会传递一个filterChain对象进来,filterChain对象是filter接口中最重要的一个对象,它也提供了一个doFilter方法,开发人员可以根据需求决定是否调用此方法,调用该方法,则web服务器就会调用web资源的service方法,即web资源就会被访问,否则web资源不会被访问。
3,
调用目标资源之后,让一段代码执行
编写Filter的步骤
1,创建jsp
2,实现Filter接口覆盖其中的doFilter等方法
3,在web.xml中配置注册过滤器以及过滤目标资源的路径。
Filter的编写与配置与Servlet类似,但是注意Filter类是在服务器启动时就创建了Filter对象,而Servlet是在访问时才会创建对象。当配置Filter拦截后,请求访问目标资源时,过滤器与目标资源构成了调用链对象,会先执行过滤器的doFilter方法,当需要调用目标资源时,即需要访问调用链的下一个环节的时候,需要在dofilter方法中调用filterChain对象的doFilter方法。
在一个filter调用链中可以对同一个web资源配置多个过滤器。过滤器的执行顺序是由web.xml中过滤器的mapping注册顺序决定的。
Filter的生命周期
1,服务器web应用程序启动时会创建Filter对象实例并调用init方法,
2,在访问目标资源时,doFilter方法执行拦截过滤,每次请求执行一次
3,在服务器关闭时,detory方法被执行
FilterConfig接口
用户配置filter时,可以使用<init-param>为filter配置一些初始化参数,在web容器实例化Filter对象,调用其init方法时,会把封装了fiter初始化参数的filterConfig对象传递进来,通过该对象可以获取filter对象的一些信息
getFilterName();得到filter的名称
getInitParamter(String name);获取指定名称的初始化参数值,不存在返回null
Enumeration getInitParameterNames();返回过滤器的所有初始化参数的名字的枚举合集
getServletContext();返回Servlet上下文的引用对象,用来读取资源。
配置filter-mapping
元素用于设置一个 Filter 所负责拦截的资源。一个Filter拦截的资源可通过两种方式来指定:Servlet 名称和资源访问的请求路径,一个web资源可以配置多个过滤器,一个过滤器也可以配置多个web资源
<filter-name>子元素用于设置filter的注册名称。该值必须是在<filter>元素中声明过的过滤器的名字
<url-pattern>设置 filter 所拦截的请求路径(过滤器关联的URL样式)
<servlet-name>指定过滤器所拦截的Servlet名称。
<dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认REQUEST。用户可以设置多个<dispatcher> 子元素用来指定 Filter 对资源的多种调用方式进行拦截。
<dispatcher> 子元素可以设置的值及其意义:
REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。
INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。
FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。
ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。
Filter常见应用
1,统一全站字符编码的过滤器
通过配置参数encoding指明使用何种字符编码,以处理Html Form请求参数的中文问题
2,禁止浏览器缓存所有动态页面的过滤器:
有 3 个 HTTP 响应头字段都可以禁止浏览器缓存当前页面,它们在 Servlet 中的示例代码如下:
response.setDateHeader("Expires",-1);
response.setHeader("Cache-Control","no-cache");
response.setHeader("Pragma","no-cache");
并不是所有的浏览器都能完全支持上面的三个响应头,因此最好是同时使用上面的三个响应头。
Expires数据头:值为GMT时间值,为-1指浏览器不要缓存页面
Cache-Control响应头有两个常用值:
no-cache指浏览器不要缓存当前页面。
max-age:xxx指浏览器缓存页面xxx秒
3,控制浏览器缓存页面中的静态资源的过滤器:
场景:有些动态页面中引用了一些图片或css文件以修饰页面效果,这些图片和css文件经常是不变化的,所以为减轻服务器的压力,可以使用filter控制浏览器缓存这些文件,以提升服务器的性能。
4,实现用户自动登陆的过滤器
在用户登陆成功后,以cookis形式发送用户名、密码给客户端
编写一个过滤器,filter方法中检查cookie中是否带有用户名、密码信息,如果存在则调用业务层登陆方法,登陆成功后则向session中存入user对象(即用户登陆标记),以实现程序完成自动登陆。
5,MD5加密
/**
* 使用md5的算法进行加密
*
* @param plainText
* 加密原文
* @return 加密密文
*/
public static String md5(String plainText) {
byte[] secretBytes = null;
try {
secretBytes = MessageDigest.getInstance("md5").digest(
plainText.getBytes());
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("没有md5这个算法!");
}
return new BigInteger(1, secretBytes).toString(16);
}
6,BASE64,常用来对网络中传输的信息编码加密
例如:用户名、密码、下载软件地址等
BASE64Encoder encoder = new BASE64Encoder();
String s = "aaa";
String s1 = encoder.encode(s.getBytes());
out.println(s1);
BASE64Decoder decoder = new BASE64Decoder();
String s2 = new String(decoder.decodeBuffer(s1));
out.println(s2);
7,使用Filter实现URL级别的权限认证
使用Filter实现URL级别的权限认证
情景:在实际开发中我们经常把一些执行敏感操作的servlet映射到一些特殊目录中,并用filter把这些特殊目录保护起来,限制只能拥有相应访问权限的用户才能访问这些目录下的资源。从而在我们系统中实现一种URL级别的权限功能。
要求:为使Filter具有通用性,Filter保护的资源和相应的访问权限通过filter参数的形式予以配置。