Chinaunix首页 | 论坛 | 博客
  • 博客访问: 29955003
  • 博文数量: 2065
  • 博客积分: 10377
  • 博客等级: 上将
  • 技术积分: 21525
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-04 17:50
文章分类

全部博文(2065)

文章存档

2012年(2)

2011年(19)

2010年(1160)

2009年(969)

2008年(153)

分类: Java

2010-02-02 18:04:36

Jsp开发中的过滤器专题整理

[整理:hkebao@126.com 整理时间:2010-2-2]

刚在整理Django框架中发现其自带的中间件非常强。实现的功能好像不比JSP中的过滤器弱。现在整理一个专题文档以供参考学习。关键是学习人家的思想。

Django里面想实现中间件是不需要继承什么父类的。在JSP中就不一样

所有的Servlet过滤器类都必须实现javax.servlet.Filter接口。

这个接口含有3个过滤器类必须实现的方法: PS:在Django中实现中间件是有几个方法可以重写)
方法                         说明
init(FilterConfig cfg)
这是Servlet过滤器的初始化方法,性质等同与servletinit方法。
doFilter(ServletRequest,ServletResponse,FilterChain)
完成实际的过滤操作,当请求访问过滤器关联的URL时,Servlet容器将先调用过滤器的doFilter方法。FilterChain参数用于访问后续过滤器
destroy() Servlet
容器在销毁过滤器实例前调用该方法,这个方法中可以释放Servlet过滤器占用的资源。,性质等同与servletdestory()方法。

 

Servlet过滤器的创建步骤:
A
.实现javax.servlet.Filter接口的servlet (实现接口)
B
.实现init方法,读取过滤器的初始化函数          
C
.实现doFilter方法,完成对请求或过滤的响应      (对请求与响应的过滤处理)
D
.调用FilterChain接口对象的doFilter方法,向后续的过滤器传递请求或响应
F.
web.xml中配置Filter                        (加载过滤器进来)

 

一、过滤器的原理

过滤器是一个程序,它先于与之相关的servletJSP页面运行在服务器上。过滤器可附加到一个或多个servletJSP页面上,并且可以检查进入这些资源的请求信息。在这之后,过滤器可以作如下的选择:

  以常规的方式调用资源(即,调用servletJSP页面)。(返回None类似于Django中的)

  利用修改过的请求信息调用资源。

  调用资源,但在发送响应到客户机前对其进行修改。(先一步操作)

  阻止该资源调用,代之以转到其他的资源,返回一个特定的状态代码或生成替换输出。

Servlet作为过滤器使用时,它可以对客户的请求进行处理。处理完成后,它会交给下一个过滤器处理,这样,客户的请求在过滤链里逐个处理,直到请求 发送到目标为止。例如,某网站里有提交修改的注册信息的网页,当用户填写完修改信息并提交后,服务器在进行处理时需要做两项工作:判断客户端的会话是 否有效;对提交的数据进行统一编码。这两项工作可以在由两个过滤器组成的过滤链里进行处理。当过滤器处理成功后,把提交的数据发送到最终目标;如果过滤器 处理不成功,将把视图派发到指定的错误页面。(编写一个过滤器链)

 

 

 

二、ORCLA官网的教程

下面的图表展示了三个场景中的请求/响应流程:具有一个客户端 (C) 和一个 servlet (S) 但没有过滤器的应用程序,使用一个过滤器 (F) 的同一个应用程序,以及在一个过滤器链中使用两个过滤器(F1 F2)的同一个程序。注意,虽然过滤器可以修改请求或响应对象,但是它并不一定要执行该操作。过滤器可以传递对象,而同时保持它未被修改。并且,您在后端无需 servlet 即可使用过滤器您可以通过配置应用程序服务器(或其它容器)将过滤器应用于任何请求。

无过滤器

一个过滤器

两个过滤器链

无过滤器

一个过滤器 (F)

两个过滤器链

除了实施过滤器外,您必须编辑 Web 应用程序部署描述符文件 (web.xml),容器才能找到并调用该过滤器。以下是 web.xml 文件的一部分,其中包括一个简单过滤器、实施它的 Java 类和应用该过滤器的 URL 模式。由开发人员定义的过滤器名称将 Java 类映射到 URL 模式。在本示例中,名为 FilterAllRequests 的过滤器在 mypackage1.FilterOne.java 中实施,且容器将其应用于所有接收的请求(URL 模式中,使用星号作为通配符)。您还可将过滤器应用到特定目录或资源(文件)。其他标记用于声明过滤器属性,但以下所显示的是非常重要的。

配置文件:

  
    FilterAllRequests
    mypackage1.FilterOne
 

 
    FilterAllRequests
    /* 应用的URL目录 相当于Django中间件中获取的path路径出来匹配是否需要应用此中间件-à
 

 

  
    FilterMyDocs
    mypackage1.FilterTwo
 

 
    FilterMyDocs
    /mydocs/*
 

表示容器只有在接收到对 /mydocs 目录中的资源的请求时才会应用该过滤器

PS:比如说在请求静态图片或CSS资源的时候可以编写一个GZIP算法进行压缩输出。

或者在管理后台开始的目录/sysadmin 都可应用用户认证的过滤器。

 

三、示例

3.1 简单应用过滤器。针对全部的URL的过滤器

第一步:编写过滤器类

我创建了一个包其名称为:package cn.filter;

具体代码如下:

package cn.filter;

import java.io.IOException;

import javax.servlet.Filter;

import javax.servlet.FilterChain;

import javax.servlet.FilterConfig;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import javax.servlet.http.HttpServlet;

public class Test implements Filter {

    private FilterConfig config=null; 

    public void destroy() {

    }

    public void doFilter(ServletRequest request, ServletResponse response,

            FilterChain chain) throws IOException, ServletException {

        System.out.println("test");

        chain.doFilter(request, response);//将请求传给后台即经过了过滤器转换之后

    }

    public void init(FilterConfig filterConfig) throws ServletException {

        this.config = filterConfig;

    }

}

只是测试用!

第三步:编写配置文件使过滤器生效

找到站点中的web.xml文件

  <filter>

    <filter-name>TestFilterAllRequestfilter-name>

    <filter-class>cn.filter.Testfilter-class>

  filter>

  <filter-mapping>

    <filter-name>TestFilterAllRequestfilter-name>

    <url-pattern>/*url-pattern>  表示应用此过滤器到全部的URL请求

  filter-mapping>

 

3.2 编写一个过滤器实现对静态资源的缓存

思路:我的静态资源文件存放在static目录下面即全部的/static/*  都将应用此过滤器。现在开始编写过滤器内容。关键是要知道如何缓存内容

 

 

 

输入:  显示图片。需要对/static/* 目录做缓存过滤。类似于配置nginx中的静态缓存

1.     jsp cache最好做在过滤器上,把需要缓冲的页面集中在同一个目录下,每次更改只须更改web.xml就可以完成缓冲设置,这样比较方便.(目前是对一个目录做缓存处理)

2.     Gzip压缩可以将页面压缩得很小,平均压缩比为1/3,jsp cacheHashMap缓冲压缩后的页面,肯定比没压缩前更节约内存消耗,并且效率更高

实现对某个目录的整体缓存过滤器代码如下:

第一步:编写过滤器类

package cn.filter;

import java.io.IOException;

import javax.servlet.Filter;

import javax.servlet.FilterChain;

import javax.servlet.FilterConfig;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletResponse;

public class Test implements Filter {

    public void destroy() {

    }

    public void doFilter(ServletRequest request, ServletResponse response,

            FilterChain chain) throws IOException, ServletException {

        HttpServletResponse rpo = (HttpServletResponse) response;//转换

        long now = System.currentTimeMillis();

        rpo.setDateHeader("Expires", now + 1 * 60000);//设置过期时间

        chain.doFilter(request, response);//将请求转发到后台处理程序处理

    }

    public void init(FilterConfig filterConfig) throws ServletException {

    }

}

第二步、配置

<filter>

    <filter-name>TestFilterAllRequestfilter-name>

    <filter-class>cn.filter.Testfilter-class>

  filter>

  <filter-mapping>

    <filter-name>TestFilterAllRequestfilter-name>

    <url-pattern>/static/*url-pattern> 

 filter-mapping>

可以对此目录的全部文件进行缓存处理!

 

 

3.3 实现对某个目录进行GZIP压缩

可以考虑如何实现这块的功能。

 

3.4 编码统一的过滤器,即在请求提交给服务器CGI之前经过一次编码转换处理

编写过滤器类

package cn.filter;

import java.io.IOException;

import javax.servlet.Filter;

import javax.servlet.FilterChain;

import javax.servlet.FilterConfig;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

 

public class Test implements Filter {

    protected FilterConfig filterConfig = null;

    protected String encoding = "";

    public void destroy() {

        this.filterConfig = null;

        this.encoding = null;

    }

    public void doFilter(ServletRequest request, ServletResponse response,

            FilterChain chain) throws IOException, ServletException {

        System.out.println(this.encoding);

        if(encoding != null)

            request.setCharacterEncoding(encoding);

        chain.doFilter(request, response);

    }

    public void init(FilterConfig filterConfig) throws ServletException {

        this.filterConfig = filterConfig;

        this.encoding = filterConfig.getInitParameter("encoding");//读配置文件参数

       

    }

}

PS:这样全部的客户端的数据都会统一进行UTF-8编码处理掉

第二步:配置发布

<filter>

    <filter-name>TestFilterAllRequestfilter-name>

    <filter-class>cn.filter.Testfilter-class>

     <init-param>  #注意:配置过滤器中的参数值

    <param-name>encodingparam-name>

    <param-value>utf-8param-value>

    init-param>

  filter>

  <filter-mapping>

    <filter-name>TestFilterAllRequestfilter-name>

    <url-pattern>/*url-pattern>    

  filter-mapping>

 

3.5 限制用户浏览某个文件夹的限制,比如说admin目录不可随便浏览就可以如下控制

package cn.filter;

import java.io.IOException;

import javax.servlet.Filter;

import javax.servlet.FilterChain;

import javax.servlet.FilterConfig;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

 

public class Test implements Filter {

    protected FilterConfig filterConfig = null;

    protected String paths = "";

    public void destroy() {

        this.filterConfig = null;

        this.paths = null;

    }

    public void doFilter(ServletRequest requ, ServletResponse sres,

            FilterChain chain) throws IOException, ServletException {

        // 获取uri地址

        HttpServletRequest request=(HttpServletRequest)requ;

        String uri = request.getRequestURI();

        String ctx=request.getContextPath();

        uri = uri.substring(ctx.length());

        //判断admin级别网页的浏览权限

        if(uri.startsWith("/"+paths)) {

            if(request.getSession().getAttribute("admin")==null) {

                request.setAttribute("message","您没有这个权限");

                request.getRequestDispatcher("/index.jsp").forward(requ,sres);

                return;

            }

        }chain.doFilter(requ, sres);

    }

    public void init(FilterConfig filterConfig) throws ServletException {

        this.filterConfig = filterConfig;

        this.paths = filterConfig.getInitParameter("paths");//读配置文件参数

       

    }

}

PS:这样可以方便管理目录的浏览权限,只有特定的用户才能访问特定的目录

第二步:配置

<filter>

    <filter-name>TestFilterAllRequestfilter-name>

    <filter-class>cn.filter.Testfilter-class>

    <init-param> 

    <param-name>pathsparam-name>

    <param-value>staticparam-value>

    init-param>   

  filter>

  <filter-mapping>

    <filter-name>TestFilterAllRequestfilter-name>

    <url-pattern>/static/*url-pattern>    

  filter-mapping>

 

阅读(1049) | 评论(1) | 转发(0) |
0

上一篇:学习使用 iptables

下一篇:MySQL表分区专题

给主人留下些什么吧!~~

chinaunix网友2010-02-02 18:08:57

以后遇到编写过滤器方面的应用可以继续扩展