责任链模式

简单介绍一下什么是责任链模式?

         如果您了解Servlet规范的话,一定会知道Filter;如果您使用过Struts2的话,一定清楚无处不在的interceptor。责任链模式顾名思义,对一个请求设计出一个链状的处理流程,处于链条上的每个类都可以处理这个请求,或者放弃对请求的处理然后交给链条上的下一个类。

如果你没有学过Filter或者interceptor,没关系,给出Filter的原理图你就会发现其实它们很简单

原理图:下面是没有使用Filter的web应用

 

下面是使用了Filter的web应用

 

 

         当客户端发出Web资源的请求时,Web服务器根据应用程序配置文件设置过滤规则进行检查,若客户请求满足过滤规则,则对客户请求/响应进行拦截,对请求头和请求数据检查或改动,并以此通过过滤器链,最后把请求/响应交给请求的Web资源处理。请求信息在过滤器链中可以被修改,也可以根据时间让请求不发往资源处理器,并直接向客户机发回一个响应。当资源处理器完成了对资源的处理后,响应信息将逐级逆向返回。同样在这个过程中,用户可以修改响应信息,从而完成一定的任务。 

实例:来源于马士兵老师的视频,这个实例简单地模拟了Servlet的Filter功能

案例1:实现了将Msg由客户端向服务器端的过滤,如下图清晰地解析了程序的执行过程

 

Main类:调用MsgProcessor类的process()方法完成对客户端信息的过滤处理

public class Main {

    public static void main(String[] args) {
        String msg = "大家好:),<script>,敏感,被就业,网络授课没感觉,因为看不见大家伙儿";
        MsgProcessor mp = new MsgProcessor();
        mp.setMsg(msg);
        FilterChain fc = new FilterChain();
        fc.addFilter(new HTMLFilter())
          .addFilter(new SesitiveFilter())
          ;
        FilterChain fc2 = new FilterChain();
        fc2.addFilter(new FaceFilter());
        
        fc.addFilter(fc2);
        mp.setFc(fc);
        String result = mp.process();
        System.out.println(result);
    }

}

MsgProcessor类:中间类,实际上是调用FilterChain的doFilter()方法

public class MsgProcessor {
    private String msg;
    
    //Filter[] filters = {new HTMLFilter(), new SesitiveFilter(), new FaceFilter()};
    FilterChain fc;
    
    public FilterChain getFc() {
        return fc;
    }

    public void setFc(FilterChain fc) {
        this.fc = fc;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public String process() {
        
        
        return fc.doFilter(msg);
        
        
    }
}

定义接口类Filter

public interface Filter {
    String doFilter(String str);
}

3个具体实现上面接口的类

SesitiveFilter类

public class SesitiveFilter implements Filter {

    @Override
    public String doFilter(String str) {
        //process the sensitive words
        String r = str.replace("被就业", "就业")
             .replace("敏感", "");
        
        return r;
    }

}

FaceFilter类

public class FaceFilter implements Filter {

    @Override
    public String doFilter(String str) {
        return str.replace(":)", "^V^");
    }

}

HTMLFilter类

public class HTMLFilter implements Filter {

    @Override
    public String doFilter(String str) {
        //process the html tag <>
        String r = str.replace('<', '[')
                   .replace('>', ']');
        return r;
    }

}

FilterChain类:完成对Filter类的批量处理 

import java.util.ArrayList;
import java.util.List;

public class FilterChain implements Filter {
    List<Filter> filters = new ArrayList<Filter>();
    
    public FilterChain addFilter(Filter f) {
        this.filters.add(f);
        return this;
    }
    
    public String doFilter(String str) {
        String r = str;
        for(Filter f: filters) {
            r = f.doFilter(r);
        }
        return r;
    }
}

 

上面的案例只能实现单一方向的过滤,而实际上,在web应用中,客户端和服务器端的响应通常是这样的:

同一个Filter既对客户端发往服务器端的消息进行过滤处理,又对服务器端发往客户端的消息进行过滤处理。

案例2:如下图清晰地解析了程序的执行过程

                               A                 B              C

现在就真正在模拟Servlet的Filter功能或Struts的Intecerpter功能了,这里我们用Request对象封装客户端的请求信息,用Response对象封装服务器端反馈回来的信息

因为Filter是在FilterChain中,信息的过滤处理类似于栈的结构,比如在客户端往服务器端处理的过程中,是排在前面A的Filter先处理,排在后面的c后处理;而在服务器端往客户端处理过程中,是排在后面的C先处理,排在前面的A后处理,怎么处理呢?

可以这样考虑:将FilterChain的引用传递给Filter,因为FilterChain中包含了排列好了的Filter,若是信息被过滤器A执行处理,将获得FilterChain对象,信息将会按照FilterChain中的Filter的顺序执行下去

Request对象:封装客户端发送的信息

public class Request {
    String requestStr;

    public String getRequestStr() {
        return requestStr;
    }

    public void setRequestStr(String requestStr) {
        this.requestStr = requestStr;
    }
}

Response对象:封装服务器端反馈的信息

public class Response {
    String responseStr;

    public String getResponseStr() {
        return responseStr;
    }

    public void setResponseStr(String responseStr) {
        this.responseStr = responseStr;
    }
    
}

接口类: Filter

public interface Filter {
    void doFilter(Request request, Response response, FilterChain chain);
}

实现上述接口的两个类:

SesstiveFilter:处理敏感信息 

public class SesitiveFilter implements Filter {

    @Override
    public void doFilter(Request request, Response response, FilterChain chain) {
        request.requestStr = request.requestStr.replace("被就业", "就业")
         .replace("敏感", "") + "---SesitiveFilter()";
        chain.doFilter(request, response, chain);
        response.responseStr += "---SesitiveFilter()";
    }    
    
} 

HTMLFilter:处理HTML标签

public class HTMLFilter implements Filter {

    @Override
    public void doFilter(Request request, Response response, FilterChain chain) {
        //process the html tag <>
        request.requestStr = request.requestStr.replace('<', '[')
                   .replace('>', ']') + "---HTMLFilter()";
        chain.doFilter(request, response, chain);
        response.responseStr += "---HTMLFilter()";
    }

}

FilterChain:下面的着红色的代码解决了Response对象逆向被Filter处理

public class FilterChain implements Filter {
    List<Filter> filters = new ArrayList<Filter>();
    int index = 0;
    
    public FilterChain addFilter(Filter f) {
        this.filters.add(f);
        return this;
    }
    
    @Override
    public void doFilter(Request request, Response response, FilterChain chain) {
        if(index == filters.size()) return ;
        
        Filter f = filters.get(index);
        index ++;
        f.doFilter(request, response, chain);
    }
}

测试代码:

public class Main {

    /**
     * 模拟Servlet中Request和Response的调用过程
     */
    public static void main(String[] args) {
        String msg = "大家好:),<script>,敏感,被就业,网络授课没感觉,因为看不见大家伙儿";
        Request request = new Request();
        request.setRequestStr(msg);
        Response response = new Response();
        response.setResponseStr("response");
        FilterChain fc = new FilterChain();
        fc.addFilter(new HTMLFilter())
          .addFilter(new SesitiveFilter())
          ;
        
        fc.doFilter(request, response, fc);
        System.out.println(request.getRequestStr());
        System.out.println(response.getResponseStr());
    }

}

下面是测试结果:

大家好:),[script],,就业,网络授课没感觉,因为看不见大家伙儿---HTMLFilter()---SesitiveFilter()
response---SesitiveFilter()---HTMLFilter()
posted @ 2012-04-30 13:34  ^_TONY_^  阅读(983)  评论(0编辑  收藏  举报