模拟实现Tomcat过滤器链,Struts2拦截器链-设计模式之责任链模式(任务链模式)

模拟实现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----跨域--

 

 任务链的这种结构和栈的结构十分相似。

 

posted @ 2019-02-27 11:15  大火yzs  阅读(960)  评论(0编辑  收藏  举报