过滤器与责任链模式

Filter

说起Filter大家应该都不陌生。Filter一般用于Servlet处理之前做一些前置的校验。如果校验通过,那么调用chain.doFilter(request, response)就可以让下一个filter继续执行逻辑。Filter是责任链模式的一种应用。接下来我们将探索、模拟Filter的实现逻辑。

责任链模式

责任链模式是一种行为设计模式,允许你将请求沿着处理者链进行发送。收到请求后,每个处理者均可对请求进行处理,或将其传递给连上的下一个处理者。

通过责任链对消息进行处理

对消息进行处理是一个非常简单的责任链模式的应用,直接看代码吧:

源码

public class SimpleFilterChainMain {
    public static void main(String[] args) {
    	//定义一个简单的消息对象
        Msg msg = new Msg();
        //消息内容
        msg.setContent("hello,<script>alert(\"I am an alert box!!\")</script> world! ${jndi:rim:/xxx} ");
        //定义一个过滤器链filterChain1 
        FilterChain filterChain1 = new FilterChain();
        //为filterChain1中添加一个HTML标签的过滤器
        filterChain1.add(new HTMLFilter());
        //定义另一个过滤器链filterChain2
        FilterChain filterChain2 = new FilterChain();
        //为filterChain2添加一个敏感词的过滤器
        filterChain2.add(new SensitiveFilter());
        //将filterChain2本身也作为一个过滤器添加到filterChain1中
        filterChain1.add(filterChain2);
        //使用filterChain1对消息进行过滤
        filterChain1.doFilter(msg);
        //输出一下过滤之后的结果
        System.out.println(msg.getContent());
    }

	/**
	 * 过滤器接口
	 */
    private interface Filter {
        /**
         * 过滤msg
         * @param msg
         */
        void doFilter(Msg msg);
    }

	/**
	 * 消息对象
	 */
    private static class Msg {
        private String content;

        public String getContent() {
            return content;
        }

        public void setContent(String content) {
            this.content = content;
        }
    }

	/**
	 * HTML标签的过滤器
	 */
    private static class HTMLFilter implements Filter {

        @Override
        public void doFilter(Msg msg) {
            String content = msg.getContent();
            content = content.replace('<', '[');
            content = content.replace('>', ']');
            msg.setContent(content);
        }
    }

	/**
	 * 敏感词的过滤器
	 */
    private static class SensitiveFilter implements Filter {

        @Override
        public void doFilter(Msg msg) {
            String content = msg.getContent();
            content = content.replaceAll("\\$\\{jndi:", "***");
            msg.setContent(content);
        }
    }

	/**
	 * 过滤器链,同时也实现了过滤器接口
	 */
    private static class FilterChain implements Filter {
        List<Filter> filters = new ArrayList<>();

		/**
		 * 向链中添加一个过滤器
		 */
        public void add(Filter filter) {
            filters.add(filter);
        }

        @Override
        public void doFilter(Msg msg) {
            for (Filter filter : filters) {
                filter.doFilter(msg);
            }
        }
    }
}

结果

我们先看下结果:
在这里插入图片描述
从结果上看,我的过滤器应该是都生效了。

反思与思考

以前我对责任链的理解仅仅只是到了Filter这一层,我认为只要有了一个List<Filter> filters 就算是责任链的体现了。所以所谓的“”在我这里只是一个list而已。而在上面的例子中,我的责任链已经是一个FilterChain对象了。这个从list到对象的过程就体现了封装,封装是为了更好的变化。封装之后我的FilterChain还实现了Filter接口。这样做的好处是,链中每个过滤器既可以是独立的过滤器,比如HTMLFilter,也可以是另一个过滤器链,比如filterChain2就这么连上了。

Servlet中的Filter

我们先看看Servlet中的Filter是什么样的效果。
首先,我定义了一个Controller和3个Filter
在这里插入图片描述
在具体的Filter中其实什么也没有做,只是打印了两句话
在这里插入图片描述
接下来我们看下效果
在这里插入图片描述
也就是说先Filter1先处理Request,然后交给Filter2处理,最后交给Filter3处理,当Servlet处理完请求之后,再按照Filter321的顺序处理Response,就像下面的图这样。
在这里插入图片描述

模拟Servlet中Filter的处理模式

Servlet中的Filter之所以能够实现这么神奇的功能,核心原因在于Servlet的Filter有三个参数,Request、Response和FilterChain。

demo

接下来我们用demo演示一下:

/**
 * 尝试模拟一下servlet的filter调用过程
 * @author skyline
 */
public class ServletFilterMain {

    public static void main(String[] args) {
        FilterChain filterChain = new MyFilterChain();
        filterChain.addFilter(new Filter1());
        filterChain.addFilter(new Filter2());
        filterChain.addFilter(new Filter3());
        filterChain.doFilter(new Request(), new Response());
    }

    /**
     * 自定义过滤器
     */
    private interface Filter {
        /**
         * 执行过滤的逻辑
         * @param request
         * @param response
         */
        void doFilter(Request request, Response response, FilterChain filterChain);
    }

    /**
     * 过滤器链
     */
    private interface FilterChain {

        void doFilter(Request request, Response response);

        /**
         * 添加过滤器
         * @param filter
         */
        void addFilter(Filter filter);
    }

    private static class Filter1 implements Filter {
        private static final Logger logger = LoggerFactory.getLogger(Filter1.class);

        @Override
        public void doFilter(Request request, Response response, FilterChain filterChain) {
            logger.info("before filterChain.doFilter");
            filterChain.doFilter(request, response);
            logger.info("after filterChain.doFilter");
        }
    }

    private static class Filter2 implements Filter {
        private static final Logger logger = LoggerFactory.getLogger(Filter2.class);

        @Override
        public void doFilter(Request request, Response response, FilterChain filterChain) {
            logger.info("before filterChain.doFilter");
            filterChain.doFilter(request, response);
            logger.info("after filterChain.doFilter");
        }
    }

    private static class Filter3 implements Filter {
        private static final Logger logger = LoggerFactory.getLogger(Filter3.class);

        @Override
        public void doFilter(Request request, Response response, FilterChain filterChain) {
            logger.info("before filterChain.doFilter");
            filterChain.doFilter(request, response);
            logger.info("after filterChain.doFilter");
        }
    }

    /**
     * 模拟请求
     */
    private static class Request {}

    /**
     * 模拟响应
     */
    private static class Response {}

    private static class MyFilterChain implements FilterChain {

        private final List<Filter> filters;
        private int index;

        private MyFilterChain() {
            filters = new ArrayList<>();
            index = -1;
        }

        @Override
        public void doFilter(Request request, Response response) {
        	//这里再次体现了封装的必要性,因为如果单纯的遍历filters就无法实现我们想要的效果
            int size = filters.size();
            //每次doFilter时索引+1
            index++;
            if (index < size) {
            	//从filters中取出index位置的Filter,调用并调用doFilter
                filters.get(index).doFilter(request, response, this);
            }
        }

        @Override
        public void addFilter(Filter filter) {
            filters.add(filter);
        }
    }
}

效果

先看下效果:
在这里插入图片描述
确实实现了123321的效果。

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值