责任链模式
简单介绍一下什么是责任链模式?
如果您了解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()