我以为play的拦截器有点AOP的思想,至关于struts的filter,play的拦截器使用注解方式实现的。java
源码定义了这么几种注解:@before、@after、@catch、@finally 可谓是三百六十度无死角的拦截了。session
标注了@Before的方法会在该类的全部方法以前执行,举例:less
[java] view plaincopysocket
public class Admin extends Controller { 源码分析
@Before spa
static void checkAuthentification() { .net
if(session.get("user") == null) login(); 日志
} code
public static void index() { orm
List<User> users = User.findAll();
render(users);
}
…
}
当请求进入Admin时会先检查这个类中是否有@before注解,有就优先执行。
固然还有高级点的特性,若是您不想拦截某些方法,您能够使用unless代表,这样若是用户发来login的请求就不会执行@Before了,以下:
[java] view plaincopy
public class Admin extends Controller {
@Before(unless="login")
static void checkAuthentification() {
if(session.get("user") == null) login();
}
public static void index() {
List<User> users = User.findAll();
render(users);
}
…
}
一样,您也能够使用only属性,指定须要拦截的请求:
[java] view plaincopy
public class Admin extends Controller {
@Before(only={"login","logout"})
static void doSomething() {
…
}
…
}
@After注解的道理是同样的,不过是执行了请求方法以后执行
[java] view plaincopy
public class Admin extends Controller {
@After
static void log() {
Logger.info("Action executed ...");
}
public static void index() {
List<User> users = User.findAll();
render(users);
}
…
}
下面说说@Catch注解,这个很好用,当程序抛出异常时候能够被标注了@Catch的方法抓住,咱们能够在里面作一些必要的操做,好比rollback等。
[java] view plaincopy
public class Admin extends Controller {
@Catch(IllegalStateException.class)
public static void logIllegalState(Throwable throwable) {
Logger.error("Illegal state %s…", throwable);
}
public static void index() {
List<User> users = User.findAll();
if (users.size() == 0) {
throw new IllegalStateException("Invalid database - 0 users");
}
render(users);
}
}
对了,其中的prioroty属性能够设置执行顺序的优先级,priority=1是最早执行的。
[java] view plaincopy
public class Admin extends Controller {
@Catch(value = Throwable.class, priority = 1)
public static void logThrowable(Throwable throwable) {
// Custom error logging…
Logger.error("EXCEPTION %s", throwable);
}
@Catch(value = IllegalStateException.class, priority = 2)
public static void logIllegalState(Throwable throwable) {
Logger.error("Illegal state %s…", throwable);
}
public static void index() {
List<User> users = User.findAll();
if(users.size() == 0) {
throw new IllegalStateException("Invalid database - 0 users");
}
render(users);
}
}
@Finally注解的方法和java的finally同样,无论有没有执行成功都会进入该方法,咱们能够在里面打印日志:
[java] view plaincopy
public class Admin extends Controller {
@Finally
static void log(Throwable e) {
if( e == null ){
Logger.info("action call was successful");
} else{
Logger.info("action call failed", e);
}
}
public static void index() {
List<User> users = User.findAll();
render(users);
}
…
}
上述全部的注解做用域都是类级别的,若是您想对另外的类也起做用,请用@With标签:
[java] view plaincopy
public class Secure extends Controller {
@Before
static void checkAuthenticated() {
if(!session.containsKey("user")) {
unAuthorized();
}
}
}
@With(Secure.class)
public class Admin extends Controller {
…
}
实现的原理应该是这样:socket请求发过来的时候,play 的路由会去匹配进入哪一个Controller,而后看这个Controller里面有哪些系统标签,而后按规定好的执行顺序依次执行,这就是所谓的拦截了。(有时间把源码分析也一块儿发出来)
知道原理,咱们就能够写本身的拦截器了,好比权限管理:在每一个须要权限的方法上加上自定义的权限注解如:@MyAnatation(priority=1),用户发起请求——@Before拦截——从登陆token拿到用户信息——查看该用户全部权限ID——对比自定义注解的priority——priority在权限ID中则容许访问,不包含返回无此权限信息。
[java] view plaincopy
@Before(priority = 1)
public static void doAuth(){
Annotation annotation = request.invokedMethod.getAnnotation(MyAnotation.class);
if(annotation !=null){
//鉴权开始
QicFunction function = (QicFunction)annotation;
//todo
}
}
有了这种思想,咱们能够作任何自定义的拦截行为,谁也拦不住。
最后,要提醒本身,路漫漫其修远兮,吾将上下而求索。加油啊!