模拟实现Tomcat过滤器链,Struts2拦截器链-设计模式之责任链模式(任务链模式)
在javaWeb项目中,大家应该经常会用到这样的代码;
Sevlet Filter
下方代码作用:用于过滤请求,修改Request对象和Response对象的编码
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException { HttpServletRequest req=(HttpServletRequest) arg0; HttpServletResponse resp=(HttpServletResponse) arg1; req.setCharacterEncoding("utf-8"); resp.setCharacterEncoding("utf-8"); resp.setContentType("text/html;charset=UTF-8"); arg2.doFilter(req, resp); }
Struts2 拦截器
下方代码作用:用于实现自定义拦截器功能,实现最为普遍的登陆验证。
protected String doIntercept(ActionInvocation invocation) throws Exception { //获取session对象(经过struts2包装过) Map session = ActionContext.getContext().getSession(); //获取session作用域内是否有值 Users user = (Users) session.get("user"); if(user!=null){//合法访问 return invocation.invoke(); }else{//user为空说明未经过登陆,保存错误提示信息,跳到登陆页面 ActionContext.getContext().put("noright", "请先登陆再进行操作!"); return Action.LOGIN; } }
当我们使用多个Filter和 Interceptor时,就会组成一个任务链,什么是任务链呢?
过滤器链——FilterChain的执行流程
组过滤器对某些web资源进行拦截,那么这组过滤器就称为过滤器链。过滤器的执行顺序和<filter-mapping>有关(谁在前先执行谁)。
那么我们怎么模拟一个这样的功能呢?
下面我们就用代码简单的模拟一下Sevlet中的FilterChain
项目文件
其中myfilter下的各种filter都实现了Filter接口的doFilter方法,模拟web项目中自定义的Filter对象
下面展示各部分代码:
--------------------------------------------------------------------------------------------关键代码开始----------------------------------------------------------------------------------------
Filter.java
package com.bigfire.chain; /* 时间:2019年2月26日 10点47分 内容:设计模式--责任链模式 作者:大火yzs */ //定义接口模拟javax.servlet.Filter接口 public interface Filter { void doFilter(Request req,Response res,FilterChain chain); }
Tomcat.java
package com.bigfire.chain; import com.bigfire.chain.myfilter.CORSFilter; import com.bigfire.chain.myfilter.LoginFilter; import com.bigfire.chain.myfilter.URLEcodeFilter; import com.bigfire.chain.myfilter.UTF8Filter; /* 时间:2019年2月26日 10点47分 内容:设计模式--责任链模式 作者:大火yzs */ //定义类模拟Tomcat容器,产生一些对象。 public class Tomcat { public static void main(String[] args) { Request req = new Request("RequestMsg");//模拟Tomcat产生Request对象 Response res = new Response("ResponseMsg");//模拟Tomcat产生Response对象 FilterChain chain1 = new FilterChain();//创建任务链1 FilterChain chain2 = new FilterChain();//创建任务链2 chain2.addFilter(new UTF8Filter()) //在任务链2中添加UTF-8过滤器 .addFilter(new URLEcodeFilter()) //在任务链2中添加URLEcode过滤器 .addFilter(new URLEcodeFilter()); //在任务链2中添加URLEcode过滤器 chain1.addFilter(new CORSFilter()) //在任务链1中添加跨域过滤器 .addFilter(chain2) //在任务链1中添加任务链2 .addFilter(new LoginFilter()); //在任务链1中添加登陆过滤器 chain1.doFilter(req, res, chain1); //执行任务链1 System.out.println(req.msg); //输出过滤后的结果 System.out.println(res.msg); //输出过滤后的结果 } }
Request
package com.bigfire.chain; /* 时间:2019年2月26日 10点47分 内容:设计模式--责任链模式 作者:大火yzs */ //定义类模拟javax.servlet.ServletRequest类 public class Request { public String msg;//模拟Request中的消息 public Request() {} public Request(String msg) { this.msg = msg; } }
Res
package com.bigfire.chain; /* 时间:2019年2月26日 10点47分 内容:设计模式--责任链模式 作者:大火yzs */ //定义类模拟javax.servlet.ServletResponse类 public class Response { public String msg;//模拟Response中的消息 public Response() {} public Response(String msg) { this.msg = msg; } }
FilterChain.java
package com.bigfire.chain; import java.util.ArrayList; import java.util.List; /* 时间:2019年2月26日 10点47分 内容:设计模式--责任链模式 作者:大火yzs */ /* 定义类模拟javax.servlet.FilterChain类 过滤器链核心类 */ public class FilterChain implements Filter{//实现Filter接口 List<Filter> list = new ArrayList<Filter>();//存放过滤器的集合 int index = 0;//计数器 public int layer = 0;//责任链进入的层数 @Override public void doFilter(Request req, Response res, FilterChain chain) { if (index == list.size()) return;//如果已经冲到list的结尾了就返回 Filter filter = list.get(index);//没有到结尾就拿一个filter; index++;//自增 filter.doFilter(req, res, chain);//往里执行 } //用于添加过滤器,返回值是本对象,方便链式添加 public FilterChain addFilter(Filter filter) { if (filter instanceof FilterChain) {//添加的时候判断添加的是否是责任链 List<Filter> temlist=((FilterChain) filter).list;//获取子链中的Filter放到主链容器中 for (Filter filter2 : temlist) { this.list.add(filter2); } }else this.list.add(filter);//普通过滤器添加 return this; } }
--------------------------------------------------------------------------------------------关键代码结束----------------------------------------------------------------------------------------
myfilter包下的过滤器
--------------------------------------------------------------------------------------------自定义过滤器代码开始----------------------------------------------------------------------------------------
CORSFilter.java
package com.bigfire.chain.myfilter; import com.bigfire.chain.Filter; import com.bigfire.chain.FilterChain; import com.bigfire.chain.Request; import com.bigfire.chain.Response; /* 时间:2019年2月26日 10点47分 内容:设计模式--责任链模式 作者:大火yzs */ //定义过滤器用于解决跨域问题 public class CORSFilter implements Filter{ @Override public void doFilter(Request req, Response res, FilterChain chain) { System.out.println(chain.layer++); req.msg+="--跨域--"; chain.doFilter(req, res, chain); System.out.println(--chain.layer); res.msg+="--跨域--"; } }
LoginFilter.java
package com.bigfire.chain.myfilter; import com.bigfire.chain.Filter; import com.bigfire.chain.FilterChain; import com.bigfire.chain.Request; import com.bigfire.chain.Response; /* 时间:2019年2月26日 10点47分 内容:设计模式--责任链模式 作者:大火yzs */ //定义过滤器用于验证账号密码,过滤一些敏感词。 public class LoginFilter implements Filter{ @Override public void doFilter(Request req, Response res, FilterChain chain) { System.out.println(chain.layer++); req.msg+="--登陆--"; chain.doFilter(req, res, chain); System.out.println(--chain.layer); res.msg+="--登陆--"; } }
URLEcodeFilter.java
package com.bigfire.chain.myfilter; import com.bigfire.chain.Filter; import com.bigfire.chain.FilterChain; import com.bigfire.chain.Request; import com.bigfire.chain.Response; /* 时间:2019年2月26日 10点47分 内容:设计模式--责任链模式 作者:大火yzs */ //定义过滤器用于URL编码 public class URLEcodeFilter implements Filter{ @Override public void doFilter(Request req, Response res, FilterChain chain) { System.out.println(chain.layer++); req.msg+="--URLEcode--"; chain.doFilter(req, res, chain); System.out.println(--chain.layer); res.msg+="--URLEcode--"; } }
UTF8Filter.java
package com.bigfire.chain.myfilter; import com.bigfire.chain.Filter; import com.bigfire.chain.FilterChain; import com.bigfire.chain.Request; import com.bigfire.chain.Response; /* 时间:2019年2月26日 10点47分 内容:设计模式--责任链模式 作者:大火yzs */ //定义过滤器用于修改请求的编码方式为UTF-8。 public class UTF8Filter implements Filter{ @Override public void doFilter(Request req, Response res, FilterChain chain) { System.out.println(chain.layer++); req.msg+="--UTF8--"; chain.doFilter(req, res, chain); System.out.println(--chain.layer); res.msg+="--UTF8--"; } }
--------------------------------------------------------------------------------------------自定义过滤器代码结束----------------------------------------------------------------------------------------
运行结果:
0 //任务链第0层 1 2 3 4 //任务链第4层 4 3 2 1 0 RequestMsg--跨域----UTF8----URLEcode----URLEcode----登陆-- ResponseMsg--登陆----URLEcode----URLEcode----UTF8----跨域--
任务链的这种结构和栈的结构十分相似。