过滤器的主要目的是拦截每次请求之前和之后的一些操作。有别于 Servlet 标准过滤器,这是 MVC 框架中重写的过滤器。为简化概念,框架中不单独另设 AOP 机制,但可把过滤器当作 AOP 的代替品。其发挥如下作用:初始化数据库连接、日志记录、权限校验等等。
如下例子中注解 @MvcFilter
引入了数据库连接过滤器 DataBaseFilter,通过过滤器before()
方法在list()
执行之前调用了数据库连接的逻辑。除此之外,@Authority
也是过滤器注解,引入 PrivilegeFilter 实现权限的校验,注解的 value 属性是创建PrivilegeFilter 所必需的构造器参数。
@GET
@MvcFilter(filters = { DataBaseFilter.class })
@Authority(filter = PrivilegeFilter.class, value = RightConstant.ARTICLE_ONLINE)
public String list(@QueryParam(START) int start, @QueryParam(LIMIT) int limit) {
return page("article-list");
}
MvcFilter 的 filters 属性是 FilterAction 接口派生类的数组,类型为 Class<? extends FilterAction>[]
。当用户自定义过滤器时须实现 FilterAction 接口,给出before(FilterContext ctx)
与after(FilterAfterArgs ctx)
的实现。接口 FilterAction 源码如下。
package com.ajaxjs.web.mvc.filter;
/**
* 过滤器动作
*
* @author sp42 frank@ajaxjs.com
*/
public interface FilterAction {
/**
* 是异常但不记录到 FileHandler,例如密码错误之类的。放在 ModelAndView 中传递,例如
* model.put(NOT_LOG_EXCEPTION, true);
*/
public static final String NOT_LOG_EXCEPTION = "NOT_LOG_EXCEPTION";
/**
* 在 MVC 方法之前调用
*
* @return 是否要中止控制器方法的执行,true 表示为不中断
*/
public boolean before(FilterContext ctx);
/**
* 在 MVC 方法之后调用
*
* @param model 页面数据中间件
* @param request 请求对象
* @param response 响应对象
* @param method 方法对象
* @param isbeforeSkip 是否已经中止控制器方法的执行,也就是 before() 返回的值
* @return 是否要中止控制器方法默认返回的执行,一般返回 true 表示按原来的执行(大多数情况)
*/
public boolean after(FilterAfterArgs ctx);
}
FilterContext/FilterAfterArgs 均是前置/后置方法所需的参数列表,用户可按需调用。值得注意是方法的 boolean 类型返回值,决定了后续方法是否继续执行。前置方法before()
返回 true 是一般正常情况,控制器方法会继续执行;若before()
返回 false 或抛出异常会发生如下两件事:一、中止后续的过滤器执行;二、控制器方法不会执行。没有了控制器执行的结果,自然也不能按原流程返回结果给客户端。此时有两种分支可供用户选择:
1、后置方法after()
参数中的FilterAfterArgs.isbeforeSkip
属性就是前置方法为 false 时的状态,用户在after()
实现中应判断isbeforeSkip
而给出相应的 response 响应。2、如果想简单一点,可在before()
中抛出异常,那样控制器也会接受到异常进而转化为 response 响应输出(可兼容 HTML/JSON 格式)。后者的做法更简单直接一点。本来多数情况下,若前置方法不能满足,则后面的未执行逻辑亦无须执行,除非有需要进行特定情况的处理。
框架中内建若干实用的过滤器供用户使用,如下表所示,在com.ajaxjs.framework.filter.*
包和用户模块的com.ajaxjs.user.filter.*
。