代码改变世界

设计模式之责任链模式

2018-09-15 16:58  默念默  阅读(181)  评论(0编辑  收藏  举报

过滤器之双向过滤? 在WEB应用中无非就是一个request,response.

怎么样定义过滤器进行双向拦截呢?即在request过去的时候进行一系列的拦截,在response回来的时候也进行一系列的拦截。

说代码:

定义两个的JavaBean :Request,Response

复制代码
package cn.asto.filter;

public class Request {

    private String requestStr;

    public String getRequestStr() {
        return requestStr;
    }

    public void setRequestStr(String requestStr) {
        this.requestStr = requestStr;
    }
    
}
复制代码
复制代码
package cn.asto.filter;

public class Resopnse {

    private String requestStr;

    public String getRequestStr() {
        return requestStr;
    }

    public void setRequestStr(String requestStr) {
        this.requestStr = requestStr;
    }
    
}
复制代码

定义一个Filter接口:

package cn.asto.filter;

public interface Filter {

    public void doFilter(Request req,Response res);
}

实现此接口,写两个过滤器,完成对request和response的过滤

HtmlFilter类(对一些标签过滤):

复制代码
package cn.asto.filter;

public class HtmlFilter implements Filter{

    

    @Override
    public void doFilter(Request req, Response res) {
        String newReqStr = req.getRequestStr().replace("<", "[").replace(">", "]")+"request被HTMLFilter处理";
        req.setRequestStr(newReqStr);
        System.out.println(newReqStr);
        
        String newResStr = res.getRequestStr().replace("<", "[").replace(">", "]")+"response被HTMLFilter处理";
        res.setRequestStr(newResStr);
     System.out.println(newResStr); } }
复制代码

SensitiveFilter(对敏感词汇的过滤):

复制代码
package cn.asto.filter;

public class SensitiveFilter implements Filter{

    @Override
    public void doFilter(Request req, Response res) {
        String newReqStr = req.getRequestStr().replace("敏感词汇", "根据法律,相关内容不能显示")+"request被SensitiveFitler处理";
        req.setRequestStr(newReqStr);

      System.out.println(newReqStr);

        
        String newResStr = res.getRequestStr().replace("敏感词汇", "根据法律,相关内容不能显示")+"response被SensitiveFitler处理";
        res.setRequestStr(newResStr);
        System.out.println(newResStr);
    }

}
复制代码

在定义一个Chain来对过滤器进行遍历:

复制代码
package cn.asto.filter;

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

public class FilterChain implements Filter{

    List<Filter> filters = new ArrayList<Filter>();
    public FilterChain addFilter(Filter filter){
        filters.add(filter);
        return this ;
    }

    @Override
    public void doFilter(Request req, Response res) {
        for(Filter filter:filters){
            filter.doFilter(req, res);
        }
    }
}
复制代码

写一个Test类:

复制代码
package cn.asto.filter;

public class Test {

    public static void main(String args[]){
        Request req = new Request();
        req.setRequestStr("<script>,hello,敏感词汇!");
        Response res = new Response();
        res.setRequestStr("<script>,hello,敏感词汇!");
        FilterChain chain = new FilterChain();
        chain.addFilter(new HtmlFilter())
             .addFilter(new SensitiveFilter());
        chain.doFilter(req, res);
    
    }
}
复制代码

 

输出结果:

[script],hello,敏感词汇!request被HTMLFilter处理
[script],hello,敏感词汇!response被HTMLFilter处理
[script],hello,根据法律,相关内容不能显示!request被HTMLFilter处理request被SensitiveFitler处理
[script],hello,根据法律,相关内容不能显示!response被HTMLFilter处理response被SensitiveFitler处理

 

 

从结果上分析好像没什么问题了,request和response分别都经过了HTMLFilter和SensitiveFilter的的过滤。但是你有见过把request过滤到一半,然后开始过滤response的吗?

只有当且仅当request经过的所有的过滤器,response才能开始工作,而且是倒叙经过过滤器.上个图:

大概就这么个意思吧。下面的代码写起来很简单,但是设计起来有点精髓了。

我准备把FilterChain作为参数传递下去。

修改那么几个类:

Filter:

package cn.asto.filter;

public interface Filter {

    public void doFilter(Request req,Response res,FilterChain chain);
}

HtmlFilter:

复制代码
package cn.asto.filter;

public class HtmlFilter implements Filter{

    

    @Override
    public void doFilter(Request req, Response res,FilterChain chain) {
        String newReqStr = req.getRequestStr().replace("<", "[").replace(">", "]")+"request被HTMLFilter处理";
        req.setRequestStr(newReqStr);
        System.out.println(newReqStr);
        chain.doFilter(req, res,chain);
        String newResStr = res.getRequestStr().replace("<", "[").replace(">", "]")+"response被HTMLFilter处理";
        res.setRequestStr(newResStr);
        System.out.println(newResStr);
        
    }
}
复制代码

SensitiveFilter:

复制代码
package cn.asto.filter;

public class SensitiveFilter implements Filter{

    @Override
    public void doFilter(Request req, Response res,FilterChain chain) {
        String newReqStr = req.getRequestStr().replace("敏感词汇", "根据法律,相关内容不能显示")+"request被SensitiveFitler处理";
        req.setRequestStr(newReqStr);
        System.out.println(newReqStr);
        chain.doFilter(req, res,chain);
        String newResStr = res.getRequestStr().replace("敏感词汇", "根据法律,相关内容不能显示")+"response被SensitiveFitler处理";
        res.setRequestStr(newResStr);
     System.out.println(newResStr);
} }
复制代码

FilterChain:

复制代码
package cn.asto.filter;

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

public class FilterChain implements Filter{

    List<Filter> filters = new ArrayList<Filter>();
    public FilterChain addFilter(Filter filter){
        filters.add(filter);
        return this ;
    }
    private int index = -1;
    @Override
    public void doFilter(Request req, Response res,FilterChain chain) {
        index++;
        if(index==filters.size()) return ;
        filters.get(index).doFilter(req, res, chain);
        
    }
}
复制代码

 

测试一下:

复制代码
package cn.asto.filter;

public class Test {

    public static void main(String args[]){
        Request req = new Request();
        req.setRequestStr("<script>,hello,敏感词汇!");
        Response res = new Response();
        res.setRequestStr("<script>,hello,敏感词汇!");
        FilterChain chain = new FilterChain();
        chain.addFilter(new HtmlFilter())
             .addFilter(new SensitiveFilter());
        chain.doFilter(req, res,chain);
    
    }
}
复制代码

输出结果:

 

[script],hello,敏感词汇!request被HTMLFilter处理
[script],hello,根据法律,相关内容不能显示!request被HTMLFilter处理request被SensitiveFitler处理
<script>,hello,根据法律,相关内容不能显示!response被SensitiveFitler处理
[script],hello,根据法律,相关内容不能显示!response被SensitiveFitler处理response被HTMLFilter处理

 

嗯 ,真的先把request处理完了之后,再去处理response,且处理顺序变成了倒叙了,大家发现了没有?

不知道大家看懂没有。我是把这个FilterChain作为参数一直传递下去,

1.先调用FilterChain的doFilter,

2.调用HtmlFilter的doFilter(处f理request)

3.回来继续调用FilterChain的doFilter

4调用SensitiveFilter的doFilter(处理request)

5.先调用FilterChain的doFilter,(index==filters.size()成立,return;)

6.返回到SenvitiveFilter中,往下走,处理response,返回

7.返回到FilterChain中,下面没有执行语句了,直接返回

8.返回到HtmlFilter中往下走,处理resopnse.返回

9.返回到FilterChain,还是一样直接返回。

 

 

有点绕~,估计第一次看不太懂,建议在eclipse下面debug下 你就明白怎么回事了。

总结一下:

责任链模式,实现的关键就是把FilterChain作为参数传递下去。得到的效果就是先处理完一个对象,紧接着倒叙处理另一个对象。上面的那幅图就很好的说明了这个问题。

 

专业术语:责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。

 

要满足这个专业术语的话,估计要做一些改动,请求在这个链上传递,直到链上的某一个对象决定处理此请求.

稍微修改一下两个Filter实现类就可以,给出某种条件下,filter才去处理对象,不然继续往下走。当filter决定处理此对象后,处理完成后直接return不再往下走即可。