JavaWeb——Filter过滤器

来源:互联网 发布:godaddy域名转到万网 编辑:程序博客网 时间:2024/06/04 18:25

1、Filter可以做什么

Filter(过滤器)对web服务器管理的web资源进行拦截,从而实现一些特殊功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些功能。

2、Filter如何实现拦截

web浏览器<————>web服务器<————>过滤器<————>web资源

Filter接口中有一个doFilter方法,web服务器在调用doFilter方法时,会传递一个filterChain对象,该对象有一个doFilter()方法,如果调用改方法,则服务器调用web资源,否则web资源不会被访问。

Filter接口的doFilter()方法:

  • 前:对request,response做预处理
  • 是否调用目标资源,是否执行filterChain对象的diFilter()方法。
  • 后:捕获响应的web资源,实现一些新的功能。

3、Filter开发步骤

Filter开发分为两个步骤,首先要编写java类实现filter接口和doFilter方法,二是在web.xml中对编写的filter接口进行注册和映射,设置其拦截的资源。

3.1 XML配置

3.1.1 filter注册

注册Filter范例:

<filter>      <description>FilterDemo02过滤器</description>      <filter-name>FilterDemo02</filter-name>      <filter-class>me.gacl.web.filter.FilterDemo02</filter-class>      <!--配置FilterDemo02过滤器的初始化参数-->      <init-param>          <description>配置FilterDemo02过滤器的初始化参数</description>          <param-name>name</param-name>          <param-value>gacl</param-value>      </init-param>      <init-param>          <description>配置FilterDemo02过滤器的初始化参数</description>          <param-name>like</param-name>          <param-value>java</param-value>      </init-param></filter>
  • <filter>标签用于内注册一个filter过滤器
  • <description>标签用于添加描述信息(可省略)
  • <filter-name>标签用于指定过滤器的名称
  • <filter-class>标签用于指定过滤器的类名
  • <init-param>标签用于设置filter的初始化参数,<param-name><param-value>制定了某属性的名称及该属性的值。

<init-param>标签中的属性可以通过FilterConfig对象的方法获得。

3.1.2 filter映射

映射filter实例1:

<!--映射过滤器-->  <filter-mapping>      <filter-name>FilterDemo02</filter-name>      <!--“/*”表示拦截所有的请求 -->      <url-pattern>/*</url-pattern>  </filter-mapping>

映射filter实例2:

<filter-mapping>   <filter-name>testFilter</filter-name>   <url-pattern>/index.jsp</url-pattern>   <dispatcher>REQUEST</dispatcher>   <dispatcher>FORWARD</dispatcher></filter-mapping>

<dispatcher>标签设置用户以什么方式访问时,过滤器工作。标签的属性值:

  1. REQUEST:用户直接访问页面,过滤器工作。
  2. INCLUDE:目标资源通过RequestDispatcher的include()方法访问,过滤器工作。
  3. FORWARD:目标资源通过RequestDispatcher的forward()方法访问,过滤器工作。
  4. ERROR:目标资源通过声明式异常处理机制调用时,过滤器工作。

3.2 实现Filter接口并实现doFilter方法

过滤器范例:

public class FilterDemo01 implements Filter {    @Override    public void init(FilterConfig filterConfig) throws ServletException {        System.out.println("----过滤器初始化----");    }    @Override    public void doFilter(ServletRequest request, ServletResponse response,            FilterChain chain) throws IOException, ServletException {        //对request和response进行一些预处理        request.setCharacterEncoding("UTF-8");        response.setCharacterEncoding("UTF-8");        response.setContentType("text/html;charset=UTF-8");        System.out.println("FilterDemo01执行前!!!");        chain.doFilter(request, response);  //让目标资源执行,放行        System.out.println("FilterDemo01执行后!!!");    }    @Override    public void destroy() {        System.out.println("----过滤器销毁----");    }}

4、Filter的生命周期

Filter的创建和销毁都由WEB服务器负责。web应用程序启动,web服务器创建Filter的实例对象,调用init方法,这个过程只执行一次。

Filter的销毁由web容器调用destroy方法销毁Filter,释放过滤器使用的资源。在Filter的生命周期内执行一次。

5、Decorator设计模式

5.1 Decorator模式介绍

在某个对象不能满足业务需求时,通常有两种方式来对其进行增强:

  • 编写子类,继承并重写需要增强的方法。
  • 使用Decorator设计模式对方法进行增强。

一般情况下我们使用第一种方法,但在某个特殊情况下,我们只能使用第二种方法,即:被增强的对象,只能得到对象,不能得到class文件。

在filter中可以得到request,response对象,可以使用decorator模式对request和response对象进行包装, 在把包装对象传给目标资源。

5.2 Decorator模式实现

  1. 被增强对象集成了什么接口和父类,编写一个类,也继承这些接口和父类。
  2. 在类中定义变量,变量类型即被增强对象的类型。
  3. 在类中定义构造函数,接收被增强对象。
  4. 覆盖需增强的方法,编写增强的代码。

Servlet API中提供了一个request对象的Decorator设计模式的默认实现类HttpServletRequestWrapper,(HttpServletRequestWrapper类实现了request接口中的所有方法,但这些方法的内部实现都是仅仅调用了一下所包装的request对象的对应方法)以避免用户在对request对象进行增强时需要实现request接口中的所有方法。

所以当需要增强request对象时,只需要写一个类继承HttpServletRequestWrapper类,然后在重写需要增强的方法即可

当需要增强response对象时,继承HttpServletResponseWrapper类。

6、Filter的应用

6.1 统一全站字符编码

public class EncodingFilter implements Filter {    String encoding = null;    FilterConfig filterConfig = null;    public void init(FilterConfig config ) throws ServletException{        this.filterConfig=config;        this.encoding=filterConfig.getInitParameter("encoding");    }    public void doFilter(ServletRequest request , ServletResponse response , FilterChain chain)    throws IOException , ServletException{        if(encoding !=null){            request.setCharacterEncoding(encoding);        }        chain.doFilter(request, response);    }    public void destroy(){        this.encoding = null;        this.filterConfig = null;    }}

在init方法中获得XML注册时的encoding属性值,将它传递给该类的属性encoding,在doFilter方法中,使用erquest.setCharacterEncoding()方法,设置request的属性值。

6.2 禁止浏览器缓存动态页面

public class NoCacheFilter implements Filter{    public void init (){}    public void doFilter(ServletRequest req , ServletResponse resp, FliterChain chain)     throws IOException ,ServletException{        //强制转换        HttpServletRequest request = (HttpServletRequest )req;        HttpServletResponse response = (HttpServletResponse ) resp;        //三种方法设置禁止缓存        response.setDataHeader("Expires",-1);        response.setHeader("Cache-control","no-cache");        response.setHeader("Pragma","no-cache");        chain.doFilter(request,response);    }    public void destroy(){}}

XML配置:

<filter>      <filter-name>NoCacheFilter</filter-name>      <filter-class>web.filter.NoCacheFilter</filter-class></filter><filter-mapping>      <filter-name>NoCacheFilter</filter-name>        <!--只拦截Jsp请求-->      <servlet-name>*.jsp</servlet-name></filter-mapping>

HTTP响应头字段有三种禁止浏览器缓存的头字段:

  • Expires:告诉浏览器把回送的资源缓存多长时间 -1或0则是不缓存
  • Cache-Control:no-cache,控制浏览器不要缓存数据
  • Pragma:no-cache,控制浏览器不要缓存数据

HTTP请求中的常用请求字段和HTTP的响应状态码及响应头
http://blog.csdn.net/qxs965266509/article/details/8082810

6.3 控制浏览器缓存静态页面

public class NoCacheFilter implements Filter{    public void init (){}    public void doFilter(ServletRequest req , ServletResponse resp, FliterChain chain)     throws IOException ,ServletException{        //强制转换        HttpServletRequest request = (HttpServletRequest )req;        HttpServletResponse response = (HttpServletResponse ) resp;        //得到请求资源的rul        String url = request.getRequestURI();        //得到请求资源的后缀        String ext = uri.substring(uri.lastIndexOf(".")+1);        //得到该后缀在xml设置中的缓存时间属性值        String time = filterConfig.getInitParameter(ext);        if(time!=null){            long t = Long.parseLong(time)*3600*1000;            //设置响应头字段Expires的缓存时间            response.setDataHeader("Expires",System.currentTimeMillis()+t);        }    }    public void destroy(){}}

XML配置:

<!-- 配置缓存过滤器 -->   <filter>      <filter-name>CacheFilter</filter-name>      <filter-class>me.gacl.web.filter.CacheFilter</filter-class>       <!-- 配置要缓存的web资源以及缓存时间,以小时为单位 -->      <init-param>          <param-name>css</param-name>          <param-value>4</param-value>      </init-param>      <init-param>          <param-name>jpg</param-name>          <param-value>1</param-value>      </init-param>      <init-param>          <param-name>js</param-name>          <param-value>4</param-value>      </init-param>      <init-param>          <param-name>png</param-name>          <param-value>4</param-value>      </init-param>  </filter>  <!-- 配置要缓存的web资源的后缀-->  <filter-mapping>      <filter-name>CacheFilter</filter-name>      <url-pattern>*.jpg</url-pattern>  </filter-mapping>  <filter-mapping>      <filter-name>CacheFilter</filter-name>      <url-pattern>*.css</url-pattern>  </filter-mapping>  <filter-mapping>      <filter-name>CacheFilter</filter-name>      <url-pattern>*.js</url-pattern>  </filter-mapping>   <filter-mapping>      <filter-name>CacheFilter</filter-name>      <url-pattern>*.png</url-pattern>  </filter-mapping>

6.4 用户自动登陆

引用redarmychen的部分代码

实现用户自动登陆的思路:

  • 用户首次登陆成功后,发送一个名称为user的cookie给客户端,cookie的值为用户名和加密的密码,同时在session对象中存放一个用户登录记录的属性值。
  • 编写一个LoginFilter,filter检查session的属性值是否匹配,或者检查用户是否带有名称为user的cookie,(如果有,则调用dao查询cookie的用户名和密码是否和数据库匹配)以实现程序完成自动登陆。

LoginServlet的部分代码

创建cookie:

long time = System.currentTimeMillis() + expires  * 1000;  //cookie拼接的value值,(可以根据自己的想法设计)  String cookieValue = name + ":" + time + ":"  + md5Value(name + ":" + pass + ":" + time);  //创建cookie  autoCookie = new Cookie("autologin", cookieValue); 

添加cookie:

autoCookie.setMaxAge((int) expires);  autoCookie.setPath("/day56");  // 添加cookie  response.addCookie(autoCookie); 

添加session对象:

request.getSession().setAttribute("admin", entity);

LoginFilter的部分代码

查看session中是否有标志:

// 1.首先判断sesion中有没有admin  Object object = request.getSession().getAttribute("admin");  // 如果session中有用户  if (object != null) {      // 跳转到成功登录的界面      request.getRequestDispatcher("./sc.jsp").forward(request, response);      return;  } 

查看cookie中是否有用户登录记录:

// 2.判断cookie中是否存在 autologin标识符 的cookie对象          // 声明cookie          Cookie autoCookie = null;          // 获取所有的cookie          Cookie cookies[] = request.getCookies();          // 如果没有cookie信息,就继续执行login.do,跳转到login.jsp页面          if (cookies != null) {              // 如果有,就遍历cookie              for (Cookie cookie : cookies) {                  // 判断cookie中是否有autologin标识符的cookie                  if ("autologin".equals(cookie.getName())) {                      autoCookie = cookie; // 如果有 就赋值给临时变量autoCookie                  }              }              // 3. 判断autoCookie是否等于null              if (autoCookie == null) {                  // 如果等于null,则继续执行login.jsp页面                  chain.doFilter(request, response);                  return;              }              // 3.如果autoCookie不等于null,就判断cookie的值              // 获取cookie值              String value = autoCookie.getValue();              // 拆分cookie的值              String temp[] = value.split(":");              System.out.println(temp.length);              // 判断长度 是否等于自己拼接的长度              if (temp.length != 3) {                  // 如果不等于3,则继续执行login.jsp页面                  chain.doFilter(request, response);                  return;              }              // 获取cookie拆分的各个值              String name = temp[0]; // 用户名              String time = temp[1];// 获取有效时间              String service_md5Value = temp[2];// 获取md5的加密后的字符              // 4.判断cookie是否失效              if (Long.valueOf(time) <= System.currentTimeMillis()) {                  // 如果失效,则继续执行login.jsp页面                  chain.doFilter(request, response);                  return;              }              // 5.如果cookie没有失效,根据用户名,去查询用户信息              AdminService adminService = new AdminServiceImpl();              // 查询用户信息              Admin entity = adminService.checkLogin(name);              System.out.println(entity+"0000");              // 判断用户是否为null              if (entity == null) {                  // 如果没有查询的用户,则继续执行login.jsp页面                  chain.doFilter(request, response);                  return;              }              // 按照服务器拼接的字符的方式,拼接md5加密的字符串              String md5Temp = entity.getName() + ":" + entity.getPass() + ":"                      + time;              // 判断md5加密后和服务器端加密的字符是否相等              if (!(md5Value(md5Temp).equals(service_md5Value))) {                  // 在不相等的情况下,则继续执行login.jsp页面                  chain.doFilter(request, response);                  return;              }              // 如果满足了cookie取值判断的所有结果,则跳转到成功登录的界面.              request.getSession().setAttribute("admin", entity);              request.getRequestDispatcher("./sc.jsp").forward(request, response);          } else {              // 在没有cookie信息的时候,则继续login.jsp页面              chain.doFilter(request, response);              return;          }      }  
0 0
原创粉丝点击