JSP&Servlet5(三) --- 过滤器 封装器

来源:互联网 发布:淘宝微信转换工具 编辑:程序博客网 时间:2024/06/18 16:58

过滤器是什么?

抽象点来说, 就是介于Servlet之间的独立的元件, 可以随时加入到应用程序之中, 也可以随时移除.

具体点来说, 比如针对某些特定的页面, 只有特定的用户才能浏览, 这个时候我们就希望能把所有登录的用户进行过滤, 只给一些用户访问的权限, 这就可以在Servlet之前实现一个用户验证的过滤器.

过滤器通常搭配封装器来使用. 关于封装器可分为请求封装器和响应封装器, 具体概念及用法将在下面介绍.


1. 实现与设置过滤器

在Servlet中要实现过滤器, 必须要实现Filter接口, 并使用@WebFilter标注或在web.xml中定义过滤器, 让容器知道应该加载哪些过滤器类.
Filter接口有三个需要实现的方法:init(), doFilter(), destroy(), Filter接口的代码如下:

public interface Filter{    public void init(FilterConfig filterConfig) throws ServletException;    //FilterConfig类似与Servlet接口init方法参数上的ServletConfig(针对每个Servlet,容器都会为其生成一个ServletConfig对象),     //FilterConfig是实现Filter接口的类上使用标注或web.xml中过滤器设置信息的代表对象.    //如果在定义过滤器时设置了初始参数, 则可以通过FilterConfig的getInitparameter()方法来取得初始参数.    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)     throws IOException, ServletException;    public void destroy();}

重点来看一下doFilter()方法:

  • doFilter()方法类似与Servlet接口的service()方法. 当请求来到容器时, 容器发现在Servlet的service()方法之前可以应用过滤器时, 就会调用过滤器的doFilter()方法. 可以在doFilter()方法中进行service()的前置处理, 而后决定是否要调第三个参数chain的doFilter()方法, 即决定是否要运行下一个过滤器.

  • 如果调用了chain的doFilter()方法, 就会运行下一个过滤器, 如果没有过滤器了, 就会运行Servlet的service()方法. 陆续调用完过滤器的Filter()至service()后, 流程会以堆栈顺序返回.

  • 所以在FilterChain的doFilter()运行完毕后, 就可以针对service()做后续处理, 如下:

//service()前置处理chain.doFilter();//service()后置处理

实现一个过滤器

例: 以下实现一个简单评测性能的过滤器, 用于记录请求到响应之间的时间差, 了解Servlet处理请求到响应所需花费的事件.

实现Filter接口代码如下:

@WebFilter(fileName = "performance", urlPatterns = {"/*"})public class PerformanceFilter implements Filter{    private FilterConfig config;    @Override    public void init(FilterConfig config) throws ServletException{        this.config = config;    }    @Overridethrows IOException, ServletException{        long begain = System.currentTimeMillis();        chain.doFilter(request, response);        config.getServletContext().log("Request process in " +         (System.currentTimeMillis() - begain) + " milliseconds");    }    //ServletContext.log("xxxx"): 将xxxx写进tomcat的日志里.    @Override    public void destroy(){}}

还可以在@WebFilter()标注中设置dispatcherType来设置触发过滤器的时机, 代码如下:

@WebFilter(    filterName = "some",    urlPatterns = {"/some"},    dispatcherType = {        DispatcherType.REQUEST, /*不设置任何dispatcherType, 默认是REQUEST*/        DispatcherType.FORWORD, /*通过RequestDispatcher的forword()而来的请求可以套用过滤器*/        DispatcherType.INCLUDE, /*通过RequestDispatcher的include()而来的请求可以套用过滤器*/        DispatcherType.ERROR, /*由容器处理例外而转发过来的请求可以触发过滤器*/        DispatcherType.ASYNC, /*异步处理的请求可以触发过滤器*/    })

如果有某个url或者Servlet会应用多个过滤器, 则根据在web.xml中出现的先后顺序来决定过滤器的运行顺序.

2. 请求封装器

请求封装器是什么? 就是对request的已有方法进行扩充并封装.

实现一个封装器

例: 实现字符替换过滤器: 假设有一个留言板程序, 有些用户会在留言中输入一些HTML标签, 基于安全性考虑, 我们不希望用户输入的标签被浏览器当作网页的一部分, 所以要使用过滤器将<这样的符号替换为HTML实体字符&lt这样.

现在的问题是, 我们用来取得用户留言的getParameter()函数中并没有过滤HTML字符这样的设置, 我们也无法直接重定义HttpServletRequest接口的这些方法. 于是, Servlet给出了一个类: HttpServletRequestWrapper.

HttpServletRequestWrapper类实现了HttpServletRequest接口, 只要继承了HttpServletRequestWrapper类, 就可以重定义HttpServletRequest接口里面的方法, 当然也包括getParameter().

如下代码通过继承HttpServletRequestWrapper类实现了一个替换字符的请求封装器:

public class EscapeWrapper extends HttpServletRequestWrapper{//EscapeWrapper类继承了HttpServletRequestWrapper    pubic EscapeWrapper(HttpServletRequest request){        super(request); /*必须调用父类的构造器, 确保请求传入的是此构造器*/        //定义了一个接收请求的构造器,并用super()调用父类HttpServletRequestWrapper接收请求的构造器,         //这也说明真正的请求, 将不再通过HttpServletRequestWrapper的构造器传入,         //而是通过EscapeWrapper类的构造器(即此构造器)传入    }    @Override    public String getParameter(String name){    //重定义getParameter()方法        String value = getRequest().getParameter(name);        return StringEscapeUtils.escapeHtml(value);        //将取得的请求参数值进行字符替换        //StringEscapeUtils是Apache Commons Lang程序库中的一个字符串操作类    }}

使用上面的封装器搭配下面的过滤器来进行字符过滤的功能, 过滤器的代码如下:

@WebFilter("/*")public class EscapeFilter implements Filter{    public void init(FilterConfig fconfig) throws ServletException{}    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)     throws IOException, ServletException{        HttpServletRequest requestWrapper = new EscapeWrapper((HttpServletRequest) request);        //将原请求对象包裹至前面写好的封装器中        chain.doFilter(requestWrapper, response);        //将封装器中的request传入doFilter()中, 执行下一个过滤器或Servlet的service()方法    }}

3. 响应封装器

前面说完了请求封装器, 现在来说说响应封装器. 类似于请求封装器, 响应封装器就是对response的已有方法进行扩充并封装.

与HttpServletRequest对象相似, 封装器通过继承HttpServletResponseWrapper类(父类:ServletResponseWrapper类)来对HttpServletResponse对象的方法进行重定义扩充并封装.

关于响应封装器的例子(比如对响应内容的压缩处理)在这里就不再给出, 处理方法与请求封装器相似, 也是封装器搭配过滤器使用.

原创粉丝点击