玩转Spring!从拒绝Filter开始

来源:互联网 发布:怎么删除网络诽谤信息 编辑:程序博客网 时间:2024/06/03 18:38

一直以来,博客都是在写一些读书笔记或者学习心得。俗话说,举一反三,是时候沉淀一下了。索性这把这篇文章作为开端吧!

笔者知道,这篇文章的题目一定让某些developer不爽,尤其是学习过J2EE基础的人。学习过J2EE基础的童鞋,一定有自己写listener,filter和servlet的经验。经验多一些是好事,但不要陶醉于自己的经验,作为developer,我们还是要进步滴,尤其是在使用Spring之后。

在Spring中,用拦截器代替了原来的listener和filter,而且的确,Spring中的这个拦截器机制也的确是不负众望。下面笔者就举个例子,如何利用Spring中的拦截器机制写出松耦合,可插拔的代码。

多说一句,笔者非常喜欢软件模块“可插拔”的设计。

在大多数的软件架构中,都会有类似登录检查的机制。这个时候,我们就可以写一个拦截器,比如叫LoginInterceptor,让这个类集成自Spring框架的HandlerInterceptor类。

代码如下:

关于HandlerInterceptor的用法,参见SpringMVC官网地址:点击打开链接

public class LoginInterceptor extends HandlerInterceptorAdapter {    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {    if 验证不通过    return false;    return true;    }}
<bean id="loginInterceptor" class="LoginInterceptor"/><mvc:interceptors>    <mvc:interceptor>        <mvc:mapping path="/**"/>        <ref bean="loginInterceptor"/>    </mvc:interceptor></mvc:interceptors>


瞧,一个身份验证功能写好了。而且,该功能处于系统的最前端,像一层盔甲保护你的系统,无法登陆的用户压根到不了你的web层。那么问题来了,有一天,你的老板和你说:系统要完全公开,希望任何人可以访问;或者是验证登录的逻辑变了,怎么办呢?

当然不仅仅有这些场景,我想说的是这段代码不够松耦合,可插拔度太低。此时怎么办?

别忘了Spring的动态注入机制,现在的代码变成了下面的样子:


public class LoginInterceptor extends HandlerInterceptorAdapter {private InterceptorOne interceptorOne;        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {    if(!interceptorOne.check(request,response))    return false;    return true;    }        setter方法 }public class InterceptorOne{public boolean check(HttpServletRequest request, HttpServletResponse response){if(检验失败)return false;return true;}}


<bean id="loginInterceptor" class="LoginInterceptor" p:interceptorOne-ref="interceptorOne"/>  <bean id="interceptorOne" class="InterceptorOne"/>  <mvc:interceptors>      <mvc:interceptor>          <mvc:mapping path="/**"/>          <ref bean="loginInterceptor"/>      </mvc:interceptor>  </mvc:interceptors>


看出区别了吗?在第二种方式中,完全可以通过更改配置文件更换用于验证登录的类,比如有一个新的类MyInterceptor用于登录验证,直接配置xml文件如下即可:

<bean id="loginInterceptor" class="LoginInterceptor" p:interceptorOne-ref="myInterceptor"/><bean id="myInterceptor" class="MyInterceptor"/><mvc:interceptors>    <mvc:interceptor>        <mvc:mapping path="/**"/>        <ref bean="loginInterceptor"/>    </mvc:interceptor></mvc:interceptors>

上面的过程,你仅仅需要改一改xml文件,就可以动态的切换用于验证登录的类了,这就是笔者推崇的可插拔式设计。


先别急着高兴,现在问题又来了! 你的老大不但要求你做登录验证,还要求有黑名单验证,怎么办?上面的设计只能有一个拦截器,办法如下:

public class LoginInterceptor extends HandlerInterceptorAdapter {private List<AbstractInterceptor> interceptorList;        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {          while(AbstractInterceptor abstractInterceptor:interceptorList){              if(!abstractInterceptor.check(request, response))                   return false;    }    return true;    }        setter方法 }public interface AbstractInterceptor{boolean check(HttpServletRequest request, HttpServletResponse response);}public class InterceptorOne implements AbstractInterceptor{boolean check(HttpServletRequest request, HttpServletResponse response){if(登录不通过)return false;return true;}}public class InterceptorTwo implements AbstractInterceptor{boolean check(HttpServletRequest request, HttpServletResponse response){if(在黑名单中)return false;return true;}}

<bean id="loginInterceptor" class="LoginInterceptor" p:interceptorList-ref="interceptors"/><bean id="interceptorOne" class="InterceptorOne"/><bean id="interceptorTwo" class="InterceptorTwo"/><util:list class="ArrayList" id="interceptors"><ref bean="interceptorOne" /><ref bean="interceptorTwo" /></util><mvc:interceptors>    <mvc:interceptor>        <mvc:mapping path="/**"/>        <ref bean="loginInterceptor"/>    </mvc:interceptor></mvc:interceptors>

现在终于放心了,因为你再也不担心加需求了。因为你已经做到业务与框架的解耦了。不但如此,Spring的拦截器,允许自定义需要拦截的URI。


比如在上面黑名单的需求中,你希望/xxxx/**下的URI使用登录验证,/oooo/**下的URI使用黑名单验证,那么他的xml文件如下:

<bean id="xxxxInterceptor" class="LoginInterceptor" p:interceptorList-ref="xxxxInterceptors"/><bean id="ooooInterceptor" class="LoginInterceptor" p:interceptorList-ref="ooooInterceptors"/><bean id="interceptorOne" class="InterceptorOne"/><bean id="interceptorTwo" class="InterceptorTwo"/><util:list class="ArrayList" id="xxxxInterceptors"><ref bean="interceptorOne" /></util><util:list class="ArrayList" id="ooooInterceptors"><ref bean="interceptorTwo" /></util><mvc:interceptors>    <mvc:interceptor>        <mvc:mapping path="/xxxx/**"/>        <ref bean="xxxxInterceptor"/>    </mvc:interceptor>        <mvc:interceptor>    <mvc:mapping path="/oooo/**"/>    <ref bean="ooooInterceptor"/>    </mvc:interceptor></mvc:interceptors>

好了,关于这一节的内容就说完了。下面笔者来讲一讲为什么拒绝Filter,笔者讲这话的前提是你使用Spring框架。文章的开头说过,Filter是J2EE标准类,如果你用原始的J2EE标准编程的话,使用Filter无可厚非,但这是一个Spring的时代,不是吗?用Servlet类的毕竟是少数,而我希望这个少数越来越少。


期待更多的文章,就关注我吧!

觉得文章写得好的话,支付宝打赏一下吧!


代码详情,请参考我的github 点击打开链接





1 0